【Note】《深入理解Linux内核》Chapter 16 :深入理解 Linux 文件访问机制

《深入理解Linux内核》Chapter 16 :深入理解 Linux 文件访问机制

关键词:VFS、文件描述符、struct file、struct inode、open、read、write、close、dentry、权限校验、file_operations、O_NOATIME、权限继承


一、概览:Linux 文件访问路径

在 Linux 中,几乎一切资源都可以通过“文件”的形式访问。文件访问不仅涵盖传统的磁盘文件,还包括设备、管道、socket、内存映射对象等。

1.1 文件访问操作的主要系统调用

int open(const char *pathname, int flags, mode_t mode);
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
int close(int fd);

1.2 高层用户行为与内核调用链映射关系

open() ──> sys_open() ──> do_sys_open()
        └─> do_filp_open()
            └─> namei 解析
            └─> permission 检查
            └─> 创建 struct file / struct dentry / struct inode

整个文件访问路径经过 VFS(Virtual File System),它为所有具体文件系统(如 ext4、xfs)提供统一抽象接口。


二、文件访问核心数据结构

2.1 struct file

表示进程打开的一个“活跃”文件(open file instance):

struct file {
    struct file_operations *f_op;
    struct dentry *f_dentry;
    struct vfsmount *f_vfsmnt;
    loff_t f_pos;               // 文件指针
    unsigned int f_flags;      // 打开标志 O_RDONLY 等
    mode_t f_mode;             // 访问权限
    ...
};
  • 每次 open() 都会生成一个新的 struct file 实例;
  • 多个进程可共享同一 inode,但 file 各自独立。

2.2 struct inode

表示文件的元信息(持久存在于文件系统中):

struct inode {
    umode_t i_mode;
    struct file_operations *i_fop;
    unsigned long i_ino;       // inode 编号
    struct super_block *i_sb;
    ...
};
  • 包含权限、类型、大小等元数据;
  • 指向实际文件系统方法。

2.3 struct dentry

路径名与 inode 的绑定:

struct dentry {
    struct inode *d_inode;
    struct dentry *d_parent;
    struct qstr d_name;
    ...
};
  • 提供快速路径名缓存(dcache);
  • 减少路径查找成本。

三、文件描述符(File Descriptor)管理

3.1 文件描述符本质

文件描述符是用户空间表示“打开文件”的整数编号,其实是进程文件描述表的下标。

struct files_struct {
    struct file **fdt;     // file descriptor table
};

每个进程拥有一份 files_struct,记录其打开的所有文件。

3.2 分配流程

  1. get_unused_fd_flags():分配描述符;
  2. fd_install():将 struct file 与 fd 绑定;
  3. 返回 fd 给用户空间。

3.3 close() 释放流程

  1. sys_close(fd)filp_close()
  2. 文件引用计数减少;
  3. 若为0,则释放 file,关闭底层资源。

四、open 系统调用流程详解

4.1 系统调用入口

SYSCALL_DEFINE3(open, const char __user *, filename,
                int, flags, umode_t, mode)

4.2 执行路径

sys_open()
 └── do_sys_open()
     └── get_unused_fd()
     └── do_filp_open()
         └── open_namei()  // 路径解析
         └── inode_permission()
         └── alloc_file()
     └── fd_install()

4.3 特殊标志处理

  • O_CREAT:若文件不存在则创建;
  • O_TRUNC:打开时清空文件;
  • O_APPEND:每次写入追加;
  • O_DIRECTORY:仅允许打开目录;
  • O_NOATIME:不更新访问时间。

五、路径名解析与权限校验

5.1 名称解析:namei 机制

do_filp_open() 调用 path_openat() 执行路径查找:

path_lookupat()
 └── walk_component()  // 按“/”逐级查找
 └── dcache 查找 dentry
 └── 最终找到目标 inode

5.2 权限检查:inode_permission()

根据 inode 上的权限位与当前进程身份(UID/GID)判断是否允许访问。

bool inode_permission(struct inode *inode, int mask);

六、read() / write() 调用路径与文件系统接口

6.1 read() 调用链

sys_read()
 └── vfs_read()
     └── file->f_op->read_iter()
         └── generic_file_read_iter()
             └── filemap_read()   // 页缓存操作
  • 页缓存命中则直接返回数据;
  • 否则调用 readpage 从磁盘读取。

6.2 write() 调用链

sys_write()
 └── vfs_write()
     └── file->f_op->write_iter()
         └── generic_file_write_iter()
             └── filemap_write()
  • 将用户数据拷贝到页缓存;
  • 标记页面为脏(dirty);
  • 后台回写到磁盘。

七、文件关闭流程 close()

7.1 close 调用链

sys_close()
 └── filp_close()
     └── fput()
         └── file->f_op->release()
  • 文件关闭后释放内核资源;
  • 若是 socket、管道等可能触发数据发送/同步。

八、文件打开的共享与继承

8.1 多进程共享文件

  • 父子进程通过 fork() 会共享打开的文件;
  • 描述符表复制,但 struct file 不复制;
  • 使用 dup() / dup2() 可在进程中手动复制描述符。

8.2 exec() 后文件处理

  • O_CLOEXEC 文件描述符默认会保留;
  • 使用 fcntl(fd, F_SETFD, FD_CLOEXEC) 设置关闭标志。

九、VFS 中的文件操作方法表(file_operations)

文件系统驱动实现 file_operations,VFS 会在 open() 时设置 file->f_op 指针:

struct file_operations {
    ssize_t (*read) (...);
    ssize_t (*write) (...);
    int (*open) (...);
    int (*release) (...);
    int (*mmap) (...);
    ...
};
  • VFS 提供统一接口;
  • 文件系统提供底层实现;
  • 用户空间无感知。

十、访问控制机制与扩展支持

10.1 标准 UNIX 权限模型

  • 文件 inode 包含权限位(rwx);
  • UID、GID 与进程身份匹配后生效。

10.2 Access Control List(ACL)

支持更细粒度的权限控制:

getfacl file
setfacl -m u:alice:r file

10.3 LSM 与权限扩展

Linux 安全模块(LSM)如 SELinux、AppArmor、Smack 可拦截 inode_permission() 等操作,实施细粒度安全策略。


十一、缓存一致性与刷新机制

11.1 页缓存同步

  • 文件修改不会立即反映到磁盘;
  • 调用 fsync() / fdatasync() 强制同步;
  • 文件系统驱动实现 ->fsync() 方法。

11.2 内核同步点

  • close() 时可触发写回;
  • O_SYNC / O_DSYNC 方式可实现同步写入;
  • msync() 同步 mmap 页面。

十二、调试与工具支持

  • strace:跟踪系统调用(open, read, write);
  • lsof:列出进程打开的文件;
  • /proc//fd/:文件描述符映射;
  • /proc/sys/fs/file-*:查看文件句柄使用上限;
  • fstat():获取打开文件信息;
  • fadvise():优化访问模式(顺序/随机/丢弃);

十三、源码路径参考

文件路径 功能描述
fs/open.c 实现 open/close 系统调用
fs/read_write.c 实现 read/write 系统调用
fs/namei.c 路径解析(namei 系统)
fs/file_table.c 文件描述符分配与管理
include/linux/fs.h file/inode/dentry 等结构定义
fs/dcache.c dentry 缓存管理

十四、小结

  • open/read/write/close 系统调用通过 VFS 实现;
  • 文件由 struct file/inode/dentry 多层结构抽象;
  • VFS 提供统一接口,文件系统实现具体逻辑;
  • 文件描述符是用户空间与内核文件对象的桥梁;
  • 权限检查与缓存管理确保性能与安全并重。

你可能感兴趣的:(读书笔记,linux,linux,运维,服务器)