sys_open()代码分析
open
应用程序在操作任何一个文件之前,必须先调用open()来打开该文件,即通知内核新建一个代表该文件的结构,并且返回该文件的描述符(一个整数),该描述符在进程内唯一。open()的格式如下:
int open(const char * pathname,int oflag, mode_t mode )
pathname:代表需要打开的文件的文件名;
oflag:表示打开的标识;
O_ACCMODE<0003>: 读写文件操作时,用于取出flag的低2位。
O_RDONLY<00>: 只读打开
O_WRONLY<01>: 只写打开
O_RDWR<02>: 读写打开
O_CREAT<0100>: 文件不存在则创建,需要mode_t
O_EXCL<0200>: 如果同时指定了O_CREAT,而文件已经存在,则出错
O_NOCTTY<0400>: 如果pathname代表终端设备,则不将此设备分配作为此进程的控制终端
O_TRUNC<01000>: 如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0
O_APPEND<02000>: 每次写时都加到文件的尾端
O_NONBLOCK<04000>: 如果p a t h n a m e指的是一个F I F O、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I / O操作设置非阻塞方式。
O_NDELAY<O_NONBLOCK>
O_SYNC<010000>: 使每次write都等到物理I/O操作完成。
FASYNC<020000>: 兼容BSD的fcntl同步操作
O_DIRECT<040000>: 直接磁盘操作标识,每次读写都不使用内核提供的缓存,直接读写磁盘设备
O_LARGEFILE<0100000>: 大文件标识
O_DIRECTORY<0200000>: 必须是目录
O_NOFOLLOW<0400000>: 不获取连接文件
O_NOATIME<01000000>: 暂无
mode:当新创建一个文件时,需要指定mode参数,以下说明的格式如宏定义名称<实际常数值>: 描述如下:
S_IRWXU<00700>:文件拥有者有读写执行权限
S_IRUSR (S_IREAD)<00400>:文件拥有者仅有读权限
S_IWUSR (S_IWRITE)<00200>:文件拥有者仅有写权限
S_IXUSR (S_IEXEC)<00100>:文件拥有者仅有执行权限
S_IRWXG<00070>:组用户有读写执行权限
S_IRGRP<00040>:组用户仅有读权限
S_IWGRP<00020>:组用户仅有写权限
S_IXGRP<00010>:组用户仅有执行权限
S_IRWXO<00007>:其他用户有读写执行权限
S_IROTH<00004>:其他用户仅有读权限
S_IWOTH<00002>:其他用户仅有写权限
S_IXOTH<00001>:其他用户仅有执行权限
当open()系统调用进入内核时候,最终调用的函数为SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
,该函数位于fs/open.c中,下面转入分析该代码。
SYSCALL_DEFINE3
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)
{
long ret;
if (force_o_largefile())
flags |= O_LARGEFILE;
//检查内核是不是支持大文件,如果是大文件的话就对flags标记对应的标记位置位
ret = do_sys_open(AT_FDCWD, filename, flags, mode);
//完成主要的open工作,AT_FDCWD表示从当前目录开始查找
/* avoid REGPARM breakage on x86: */
asmlinkage_protect(3, ret, filename, flags, mode);
return ret;
}
该函数主要调用do_sys_open()来完成打开工作,do_sys_open()的代码分析如下。
do_sys_open
内核实现真正的打开
long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
{
struct open_flags op;
int lookup = build_open_flags(flags, mode, &op);
char *tmp = getname(filename);
//将文件名参数从用户态拷贝至内核,调用函数get_name();
int fd = PTR_ERR(tmp);
//PTR_ERR函数用于将指针型的错误码转换为长整型的。
//IS_ERR函数用于判断指针函数的返回值是否为错误码,如果是,则表示该指针函数执行失败。
if (!IS_ERR(tmp)) {
fd = get_unused_fd_flags(flags);
//用于获取尚未占用的文件描述符;
if (fd >= 0) {
struct file