Ext2文件系统初步
鸣谢:http://blog.csdn.net/kai_ding/article/details/9173903
一、磁盘布局
1.1概述
任何Ext2分区中的第一个块从不受Ext2文件系统的管理,因为这一块是为分区的引导扇区所保留的。Ext2分区的其余部分被分割成块组(blockgroup),每个块组的分布图如下图1所示。正如你从图中所看到的,一些数据结构正好可以放在一块中,而另一些可能需要更多的块。在Ext2文件系统中的所有块组大小相同并被顺序存放,因此,内核可以从块组的整数索引很容易地得到磁盘中一个块组的位置。
图1ext2磁盘布局
由于内核尽可能地把属于同一个文件的数据块存放在同一块组中,所以块组可有效地提高文件连续性。每个块组均包含如下方面的信息:
假定blocksize=4k=4096bytes
内容 |
大小(以block计) |
计算 |
使用结构 |
SuperBlock(超级块) |
1 |
|
ext2_super_block |
GDT(组描述符表) |
n |
|
ext2_group_desc |
Datablock bitmap |
1 |
1*blocksize*8 |
|
Inodebitmap |
1 |
1*blocksize*8 |
|
Inodetable |
m |
(inode_per_group*inode_size+block_size-1)/block_size |
ext2_inode |
Datablocks |
p |
|
|
block_group_count=partition_capacity/(block_size*data_block_per_group)
block_per_group=block_size*8;
以下计算GDT所占blocks.
1.计算group descriptor number,即blockgroup的数量.
number_of_gdt=partition_block_count/block_per_group;
2,计算GDT占的block数。
2.a求出每个block能容纳多少GDT结构
gdt_per_block=block_size/sizeof(structext2_group_desc);
2.b求出所有GDT需要占多少个block。
blocks_of_gdt=number_of_gdt/gdt_per_block;
3.保留的GDTblock数量
即结构ext2_super_block的s_padding1字段值。
GDT所占的block为保留的block数量与现有GDT所占block数量之和。
事实上,只有块组0中所包含超级块和组描述符才由内核使用,而其余的超级块和组描述符都保持不变,内核甚至不考虑它们。当e2fsck程序对Ext2文件系统的状态执行一致性检查时,就引用存放在块组0中的超级块和组描述符,然后将它们拷贝到其他所有的块组中。如果出现数据损坏,并且块组0中的主超级块和主描述符变为无效,那么,系统管理员就可以命令e2fsck引用存放在某个块组(除了第一个块组)中的超级块和组描述符的旧拷贝。通常情况下,这些多余的拷贝所存放的信息足以让e2fsck把Ext2分区带回到一个一致的状态。
使用dumpe2fs/dev/sda1命令,可以看到,只有group0, group 1包含Superblock和Groupdescriptor,其余的group不含superblock和GDT. Group 0的superblock为主超级块,Group1的superblock为备份超级块。
那么每个ext2文件系统到底有多少块组呢?这取决于分区的大小和块的大小。其主要限制在于块位图,块位图用来标识一个块组中块的占用和空闲状况,而且ext2块位图只占据一个单独的数据块。所以,每组中至多可包含8×b个块,b是以字节为单位的块大小。例如,一个块大小是1024Byte,那么,一个块的位图就有8192个位,正好就对应8192个块。因此,块组的总数大约是c/8×b,这里c是指分区所包含的总块组数。
举例说明,让我们考虑一下32GB的Ext2分区,换算成KB就是33554432,假定块大小为4KB。在这种情况下,每个4KB的块位图描述32KB个数据块,即128MB。因此,最多需要33554432/ 4096 * 32 =256个块组。显然,块越大,块组数越小。
inode表用于存储块组内文件的inode信息,而且只存储该块组内存储文件的inode,我们知道inode是一个文件元数据的全部,是文件身份的象征,没有inode,文件在磁盘上就是不可见的。ext2文件系统格式化时,块组内的inode表空间也一并分配好,也就意味着该块组内能存储多少个文件是确定的,那么这个值是如何确定的呢,依稀记得mkfs.ext2在格式化时,会将块组存储文件的平均大小设定为16KB,这样,知道了块组大小和文件平均大小就可以计算块组内存储文件数量了。
inode位图用来管理块组内空闲inode分配情况。
由亍(1)一个inode占用128bytes ,(2)总共有1641- 629 + 1(629本身)= 1013个 block
花在 inodetable 上,(3)每个block癿大小为4096bytes(4K)。由这些数据可以算出inode
癿数量共有1013* 4096 / 128 = 32416个 inode啦!
数据块用来存储块组内的文件数据,使用位图方式管理空闲数据块。
至此,我们已经大概了解了ext2文件系统的磁盘布局,ext2这种布局方式是源自FFS的设计思想:尽量将文件的数据元数据连续存放,同时尽量将相关文件连续存放,所谓的相关文件诸如相同目录下的所有文件,ext2的块组思想就是连续的最好体现,关于ext2的文件创建和数据块分配后续还会仔细研究。
二、数据结构
头文件:/usr/include/linux/ext2_fs.h
2.1 ext2超级块
这里的超级块指的是ext2文件系统存储在磁盘上的超级块结构,之所以这么说是因为每个文件系统除了存储在磁盘上的超级块外,还在内存中也存储了一个超级块结构,基本上内存中的超级块是在磁盘超级块的基础上增加了一些额外的管理信息而成,因此,在这里我们主要关注的是ext2存储在磁盘上的超级块的数据结构。
ext2磁盘超级块的定义如下:
/*
*Structure of the super block
*/
structext2_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 */
};
可以看到,ext2磁盘超级块结构中大部分是描述整个文件系统的信息,如文件系统中块组的数量,inode数量,磁盘块的数量等等,不一而足,基本上从代码的注释我们就能比较清楚各个成员的含义,而且在后续的文章中我们或多或少地也会遇到这些成员。
2.2 ext2块组描述符
前面的描述中我们知道,ext2文件系统将磁盘(分区)划分成大小相等的块组,以提高文件存取的连续性。而且块组中存在inode表,inode位图,数据块位图中众多信息,因此,有必要对每个块组生成一个描述符来管理块组,在ext2中,该数据结构如下定义:
/*