文件系统综述
linux 文件系统是基于MINIX 1.0文件系统,这部分的代码量是整个内核里最大的,但代码结构对应着MINIX文件系统的构成,还是比较清晰易读的。
MINIX文件系统
MINIX的文件系统由以下几部分组成:
- 引导块:由BIOS自动读入的执行代码,这部分不在文件系统里描述;
- 超级块:存放盘设备上文件系统的信息,如逻辑块数、i节点数、最大文件长度等;对应结构体super_block;
struct super_block { unsigned short s_ninodes; unsigned short s_nzones; unsigned short s_imap_blocks; unsigned short s_zmap_blocks; unsigned short s_firstdatazone; unsigned short s_log_zone_size; unsigned long s_max_size; unsigned short s_magic;/* These are only in memory */ //上面这些字段是具体存储在盘设备中,下面是在内存中初始化的结构体成员 struct buffer_head *s_imap[8]; struct buffer_head *s_zmap[8]; unsigned short s_dev; struct m_inode *s_isup; //根目录i节点 struct m_inode *s_imount; unsigned long s_time; struct task_struct *s_wait; unsigned char s_lock; unsigned char s_rd_only; unsigned char s_dirt;};
- i节点位图:表示i节点是否被使用,i节点对应文件或目录的索引,相当于能够创建或被内核管理的文件数量;
- 逻辑块位图:表示逻辑块是否被使用,逻辑块是实际上的数据块,存储文件的内容;
- i节点区域:存放具体的i节点数据;存储结构如下:
struct d_inode { unsigned short i_mode; unsigned short i_uid; unsigned long i_size; unsigned long i_time; unsigned char i_gid; unsigned char i_nlinks; unsigned short i_zone[9];//对应数据区内的逻辑块号,其中0~6是直接块号、7为一次直接块号、8是二次直接块号。};
- 数据区:即逻辑块区域;
同时在linux 0.11中还在内存开辟了缓冲区,通过hash散列表的形式支持数据块读取的缓冲。
功能分块:
从功能的角度分,linux 0.11 文件系统源码主要分为以下几块:
- 高速缓冲区操作:buffer.c,逻辑块缓冲区,会调用块设备驱动接口;
- MINIX文件系统底层操作,包括:文件系统向上提供的操作,包括:
- bitmap.c:i节点位图和逻辑块位图操作;
- truncate.c:释放某个i节点下的所有逻辑块;
- namei.c:映射文件名至i节点;
- inode.c:i节点获取、释放登操作;
- super.c:超级块操作;
- linux文件系统对上提供的调用封装:
- read_write.c:提供sys_read和sys_wirte两个系统调用的接口实现;open.c:open.c: sys_create、sys_open等系统调用实现
- block_dev.c:块设备驱动类文件操作,被read_write.c调用;
- file_dev.c:普通文件操作,被read_write.c调用;
- char_dev.c:字符驱动类文件操作,被read_write.c调用;
- pipe.c:管道操作,被read_write.c调用;
- open:sys_create、sys_open等系统调用实现;
- exec.c:主要实现do_execute,即实现加载并启动一个可执行文件.out或shell脚本;
- fcontl.c:sys_fcntl、sys_dup等系统调用接口;
- stat.c:sys_stat等系统调用接口;
- read_write.c:提供sys_read和sys_wirte两个系统调用的接口实现;open.c:open.c: sys_create、sys_open等系统调用实现
核心业务流程
以创建一个文件为例,看下linux 0.11中文件系统各部分源码的关系:
- 调用sys_open打开一个文件,输入文件名、模式等;
- 调用open_namei获取其i节点,open_namei会调用和bitmap和inode.c的底层操作,找到该文件对应的逻辑块;
- 调用buffer.c中的操作读取这些逻辑块,当缓冲中不存在逻辑块数据时,会调用块设备驱动;这些逻辑块的地址(应该是缓冲区的地址)会保存在m_inode结构体中;
- 从file_table数组中返回一个文件句柄(即数组索引),其指向的file结构中包含了m_inode。