第9章 Ext文件系统族 (2)

目录

9.2 Ext2文件系统

9.2.2 数据结构


本专栏文章将有70篇左右,欢迎+关注,查看后续文章。

9.2 Ext2文件系统

9.2.2 数据结构

1. 超级块

ext2_fill_super() 函数:

        读取超级块信息。

struct    ext2_super_block {

        __le32    s_inodes_count;               // inode总数。

        __le32    s_blocks_count;               //块的总数。

        __le32    s_r_blocks_count;            //为 s_def_resuid 用户预留的块数量。

        __le32    s_free_blocks_count;       //空闲块数。

        __le32    s_free_inodes_count;       // 空闲inodes数。

        __le32    s_log_block_size;

                //块大小,值为0 1 2,分别表示块长度为1024,2048,4096字节 ,mkfs时指定。

        __le32    s_blocks_per_group,     //每个块组中数据块数

        __le32    s_inodes_per_group        //每个块组中inode数

        __le16    s_mnt_count;                   //上一次检查后的装载次数。

        __le16   s_max_mnt_count;

                //若 s_max_mnt_count > s_mnt_count, 则会检查。

        __le16   s_magic;                            //标识文件系统版本,Ext2为0xEF53。

        __le16   s_state;                             //装载成功与否。

        __le32   s_lastcheck;

                //上次检查日期,若 now - s_lastcheck > s_checkinterval,则会检查。

        __le32   s_checkinterval;                 //检测间隔时间。

        __le16   s_def_resuid;

                //默认为0, 即 root 用户。可确保root 用户紧急情况使用磁盘空间。如ssh时。

        __le16   s_def_resgid;                       //组ID,同上。

        __le32   s_feature_compat;               //兼容特性集,增加特性使用,如ext3日志功能。

        __le32   s_feature_incompat;            //不兼容特性集。

        __le32   s_feature_ro_compat;         //只读兼容特性集。

        __u32   s_reserved[190];                  //填充到1024字节块大小。

};

struct   ext2_sb_info    =    struct super_block   *sb -> s_fs_info;

struct    ext2_sb_info   {

        struct ext2_super_block    *s_es;

        ...

}

struct    ext2_sb_info 和 struct    ext2_super_block 区别:

        1. struct ext2_super_block:

                从磁盘读取的文件系统静态原始信息。

        2. struct ext2_sb_info:

                基于超级块信息,维护的文件系统运行时的状态和辅助数据。

上述成员类型为__le32,__le16等,作用:

        将一个移动硬盘更换到不同位长的计算机时,超级块信息以相同字节和大小端存储。

s_feature_compat:兼容特性,掩码。

举例:

        EXT2_FEATURE_COMPAT_IMAGIC_INODES

        EXT3_FEATURE_COMPAT_HAS_JOURNAL

s_feature_ro_compat:只读兼容特性,掩码。

举例:

        EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER,稀疏超级块

        EXT2_FEATURE_RO_COMPAT_LARGE_FILE

s_feature_incompat:不兼容特性,掩码。

举例:

        EXT3_FEATURE_INCOMPAT_JOURNAL_DEV

上述三个掩码作用:

        了解文件系统特性,进行相应处理。

使用举例:

if (osb-> s_feature_incompat    &    OCFS2_FEATURE_INCOMPAT_INLINE_DATA )

{

}

2. GDT组描述符

每个块组都有一个组描述符,反应当前块组的信息。

如何得到指定块组的组描述符?

struct   ext2_group_desc    * ext2_get_group_desc(struct super_block   *sb,

        unsigned int    block_group,

        struct buffer_head     **bh)

struct    ext2_group_desc {

        __le32    bg_block_bitmap;             // 块位图的块号。

        __le32    bg_inode_bitmap;             // inode 位图的块号。

        __le32    bg_inode_table;                // inode 表的块号。

        __le16    bg_free_blocks_count;      // 空闲块数目。

        __le16    bg_free_inodes_count;      // 空闲 inode 数目。

        __le16    bg_used_dirs_count;         // 目录数目。

        __le16    bg_pad;

        __le32    bg_reserved[3];

};

试图将一个文件都数据存在同一个块组中,可减小寻道代价。

3. inode

每个块组有:

        1. 一个 inode 位图:表示当前块组的 inode 是否已使用。

        2. 一个本地 inode 表:当前块组的文件的 inode 信息。每个 inode 如下表示:

struct    ext2_inode {

        __le16    i_mode;              //访问权限,和文件类型。

        __le16    i_uid;                   //文件的uid的低16位。

        __le16    i_gid;                   //文件的组id的低16位。

        __le16    l_i_uid_high;        //uid 高16位。

        __le16    l_i_gid_high;        //gid 高16位。

        __le32    i_size;                  //文件长度。单位:字节。

        __le32    i_atime;                //最后访问时间。

        __le32    i_ctime;                //文件创建时间。

        __le32    i_mtime;               //最后修改时间。

        __le32    i_dtime;                //文件被删除时间。

        __le16    i_links_count;       //硬链接数目。

        __le32    i_blocks;               //文件占用块数量。

        __le32    i_flags;                 //具体看ext2实现。

        __le32    l_i_reserved1;

        __le32    i_block[EXT2_N_BLOCKS];

                //指向数据块块号 EXT2_N_BLOCKS=12,前12个直接寻址,后3个间接寻址。

        __le32    i_file_acl;             //文件ACL,细粒度的访问权限控制。

        __le32    i_dir_acl;             //目录ACL。

        __le32    i_faddr;               //碎片地址。

        __u8    l_i_frag;                 //碎片号。

        __u8    l_i_fsize;                //碎片大小。

        __u16    i_pad1;

        __u32    l_i_reserved2;

};

上述以 l_ 开头的成员表示用于Linux 系统。

struct   inode    *ext2_iget (struct   super_block    *sb,    unsigned long   ino)

        作用:根据inode编号,获取对应 struct inode。

static   int    __ext2_write_inode(struct   inode    *inode,    int   do_sync)

        作用:将内存中 inode 写回到磁盘 inode 表中。

struct super_operations    ext2_sops = {

        .alloc_inode         =     ext2_alloc_inode,

        .destroy_inode    =      ext2_destroy_inode,

        .write_inode        =      ext2_write_inode,

        .put_super          =      ext2_put_super,

        .sync_fs              =      ext2_sync_fs,

};

文件洞(File Hole):即稀疏文件(Sparse File)。

问:如何创建文件洞?

答:只改变文件指针位置。不分配实际数据块,但文件系统仍记录该数据块位置和大小。

好处:节省磁盘空间,读文件时,自动填充零。

注意:当文件传输或备份时,可能无法正确处理文件洞,导致与原始文件大小不一致。

s_inodes_per_group:

        每个块组中 inode数目,默认为128。即 128个文件。

4. 目录和文件

目录是一种特殊文件,每个目录有一个inode,并分配对应数据块。

        数据块中存储着目录项结构(即表示目录中文件或子目录),即如下结构体。

一个目录项的结构:

struct    ext2_dir_entry_2 {

        //该成员来自inode指向的数据块,代表该目录下的一个文件。多个文件就多个结构体

        __le32     inode;                //目录文件的 inode编号。

        __le16     rec_len;             //目录项占用磁盘大小,删除目录时,跳过。

        __u8        name_len;         //目录名称的长度。

        __u8        file_type;           //文件类型。

        char         name[ ];            //目录名称,小于255。

} ext2_dirent;

注意:

        文件名须为4 的整数倍,否则用 \0 填充。

rec_len 长度计算方法:

        当前目录项的 rec_len 末尾到下一个目录项 rec_len 开头的偏移量字节。

举例:

一个目录下有文件:

该目录的 数据块存储 struct    ext2_dir_entry_2 结构体,如下:

第一个文件. 的rec_len为12字节,计算方法:

        1(name_len) + 1(file_type) + 4(name) + 下一个目录项的 4(inode) + 2(rec_len)

注意:

        当删除一个目录项时使用,不用移动文件,将rec_len增加偏移,跳过即可。

该目录中文件 deldir 已被删除,则第四个文件 linux 中的 rec_len 需要偏移跳过 deldir 文件,所以rec_len 为32。

只有目录和普通文件占用硬盘的数据块。其他文件不用,如:

        1. 符号链接文件:

                目标路径小于60字节,则存在 inode中。

                大于60字节时,分配数据块来存储。

        2. 设备文件,命名管道,socket文件:

                只需要一个inode即可,无需数据块。

5. 内存中的数据结构

struct    super_block {

        void    *s_fs_info;

        //特定文件系统实现,ext2 中指向 struct    ext2_sb_info,只存在于内存。

}

struct    inode {

        void    *i_private;

        //特定文件系统实现,ext2 中指向 struct   ext2_inode_info,只存在于内存。

}

块的预分配

文件请求分配数据块时,多分配些连续的数据块,秘密标记。

        优点:节省时间,防止碎片。

预留窗口:定义了预留的区域。

struct    ext2_reserve_window {

        ext2_fsblk_t         _rsv_start;         //预留的起始字节。

        ext2_fsblk_t         _rsv_end;          //预留的结束字节。

}

  • 26
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山下小童

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值