perftrace@gmail.com
本文主要通过分析 linux 系统中的文件打开逻辑, 来掌握 linux 虚拟文件系统相关的数据结构, 函数等知识点, 将之前的各个点的知识串联成一个整体.
1 文件系统简介
系统中给所有文件系统不但依赖 VFS, 而且依靠 VFS 系统协同工作. 使用 VFS 可以利用标准的 Unix 系统调用对不同的文件系统, 甚至不同介质上的文件系统进行读写操作.
Unix 使用了四种和文件系统相关的传统抽象概念: 文件, 目录项, 索引节点和安装点.
VFS 中共有四个主要对象类型分别是:
l  超级块对象, 代表一个具体的已安装文件系统, 操作对象为 super_operations
l  索引节点对象, 代表一个具体文件, 操作对象为 inode_operations
l  目录项对象, 代表一个目录项, 是路径的一个组成部分, 操作对象为 dentry_operations
l  文件对象, 代表由进程打开的文件, 操作对象为 file_operations
不存在目录对象.
涉及的数据结构在文中会逐一出现. 下面我们从上层应用开始来看下 linux 系统打开一个文件的逻辑过程.
2 应用触发
使用一个C程序如下:
- #include <unistd.h>
- #include <stdio.h>
- #include <sys/mman.h>
- #include <fcntl.h>
- #include <stdlib.h>
- int
- main ()
- {
- int i, f;
- FILE *fp;
- char string[24];
- fp = fopen ("test.dat", "w+");
- sprintf (string, "helloworld\n");
- fwrite (string, 11, 1, fp);
- fclose (fp);
- }
直接使用 gcc 编译,#gcc -g -o io io.c
这里我们看到在应用中使用了函数 fopen(库函数), 该函数来负责打开文件.
这个函数在 linux 中就是 glibc . 其官方下载链接是: https://www.gnu.org/software/libc/sources.html .
3 内核入口
使用 strace ./io 后, 可以发现会调用系统调用 open 来实现文件的打开.
- ......
- open("test.dat", O_RDWR|O_CREAT|O_TRUNC, 0666) = 3
- ......
这个系统调用才是内核中的函数, 该函数定义在如下:
- SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
- {
- if (force_o_largefile())
- flags |= O_LARGEFILE;
- return do_sys_open(AT_FDCWD, filename, flags, mode);
- }
这个是系统调用, 会调用 do_sys_open 函数.
在 do_sys_open 函数中, 会通过函数 build_open_flags 来设置需要打开文件的 flags(其结构体为 open_flags), 接着通过函数 get_unused_fd_flags 获取一个可用的 fd, 此函数调用 alloc_fd() 函数从 fd_table 中获取一个可用 fd, 并做些简单初始化得到一个文件描述符 (). 接着调用 do_filp_open 函数获取 file 对象. 最后通过 fd_install, 建立文件描述符和 file 之间的关联, 即安装在进程的 fd 数组中.
4 逻辑流程
逻辑流程如下图:
5 参考
从文件 IO 看 Linux 的虚拟文件系统 https://www.ibm.com/developerworks/cn/linux/l-cn-vfs/index.html
来源: https://yq.aliyun.com/articles/617364