Board logo

标题: 如何恢复 Linux 上删除的文件-reiserfs 文件系统原理(1) [打印本页]

作者: look_w    时间: 2018-5-22 16:03     标题: 如何恢复 Linux 上删除的文件-reiserfs 文件系统原理(1)

reiserfs 是由 namesys 公司的 Hans Reiser 设计并开发的一种通用日志文件系统,它是第一个进入 Linux 标准内核日志文件系统。从诞生之日起,reiserfs 就由于其诸多非常有吸引力的特性而受到很多用户的青睐,迅速成为 Slackware 等发行版的默认文件系统。它也一度也是 SUSE Linux Enterprise 发行版上的默认文件系统,直到 2006 年 10 月 12 日 Novell 公司决定将默认文件系统转换到 ext3 为止。尽管其主要设计人员 Hans Reiser 由于涉嫌杀害妻子遭到指控而入狱,从而导致他不得不试图出售 namesys 公司来支付庞大的诉讼费用,但是 reiserfs 已经受到广大社区开发人员和用户的极大关注,有很多志愿者已经投入到新的 reiserfs 4 的开发工作中来。本文中的介绍都是基于最新的稳定版本 3.6 版本的,所引用的代码都基于 2.6.23 版本的内核。
reiserfs 最初的设计目标是为了改进 ext2 文件系统的性能,提高文件系统的利用率,并增强对包含大量文件的目录的处理能力(ext2/ext3 文件系统中一个目录下可以包含的子目录最多只能有 31998 个)。传统的 ext2 和 ufs 文件系统都采用了将文件数据和文件元数据分离开保存的形式,将元数据保存到索引节点中,将文件数据保存到单独的磁盘块中,并通过索引节点中的 i_block 数组利用直接索引和间接索引的形式在磁盘上定位文件数据。这种设计非常适合存储较大的文件(比如20KB以上),但是对于具有大量小文件的系统来说就存在一些问题。首先在于文件系统的利用率,由于 ext2 会将文件数据以数据块为单位(默认为 4KB)进行存储,因此对于存储只有几十个字节的文件来说,会造成空间的极大浪费。另外由于在读取文件时需要分别读取文件元数据和文件数据,加上多读取数据块的开销,ext2 文件系统在处理大量小文件时,性能会比较差。为了获取最好的性能和最大程度地利用磁盘空间,很多用户会在文件系统之上采用数据库之类的解决方案来存储这些小文件,因此会导致上层应用程序的接口极不统一。
为了解决上面提到的问题,reiserfs 为每个文件系统采用一棵经过专门优化的 B+ 树来组织所有的文件数据,并实现了很多新特性,例如元数据日志。为了提高文件系统的利用率,reiserfs 中采用了所谓的尾部封装(tail packing)设计,可以充分利用已分配磁盘块中的剩余空间来存储小文件。实际上,reiserfs 文件系统中存储的文件会比 ext2/ext3 大 5% - 6% 以上。下面让我们来探索一下 reiserfs 文件系统中数据在磁盘上究竟是如何存储的。
磁盘布局与 ext2/ext3 类似,reiserfs 文件系统在创建时,也会将磁盘空间划分成固定大小的数据块。数据块从 0 开始编号,最多可以有 232 个数据块。因此如果采用默认的 4KB 大小的数据块,单个 reiserfs 文件系统的上限是 16TB。reiserfs 分区的前 64KB 保留给引导扇区、磁盘标签等使用。超级块(super block)从 64KB 开始,会占用一个数据块;之后是一个数据块位图,用来标识对应的数据块是否处于空闲状态。如果一个数据块位图可以标识 n 个数据块,那么 reiserfs 分区中的第 n 个数据块也都是这样一个数据块,用来标识此后(包括自己)n 的数据块的状态。reiserfs 文件系统的磁盘结构如图 1 所示。
图 1. reiserfs 分区磁盘布局与 ext2/ext3 类似,reiserfs 文件系统的一些关键信息也保存超级块中。reiserfs 的超级块使用一个 reiserfs_super_block 结构来表示,其定义如清单1 所示:
清单1. reiserfs_super_block 结构定义
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
36
37
38
39
40
41
42
135 struct reiserfs_super_block_v1 {
136         __le32 s_block_count;   /* blocks count         */
137         __le32 s_free_blocks;   /* free blocks count    */
138         __le32 s_root_block;    /* root block number    */
139         struct journal_params s_journal;
140         __le16 s_blocksize;     /* block size */
141         __le16 s_oid_maxsize;   /* max size of object id array, see
142                                  * get_objectid() commentary  */
143         __le16 s_oid_cursize;   /* current size of object id array */
144         __le16 s_umount_state;  /* this is set to 1 when filesystem was
145                                  * umounted, to 2 - when not */
146         char s_magic[10];       /* reiserfs magic string indicates that
147                                  * file system is reiserfs:
148                                  * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
149         __le16 s_fs_state;      /* it is set to used by fsck to mark which
150                                  * phase of rebuilding is done */
151         __le32 s_hash_function_code;    /* indicate, what hash function is being use
152                                          * to sort names in a directory*/
153         __le16 s_tree_height;   /* height of disk tree */
154         __le16 s_bmap_nr;       /* amount of bitmap blocks needed to address
155                                  * each block of file system */
156         __le16 s_version;       /* this field is only reliable on filesystem
157                                  * with non-standard journal */
158         __le16 s_reserved_for_journal;  /* size in blocks of journal area on main
159                                          * device, we need to keep after
160                                          * making fs with non-standard journal */
161 } __attribute__ ((__packed__));
162
163 #define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1))
164
165 /* this is the on disk super block */
166 struct reiserfs_super_block {
167         struct reiserfs_super_block_v1 s_v1;
168         __le32 s_inode_generation;
169         __le32 s_flags;     /* Right now used only by inode-attributes, if enabled */
170         unsigned char s_uuid[16];       /* filesystem unique identifier */
171         unsigned char s_label[16];      /* filesystem volume label */
172         char s_unused[88];      /* zero filled by mkreiserfs and
173                                  * reiserfs_convert_objectid_map_v1()
174                                  * so any additions must be updated
175                                  * there as well. */
176 } __attribute__ ((__packed__));




该结构定义中还包含了其他结构的定义,例如 journal_params,这是有关日志的一个结构,并非本文关注的重点,读者可以自行参考内核源代码中的 include/linux/ reiserfs_fs.h 文件。
实际上,超级块并不需要一个完整的数据块来存储,这个数据块中剩余的空间用来解决文件对象 id 的重用问题,详细内容请参看本系列文章下一部分的介绍。




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