文件系统简介及简单实现

1. 磁盘分区

文件系统是建立在已经给磁盘分好区的基础之上的。分过区后磁盘的分布情况如下图,具体内容不展开。
在这里插入图片描述

使用的分区工具是fdisk,之前已经完成的内核是在一个裸盘上,所以这里新加了一个硬盘用来创建文件系统。
硬盘2有一个MBR扇区剩余都是拓展分区,拓展分区下有5个子拓展分区。

2. inode

UNIX文件系统是以索引结构组织的,好处是可以直接访问要访问的块不需要从头遍历。文件系统为每个文件建立一个索引表,索引表就是块地址数据,每个数组元素就是块的地址,数组元素的下标是文件块的索引。
包含此索引表的结构称为inode,即index inode,索引节点,用来索引、跟踪一个文件的所有块。inode是文件索引结构的具体体现,必须为每个文件都单独配备一个这样的数据结构,所以在UNIX文件系统中,一个文件对应一个inode,有多少文件就有多少个inode数据结构。
索引结构存储文件A的逻辑示意图如下所示。
在这里插入图片描述

这一使用的块大小为4KB一个块。在数据处理的时候比较简单,硬盘的一个块对应的一个内存页。

使用索引结构的缺点是索引表本身要占据一定的空间,如果文件很大的话就会占很多的块,那么inode的大小就需要很大。UNIX为了解决这一问题,将每个索引表中的15个索引项分为两部分,前12个索引项为文件的直接块,存储的是数据块的直接lba地址。当文件所占的数据块超过12个时,就再创建一个索引表称为一级间接块索引表。如果一个块的大小为4KB那么一个块大小的索引表可以存储1024个数据块(数据块地址为32位),那么此时文件的大小可以达到12+1024个块。若文件大小更大,则需要二级间接索引表,二级间接索引表的内容为一级间接索引表,这样文件的大小可以为12+1024+10241024。若更大则需要三级间接索引表,内容为二级间接索引表,大小可以达到12+10241024+1024 * 1024 * 1024。
如下图所示。
在这里插入图片描述

inode数据结构:

/*inode结构*/
struct inode
{
    uint32_t i_no;         //inode编号

    uint32_t i_size;       //当此inode是文件时,i_size是指文件大小,若是目录,i_size是指目录下所有目录项大小之和

    uint32_t i_open_cnts;   //记录此文件被打开的次数
    bool write_deny;        //写文件不能并行,进程写文件前检查此标志

    uint32_t i_sectors[13]; //0~11是直接块,12永远存储一级间接块指针
    struct list_elem inode_tag;   //此inode的标识,用于加入已打开的inode列表
};

这里的系统中没有权限管理和时间,所以要比常规的inode内容要少。该inode中要记录inode的编号,用来结合inode位图索引inode。这里使用12个直接块和1个一级间接索引表。所以该系统中文件的大小最大为(12+1024)个块(4KB)。

3. 目录项与目录

用户在使用文件系统的使用,用的更多的是文件名而不是inode编号。如何将文件名和inode编号联系起来就是目录项的作用。同时一个inode不一定就是记录信息的不同文件,也有可能是一个目录,目录项中也要表示该目录项对应的inode中记录的内容是文件信息还是普通数据信息。
对应关系如下图所示。
在这里插入图片描述
图中inode1为一个目录的indoe,数据块中记录由n个目录项。其中目录项1为普通文件,指向indoe2。目录项n为目录类型,指向inode3,inode3中又记录着n个目录项。

目录项数据结构:

/*目录结构*/
struct dir
{
    struct inode* inode;   //该目录对应的inode,用于指向内存中的inode
    uint32_t dir_pos;      //记录在目录内的偏移
    uint8_t dir_buf[512];  //目录的数据缓存
};

/*目录项结构*/
struct dir_entry
{
    char filename[MAX_FILE_NAME_LEN];   //不同文件或目录名称
    uint32_t i_no;   //不同文件或目录对应的inode编号
    enum file_types f_type;   //文件类型
};

目录通常是需要在系统中有一个缓存的,这里的struct dir就是该缓存所需要的结构。目录项中记录有文件名、inode编号和文件类型,这样就将文件名和inode编号联系到一起了。

这里的目录项结构已经是很简化的了,仅仅满足了文件名和inode相关联。

4. 超级块与文件系统布局

inode需要有inode数据来记录,现在问题是inode数组的大小和地址又该如何记录。根目录是固定的,根目录又该如何存储。超级块中就需要记录像这样的元信息。这些元信息是事先规定好的,相当于该文件系统的配置信息。
超级块结构:

/*超级块*/
struct super_block
{
    uint32_t magic;                 //用来表示文件系统类型,支持多文件系统的操作系统通过此标志来识别文件系统类型
    uint32_t sec_cnt;               //本分区总共的扇区数,数据块数
    uint32_t inode_cnt;             //本分区中inode数量
    uint32_t part_lba_base;        //本分区的起始lba地址

    uint32_t block_bitmap_lba;      //块位图本身起始扇区地址
    uint32_t block_bitmap_sects;    //块位图本身占用的扇区数量

    uint32_t inode_bitmap_lba;      //i节点位图起始扇区lba地址
    uint32_t inode_bitmap_sects;    //i节点位图占用的扇区数量

    uint32_t inode_table_lba;       //i节点表起始扇区lba地址
    uint32_t inode_table_sects;     //i节点表占用的扇区数量

    uint32_t data_start_lba;        //数据区开始的第一个扇区号
    uint32_t root_inode_no;         //根目录所在的i节点号
    uint32_t dir_entry_size;        //目录项大小

    uint8_t pad[460];   //加上460字节,凑够512字节1扇区大小
}__attribute__ ((packed));

以上的内容就是该文件系统的超级块。结构体最后的__attribute__((packed))是在编译过程中内存大小严格按照程序所写的大小,因为这里要保证超级块的大小为512字节。
有了超级块,硬盘中的简单的文件系统就构建完成了,最后呈现出来的布局如下图所示。
在这里插入图片描述


参考书籍:《操作系统真相还原》-- 郑刚

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值