挂载完成之后,文件系统就可以使用了,可以拉出来练练了。
open
常见的编程语言的文件操作,都会有一个open函数,它们最终都会调用系统调用open
。这个系统调用的定义在kernel/fs/open.c。
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
是所有文件打开的必经之路,有必要好好的研究一下它。
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
struct open_flags op;
int fd = build_open_flags(flags, mode, &op);
struct filename *tmp;
if (fd)
return fd;
tmp = getname(filename);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
fd = get_unused_fd_flags(flags);
if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, &op);
if (IS_ERR(f)) {
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
fsnotify_open(f);
fd_install(fd, f);
}
}
putname(tmp);
return fd;
}
先看fd = get_unused_fd_flags(flags);
,这句是要获得fd。fd是file descriptor,即文件描述符。对于小白来说,这个东西会比较抽象,这里先理清一下。
文件描述符
现代计算机可以并发运行多个程序,每个程序就是一个进程。当我们说打开文件时,主语就是某一个进程,即我们可以说“某个进程打开了文件”。
文件在被访问之前都要先打开(原因这里先不管),若甲进程打开了一个文件后,乙进程也要访问这个文件,那么乙进程也要打开文件,然后才能访问。也就是说,每个进程对文件的开关状态都是独立的。
将视角聚焦到一个进程上,它可以同时打开多个文件,这些被这个进程打开的文件都会有一份相关信息被放在内存里,其中一个信息就是这个fd。这个fd可以简单理解为进程打开的文件的编号,编号从0开始。在Linux系统中,新创建的进程会默认打开标准输入、标准输出和标准错误输出文件,它们的fd值是0,1,2,当我们再打开一个文件时,它的fd会是3。当我们关闭文件时,它的fd值会被释放,可以重新用作其它文件的打开。看get_unused_fd_flags
可知,最小的没被占用的fd会被优先返回。