文件系统组件:

  • 在应用层,进程在进行文件读写操作时,可通过系统调用如 sys_open、sys_read、sys_write 等。
  • 在内核,每个进程都需要为打开的文件,维护一定的数据结构。
  • 在内核,整个系统打开的文件,也需要维护一定的数据结构。
  • Linux 可以支持多达数十种不同的文件系统。它们的实现各不相同,因此 Linux 内核向用户空间提供了虚拟文件系统这个统一的接口,来对文件系统进行操作。它提供了常见的文件系统对象模型,例如 inode、directory entry、mount 等,以及操作这些对象的方法,例如 inode operations、directory operations、file operations 等。
  • 然后就是对接的是真正的文件系统,例如我们上节讲的 ext4 文件系统。
  • 为了读写 ext4 文件系统,要通过块设备 I/O 层,也即 BIO 层。这是文件系统层和块设备驱动的接口。
  • 为了加快块设备的读写效率,我们还有一个缓存层。
  • 最下层是块设备驱动程序。

image.png

在这之前,有一点你需要注意。解析系统调用是了解内核架构最有力的一把钥匙,这里我们只要重点关注这几个最重要的系统调用就可以了:

  • mount 系统调用用于挂载文件系统;
  • open 系统调用用于打开或者创建文件,创建要在 flags 中设置 O_CREAT,对于读写要设置 flags 为 O_RDWR;
  • read 系统调用用于读取文件内容;
  • write 系统调用用于写入文件内容。

挂载文件系统

  • 通过 register_filesystem 进行注册,传入的参数是 ext4_fs_type,表示注册的是 ext4 类型的文件系统。
  • 这里面最重要的一个成员变量就是 ext4_mount。
  1. register_filesystem(&ext4_fs_type);
  2. static struct file_system_type ext4_fs_type = {
  3. .owner = THIS_MODULE,
  4. .name = "ext4",
  5. .mount = ext4_mount,
  6. .kill_sb = kill_block_super,
  7. .fs_flags = FS_REQUIRES_DEV,
  8. };

mount 系统调用的定义如下:

  1. SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, char __user *, type, unsigned long, flags, void __user *, data)
  2. {
  3. ......
  4. ret = do_mount(kernel_dev, dir_name, kernel_type, flags, options);
  5. ......
  6. }

在文件系统的实现中,每个在硬盘上的结构,在内存中也对应相同格式的结构。当所有的数据结构都读到内存里面,内核就可以通过操作这些数据结构,来操作文件系统了。

image.png

  • 第一条线是最左边的向左斜的 dentry 斜线。每一个文件和文件夹都有 dentry,用于和 inode 关联
  • 第二条线是最右面的向右斜的 mount 斜线,因为这个例子涉及两次文件系统的挂载,再加上启动的时候挂载的根文件系统,一共三个 mount。
  • 第三条线是中间的向右斜的 file 斜线,每个打开的文件都有一个 file 结构,它里面有两个变量,一个指向相应的 mount,一个指向相应的 dentry。

文件管理解释:

  • dentry
    • 磁盘上的结构
  • mount
    • 挂载到哪
    • 挂载什么
  • file
    • 打开的文件

打开文件

  • 要打开一个文件,首先要通过 get_unused_fd_flags 得到一个没有用的文件描述符。

下标就是文件描述符:

  1. struct files_struct {
  2. ......
  3. struct file __rcu * fd_array[NR_OPEN_DEFAULT];
  4. };

对于任何一个进程,默认情况下,文件描述符 0 表示 stdin 标准输入,文件描述符 1 表示 stdout 标准输出,文件描述符 2 表示 stderr 标准错误输出。另外,再打开的文件,都会从这个列表中找一个空闲位置分配给它

文件描述符列表的每一项都是一个指向 struct file 的指针,也就是说,每打开一个文件,都会有一个 struct file 对应。fd_install(fd, f) 是将文件描述符和 struct file 关联起来
**

总结

image.png