ext2、ext3、ext4、brtfs文件系统区别
EXT2
EXT2是second extended file system的简写。这个文件最早的目的是取代minix文件系统。开发于1993年。在设计之初没有提供journal的功能。
EXT2的磁盘分布
在ext2文件系统中,硬盘分区首先被划分为一个个的 block,一个 ext2 文件系统上的每个 block 都是一样大小的,但是对于不同的 ext2 文件系统,block 的大小可以有区别。典型的 block 大小是 1024 bytes 或者 4096 bytes。这个大小在创建 ext2 文件系统的时候被决定。
这些 blocks 被聚在一起分成几个大的 block group。每个 block group 中有多少个block 是固定的。
每个 block group 都相对应一个 group descriptor,这些 group descriptor 被聚在一起放在硬盘分区的开头部分,跟在 super block 的后面。在这个 descriptor 当中有几个重要的 block 指针。一个硬盘分区上的 block 计数是从 0 开始的,并且这个计数对于这个硬盘分区来说是全局性质的。
在 block group 的 group descriptor 中,其中有一个 block 指针指向这个 block group 的 block bitmap,block bitmap 中的每个 bit 表示一个 block,如果该 bit 为 0,表示该 block 中有数据,如果 bit 为 1,则表示该 block 是空闲的。
这个 block bitmap 只占用一个block。假设 block 大小为 S bytes,那么 block bitmap 当中只能记载 8*S 个 block 的情况。一个 block group 最多只能有 8*S*S bytes 这么大。
在 block group 的 group descriptor 中另有一个 block 指针指向 inode bitmap,这个 bitmap 同样也是正好有一个 block 那么大,里面的每一个 bit 相对应一个 inode。硬盘上的一个 inode 大体上相对应于文件系统上的一个文件或者目录。关于 inode,我们下面还要进一步讲到。
在 block group 的 descriptor 中另一个重要的 block 指针,是指向的 inode table。这个 inode table 就不止一个 block 那么大了。这个 inode table 就是这个 block group 中所聚集到的全部 inode 放在一起形成的。
SuperBlock
ext2 文件系统的 super block,就是硬盘分区开头(开头的第一个 byte 是 byte 0)从 byte 1024 开始往后的一部分数据。由于 block size 最小是 1024 bytes,所以 super block 可能是在 block 1 中(此时 block 的大小正好是 1024 bytes),也可能是在 block 0 中。
下面是superblock的数据结构。
struct ext2_super_block {
__le32 s_inodes_count; /* Inodes count */
__le32 s_blocks_count; /* Blocks count */
__le32 s_r_blocks_count; /* Reserved blocks count */
__le32 s_free_blocks_count; /* Free blocks count */
__le32 s_free_inodes_count; /* Free inodes count */
__le32 s_first_data_block; /* First Data Block */
__le32 s_log_block_size; /* Block size */
__le32 s_log_frag_size; /* Fragment size */
__le32 s_blocks_per_group; /* # Blocks per group */
__le32 s_frags_per_group; /* # Fragments per group */
__le32 s_inodes_per_group; /* # Inodes per group */
__le32 s_mtime; /* Mount time */
__le32 s_wtime; /* Write time */
__le16 s_mnt_count; /* Mount count */
__le16 s_max_mnt_count; /* Maximal mount count */
__le16 s_magic; /* Magic signature */
__le16 s_state; /* File system state */
__le16 s_errors; /* Behaviour when detecting errors */
__le16 s_minor_rev_level; /* minor revision level */
__le32 s_lastcheck; /* time of last check */
__le32 s_checkinterval; /* max. time between checks */
__le32 s_creator_os; /* OS */
__le32 s_rev_level; /* Revision level */
__le16 s_def_resuid; /* Default uid for reserved blocks */
__le16 s_def_resgid; /* Default gid for reserved blocks */
/*
* These fields are for EXT2_DYNAMIC_REV superblocks only.
*
* Note: the difference between the compatible feature set and
* the incompatible feature set is that if there is a bit set
* in the incompatible feature set that the kernel doesn't
* know about, it should refuse to mount the filesystem.
*
* e2fsck's requirements are more strict; if it doesn't know
* about a feature in either the compatible or incompatible
* feature set, it must abort and not try to meddle with
* things it doesn't understand...
*/
__le32 s_first_ino; /* First non-reserved inode */
__le16 s_inode_size; /* size of inode structure */
__le16 s_block_group_nr; /* block group # of this superblock */
__le32 s_feature_compat; /* compatible feature set */
__le32 s_feature_incompat; /* incompatible feature set */
__le32 s_feature_ro_compat; /* readonly-compatible feature set */
__u8 s_uuid[16]; /* 128-bit uuid for volume */
char s_volume_name[16]; /* volume name */
char s_last_mounted[64]; /* directory where last mounted */
__le32 s_algorithm_usage_bitmap; /* For compression */
/*
* Performance hints. Directory preallocation should only
* happen if the EXT2_COMPAT_PREALLOC flag is on.
*/
__u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
__u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
__u16 s_padding1;
/*
* Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
*/
__u8 s_journal_uuid[16]; /* uuid of journal superblock */
__u32 s_journal_inum; /* inode number of journal file */
__u32 s_journal_dev; /* device number of journal file */
__u32 s_last_orphan; /* start of list of inodes to delete */
__u32 s_hash_seed[4]; /* HTREE hash seed */
__u8 s_def_hash_version; /* Default hash version to use */
__u8 s_reserved_char_pad;
__u16 s_reserved_word_pad;
__le32 s_default_mount_opts;
__le32 s_first_meta_bg; /* First metablock block group */
__u32 s_reserved[190]; /* Padding to the end of the block */
};
super block 一共有 1024 bytes 那么大。在 super block 中,我们第一个要关心的字段是 magic 签名,EXT3的对应字段的值应该正好等于 0xEF53。
在 super block 中另一个重要的字段是 s_log_block_size。从这个字段,我们可以得出真正的 block 的大小。我们把真正 block 的大小记作 B,B = 1 << (s_log_block_size + 10),单位是 bytes。举例来说,如果这个字段是 0,那么 block 的大小就是 1024 bytes,这正好就是最小的 block 大小;如果这个字段是 2,那么 block 大小就是 4096 bytes。从这里我们就得到了 block 的大小这一非常重要的数据
GroupDescription
而 group descriptors 是从 super block 后面的第一个 block 开始。那么硬盘分区上一共有多少个 block group,或者说一共有多少个 group descriptors,这我们要在 super block 中找答案。super block 中的 s_blocks_count 记录了硬盘分区上的 block 的总数,而 s_blocks_per_group 记录了每个 group 中有多少个 block。
知道了硬盘分区上一共有多少个 block group,我们就可以把这么多个 group descriptors 读出来了。先来看看 group descriptor 是什么样子的。
除了superblock之外,需要介绍的是块组描述符group descriptor, 他提供了块组中的块位图 block bitmap,inode的位图和inode table的起始块等信息。
/*
* Structure of a blocks group descriptor
*/
struct ext2_group_desc
{
__le32 bg_block_bitmap; /* Blocks bitmap block */
__le32 bg_inode_bitmap; /* Inodes bitmap block */
__le32 bg_inode_table; /* Inodes table block */
__le16 bg_free_blocks_count; /* Free blocks count */
__le16 bg_free_inodes_count; /* Free inodes count */
__le16 bg_used_dirs_count; /* Directories count */
__le16 bg_pad;
__le32 bg_reserved[3];
};
inode
另一个重要的数据结构是ext2 inode, 就是所谓的ext2索引节点。这个inode和kernel中的vfs的inode是不完全一样的。Ext2 inode决定了如何把物理磁盘上的数据块组织成为文件。
前面都准备好了以后,我们现在终于可以开始读取文件了。首先要读的,当然是文件系统的根目录。注意,这里所谓的根目录,是相对于这一个文件系统或者说硬盘分区而言的,它并不一定是整个 Linux 操作系统上的根目录。这里的这个 root 目录存放在一个固定的 inode 中,这就是文件系统上的 inode 2。需要提到 inode 计数同 block 计数一样,也是全局性质的。这里需要特别注意的是,inode 计数是从 1 开始的,而前面我们提到过 block 计数是从 0 开始,这个不同在开发程序的时候要特别留心。(这一奇怪的 inode 计数方法,曾经让本文作者大伤脑筋。)
那么,我们先来看一下得到一个 inode 号数以后,怎样读取这个 inode 中的用户数据。在 super block 中有一个字段 s_inodes_per_group 记载了每个 block group 中有多少个 inode。用我们得到的 inode 号数除以 s_inodes_per_group,我们就知道了我们要的这个 inode 是在哪一个 block group 里面,这个除法的余数也告诉我们,我们要的这个 inode 是这个 block group 里面的第几个 inode;然后,我们可以先找到这个 block group 的 group descriptor,从这个 descriptor,我们找到这个 group 的 inode table,再从 inode table 找到我们要的第几个 inode,再以后,我们就可以开始读取 inode 中的用户数据了。
这个公式是这样的:block_group = (ino - 1) / s_inodes_per_group。这里 ino 就是我们的 inode 号数。而 offset = (ino - 1) % s_inodes_per_group,这个 offset 就指出了我们要的 inode 是这个 block group 里面的第几个 inode。
找到这个 inode 之后,我们来具体的看看 inode 是什么样的。
/*
* Structure of an inode on the disk
*/
struct ext2_inode {
__le16 i_mode; /* File mode */
__le16 i_uid; /* Low 16 bits of Owner Uid */
__le32 i_size; /* Size in bytes */
__le32 i_atime; /* Access time */
__le32 i_ctime; /* Creation time */
__le32 i_mtime; /* Modification time */
__le32 i_dtime; /* Deletion Time */
__le16 i_gid; /* Low 16 bits of Group Id */
__le16 i_links_count; /* Links count */
__le32 i_blocks; /* Blocks count */
__le32 i_flags; /* File flags */
union {
struct {
__le32 l_i_reserved1;
} linux1;
struct {
__le32 h_i_translator;
} hurd1;
struct {
__le32 m_i_reserved1;
} masix1;
} osd1; /* OS dependent 1 */
__le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
__le32 i_generation; /* File version (for NFS) */
__le32 i_file_acl; /* File ACL */
__le32 i_dir_acl; /* Directory ACL */
__le32 i_faddr; /* Fragment address */
union {
struct {
__u8 l_i_frag; /* Fragment number */
__u8 l_i_fsize; /* Fragment size */
__u16 i_pad1;
__le16 l_i_uid_high; /* these 2 fields */
__le16 l_i_gid_high; /* were reserved2[0] */
__u32 l_i_reserved2;
} linux2;
struct {
__u8 h_i_frag; /* Fragment number */
__u8 h_i_fsize; /* Fragment size */
__le16 h_i_mode_high;
__le16 h_i_uid_high;
__le16 h_i_gid_high;
__le32 h_i_author;
} hurd2;
struct {
__u8 m_i_frag; /* Fragment number */
__u8 m_i_fsize; /* Fragment size */
__u16 m_pad1;
__u32 m_i_reserved2[2];
} masix2;
} osd2; /* OS dependent 2 */
};
正如前面已经提到的,inode 只在超级块中唯一编号,且每个分区只有一个超级块,这就是硬链接无法跨越多个分区的原因。
通过对以上内容的了解,可以看出,EXT2会有如下逻辑块结构。inode中有数据结构i_block[EXT2_N_BLOCKS], 其中前12个指针指到数据块,第 13 个 block,也就是所谓的 indirect block,里面存放的全部是 block 指针,这些 block 指针指向的 block 才被用来存放用户数据。第 14 个 block 是所谓的 double indirect block,里面存放的全是 block 指针,这些 block 指针指向的 block 也被全部用来存放 block 指针,而这些 block 指针指向的 block,才被用来存放用户数据。第 15 个 block 是所谓的 triple indirect block,比上面说的 double indirect block 有多了一层 block 指针。
在indirect block中,由于每个指针的长度是32bit, 即4个byte. 所以一个4096B的数据块可以包含1024个指针。
因为这个结构,可以计算出,如果文件系统的block大小为1024B, 那么最大的当个文件可以到达16GB,12*1024+(1024/4)*1024+(1024/4)*1024/4*1024+(1024/4)*1024/4*1024/4*1024=17247252480=16GB
Theoretical ext2 filesystem limits under Linux
Block size: 1 KiB 2 KiB 4 KiB 8 KiB
max. file size: 16 GiB 256 GiB 2 TiB 64 TiB
max. filesystem size: 2 TiB 8 TiB 16 TiB 32 TiB
由于各个架构上的限制,在i386结构上,ext3文件只能达到2TB, 而且不支持8k的页面。 由于系统调用的限制,有些应用程序不能支持大于2GB文件的读写。
Ext3(Third extended file system)
Ext3是一种日志式文件系统,是对ext2系统的扩展,它兼容ext2。日志式文件系统的优越性在于:由于文件系统都有快取层参与运作,如不使用时必须将文件系统卸下,以便将快取层的资料写回磁盘中。因此每当系统要关机时,必须将其所有的文件系统全部shutdown后才能进行关机。如果在文件系统尚未shutdown前就关机如(停电)时,下次重开机后会造成文件系统的资料不一致,故这时必须做文件系统的重整工作,将不一致与错误的地方修复。然而,此一重整的工作是相当耗时的,特别是容量大的文件系统,而且也不能百分之百保证所有的资料都不会流失。 为了克服此问题,使用所谓“日志式文件系统 (Journal File System)” 。此类文件系统最大的特色是,它会将整个磁盘的写入动作完整记录在磁盘的某个区域上,以便有需要时可以回溯追踪。 由于资料的写入动作包含许多的细节,像是改变文件标头资料、搜寻磁盘可写入空间、一个个写入资料区段等等,每一个细节进行到一半若被中断,就会造成文件系统的不一致,因而需要重整。 然而,在日志式文件系统中,由于详细纪录了每个细节,故当在某个过程中被中断时,系统可以根据这些记录直接回溯并重整被中断的部分,而不必花时间去检查其他的部分,故重整的工作速度相当快,几乎不需要花时间。Ext3日志文件系统特点
1、高可用性 系统使用了ext3文件系统后,即使在非正常关机后,系统也不需要检查文件系统。宕机发生后,恢复ext3文件系统的时间只要数十秒钟。 2、数据的完整性 ext3文件系统能够极大地提高文件系统的完整性,避免了意外宕机对文件系统的破坏。在保证数据完整性方面,ext3文件系统有2种模式可供选择。其中之一就是“同时保持文件系统及数据的一致性”模式。采用这种方式,你永远不再会看到由于非正常关机而存储在磁盘上的垃圾文件。 3、文件系统的速度 尽管使用ext3文件系统时,有时在存储数据时可能要多次写数据,但是,从总体上看来,ext3比ext2的性能还要好一些。这是因为ext3的日志功能对磁盘的驱动器读写头进行了优化。所以,文件系统的读写性能较之Ext2文件系统并来说,性能并没有降低。 4、数据转换 [1]由ext2文件系统转换成ext3文件系统非常容易,只要简单地键入两条命令即可完成整个转换过程,用户不用花时间备份、恢复、格式化分区等。用一个ext3文件系统提供的小工具tune2fs,它可以将ext2文件系统轻松转换为ext3日志文件系统。另外,ext3文件系统可以不经任何更改,而直接加载成为ext2文件系统。 5、多种日志模式 Ext3有多种日志模式,一种工作模式是对所有的文件数据及metadata(定义文件系统中数据的数据,即数据的数据)进行日志记录(data=journal模式);另一种工作模式则是只对metadata记录日志,而不对数据进行日志记录,也即所谓data=ordered或者data=writeback模式。系统管理人员可以根据系统的实际工作要求,在系统的工作速度与文件数据的一致性之间作出选择。[2]Ext3概述
开发商:开放源代码 全称:Third extended file system 发布时间:2001年11月(Linux 2.4.15) 分区标识:0x83 (MBR);EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 (GPT)Ext3结构
目录内容:表, 树 文件分配:位图(空闲区域),表(元数据) 坏块:表限制
最大文件大小:16GB – 64TB 最大文件数量:可变 最长文件名限制:255字节 最大卷大小:2TB – 32TB 文件名允许的字符数: 除NUL和'/'外的所有字节功能
记录日期:修改(mtime), 属性修改 (ctime), 访问(atime) 日期范围:1901年12月14日——2038年1月18日 日期分辨率:1秒 岔流:是 属性:No-atime, append-only, synchronous-write, no-dump, h-tree (directory), immutable, journal, secure-delete, top (directory), allow-undelete 访问权限:Unix权限,ACLs和arbitrary security attributes (Linux 2.6 and later) 透明压缩:否 透明加密:否(块设备级上提供) 支持操作系统:Linux、BSD、Windows (通过 IFS)反删除
和ext2不同,ext3会在删除文件时把文件的节点(inode)中的块指标清除。这样做可以在unclean载入文件系统后,重放日志时,可以减少对文件系统的访问。但也同样了文件在反删除上面的困难。用户唯一的补救是在硬盘中捞取数据,并且要知道文件的起始到结束的块指标。尽管提供了比ext2在删除文件上稍微高一些的安全性,却也无可避免的带来了不便之处。 Ext4(The fourth extended file system) Ext4是一种针对ext3系统的扩展日志式文件系统,是专门为 Linux 开发的原始的扩展文件系统(ext 或 extfs)的第四版。 Linux kernel 自 2.6.28 开始正式支持新的文件系统 Ext4。 Ext4 是 Ext3 的改进版,修改了 Ext3 中部分重要的数据结构,而不仅仅像 Ext3 对 Ext2 那样,只是增加了一个日志功能而已。Ext4 可以提供更佳的性能和可靠性,还有更为丰富的功能。相对于Ext3,特点如下:1. 与 Ext3 兼容。 执行若干条命令,就能从 Ext3 在线迁移到 Ext4,而无须重新格式化磁盘或重新安装系统。原有 Ext3数据结构照样保留,Ext4 作用于新数据,当然,整个文件系统因此也就获得了 Ext4 所支持的更大容量。2. 更大的文件系统和更大的文件。 较之 Ext3 目前所支持的最大 16TB 文件系统和最大 2TB 文件,Ext4 分别支持 1EB(1,048,576TB, 1EB=1024PB, 1PB=1024TB)的文件系统,以及 16TB 的文件。3. 无限数量的子目录。 Ext3 目前只支持 32,000 个子目录,而 Ext4 支持无限数量的子目录。4. Extents。 Ext3 采用间接块映射,当操作大文件时,效率极其低下。比如一个 100MB 大小的文件,在 Ext3 中要建立 25,600 个数据块(每个数据块大小为 4KB)的映射表。而 Ext4 引入了现代文件系统中流行的 extents 概念,每个 extent 为一组连续的数据块,上述文件则表示为“该文件数据保存在接下来的 25,600 个数据块中”,提高了不少效率。5. 多块分配。 当 写入数据到 Ext3 文件系统中时,Ext3 的数据块分配器每次只能分配一个 4KB 的块,写一个 100MB 文件就要调用 25,600 次数据块分配器,而 Ext4 的多块分配器“multiblock allocator”(mballoc) 支持一次调用分配多个数据块。6. 延迟分配。 Ext3 的数据块分配策略是尽快分配,而 Ext4 和其它现代文件操作系统的策略是尽可能地延迟分配,直到文件在 cache 中写完才开始分配数据块并写入磁盘,这样就能优化整个文件的数据块分配,与前两种特性搭配起来可以显著提升性能。7. 快速 fsck。 以前执行 fsck 第一步就会很慢,因为它要检查所有的 inode,现在 Ext4 给每个组的 inode 表中都添加了一份未使用 inode 的列表,今后 fsck Ext4 文件系统就可以跳过它们而只去检查那些在用的 inode 了。8. 日志校验。 日志是最常用的部分,也极易导致磁盘硬件故障,而从损坏的日志中恢复数据会导致更多的数据损坏。Ext4 的日志校验功能可以很方便地判断日志数据是否损坏,而且它将 Ext3 的两阶段日志机制合并成一个阶段,在增加安全性的同时提高了性能。9. “无日志”(No Journaling)模式。 日志总归有一些开销,Ext4 允许关闭日志,以便某些有特殊需求的用户可以借此提升性能。10. 在线碎片整理。 尽管延迟分配、多块分配和 extents 能有效减少文件系统碎片,但碎片还是不可避免会产生。Ext4 支持在线碎片整理,并将提供 e4defrag 工具进行个别文件或整个文件系统的碎片整理。11. inode 相关特性。 Ext4 支持更大的 inode,较之 Ext3 默认的 inode 大小 128 字节,Ext4 为了在 inode 中容纳更多的扩展属性(如纳秒时间戳或 inode 版本),默认 inode 大小为 256 字节。Ext4 还支持快速扩展属性(fast extended attributes)和 inode 保留(inodes reservation)。12. 持久预分配(Persistent preallocation)。 P2P 软件为了保证下载文件有足够的空间存放,常常会预先创建一个与所下载文件大小相同的空文件,以免未来的数小时或数天之内磁盘空间不足导致下载失败。 Ext4 在文件系统层面实现了持久预分配并提供相应的 API(libc 中的 posix_fallocate()),比应用软件自己实现更有效率。13. 默认启用 barrier。 磁 盘上配有内部缓存,以便重新调整批量数据的写操作顺序,优化写入性能,因此文件系统必须在日志数据写入磁盘之后才能写 commit 记录,若 commit 记录写入在先,而日志有可能损坏,那么就会影响数据完整性。Ext4 默认启用 barrier,只有当 barrier 之前的数据全部写入磁盘,才能写 barrier 之后的数据。(可通过 "mount -o barrier=0" 命令禁用该特性。)如何使用Ext4
目前的Ext4文件系统是第一个稳定版本,整个的开发进度和发布计划都被放缓了,就是为了保证用户可以享受到“和使用Ext3同等级”的稳定。一个非常重要的事情是,目前还没有Ext4 Grub。更准确的说,就是目前没有grub支持ext4。换句话说,就是你目前的发行版本的grub不支持ext4。目前我们的Grub2正在开发之中,在ubuntu和debian发行版中已经有了grub2的grub-pc软件包了,但是目前官方仍没有宣布正式支持。在Google SoC中也包含了一个开发版本,且发布了相关补丁。你可以试用一下,你自己选择喽。在你的发行版本的下一个新版本之中,可能会有相关的支持出现。所以安全起见,尽量保持你的/boot目录为Ext3文件系统类型。警告归警告,转换到Ext4其实是件很容易的事情,如下方法均可:1 建立一个全新的Ext4文件系统。这是最简单的方法,你只需要升级你的e2fsprogs到Ext4,并且使用mkfs.ext4命令创建文件系统即可。2 从Ext3迁移到Ext4。你需要使用tune2fs命令和fsck命令,并且当前文件系统需要被卸载才可以。运行命令tune2fs -O extents,uninit_bg,dir_index /dev/yourfilesystem此后,你务必运行fsck命令,否则Ext4将无法挂载你的新文件系统。在fsck过程中,可能会有一些error需要你的确认。你可以考虑使用 -p选项,来告诉fsck你想要的是“automatic repair”,即fsck -pf /dev/yourfilesystem3 使用Ext4来挂载一个Ext3文件系统。你可以使用mount -t ext4 /dev/yourpartition /mnt来将一个Ext3文件系统用Ext4来挂载,但你将享受不到那些需要改变磁盘格式才可以享受得到的特性,比如Extents。你可以享受到的只有 那些不需要改变磁盘格式即可享受得到的特性,比如多块分配、延迟分配等。我们当然不建议您这么做,因为Ext4的优秀特性,您将无法体会。