本笔记主要针对 linux/fs/open.c
中的系统调用进行分析。
open
系统调用的基本处理流程如下:
off_t
配置为32位:
CONFIG_ARCH_32BIT_OFF_T
被启用,则 off_t
最多支持2GB的偏移量。若用户态程序想要读取大文件,则用户态需要显式定义 _FILE_OFFSET_BITS=64
或使用 O_LARGEFILE
标志来启用64位的off_t
。CONFIG_ARCH_32BIT_OFF_T
未启用,则默认开启大文件模式。off_t
,默认开启大文件模式。long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
:
build_open_how
将用户态的 umode_t
转化为内核态的 open_how
结构体,同时过滤掉非法标志位或模式位。在该结构体中:
__u64 flags
:表示用户态使用 open
时指定的行为,例如读写、文件创建、文件追加等。__u64 mode
:当需要创建文件时,文件的权限。不需要创建文件时该成员值为0。__u64 resolve
:指定用于路径解析的方式,例如禁止解析符号链接、避免跨越设备边界进行路径解析等。static long do_sys_openat2(int dfd, const char __user *filename, struct open_how *how)
:
build_open_flags
将 open_how
转换为 flags
,同时进行大量的文件行为标识符、文件权限以及路径解析的方式的参数检查,如果失败则返回对应错误码。成功时返回0。getname
获取文件名,如果失败则返回对应错误码。get_unused_fd_flags
获取一个未使用的文件标识符。fd
大于0时,调用 struct file *do_filp_open(int dfd, struct filename *pathname, const struct open_flags *op)
打开文件:
set_nameidata
struct file *path_openat(struct nameidata *nd, const struct open_flags *op, unsigned flags)
打开文件:
alloc_empty_file
创建一个空的文件对象( struct file
)。fput
减少对文件对象的引用。restore_nameidata
struct file
对象。do_filp_open
执行成功时,返回内核文件对象 struct file
,并调用 fd_install
向 fd_table
中添加一个 fd
及其对应的 file
对象。do_filp_open
发生错误时,调用 put_unused_fd
归还未使用的 fd
,并用 fd
存放错误信息fd
。close
系统调用的基本处理流程如下:
struct file *file_close_fd(unsigned int fd);
,从 fdt
( fd_table
)中寻找 fd
对应的 file
结构体指针。 filp_flush
刷新文件缓冲区。
BUG()
停止系统。f_op->flush
时调用 f_op->flush
。dnotify_flush
处理目录通知。locks_remove_posix
移除该文件的POSIX锁。void __fput_sync();
减少文件的引用计数器(下面全都在干这个),并当最后一个引用被释放时:
void __fput(struct file *file)
释放文件的最后一个引用:
struct file
结构体。might_sleep
标注,该标注在release模式下无效,在调试模式下可以在原子上下文中捕获该标注,并打印堆栈等信息。fsnotify_close
向监听者触发文件关闭事件。eventpoll_release
回收与 epoll
相关的资源。locks_remove_file
释放与该文件相关的所有锁。security_file_release
,该函数是Linux安全模块的钩子函数,允许安全模块对该事件的监听。f_op->fasync
时,调用 f_op->fasync
将该文件从驱动程序的通知队列中移除。f_op->release
时,调用 f_op->release
释放文件。S_ISCHR
检查 inode
是否是一个字符设备,如果满足如下若干条件则减少对字符设备的引用计数:
void module_put(struct module *module)
减少对该文件的内核模块的引用计数。void put_pid(struct pid *pid)
减少对该PID结构体的引用计数。void put_file_access(struct file *file)
减少对该文件的读取和写入计数器。dput
减少对该文件的目录项结构体( struct dentry
)的引用。FMODE_NEED_UNMOUNT
(是否需要取消挂载该挂载实例),如果设置了则调用 dissolve_on_fput
取消挂载。mntput
减少对文件系统挂载实例( struct vfsmount
)的引用。file_free
释放 struct file
结构体。filp_flush
的特定错误。filp_flush
的返回值。需要注意的是: