Board logo

标题: 如何恢复 Linux 上删除的文件-ext4(2) [打印本页]

作者: look_w    时间: 2018-5-22 15:47     标题: 如何恢复 Linux 上删除的文件-ext4(2)

extentext2/ext3 文件系统与大部分经典的 UNIX/Linux 文件系统一样,都使用了直接、间接、二级间接和三级间接块的形式来定位磁盘中的数据块。对于小文件或稀疏文件来说,这非常有效(以 4KB 大小的数据块为例,小于 48KB 的文件只需要通过索引节点中 i_block 数组的前 12 个元素一次定位即可),但是对于大文件来说,需要经过几级间接索引,这会导致在这些文件系统上大文件的性能较差。
测试表明,在生产环境中,数据不连续的情况不会超过10%。因此,在 ext4 中引入了 extent 的概念来表示文件数据所在的位置。所谓 extent 就是描述保存文件数据使用的连续物理块的一段范围。每个 extent 都是一个 ext4_extent 类型的结构,大小为 12 字节。定义如下所示:
清单3. ext4 文件系统中有关 extent 的结构定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
69 /*
70  * This is the extent on-disk structure.
71  * It's used at the bottom of the tree.
72  */
73 struct ext4_extent {
74         __le32  ee_block;       /* first logical block extent covers */
75         __le16  ee_len;         /* number of blocks covered by extent */
76         __le16  ee_start_hi;    /* high 16 bits of physical block */
77         __le32  ee_start;       /* low 32 bits of physical block */
78 };
79
80 /*
81  * This is index on-disk structure.
82  * It's used at all the levels except the bottom.
83  */
84 struct ext4_extent_idx {
85         __le32  ei_block;       /* index covers logical blocks from 'block' */
86         __le32  ei_leaf;        /* pointer to the physical block of the next *
87                                  * level. leaf or next index could be there */
88         __le16  ei_leaf_hi;     /* high 16 bits of physical block */
89         __u16   ei_unused;
90 };
91
92 /*
93  * Each block (leaves and indexes), even inode-stored has header.
94  */
95 struct ext4_extent_header {
96         __le16  eh_magic;       /* probably will support different formats */
97         __le16  eh_entries;     /* number of valid entries */
98         __le16  eh_max;         /* capacity of store in entries */
99         __le16  eh_depth;       /* has tree real underlying blocks? */
100         __le32  eh_generation;  /* generation of the tree */
101 };
102
103 #define EXT4_EXT_MAGIC          cpu_to_le16(0xf30a)




每个 ext4_extent 结构可以表示该文件从 ee_block 开始的 ee_len 个数据块,它们在磁盘上的位置是从 ee_start_hi<<32 + ee_start 开始,到 ee_start_hi<<32 + ee_start + ee_len – 1 结束,全部都是连续的。尽管 ee_len 是一个 16 位的无符号整数,但是其最高位被在预分配特性中用来标识这个 extent 是否被初始化过了,因此可以一个 extent 可以表示 215 个连续的数据块,如果采用 4KB 大小的数据块,就相当于 128MB。
如果文件大小超过了一个 ext4_extent 结构能够表示的范围,或者其中有不连续的数据块,就需要使用多个 ext4_extent 结构来表示了。为了解决这个问题,ext4 文件系统的设计者们采用了一棵 extent 树结构,它是一棵高度固定的树,其布局如下图所示:
图 2. ext4 中 extent 树的布局结构在 extent 树中,节点一共有两类:叶子节点和索引节点。保存文件数据的磁盘块信息全部记录在叶子节点中;而索引节点中则存储了叶子节点的位置和相对顺序。不管是叶子节点还是索引节点,最开始的 12 个字节总是一个 ext4_extent_header 结构,用来标识该数据块中有效项(ext4_extent 或 ext4_extent_idx 结构)的个数(eh_entries 域的值),其中 eh_depth 域用来表示它在 extent 树中的位置:对于叶子节点来说,该值为 0,之上每层索引节点依次加 1。extent 树的根节点保存在索引节点结构中的 i_block 域中,我们知道它是一个大小为 60 字节的数组,最多可以保存一个 ext4_extent_header 结构以及 4 个 ext4_extent 结构。对于小文件来说,只需要一次寻址就可以获得保存文件数据块的位置;而超出此限制的文件(例如很大的文件、碎片非常多的文件以及稀疏文件)只能通过遍历 extent 树来获得数据块的位置。
索引节点索引节点是 ext2/ext3/ext4 文件系统中最为基本的一个概念,它是文件语义与数据之间关联的桥梁。为了最大程度地实现向后兼容性,ext4 尽量保持索引节点不会发生太大变化。ext4_inode 结构定义如下所示:
清单4. ext4_inode 结构定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
284 /*
285  * Structure of an inode on the disk
286  */
287 struct ext4_inode {
288         __le16  i_mode;         /* File mode */
289         __le16  i_uid;          /* Low 16 bits of Owner Uid */
290         __le32  i_size;         /* Size in bytes */
291         __le32  i_atime;        /* Access time */
292         __le32  i_ctime;        /* Inode Change time */
293         __le32  i_mtime;        /* Modification time */
294         __le32  i_dtime;        /* Deletion Time */
295         __le16  i_gid;          /* Low 16 bits of Group Id */
296         __le16  i_links_count;  /* Links count */
297         __le32  i_blocks;       /* Blocks count */
298         __le32  i_flags;        /* File flags */

310         __le32  i_block[EXT4_N_BLOCKS];/* Pointers to blocks */
311         __le32  i_generation;   /* File version (for NFS) */
312         __le32  i_file_acl;     /* File ACL */
313         __le32  i_dir_acl;      /* Directory ACL */
314         __le32  i_faddr;        /* Fragment address */

339         __le16  i_extra_isize;
340         __le16  i_pad1;
341         __le32  i_ctime_extra;  /* extra Change time      (nsec << 2 | epoch) */
342         __le32  i_mtime_extra;  /* extra Modification time(nsec << 2 | epoch) */
343         __le32  i_atime_extra;  /* extra Access time      (nsec << 2 | epoch) */
344         __le32  i_crtime;       /* File Creation time */
345         __le32  i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
346 };




与 ext3 文件系统中使用的 ext3_inode 结构对比一下可知,索引节点结构并没有发生太大变化,不同之处在于最后添加了 5 个与时间有关的字段,这是为了提高时间戳的精度。在 ext2/ext3 文件系统中,时间戳的精度只能达到秒级。随着硬件性能的提升,这种精度已经无法区分在同一秒中创建的文件的时间戳差异,这对于对精度要求很高的程序来说是无法接受的。在 ext4 文件系统中,通过扩充索引节点结构解决了这个问题,可以实现纳秒级的精度。最后两个新增字段 i_crtime 和 i_crtime_extra 用来表示文件的创建时间,这可以用来满足某些应用程序的需求。
前面已经介绍过,尽管索引节点中的 i_block 字段保持不变,但是由于 extent 概念的引入,对于这个数组的使用方式已经改变了,其前 3 个元素一定是一个 ext4_extent_header 结构,后续每 3 个元素可能是一个 ext4_extent 或 ext4_extent_idx 结构,这取决于所表示的文件的大小。这种设计可以有效地表示连续存放的大文件,但是对于包含碎片非常多的文件或者稀疏文件来说,就不是那么有效了。为了解决这个问题,ext4 的设计者们正在讨论设计一种新型的 extent 来表示这种特殊文件,它将在叶子节点中采用类似于 ext3 所采用的间接索引块的形式来保存为该文件分配的数据块位置。该类型的 ext4_extent_header 结构中的 eh_magic 字段将采用一个新值,以便与目前的 extent 区别开来。
采用这种结构的索引节点还存在一个问题:我们知道,在 ext3 中 i_blocks 是以扇区(即 512 字节)为单位的,因此单个文件的最大限制是 232 * 512 B = 2 TB。为了支持更大的文件,ext4 的 i_blocks 可以以数据块大小为单位(这需要 HUGE_FILE 特性的支持),因此文件上限可以扩充到 16TB(数据块大小为 4KB)。同时为了避免需要对整个文件系统都需要进行类似转换,还引入了一个 EXT4_HUGE_FILE_FL 标志,i_flags 中不包含这个标志的索引节点的 i_blocks 依然以 512 字节为单位。当文件所占用的磁盘空间大小增大到不能够用以512字节为单位的i_blocks来表示时,ext4自动激活EXT4_HUGE_FILE_FL标志,以数据块为单位重新计算i_blocks的值。该转换是自动进行的,对用户透明。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0