打开一个文件,是通过内核提供的系统调用sys_open来实现的,在用户空间的open函数会被编译器编译成为int 80的汇编代码,进入内核空间执行打开操作,我们来顺着内核的代码来看一下具体的实现过程。
sys_open函数定义在fs/open.c文件,定义如下
核心的操作都在do_sys_open(AT_FDCWD, filename, flags, mode);里边,其他的都只是检查一下参数是否合法,我们来看do_sys_open是怎么实现的吧,do_sys_open定义在fs/open.c文件,定义如下
然后我们继续看do_filp_open函数,do_filp_open函数定义在fs/open.c文件,定义如下
sys_open函数定义在fs/open.c文件,定义如下
asmlinkage long sys_open(const char __user *filename, int flags, int mode)
{
long ret;
/*检查内核是不是支持大文件,如果是大文件的话就对flags标记对应的标记位置位*/
if (force_o_largefile())
flags |= O_LARGEFILE;
/*封装的操作*/
ret = do_sys_open(AT_FDCWD, filename, flags, mode);
/* 禁止编译器尾部优化 */
prevent_tail_call(ret);
return ret;
}
核心的操作都在do_sys_open(AT_FDCWD, filename, flags, mode);里边,其他的都只是检查一下参数是否合法,我们来看do_sys_open是怎么实现的吧,do_sys_open定义在fs/open.c文件,定义如下
long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
{
/*把用户空间的存在内存的文件名字符串复制到内核空间*/
char *tmp = getname(filename);
int fd = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
/*寻找一个暂时没用的文件描述符,或者没有的话返回错误*/
fd = get_unused_fd();
if (fd >= 0) {
/*如果找到的话,就执行打开操作*/
struct file *f = do_filp_open(dfd, tmp, flags, mode);
if (IS_ERR(f)) {
/*打开失败,就释放文件描述符*/
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
fsnotify_open(f->f_path.dentry);
fd_install(fd, f);
}
}
putname(tmp);
}
return fd;
}
然后我们继续看do_filp_open函数,do_filp_open函数定义在fs/open.c文件,定义如下
/*
* 注意flag标记位低