如何恢复 Linux 上删除的文件-ext4(1)
- UID
- 1066743
|
如何恢复 Linux 上删除的文件-ext4(1)
ext3 自从诞生之日起,就由于其可靠性好、特性丰富、性能高、版本间兼容性好等优势而迅速成为 Linux 上非常流行的文件系统,诸如 Redhat 等发行版都将 ext3 作为默认的文件系统格式。为了尽量保持与 ext2 文件系统实现更好的兼容性,ext3 在设计时采用了很多保守的做法,这些保守的设计为 ext3 赢得了稳定、健壮的声誉,迅速得到了 Linux 用户(尤其是原有的 ext2 文件系统的用户)的青睐,但同时这也限制了它的可扩展能力,无法支持特别大的文件系统。
随着硬盘存储容量越来越大(硬盘容量每年几乎都会翻一倍,现在市面上已经有 1TB 的硬盘出售,很快桌面用户也可以享用这么大容量的存储空间了),企业应用所需要和产生的数据越来越多(Lawrence Livermore National Labs 使用的 BlueGene/L 系统上所使用的数据早已超过了 1PB),以及在线重新调整大小特性的支持,ext3 所面临的可扩充性问题和性能方面的压力也越来越大。在 ext3 文件系统中,如果使用 4KB 大小的数据块,所支持的最大文件系统上限为16TB,这是由于它使用了 32 位的块号所决定的(232 * 212 B = 244 B = 16 TB)。为了解决这些限制,从 2006 年 8 月开始,陆续有很多为 ext3 设计的补丁发布出来,这些补丁主要是扩充了两个特性:针对大文件系统支持的设计和 extent 映射技术。不过要想支持更大的文件系统,就必须对磁盘上的存储格式进行修改,这会破坏向前兼容性。因此为了为庞大的 ext3 用户群维护更好的稳定性,设计人员决定从 ext3 中另辟一支,设计下一代 Linux 上的文件系统,即 ext4。
ext4 的主要目标是解决 ext3 所面临的可扩展性、性能和可靠性问题。从 2.6.19 版本的内核开始,ext4 已经正式进入内核源代码中,不过它被标记为正在开发过程中,即 ext4dev。本文将介绍 ext4 为了支持更好的可扩展性方面所采用的设计,并探讨由此而引起的磁盘数据格式的变化,以及对恢复删除文件所带来的影响。
可扩展性为了支持更大的文件系统,ext4 决定采用 48 位的块号取代 ext3 原来的 32 位块号,并采用 extent 映射来取代 ext3 所采用的间接数据块映射的方法。这样既可以增大文件系统的容量,又可以改进大文件的访问效率。在使用 4KB 大小的数据块时,ext4 可以支持最大 248 * 212 = 260 B(1 EB)的文件系统。之所以采用 48 位的块号而不是直接将其扩展到 64 位是因为,ext4 的开发者认为 1 EB 大小的文件系统对未来很多年都足够了(实际上,按照目前的速度,要对 1 EB 大小的文件系统执行一次完整的 fsck 检查,大约需要 119 年的时间),与其耗费心机去完全支持 64 位的文件系统,还不如先花些精力来解决更加棘手的可靠性问题。
将块号从 32 位修改为 48 位之后,存储元数据的结构都必须相应地发生变化,主要包括超级块、组描述符和日志。下面给出了 ext4 中所使用的新结构的部分代码。
清单1. ext4_super_block 结构定义1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| 520 /*
521 * Structure of the super block
522 */
523 struct ext4_super_block {
524 /*00*/ __le32 s_inodes_count; /* Inodes count */
525 __le32 s_blocks_count; /* Blocks count */
526 __le32 s_r_blocks_count; /* Reserved blocks count */
527 __le32 s_free_blocks_count; /* Free blocks count */
528 /*10*/ __le32 s_free_inodes_count; /* Free inodes count */
529 __le32 s_first_data_block; /* First Data Block */
530 __le32 s_log_block_size; /* Block size */
…
594 /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
595 /*150*/ __le32 s_blocks_count_hi; /* Blocks count */
596 __le32 s_r_blocks_count_hi; /* Reserved blocks count */
597 __le32 s_free_blocks_count_hi; /* Free blocks count */
…
606 };
|
在 ext4_super_block 结构中,增加了 3 个与此相关的字段:s_blocks_count_hi、s_r_blocks_count_hi、s_free_blocks_count_hi,它们分别表示 s_blocks_count、s_r_blocks_count、s_free_blocks_count 高 32 位的值,将它们扩充到 64 位。
清单2. ext4_group_desc 结构定义1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| 121 /*
122 * Structure of a blocks group descriptor
123 */
124 struct ext4_group_desc
125 {
126 __le32 bg_block_bitmap; /* Blocks bitmap block */
127 __le32 bg_inode_bitmap; /* Inodes bitmap block */
128 __le32 bg_inode_table; /* Inodes table block */
129 __le16 bg_free_blocks_count; /* Free blocks count */
130 __le16 bg_free_inodes_count; /* Free inodes count */
131 __le16 bg_used_dirs_count; /* Directories count */
132 __u16 bg_flags;
133 __u32 bg_reserved[3];
134 __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */
135 __le32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */
136 __le32 bg_inode_table_hi; /* Inodes table block MSB */
137 };
|
类似地,在 ext4_group_desc 中引入了另外 3 个字段:bg_block_bitmap_hi、bg_inode_bitmap_hi、bg_inode_table_hi,分别表示 bg_block_bitmap、bg_inode_bitmap、bg_inode_table 的高 32 位。
另外,由于日志中要记录所修改数据块的块号,因此 JBD也需要相应地支持 48 位的块号。同样是为了为 ext3 广大的用户群维护更好的稳定性,JBD2 也从 JBD 中分离出来,详细实现请参看内核源代码。
采用 48 位块号取代原有的 32 位块号之后,文件系统的最大值还受文件系统中最多块数的制约,这是由于 ext3 原来采用的结构决定的。回想一下,对于 ext3 类型的分区来说,在每个分区的开头,都有一个引导块,用来保存引导信息;文件系统的数据一般从第 2 个数据块开始(更确切地说,文件系统数据都是从 1KB 之后开始的,对于 1024 字节大小的数据块来说,就是从第 2 个数据块开始;对于超过 1KB 大小的数据块,引导块与后面的超级块等信息共同保存在第 1 个数据块中,超级块从 1KB 之后的位置开始)。为了管理方便,文件系统将剩余磁盘划分为一个个块组。块组前面存储了超级块、块组描述符、数据块位图、索引节点位图、索引节点表,然后才是数据块。通过有效的管理,ext2/ext3 可以尽量将文件的数据放入同一个块组中,从而实现文件数据在磁盘上的最大连续性。
在 ext3 中,为了安全性方面的考虑,所有的块描述符信息全部被保存到第一个块组中,因此以缺省的 128MB (227 B)大小的块组为例,最多能够支持 227 / 32 = 222 个块组,最大支持的文件系统大小为 222 * 227 = 249 B= 512 TB。而ext4_group_desc 目前的大小为 44 字节,以后会扩充到 64 字节,所能够支持的文件系统最大只有 256 TB。
为了解决这个问题,ext4 中采用了元块组(metablock group)的概念。所谓元块组就是指块组描述符可以存储在一个数据块中的一些连续块组。仍然以 128MB 的块组(数据块为 4KB)为例,ext4 中每个元块组可以包括 4096 / 64 = 64 个块组,即每个元块组的大小是 64 * 128 MB = 8 GB。
采用元块组的概念之后,每个元块组中的块组描述符都变成定长的,这对于文件系统的扩展非常有利。原来在 ext3 中,要想扩大文件系统的大小,只能在第一个块组中增加更多块描述符,通常这都需要重新格式化文件系统,无法实现在线扩容;另外一种可能的解决方案是为块组描述符预留一部分空间,在增加数据块时,使用这部分空间来存储对应的块组描述符;但是这样也会受到前面介绍的最大容量的限制。而采用元块组概念之后,如果需要扩充文件系统的大小,可以在现有数据块之后新添加磁盘数据块,并将这些数据块也按照元块组的方式进行管理即可,这样就可以突破文件系统大小原有的限制了。当然,为了使用这些新增加的空间,在 superblock 结构中需要增加一些字段来记录相关信息。(ext4_super_block 结构中增加了一个 s_first_meta_bg 字段用来引用第一个元块组的位置,这样还可以解决原有块组和新的元块组共存的问题。)下图给出了 ext3 为块组描述符预留空间和在 ext4 中采用元块组后的磁盘布局。
图 1. ext3 与 ext4 磁盘布局对比 |
|
|
|
|
|