1.Ext2物理结构
2.Ext2数据结构
3.Ext2文件系统操作
Ext2第二代扩展文件系统(Second extended filesystem),是LINUX内核使用的文件系统
Ext2文件系统特性:
1.磁盘块分为组
2.支持快速符号链接
3.在启动时支持对文件系统的状态进行自动的一致性检查
4.Ext2索引节点中引入新的字段(块、删除逻辑、日志)
必须建立各种结构(在内核中定义为C语言数据类型),来存放文件系统的数据,包括文件内容、目录层次结构的表示、相关的管理数据(如访问权限与用户和组的关联),以及用于管理文件系统内部信息的元数据。这些对从块设备读取数据进行分析而言,都是必要的。这些结构的持久副本显然需要存储在硬盘上,这样数据再两次会话之间不会丢失。下一次启动重新激活内核时,数据仍然时可用的。因为硬盘和物理内存的需求不同,同一数据结构通常会有两个版本,一个用在磁盘上的持久存储,另一个用在内存中的处理。
Ext2文件系统专注于高性能
1.支持可变块长,使得文件系统能够处理预期的应用;
2.快速符号链接,如果链接目标的路径足够短,则将其存储在inode自身中;
3.将扩展能力集成到设计当中,从旧版本迁移到新版本时,无需重新格式化和重新加载硬盘;
4.Ext2有一个非常大的有点(与现代文件系统相比,Ext2文件系统的代码非常紧凑,使用不到10000行代码就足以实现了)。
块(block)的两个含义
1.有些文件系统存储在面向块的设备上,与设备之间的数据传输都以块为单位进行,不会传输单个字符。
2.Ext2文件系统是一种基于块的文件系统,他将硬盘分为若干块,每个块的长度都相同,按块管理元数据和文件内容。
块组
块组是该文件系统的基本成分,容纳文件系统其他结构,每个文件系统都由大量块组成,直接在硬盘上相继排列。
块组是Ext2文件系统的核心要素。块组是该文件系统的基本成分,容纳了文件系统的其他结构。
为什么Ext2文件系统允许这样浪费空间?有两个原因,可以证明提供额外的空间的做法是正确的。
1.如果系统崩溃破坏的超级块,有关文件系统结构和内容所有信息都会丢失。如果有冗余的副本,该信息是可能恢复的。
2.通过使文件和管理数据尽可能的接近,减少磁头寻道和旋转,这可以提高文件系统的性能。
超级块:用于存储文件系统自身元数据的核心结构,内核只使用第一个块组的超级块读取文件系统的元信息。
块描述符:包含的信息反映文件系统各个块组的状态,比如:块组中空闲块和inode数目,每个块组都包含了文件系统中所有块组的组描述符信息。
indoe表:包含块组中所有的inode,inode用于保存文件系统中与各个文件和目录相关的所有元数据。
数据块:包含文件系统中的文件的有用数据。
超级块
超级块:超级块是文件系统的核心结构,保存了文件系统所有的特征数据。内核在装载文件系统时,最先看到的就是超级块的内容。使用ext2_super_block结构定义超级块。
struct ext2_super_block {__le32s_inodes_count;__le32s_blocks_count;__le32s_r_blocks_count;__le32s_free_blocks_count;__le32s_free_inodes_count;__le32s_first_data_block;__le32s_log_block_size;__le32s_log_frag_size;__le32s_blocks_per_group;__le32s_frags_per_group;__le32s_inodes_per_group;__le32s_mtime;__le32s_wtime;__le16s_mnt_count;__le16s_max_mnt_count;__le16s_magic;__le16s_state;__le16s_errors;__le16s_minor_rev_level; __le32s_lastcheck;__le32s_checkinterval;__le32s_creator_os;__le32s_rev_level;__le16s_def_resuid;__le16s_def_resgid;__le32s_first_ino; __le16 s_inode_size; __le16s_block_group_nr; __le32s_feature_compat; __le32s_feature_incompat; __le32s_feature_ro_compat; __u8s_uuid[16];chars_volume_name[16]; chars_last_mounted[64]; __le32s_algorithm_usage_bitmap; __u8s_prealloc_blocks;__u8s_prealloc_dir_blocks;__u16s_padding1;__u8s_journal_uuid[16];__u32s_journal_inum;__u32s_journal_dev;__u32s_last_orphan;__u32s_hash_seed[4];__u8s_def_hash_version;__u8s_reserved_char_pad;__u16s_reserved_word_pad;__le32s_default_mount_opts; __le32s_first_meta_bg; __u32s_reserved[190];};
s_magic字段存储一个魔数,该数值确认装载的文件系统确实是Ext2类型。s_minor_rev_level用于区分文件系统的不同版本。
组描述符
前面如图所示,每个块组都有一个组描述符的集合,紧随超级块之后,其中保存的信息反应了文件系统每个块组的内容,因此,不仅关系到当前块组的数据块,还与其他块组的数据块和inode块相关。用于定义单个组描述符的数据结构比超级块结构短的多。
struct ext2_group_desc{__le32bg_block_bitmap;__le32bg_inode_bitmap;__le32bg_inode_table;__le16bg_free_blocks_count;__le16bg_free_inodes_count;__le16bg_used_dirs_count;__le16bg_pad; __le32bg_reserved[3];};
inode
每个块组都包含一个inode位图和一个本地的inode表,inode表可能延续到几个块。位图的内容与本地块组相关,不会复制到文件系统中的其他位置。inode位图用于概述块组中已用和空闲的inode。
struct ext2_inode {__le16i_mode;__le16i_uid;__le32i_size;__le32i_atime;__le32i_ctime;__le32i_mtime;__le32i_dtime;__le16i_gid;__le16i_links_count;__le32i_blocks;__le32i_flags;union {struct {__le32 l_i_reserved1;} linux1;struct {__le32 h_i_translator;} hurd1;struct {__le32 m_i_reserved1;} masix1;} osd1;__le32i_block[EXT2_N_BLOCKS];__le32i_generation;__le32i_file_acl;__le32i_dir_acl;__le32i_faddr;union {struct {__u8l_i_frag;__u8l_i_fsize;__u16i_pad1;__le16l_i_uid_high;__le16l_i_gid_high;__u32l_i_reserved2;} linux2;struct {__u8h_i_frag;__u8h_i_fsize;__le16h_i_mode_high;__le16h_i_uid_high;__le16h_i_gid_high;__le32h_i_author;} hurd2;struct {__u8m_i_frag;__u8m_i_fsize;__u16m_pad1;__u32m_i_reserved2[2];} masix2;} osd2;};
四、目录和文件文件系统的拓扑结构,在LINUX中,目录是一种特殊的文件,其中是inode指针和对应的文件名列表,表示了当前目录下的文件和子目录,对于EXT2文件系统,也是这样,每个目录表示为一个inode,会对其分配数据块,数据块中包含了用于描述目录项的结构。在内核源代码中目录项结构定义如下,
struct ext2_dir_entry_2 {__le32inode;__le16rec_len;__u8name_len;__u8file_type;charname[];};
enum {EXT2_FT_UNKNOWN= 0,EXT2_FT_REG_FILE= 1,EXT2_FT_DIR= 2, //普通文件EXT2_FT_CHRDEV= 3,//字符特殊文件和快特殊文件EXT2_FT_BLKDEV= 4,EXT2_FT_FIFO= 5,//命名管道EXT2_FT_SOCK= 6,//套接字EXT2_FT_SYMlink= 7,EXT2_FT_MAX};
五、EXT2文件系统操作 虚拟文件系统和具体实现之间的关联大体上由3个结构建立,结构中包含了一系列的函数指针。所有的文件系统都必须实现该关联。
1.用于操作文件内容的操作保存在file_operations中;
2.用于此类文件对象自身操作的操作保存在inode_operations中;
3.用于一般地址空间操作保存在address_space_operations中。
(1)Ext2文件系统对不同的文件类型提供了不同的file_operations实例:
const struct file_operations ext2_file_operations = {.llseek= generic_file_llseek,.read_iter= generic_file_read_iter,.write_iter= generic_file_write_iter,.unlocked_ioctl = ext2_ioctl,#ifdef CONFIG_COMPAT.compat_ioctl= ext2_compat_ioctl,#endif.mmap= ext2_file_mmap,.open= dquot_file_open,.release= ext2_release_file,.fsync= ext2_fsync,.splice_read= generic_file_splice_read,.splice_write= iter_file_splice_write,};
(2)目录也有自身的file_operations实例,具体源码如下:
const struct file_operations ext2_dir_operations = {.llseek= generic_file_llseek,.read= generic_read_dir,.iterate= ext2_readdir,.unlocked_ioctl = ext2_ioctl,#ifdef CONFIG_COMPAT.compat_ioctl= ext2_compat_ioctl,#endif.fsync= ext2_fsync,};
(3)目录有更多的inode操作源码如下:
const struct inode_operations ext2_dir_inode_operations = {.create= ext2_create,.lookup= ext2_lookup,.link= ext2_link,.unlink= ext2_unlink,.symlink= ext2_symlink,.mkdir= ext2_mkdir,.rmdir= ext2_rmdir,.mknod= ext2_mknod,.rename= ext2_rename,#ifdef CONFIG_EXT2_FS_XATTR.setxattr= generic_setxattr,.getxattr= generic_getxattr,.listxattr= ext2_listxattr,.removexattr= generic_removexattr,#endif.setattr= ext2_setattr,.get_acl= ext2_get_acl,.set_acl= ext2_set_acl,.tmpfile= ext2_tmpfile,};
(4)文件系统和块层通过address_space_operations关联。
const struct address_space_operations ext2_aops = {.readpage= ext2_readpage,.readpages= ext2_readpages,.writepage= ext2_writepage,.write_begin= ext2_write_begin,.write_end= ext2_write_end,.bmap= ext2_bmap,.direct_IO= ext2_direct_IO,.writepages= ext2_writepages,.migratepage= buffer_migrate_page,.is_partially_uptodate= block_is_partially_uptodate,.error_remove_page= generic_error_remove_page,};
(5)此结构(super_operations)用于与超级块交互(读、写、分配inode)。
static const struct super_operations ext2_sops = {.alloc_inode= ext2_alloc_inode,.destroy_inode= ext2_destroy_inode,.write_inode= ext2_write_inode,.evict_inode= ext2_evict_inode,.put_super= ext2_put_super,.sync_fs= ext2_sync_fs,.freeze_fs= ext2_freeze,.unfreeze_fs= ext2_unfreeze,.statfs= ext2_statfs,.remount_fs= ext2_remount,.show_options= ext2_show_options,#ifdef CONFIG_QUOTA.quota_read= ext2_quota_read,.quota_write= ext2_quota_write,.get_dquots= ext2_get_dquots,#endif};