Linux 文件系统 API 概述

本节包含 API 级别的文档,主要取自源代码本身。

Linux VFS

文件系统类型

enum positive_aop_returns

具有特定语义的 aop 返回码

常量

AOP_WRITEPAGE_ACTIVATE

通知调用者页面回写已完成,页面仍被锁定,应被视为活动。VM 使用此提示将页面返回到活动列表——它在不久的将来不会再次成为回写的候选者。其他调用者必须小心,如果他们得到此返回,则解锁页面。由 writepage() 返回;

AOP_TRUNCATED_PAGE

被传递了锁定页面的 AOP 方法已将其解锁,并且页面可能已被截断。调用者应该返回到获取新页面并重试。aop 将采取合理的预防措施以避免活锁。如果调用者持有页面引用,则应在重试之前将其删除。由 read_folio() 返回。

描述

address_space_operation 函数返回这些大型常量,以向调用者指示特殊的语义。这些常量比页面中的字节大得多,以便允许函数返回给定页面中操作的字节数。

struct address_space

可缓存、可映射对象的内容。

定义:

struct address_space {
    struct inode            *host;
    struct xarray           i_pages;
    struct rw_semaphore     invalidate_lock;
    gfp_t gfp_mask;
    atomic_t i_mmap_writable;
#ifdef CONFIG_READ_ONLY_THP_FOR_FS;
    atomic_t nr_thps;
#endif;
    struct rb_root_cached   i_mmap;
    unsigned long           nrpages;
    pgoff_t writeback_index;
    const struct address_space_operations *a_ops;
    unsigned long           flags;
    errseq_t wb_err;
    spinlock_t i_private_lock;
    struct list_head        i_private_list;
    struct rw_semaphore     i_mmap_rwsem;
    void *                  i_private_data;
};

成员

host

所有者,inode 或 block_device。

i_pages

缓存的页面。

invalidate_lock

在无效期间,保护页面缓存内容与文件偏移量 -> 磁盘块映射之间的连贯性。它还用于阻止通过内存映射修改页面缓存内容。

gfp_mask

用于分配页面的内存分配标志。

i_mmap_writable

VM_SHARED、VM_MAYWRITE 映射的数量。

nr_thps

页面缓存中 THP 的数量(仅限非共享内存)。

i_mmap

私有和共享映射树。

nrpages

页面条目的数量,受 i_pages 锁保护。

writeback_index

回写从此开始。

a_ops

方法。

flags

错误位和标志 (AS_*)。

wb_err

最近发生的错误。

i_private_lock

供 address_space 的所有者使用。

i_private_list

供 address_space 的所有者使用。

i_mmap_rwsem

保护 i_mmapi_mmap_writable

i_private_data

供 address_space 的所有者使用。

struct file_ra_state

跟踪文件的预读状态。

定义:

struct file_ra_state {
    pgoff_t start;
    unsigned int size;
    unsigned int async_size;
    unsigned int ra_pages;
    unsigned int mmap_miss;
    loff_t prev_pos;
};

成员

start

最近的预读开始的位置。

size

最近的预读中读取的页面数。

async_size

立即不需要,因此是真正“提前”的页面数。当访问这些页面中的第一个页面时,启动下一个预读。

ra_pages

预读请求的最大大小,从 bdi 复制。

mmap_miss

在页面缓存中错过了多少次 mmap 访问。

prev_pos

最近读取请求中的最后一个字节。

描述

当此结构传递给 ->readahead() 时,“最近的”预读表示当前的预读。

struct file

表示一个文件

定义:

struct file {
    file_ref_t f_ref;
    spinlock_t f_lock;
    fmode_t f_mode;
    const struct file_operations    *f_op;
    struct address_space            *f_mapping;
    void *private_data;
    struct inode                    *f_inode;
    unsigned int                    f_flags;
    unsigned int                    f_iocb_flags;
    const struct cred               *f_cred;
    struct path                     f_path;
    union {
        struct mutex            f_pos_lock;
        u64 f_pipe;
    };
    loff_t f_pos;
#ifdef CONFIG_SECURITY;
    void *f_security;
#endif;
    struct fown_struct              *f_owner;
    errseq_t f_wb_err;
    errseq_t f_sb_err;
#ifdef CONFIG_EPOLL;
    struct hlist_head               *f_ep;
#endif;
    union {
        struct callback_head    f_task_work;
        struct llist_node       f_llist;
        struct file_ra_state    f_ra;
        freeptr_t f_freeptr;
    };
};

成员

f_ref

引用计数

f_lock

保护 f_ep、f_flags。不得从 IRQ 上下文获取。

f_mode

FMODE_* 标志通常在热路径中使用

f_op

文件操作

f_mapping

可缓存、可映射对象的内容。

private_data

文件系统或驱动程序特定数据

f_inode

缓存的 inode

f_flags

文件标志

f_iocb_flags

iocb 标志

f_cred

创建者/打开者的隐藏凭据

f_path

文件路径

{unnamed_union}

匿名

f_pos_lock

保护文件位置的锁

f_pipe

特定于管道

f_pos

文件位置

f_security

此文件的 LSM 安全上下文

f_owner

文件所有者

f_wb_err

回写错误

f_sb_err

每个 sb 的回写错误

f_ep

此文件的所有 epoll 钩子的链接

{unnamed_union}

匿名

f_task_work

任务工作入口点

f_llist

工作队列入口点

f_ra

文件的预读状态

f_freeptr

SLAB_TYPESAFE_BY_RCU 文件缓存使用的指针(请勿触摸)。

vfsuid_t i_uid_into_vfsuid(struct mnt_idmap *idmap, const struct inode *inode)

根据 idmapping 映射 inode 的 i_uid

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

const struct inode *inode

要映射的 inode

返回

根据 idmap 映射的 inode 的 i_uid。如果 inode 的 i_uid 没有映射,则返回 INVALID_VFSUID。

bool i_uid_needs_update(struct mnt_idmap *idmap, const struct iattr *attr, const struct inode *inode)

检查 inode 的 i_uid 是否需要更新

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

const struct iattr *attr

inode 的新属性

const struct inode *inode

要更新的 inode

描述

检查 $inode 的 i_uid 字段是否需要更新,如果文件系统支持,则考虑 idmapped 挂载。

返回

如果 inode 的 i_uid 字段需要更新,则为 true,否则为 false。

void i_uid_update(struct mnt_idmap *idmap, const struct iattr *attr, struct inode *inode)

更新 inode 的 i_uid 字段

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

const struct iattr *attr

inode 的新属性

struct inode *inode

要更新的 inode

描述

安全地更新 inode 的 i_uid 字段,将任何 idmapped 挂载的 vfsuid 转换为文件系统 kuid。

vfsgid_t i_gid_into_vfsgid(struct mnt_idmap *idmap, const struct inode *inode)

根据 idmapping 映射 inode 的 i_gid

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

const struct inode *inode

要映射的 inode

返回

根据 idmap 映射的 inode 的 i_gid。如果 inode 的 i_gid 没有映射,则返回 INVALID_VFSGID。

bool i_gid_needs_update(struct mnt_idmap *idmap, const struct iattr *attr, const struct inode *inode)

检查 inode 的 i_gid 是否需要更新

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

const struct iattr *attr

inode 的新属性

const struct inode *inode

要更新的 inode

描述

检查 $inode 的 i_gid 字段是否需要更新,如果文件系统支持,则考虑 idmapped 挂载。

返回

如果 inode 的 i_gid 字段需要更新,则为 true,否则为 false。

void i_gid_update(struct mnt_idmap *idmap, const struct iattr *attr, struct inode *inode)

更新 inode 的 i_gid 字段

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

const struct iattr *attr

inode 的新属性

struct inode *inode

要更新的 inode

描述

安全地更新 inode 的 i_gid 字段,将任何 idmapped 挂载的 vfsgid 转换为文件系统的 kgid。

void inode_fsuid_set(struct inode *inode, struct mnt_idmap *idmap)

使用调用者的 fsuid 初始化 inode 的 i_uid 字段

参数

struct inode *inode

要初始化的 inode

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

描述

初始化 inode 的 i_uid 字段。如果 inode 是通过 idmapped 挂载找到/创建的,则根据 idmap 映射调用者的 fsuid。

void inode_fsgid_set(struct inode *inode, struct mnt_idmap *idmap)

使用调用者的 fsgid 初始化 inode 的 i_gid 字段

参数

struct inode *inode

要初始化的 inode

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

描述

初始化 inode 的 i_gid 字段。如果 inode 是通过 idmapped 挂载找到/创建的,则根据 idmap 映射调用者的 fsgid。

bool fsuidgid_has_mapping(struct super_block *sb, struct mnt_idmap *idmap)

检查是否映射了调用者的 fsuid/fsgid

参数

struct super_block *sb

我们想要映射的超级块

struct mnt_idmap *idmap

相关挂载的 idmap

描述

检查调用者的 fsuid 和 fsgid 在超级块 sb 的 s_user_ns 中是否具有有效的映射。如果调用者在 idmapped 挂载上,则首先根据 idmap 映射调用者的 fsuid 和 fsgid。

返回

如果 fsuid 和 fsgid 已映射,则为 true,否则为 false。

struct timespec64 inode_set_ctime(struct inode *inode, time64_t sec, long nsec)

在 inode 中设置 ctime

参数

struct inode *inode

在其中设置 ctime 的 inode

time64_t sec

要设置的 tv_sec 值

long nsec

要设置的 tv_nsec 值

描述

inode 中的 ctime 设置为 { sec, nsec }

int __sb_write_started(const struct super_block *sb, int level)

检查是否持有 sb 冻结级别

参数

const struct super_block *sb

我们写入的超级块

int level

冻结级别

描述

  • > 0 - 持有 sb 冻结级别

  • 0 - 未持有 sb 冻结级别

  • < 0 - !CONFIG_LOCKDEP/LOCK_STATE_UNKNOWN

bool sb_write_started(const struct super_block *sb)

检查是否持有 SB_FREEZE_WRITE

参数

const struct super_block *sb

我们写入的超级块

描述

使用 !CONFIG_LOCKDEP/LOCK_STATE_UNKNOWN 可能出现误报。

bool sb_write_not_started(const struct super_block *sb)

检查是否未持有 SB_FREEZE_WRITE

参数

const struct super_block *sb

我们写入的超级块

描述

使用 !CONFIG_LOCKDEP/LOCK_STATE_UNKNOWN 可能出现误报。

bool file_write_started(const struct file *file)

检查是否持有 SB_FREEZE_WRITE

参数

const struct file *file

我们写入的文件

描述

使用 !CONFIG_LOCKDEP/LOCK_STATE_UNKNOWN 可能出现误报。使用 !S_ISREG 可能出现误报,因为 file_start_write() 对 !S_ISREG 无效。

bool file_write_not_started(const struct file *file)

检查是否未持有 SB_FREEZE_WRITE

参数

const struct file *file

我们写入的文件

描述

使用 !CONFIG_LOCKDEP/LOCK_STATE_UNKNOWN 可能出现误报。使用 !S_ISREG 可能出现误报,因为 file_start_write() 对 !S_ISREG 无效。

void sb_end_write(struct super_block *sb)

释放对超级块的写入访问权限

参数

struct super_block *sb

我们写入的超级块

描述

减少文件系统的写入器数量。唤醒可能想要冻结文件系统的等待者。

void sb_end_pagefault(struct super_block *sb)

从页面错误中释放对超级块的写入访问权限

参数

struct super_block *sb

我们写入的超级块

描述

减少处理文件系统写入页面错误的进程数量。唤醒可能想要冻结文件系统的等待者。

void sb_end_intwrite(struct super_block *sb)

为内部 fs 目的释放对超级块的写入访问权限

参数

struct super_block *sb

我们写入的超级块

描述

减少文件系统内部对文件系统的写入器数量。唤醒可能想要冻结文件系统的等待者。

void sb_start_write(struct super_block *sb)

获取对超级块的写入访问权限

参数

struct super_block *sb

我们写入的超级块

描述

当进程想要向文件系统写入数据或元数据时(例如,将页面或 inode 标记为脏),它应该将操作嵌入 sb_start_write() - sb_end_write() 对中,以获得对文件系统冻结的互斥。此函数会增加写入器数量,从而防止冻结。如果文件系统已冻结,则该函数会等待,直到文件系统解冻。

由于冻结保护的行为类似于锁,因此用户必须保留冻结保护和其他文件系统锁的顺序。通常,冻结保护应该是最外层的锁。特别是,我们有

sb_start_write

-> i_mutex (写入路径、截断、目录操作等) -> s_umount (freeze_super, thaw_super)

void sb_start_pagefault(struct super_block *sb)

从页面错误中获取对超级块的写入访问权限

参数

struct super_block *sb

我们写入的超级块

描述

当进程开始处理写页面错误时,它应该将该操作嵌入到 sb_start_pagefault() - sb_end_pagefault() 对中,以防止文件系统冻结。这是必需的,因为页面错误将要脏化一个页面。此函数会增加正在运行的页面错误的数量,从而防止冻结。如果文件系统已经冻结,该函数会等待直到文件系统解冻。

由于页面错误的冻结保护行为类似于锁,用户必须保持冻结保护和其他文件系统锁的顺序。建议将 sb_start_pagefault() 放置在锁顺序中接近 mmap_lock 的位置。页面错误处理代码意味着锁依赖关系

mmap_lock

-> sb_start_pagefault

void sb_start_intwrite(struct super_block *sb)

获取超级块的写入访问权限,用于内部文件系统目的

参数

struct super_block *sb

我们写入的超级块

描述

这是防止文件系统冻结的第三级保护。文件系统可以自由使用它。唯一的要求是它必须低于 sb_start_pagefault。

例如,文件系统可以在启动事务时调用 sb_start_intwrite(),这在某种程度上简化了处理文件系统更改的内部来源(内部文件系统线程、在文件关闭时丢弃预分配等)的冻结。

struct renamedata

包含重命名所需的所有信息

定义:

struct renamedata {
    struct mnt_idmap *old_mnt_idmap;
    struct inode *old_dir;
    struct dentry *old_dentry;
    struct mnt_idmap *new_mnt_idmap;
    struct inode *new_dir;
    struct dentry *new_dentry;
    struct inode **delegated_inode;
    unsigned int flags;
};

成员

old_mnt_idmap

找到 inode 的旧挂载的 idmap

old_dir

源的父目录

old_dentry

new_mnt_idmap

找到 inode 的新挂载的 idmap

new_dir

目标的父目录

new_dentry

目标

delegated_inode

返回需要委托中断的 inode

flags

重命名标志

enum freeze_holder

冻结的持有者

常量

FREEZE_HOLDER_KERNEL

内核想要冻结或解冻文件系统

FREEZE_HOLDER_USERSPACE

用户空间想要冻结或解冻文件系统

FREEZE_MAY_NEST

是否允许嵌套冻结和解冻请求

描述

指示冻结或解冻请求的所有者以及冻结是需要独占还是可以嵌套。如果没有 FREEZE_MAY_NEST,则不允许来自同一持有者的多个冻结和解冻请求。但是,允许同时持有单个 FREEZE_HOLDER_USERSPACE 和单个 FREEZE_HOLDER_KERNEL 冻结。一些文件系统在在线修复或类似情况下依赖于此。

bool is_mgtime(const struct inode *inode)

此 inode 是否使用多粒度时间戳

参数

const struct inode *inode

要测试多粒度时间戳的 inode

描述

如果 inode 使用多粒度时间戳,则返回 true,否则返回 false。

bool is_idmapped_mnt(const struct vfsmount *mnt)

检查挂载是否已映射

参数

const struct vfsmount *mnt

要检查的挂载

描述

如果 mnt 附加了非 nop_mnt_idmap,则 mnt 已映射。

返回

如果挂载已映射,则为 true,否则为 false。

void file_start_write(struct file *file)

获取常规文件 IO 的超级块写入访问权限

参数

struct file *file

我们要写入的文件

描述

这是 sb_start_write() 的变体,它在非常规文件上是无操作的。应与调用 file_end_write() 匹配。

void file_end_write(struct file *file)

放弃对常规文件的超级块的写入访问权限

参数

struct file *file

我们写入的文件

描述

应与调用 file_start_write() 匹配。

void kiocb_start_write(struct kiocb *iocb)

获取用于异步文件 IO 的超级块写入访问权限

参数

struct kiocb *iocb

我们想要提交写入的 IO 上下文

描述

这是 sb_start_write() 的变体,用于异步 IO 提交。应与调用 kiocb_end_write() 匹配。

void kiocb_end_write(struct kiocb *iocb)

在异步文件 IO 之后放弃对超级块的写入访问权限

参数

struct kiocb *iocb

我们提交写入的 IO 上下文

描述

应与调用 kiocb_start_write() 匹配。

bool is_dot_dotdot(const char *name, size_t len)

仅当 name 为“.”或“..”时返回 true

参数

const char *name

要检查的文件名

size_t len

文件名长度,以字节为单位

void inode_dio_begin(struct inode *inode)

发出直接 I/O 请求开始的信号

参数

struct inode *inode

直接 I/O 发生的 inode

描述

一旦我们完成处理直接 I/O 请求后就会调用此函数,用于唤醒等待直接 I/O 静止的调用者。

void inode_dio_end(struct inode *inode)

发出直接 I/O 请求完成的信号

参数

struct inode *inode

直接 I/O 发生的 inode

描述

一旦我们完成处理直接 I/O 请求后就会调用此函数,用于唤醒等待直接 I/O 静止的调用者。

bool generic_ci_validate_strict_name(struct inode *dir, struct qstr *name)

检查给定的名称是否适合目录

参数

struct inode *dir

将在其中创建新文件的目录的 inode

struct qstr *name

新文件的名称

描述

此函数检查建议的文件名对于父目录是否有效。这意味着,对于使用严格编码标志创建的文件系统中启用不区分大小写的目录,只接受有效的 UTF-8 文件名。这也意味着,对于未启用不区分大小写或未严格使用编码的目录,将接受任何名称。

返回

  • True:如果文件名适合此目录。如果给定的名称不适合严格编码的目录,但正在使用的目录不严格,则可能为 true。

  • False:如果文件名不适合此目录。这仅在目录不区分大小写且文件系统对其编码严格时才会发生。

目录缓存

void d_drop(struct dentry *dentry)

删除一个 dentry

参数

struct dentry *dentry

要删除的 dentry

描述

d_drop() 从父 dentry 哈希中取消哈希该条目,使其不再能通过 VFS 查找找到。 请注意,这与删除 dentry 不同 - 如果可能,d_delete 将尝试将 dentry 标记为负数,从而提供成功的 _negative_ 查找,而 d_drop 只会使缓存查找失败。

d_drop() 主要用于由于某种原因(NFS 超时或 autofs 删除)想要使 dentry 无效的内容。

__d_drop 需要 dentry->d_lock

___d_drop 不会将 dentry 标记为“未哈希”(dentry->d_hash.pprev 将是 LIST_POISON2,而不是 NULL)。

struct dentry *d_find_any_alias(struct inode *inode)

查找给定 inode 的任何别名

参数

struct inode *inode

要查找别名的 inode

描述

如果给定 inode 存在任何别名,则获取并返回其中一个的引用。如果不存在别名,则返回 NULL

struct dentry *d_find_alias(struct inode *inode)

获取 inode 的哈希别名

参数

struct inode *inode

有问题的 inode

描述

如果 inode 有哈希别名,或者是一个目录并且有任何别名,则获取对别名的引用并返回它。否则,返回 NULL。 请注意,如果 inode 是一个目录,则只能有一个别名,并且只有当它没有子项时,或者如果它是文件系统的根目录,或者如果该目录已重命名并且 d_revalidate 是第一个注意到该重命名的 vfs 操作时,它才能被取消哈希。

如果 inode 具有 IS_ROOT、DCACHE_DISCONNECTED 别名,则优先选择任何其他哈希别名。

void shrink_dcache_sb(struct super_block *sb)

收缩超级块的 dcache

参数

struct super_block *sb

超级块

描述

收缩指定超级块的 dcache。这用于在卸载文件系统之前释放 dcache。

int path_has_submounts(const struct path *parent)

检查当前命名空间中 dentry 上的挂载。

参数

const struct path *parent

要检查的路径。

描述

如果父级或其子目录在当前命名空间中包含挂载点,则返回 true。

void shrink_dcache_parent(struct dentry *parent)

修剪 dcache

参数

struct dentry *parent

要修剪的条目的父级

描述

修剪 dcache 以删除父 dentry 的未使用的子项。

void d_invalidate(struct dentry *dentry)

分离子挂载、修剪 dcache 和删除

参数

struct dentry *dentry

要使其失效的 dentry(又名分离、修剪和删除)

struct dentry *d_alloc(struct dentry *parent, const struct qstr *name)

分配 dcache 条目

参数

struct dentry * parent

要分配的条目的父级

const struct qstr *name

名称的 qstr

描述

分配一个 dentry。如果可用内存不足,则返回 NULL。成功后,将返回 dentry。传入的名称会被复制,并且传入的副本可以在此调用后重复使用。

void d_instantiate(struct dentry *entry, struct inode *inode)

填写 dentry 的 inode 信息

参数

struct dentry *entry

要完成的 dentry

struct inode * inode

要附加到此 dentry 的 inode

描述

填写条目中的 inode 信息。

这将负 dentry 转换为有成效的社会成员。

注意!这假定调用方已递增(或以其他方式设置)inode 计数,以表明它现在正在被 dcache 使用。

struct dentry *d_obtain_alias(struct inode *inode)

查找或为给定 inode 分配 DISCONNECTED dentry

参数

struct inode *inode

要为其分配 dentry 的 inode

描述

获取通过 NFS 文件句柄转换或类似的按句柄操作打开而产生的 inode 的 dentry。 返回的 dentry 可能是匿名的,或者可能具有完整名称(如果 inode 已经在缓存中)。

当在目录 inode 上调用时,我们必须确保 inode 只有一个 dentry。 如果找到 dentry,则返回该 dentry 而不是分配新的 dentry。

成功返回时,对 inode 的引用已转移到 dentry。 如果发生错误,则释放 inode 上的引用。 为了使其更容易在导出操作中使用,可以传入 NULL 或 IS_ERR inode,并且错误将传播到返回值,其中 NULL inode 将替换为 ERR_PTR(-ESTALE)。

struct dentry *d_obtain_root(struct inode *inode)

查找或为给定 inode 分配 dentry

参数

struct inode *inode

要为其分配 dentry 的 inode

描述

获取文件系统根目录的 IS_ROOT dentry。

我们必须确保目录 inode 只有一个 dentry。 如果找到 dentry,则返回该 dentry 而不是分配新的 dentry。

成功返回时,对 inode 的引用已转移到 dentry。 如果发生错误,则释放 inode 上的引用。 可以传入 NULL 或 IS_ERR inode,并且错误将传播到返回值,其中 NULL inode 将替换为 ERR_PTR(-ESTALE)。

struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, struct qstr *name)

使用区分大小写的名称查找或分配新的 dentry

参数

struct dentry *dentry

传递给父级查找函数的负 dentry

struct inode *inode

不区分大小写的 inode 查找已找到的 inode

struct qstr *name

要与返回的 dentry 关联的区分大小写的名称

描述

这是为了避免用不区分大小写的名称填充 dcache 到同一个 inode,只有实际正确的名称大小写才会存储在不区分大小写的文件系统的 dcache 中。

对于不区分大小写的查找匹配,如果区分大小写的 dentry 已经存在于 dcache 中,则使用它并返回它。

如果不存在具有精确大小写名称的条目,则使用精确大小写分配新的 dentry,并返回拼接的条目。

bool d_same_name(const struct dentry *dentry, const struct dentry *parent, const struct qstr *name)

将 dentry 名称与区分大小写的名称进行比较

参数

const struct dentry *dentry

传递给父级查找函数的负 dentry

const struct dentry *parent

父 dentry

const struct qstr *name

要与返回的 dentry 关联的区分大小写的名称

返回

如果名称相同则返回 true,否则返回 false

struct dentry *d_lookup(const struct dentry *parent, const struct qstr *name)

搜索 dentry

参数

const struct dentry *parent

父 dentry

const struct qstr *name

我们要查找的名称的 qstr

返回

dentry,或 NULL

描述

d_lookup 在父 dentry 的子项中搜索有问题的名称。如果找到该 dentry,则其引用计数会递增并返回该 dentry。调用者必须使用 dput 在完成使用后释放条目。如果 dentry 不存在,则返回 NULL

struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name)

对 qstr 进行哈希处理,然后搜索 dentry

参数

struct dentry *dir

要在其中搜索的目录

struct qstr *name

我们要查找的名称的 qstr

描述

如果查找失败,则返回 NULL;如果名称错误,则返回 ERR_PTR(-error)

void d_delete(struct dentry *dentry)

删除 dentry

参数

struct dentry * dentry

要删除的 dentry

描述

如果可能,将 dentry 转换为负 dentry,否则将其从哈希队列中删除,以便稍后删除

void d_rehash(struct dentry *entry)

将条目添加回哈希

参数

struct dentry * entry

要添加到哈希的 dentry

描述

根据其名称将 dentry 添加到哈希中。

void d_add(struct dentry *entry, struct inode *inode)

将 dentry 添加到哈希队列

参数

struct dentry *entry

要添加的 dentry

struct inode *inode

要附加到此 dentry 的 inode

描述

这将条目添加到哈希队列并初始化 **inode**。该条目实际上是在稍早的 d_alloc() 期间填充的。

struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode)

查找并哈希精确的未哈希别名

参数

struct dentry *entry

要添加的 dentry

struct inode *inode

要与此 dentry 一起使用的 inode

描述

如果具有相同名称/父级和所需 inode 的未哈希 dentry 已存在,则对其进行哈希并返回。否则,返回 NULL。

父目录应锁定。

struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)

如果存在,将断开连接的 dentry 拼接回树中

参数

struct inode *inode

可能具有断开连接的 dentry 的 inode

struct dentry *dentry

我们希望指向 inode 的负 dentry。

描述

如果 inode 是目录且具有 IS_ROOT 别名,则 d_move 该别名以代替给定的 dentry 并返回它,否则只需将 inode 添加到 dentry 并返回 NULL。

如果找到非 IS_ROOT 目录,则文件系统已损坏,我们应该报错退出:目录不能有多个别名。

任何可导出(通过 knfsd)的文件系统的查找例程都需要这样做,以便我们可以有效地构建指向目录的 dcache 路径。

如果找到并移动了 dentry,则返回它。否则,返回 NULL。这与 ->lookup 的预期返回值匹配。

集群文件系统可能会使用负的、哈希的 dentry 调用此函数。在这种情况下,我们知道 inode 将是常规文件,并且这只会发生在 atomic_open 期间。因此,我们只需要在最后一种情况下检查 dentry 是否已进行哈希处理。

bool is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)

new_dentry 是否是 old_dentry 的子目录

参数

struct dentry *new_dentry

新的 dentry

struct dentry *old_dentry

旧的 dentry

描述

如果 new_dentry 是父目录的子目录(任何深度),则返回 true。否则返回 false。调用者必须确保在调用 is_subdir() 之前已固定“new_dentry”

struct dentry *dget_dlock(struct dentry *dentry)

获取一个 dentry 的引用。

参数

struct dentry *dentry

要获取引用的 dentry。

描述

给定一个活动的 dentry,递增引用计数并返回 dentry。调用者必须持有 dentry->d_lock。确保 dentry 处于活动状态是调用者的责任。有许多条件足以保证这一点;例如,任何具有非负引用计数的都是活动的,任何哈希的,任何正数的,任何人的父级等等。

struct dentry *dget(struct dentry *dentry)

获取一个 dentry 的引用。

参数

struct dentry *dentry

要获取引用的 dentry。

描述

给定一个 dentry 或 NULL 指针,如果合适,则递增引用计数并返回 dentry。当 dentry 有引用时,它不会被销毁。相反,没有引用的 dentry 可能会因多种原因而消失,首先是内存压力。换句话说,该原语用于克隆现有引用;在引用计数为零的对象上使用它是错误的。

注意

如果持有 dentry->d_lock,它将自旋。从避免死锁的角度来看,它等效于 spin_lock()/递增引用计数/spin_unlock(),因此在 dentry->d_lock 下调用它始终是一个错误;在其任何后代上在 ->d_lock 下调用它也是如此。

int d_unhashed(const struct dentry *dentry)

dentry 是否已哈希

参数

const struct dentry *dentry

要检查的条目

描述

如果传递的 dentry 当前未被哈希,则返回 true。

bool d_really_is_negative(const struct dentry *dentry)

确定 dentry 是否真的是负的(忽略 fallthrough)。

参数

const struct dentry *dentry

有问题的 dentry。

描述

如果 dentry 表示不存在的名称或未映射到 inode 的名称(即 ->d_inode 为 NULL),则返回 true。dentry 可能表示真正的缺失、未由 0,0 字符设备表示的白化或不透明目录中的 fallthrough 标记。

注意!(1)这应该*仅*由文件系统用来检查其自己的 dentry。它不应该用于查看其他文件系统的 dentry。(2)它还应该与 d_inode() 结合使用以获取 inode。(3)dentry 可能在 ->d_lower 上附加了某些内容,并且标志的类型字段可能设置为 miss 或 whiteout 以外的其他内容。

bool d_really_is_positive(const struct dentry *dentry)

确定 dentry 是否真的是正的(忽略 fallthrough)。

参数

const struct dentry *dentry

有问题的 dentry。

描述

如果 dentry 表示映射到 inode 的名称(即 ->d_inode 不为 NULL),则返回 true。如果介质上将 whiteout 表示为 0,0 字符设备,则 dentry 可能仍然表示 whiteout。

注意!(1)这应该*仅*由文件系统用来检查其自己的 dentry。它不应该用于查看其他文件系统的 dentry。(2)它还应该与 d_inode() 结合使用以获取 inode。

struct inode *d_inode(const struct dentry *dentry)

获取此 dentry 的实际 inode。

参数

const struct dentry *dentry

要查询的 dentry。

描述

这是辅助函数,普通文件系统应该使用它来获取其自身 dentry 中自己的 inode,并忽略叠加在它们之上的层。

struct inode *d_inode_rcu(const struct dentry *dentry)

使用 READ_ONCE() 获取此 dentry 的实际 inode。

参数

const struct dentry *dentry

要查询的 dentry。

描述

这是辅助函数,普通文件系统应该使用它来获取其自身 dentry 中自己的 inode,并忽略叠加在它们之上的层。

struct inode *d_backing_inode(const struct dentry *upper)

获取我们应该使用的上层或下层 inode。

参数

const struct dentry *upper

上层。

描述

这是辅助函数,应该用于获取如果此 dentry 要作为文件打开将使用的 inode。inode 可能在上层 dentry 上,也可能在由上层固定的下层 dentry 上。

普通文件系统不应该使用它来访问它们自己的 inode。

struct dentry *d_real(struct dentry *dentry, enum d_real_type type)

返回真实的 dentry。

参数

struct dentry *dentry

要查询的 dentry。

enum d_real_type type

真实 dentry 的类型(数据或元数据)。

描述

如果 dentry 位于联合/覆盖上,则返回底层的真实 dentry。否则,返回 dentry 本身。

另请参阅:Linux 虚拟文件系统概述

struct inode *d_real_inode(const struct dentry *dentry)

返回托管数据的真实 inode。

参数

const struct dentry *dentry

要查询的 dentry。

描述

如果 dentry 位于联合/覆盖上,则返回底层的真实 inode。否则,返回 d_inode()

Inode 处理

int inode_init_always_gfp(struct super_block *sb, struct inode *inode, gfp_t gfp)

执行 inode 结构初始化。

参数

struct super_block *sb

inode 所属的超级块。

struct inode *inode

要初始化的 inode。

gfp_t gfp

分配标志。

描述

这些是在每次分配 inode 时需要完成的初始化,因为这些字段不会被 slab 分配初始化。 如果需要额外的分配,则使用 gfp

直接减少 inode 的链接计数

参数

struct inode *inode

inode

描述

这是一个底层文件系统辅助函数,用于替换任何对 i_nlink 的直接文件系统操作。在我们尝试跟踪对文件系统的写入的情况下,减少到零意味着当文件被截断并在文件系统上实际取消链接时即将发生写入。

直接将 inode 的链接计数清零

参数

struct inode *inode

inode

描述

这是一个底层文件系统辅助函数,用于替换任何对 i_nlink 的直接文件系统操作。有关我们为什么关心 i_nlink 达到零,请参阅 drop_nlink()

直接设置 inode 的链接计数

参数

struct inode *inode

inode

unsigned int nlink

新的链接计数(应为非零)

描述

这是一个底层文件系统辅助函数,用于替换任何对 i_nlink 的直接文件系统操作。

直接递增 inode 的链接计数

参数

struct inode *inode

inode

描述

这是一个底层文件系统辅助函数,用于替换任何对 i_nlink 的直接文件系统操作。目前,它只是为了与 dec_nlink() 保持一致。

void inode_sb_list_add(struct inode *inode)

将 inode 添加到超级块的 inode 列表

参数

struct inode *inode

要添加的 inode

void __insert_inode_hash(struct inode *inode, unsigned long hashval)

哈希一个 inode

参数

struct inode *inode

未哈希的 inode

unsigned long hashval

用于在 inode_hashtable 中定位此对象的无符号长整型值。

将 inode 添加到此超级块的 inode 哈希中。

void __remove_inode_hash(struct inode *inode)

从哈希中移除一个 inode

参数

struct inode *inode

要取消哈希的 inode

从超级块中移除一个 inode。

void evict_inodes(struct super_block *sb)

清除超级块的所有可清除 inode

参数

struct super_block *sb

要操作的超级块

描述

确保不保留任何引用计数为零的 inode。 这在删除 SB_ACTIVE 标志后由超级块关闭调用,因此任何在此调用期间或之后引用计数达到零的 inode 将立即被清除。

struct inode *new_inode(struct super_block *sb)

获取一个 inode

参数

struct super_block *sb

超级块

为给定的超级块分配一个新的 inode。 与 inode->i_mapping 相关的分配的默认 gfp_mask 是 GFP_HIGHUSER_MOVABLE。 如果 HIGHMEM 页面不合适,或者已知为页面缓存分配的页面不可回收或不可迁移,则必须在新建 inode 的映射上使用合适的标志调用 mapping_set_gfp_mask()

void unlock_new_inode(struct inode *inode)

清除 I_NEW 状态并唤醒任何等待者

参数

struct inode *inode

要解锁的新 inode

描述

当 inode 完全初始化时调用,以清除 inode 的新状态并唤醒任何等待 inode 完成初始化的人。

void lock_two_nondirectories(struct inode *inode1, struct inode *inode2)

在非目录对象上获取两个 i_mutex

参数

struct inode *inode1

要锁定的第一个 inode

struct inode *inode2

要锁定的第二个 inode

描述

锁定任何非 NULL 参数。传递的对象不能是目录。 此函数可以锁定零个、一个或两个对象。

void unlock_two_nondirectories(struct inode *inode1, struct inode *inode2)

lock_two_nondirectories() 释放锁

参数

struct inode *inode1

要解锁的第一个 inode

struct inode *inode2

要解锁的第二个 inode

struct inode *inode_insert5(struct inode *inode, unsigned long hashval, int (*test)(struct inode*, void*), int (*set)(struct inode*, void*), void *data)

从已挂载的文件系统中获取 inode

参数

struct inode *inode

预先分配的 inode,用于插入缓存

unsigned long hashval

要获取的哈希值(通常是 inode 号)

int (*test)(struct inode *, void *)

用于 inode 之间比较的回调函数

int (*set)(struct inode *, void *)

用于初始化新的 struct inode 的回调函数

void *data

传递给 testset 的不透明数据指针

描述

在 inode 缓存中搜索由 hashvaldata 指定的 inode,如果存在,则返回该 inode,并增加其引用计数。这是 iget5_locked() 的一个变体,它不分配 inode。

如果 inode 不在缓存中,则插入预先分配的 inode 并将其返回,该 inode 已锁定、哈希处理,并设置了 I_NEW 标志。文件系统在通过 unlock_new_inode() 解锁之前会填充它。

请注意,testset 都是在持有 inode_hash_lock 的情况下调用的,因此它们不能睡眠。

struct inode *iget5_locked(struct super_block *sb, unsigned long hashval, int (*test)(struct inode*, void*), int (*set)(struct inode*, void*), void *data)

从已挂载的文件系统中获取 inode

参数

struct super_block *sb

文件系统的超级块

unsigned long hashval

要获取的哈希值(通常是 inode 号)

int (*test)(struct inode *, void *)

用于 inode 之间比较的回调函数

int (*set)(struct inode *, void *)

用于初始化新的 struct inode 的回调函数

void *data

传递给 testset 的不透明数据指针

描述

在 inode 缓存中搜索由 hashvaldata 指定的 inode,如果存在,则返回该 inode,并增加其引用计数。这是 iget_locked() 的通用版本,适用于 inode 号不足以唯一标识 inode 的文件系统。

如果 inode 不在缓存中,则分配并插入一个新的 inode,并将其返回,该 inode 已锁定、哈希处理,并设置了 I_NEW 标志。文件系统在通过 unlock_new_inode() 解锁之前会填充它。

请注意,testset 都是在持有 inode_hash_lock 的情况下调用的,因此它们不能睡眠。

struct inode *iget5_locked_rcu(struct super_block *sb, unsigned long hashval, int (*test)(struct inode*, void*), int (*set)(struct inode*, void*), void *data)

从已挂载的文件系统中获取 inode

参数

struct super_block *sb

文件系统的超级块

unsigned long hashval

要获取的哈希值(通常是 inode 号)

int (*test)(struct inode *, void *)

用于 inode 之间比较的回调函数

int (*set)(struct inode *, void *)

用于初始化新的 struct inode 的回调函数

void *data

传递给 testset 的不透明数据指针

描述

这等同于 iget5_locked,只是 test 回调函数必须容忍 inode 不稳定,包括正在拆卸中。

struct inode *iget_locked(struct super_block *sb, unsigned long ino)

从已挂载的文件系统中获取 inode

参数

struct super_block *sb

文件系统的超级块

unsigned long ino

要获取的 inode 号

描述

在 inode 缓存中搜索由 ino 指定的 inode,如果存在,则返回该 inode,并增加其引用计数。这适用于 inode 号足以唯一标识 inode 的文件系统。

如果 inode 不在缓存中,则分配一个新的 inode,并将其返回,该 inode 已锁定、哈希处理,并设置了 I_NEW 标志。文件系统在通过 unlock_new_inode() 解锁之前会填充它。

ino_t iunique(struct super_block *sb, ino_t max_reserved)

获取唯一的 inode 号

参数

struct super_block *sb

超级块

ino_t max_reserved

最高的保留 inode 号

为给定的超级块获取系统上唯一的 inode 号。这由没有自然的永久 inode 编号系统的文件系统使用。返回的 inode 号高于保留限制,但唯一。

BUG:当文件系统中有大量活动 inode 时,此函数当前会变得非常慢。

struct inode *ilookup5_nowait(struct super_block *sb, unsigned long hashval, int (*test)(struct inode*, void*), void *data)

在 inode 缓存中搜索 inode

参数

struct super_block *sb

要搜索的文件系统的超级块

unsigned long hashval

要搜索的哈希值(通常是 inode 号)

int (*test)(struct inode *, void *)

用于 inode 之间比较的回调函数

void *data

传递给 test 的不透明数据指针

描述

在 inode 缓存中搜索由 hashvaldata 指定的 inode。如果该 inode 在缓存中,则返回该 inode,并增加其引用计数。

注意2:test 是在持有 inode_hash_lock 的情况下调用的,因此不能睡眠。

注意

I_NEW 不会被等待,因此您必须非常小心地处理返回的 inode。您可能应该使用 ilookup5() 代替。

struct inode *ilookup5(struct super_block *sb, unsigned long hashval, int (*test)(struct inode*, void*), void *data)

在 inode 缓存中搜索 inode

参数

struct super_block *sb

要搜索的文件系统的超级块

unsigned long hashval

要搜索的哈希值(通常是 inode 号)

int (*test)(struct inode *, void *)

用于 inode 之间比较的回调函数

void *data

传递给 test 的不透明数据指针

描述

在 inode 缓存中搜索由 hashvaldata 指定的 inode,如果该 inode 在缓存中,则返回该 inode 并增加其引用计数。在返回 inode 之前,会等待 I_NEW 标志。返回时引用计数会增加。

对于 inode 编号不足以唯一标识 inode 的文件系统,这是 ilookup() 的通用版本。

注意

调用 test 时会持有 inode_hash_lock,因此不能休眠。

struct inode *ilookup(struct super_block *sb, unsigned long ino)

在 inode 缓存中搜索 inode

参数

struct super_block *sb

要搜索的文件系统的超级块

unsigned long ino

要搜索的 inode 编号

描述

在 inode 缓存中搜索 inode ino,如果该 inode 在缓存中,则返回该 inode 并增加其引用计数。

struct inode *find_inode_nowait(struct super_block *sb, unsigned long hashval, int (*match)(struct inode*, unsigned long, void*), void *data)

在 inode 缓存中查找 inode

参数

struct super_block *sb

要搜索的文件系统的超级块

unsigned long hashval

要搜索的哈希值(通常是 inode 号)

int (*match)(struct inode *, unsigned long, void *)

用于 inode 之间比较的回调函数

void *data

传递给 match 的不透明数据指针

描述

在 inode 缓存中搜索由 hashvaldata 指定的 inode,其中辅助函数 match 如果 inode 不匹配则返回 0,如果 inode 匹配则返回 1,如果应停止搜索则返回 -1。match 函数必须负责获取 i_lock 自旋锁并检查 i_state,以确定 inode 是否正在被释放或正在被初始化,并在返回 1 之前增加引用计数。它也不能休眠,因为它是在持有 inode_hash_lock 自旋锁的情况下调用的。

当函数永远不能阻塞时(find_inode() 可以在 __wait_on_freeing_inode() 中阻塞),或者当调用者不能增加引用计数时(因为结果 iput() 可能会导致 inode 驱逐),这是 ilookup5() 的更通用的版本。权衡之处在于,必须非常小心地实现 match 函数。

struct inode *find_inode_rcu(struct super_block *sb, unsigned long hashval, int (*test)(struct inode*, void*), void *data)

在 inode 缓存中查找 inode

参数

struct super_block *sb

要搜索的文件系统的超级块

unsigned long hashval

哈希键

int (*test)(struct inode *, void *)

用于测试 inode 匹配的函数

void *data

测试函数的数据

描述

在 inode 缓存中搜索由 hashvaldata 指定的 inode,其中辅助函数 test 如果 inode 不匹配则返回 0,如果匹配则返回 1。test 函数必须负责获取 i_lock 自旋锁并检查 i_state,以确定 inode 是否正在被释放或正在被初始化。

如果成功,这将返回 test 函数返回 1 的 inode,否则返回 NULL。

不允许 test 函数对提供的任何 inode 进行引用。它也不允许休眠。

调用者必须持有 RCU 读取锁。

struct inode *find_inode_by_ino_rcu(struct super_block *sb, unsigned long ino)

在 inode 缓存中查找 inode

参数

struct super_block *sb

要搜索的文件系统的超级块

unsigned long ino

要匹配的 inode 编号

描述

在 inode 缓存中搜索由 hashvaldata 指定的 inode,其中辅助函数 test 如果 inode 不匹配则返回 0,如果匹配则返回 1。test 函数必须负责获取 i_lock 自旋锁并检查 i_state,以确定 inode 是否正在被释放或正在被初始化。

如果成功,这将返回 test 函数返回 1 的 inode,否则返回 NULL。

不允许 test 函数对提供的任何 inode 进行引用。它也不允许休眠。

调用者必须持有 RCU 读取锁。

void iput(struct inode *inode)

释放一个 inode

参数

struct inode *inode

要释放的 inode

释放一个 inode,减少其使用计数。如果 inode 使用计数变为零,则释放该 inode,并且可能还会销毁该 inode。

因此,iput() 可以休眠。

int bmap(struct inode *inode, sector_t *block)

在文件中查找块号

参数

struct inode *inode

拥有所请求块号的 inode

sector_t *block

包含要查找的块的指针

*block 中的值替换为设备上与文件中请求的块号相对应的块号。也就是说,如果请求 inode 1 的块 4,则该函数会将 *block 中的 4 替换为相对于磁盘启动的磁盘块,该磁盘块保存该文件的块。

如果发生错误,则返回 -EINVAL,否则返回 0。如果映射落入空洞,则返回 0,并且 *block 也设置为 0。

int inode_update_timestamps(struct inode *inode, int flags)

更新 inode 上的时间戳

参数

struct inode *inode

要更新的 inode

int flags

需要更新的 S_* 标志

描述

当需要为读取或写入操作更新 inode 的时间戳时,会调用 update_time 函数。此函数负责更新实际时间戳。调用者有责任确保 inode 被适当地标记为脏。

如果需要更新 S_MTIME、S_CTIME 或 S_VERSION 中的任何一个,请尝试更新所有三个。S_ATIME 更新可以独立于其余更新进行处理。

返回一组 S_* 标志,指示哪些值已更改。

int generic_update_time(struct inode *inode, int flags)

更新 inode 上的时间戳

参数

struct inode *inode

要更新的 inode

int flags

需要更新的 S_* 标志

描述

当需要为读取或写入操作更新 inode 的时间戳时,将调用 update_time 函数。如果需要更新 S_MTIME、S_CTIME 或 S_VERSION 中的任何一个,我们会尝试更新所有这三个。S_ATIME 的更新可以独立于其他更新进行处理。

返回一个 S_* 掩码,指示哪些字段已更新。

int file_remove_privs(struct file *file)

删除特殊文件权限(suid,capabilities)

参数

struct file *file

要从中删除权限的文件

描述

当文件通过写入或截断被修改时,请确保删除特殊文件权限。

返回

成功返回 0,失败返回负的 errno。

struct timespec64 current_time(struct inode *inode)

返回 FS 时间(可能是精细粒度的)

参数

struct inode *inode

inode。

描述

返回当前时间,截断为 fs 支持的时间粒度,适合 ctime/mtime 更改。如果 ctime 被标记为已查询,则获取精细粒度的时间戳,但不更新下限。

对于多粒度 inode,这实际上是对文件将收到的时间戳的估计。实际更新必须通过 inode_set_ctime_current()

int file_update_time(struct file *file)

更新 mtime 和 ctime 时间

参数

struct file *file

访问的文件

描述

更新 inode 的 mtime 和 ctime 成员,并标记该 inode 以进行写回。请注意,此函数专门用于文件系统的文件写入路径,并且文件系统可以选择使用 _NOCMTIME inode 标志显式忽略通过此函数进行的更新,例如,对于由服务器处理这些时间戳的网络文件系统。对于需要分配空间以更新 inode 的文件系统,这可能会返回错误。

返回

成功返回 0,失败返回负的 errno。

int file_modified(struct file *file)

修改文件时处理强制性的 vfs 更改

参数

struct file *file

已修改的文件

描述

当文件被修改时,请确保删除特殊文件权限并更新时间设置。

上下文

调用者必须持有文件的 inode 锁。

返回

成功返回 0,失败返回负的 errno。

int kiocb_modified(struct kiocb *iocb)

修改文件时处理强制性的 vfs 更改

参数

struct kiocb *iocb

被修改的 iocb

描述

当文件被修改时,请确保删除特殊文件权限并更新时间设置。

上下文

调用者必须持有文件的 inode 锁。

返回

成功返回 0,失败返回负的 errno。

void inode_init_owner(struct mnt_idmap *idmap, struct inode *inode, const struct inode *dir, umode_t mode)

根据 posix 标准初始化新 inode 的 uid、gid、mode

参数

struct mnt_idmap *idmap

创建 inode 的挂载的 idmap

struct inode *inode

新的 inode

const struct inode *dir

目录 inode

umode_t mode

新 inode 的 mode

描述

如果 inode 是通过 idmapped 挂载创建的,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限并初始化 i_uid 和 i_gid。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

bool inode_owner_or_capable(struct mnt_idmap *idmap, const struct inode *inode)

检查当前任务对 inode 的权限

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

const struct inode *inode

正在检查的 inode

描述

如果当前用户在命名空间中拥有映射了 inode 所有者 uid 的 CAP_FOWNER,或者拥有该文件,则返回 true。

如果通过 idmapped 挂载找到 inode,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

void inode_dio_wait(struct inode *inode)

等待未完成的 DIO 请求完成

参数

struct inode *inode

要等待的 inode

描述

等待所有挂起的直接 I/O 请求完成,以便我们可以继续进行截断或等效操作。

必须在序列化获取 i_dio_count 新引用的锁下调用,通常由 inode->i_mutex 进行。

struct timespec64 timestamp_truncate(struct timespec64 t, struct inode *inode)

将 timespec 截断为粒度

参数

struct timespec64 t

Timespec

struct inode *inode

正在更新的 inode

描述

将 timespec 截断为包含 inode 的 fs 支持的粒度。始终向下舍入。gran 不能为 0,也不能大于一秒(NSEC_PER_SEC 或 10^9 纳秒)。

struct timespec64 inode_set_ctime_current(struct inode *inode)

将 ctime 设置为 current_time

参数

struct inode *inode

inode

描述

将 inode 的 ctime 设置为 inode 的当前值。返回已分配的当前值。如果这不是多粒度 inode,则我们将其设置为粗略时间和下限值中的较晚者。

如果是多粒度 inode,则我们首先查看粗粒度时间戳是否与已有的时间戳不同。如果是,则使用该时间戳。否则,获取精细粒度的时间戳。

之后,尝试将新值交换到 i_ctime_nsec 中。接受生成的 ctime,而不管交换的结果如何。如果它已经被替换,则该时间戳晚于较早的不可接受的时间戳,因此是可以接受的。

struct timespec64 inode_set_ctime_deleg(struct inode *inode, struct timespec64 update)

尝试更新委托 inode 上的 ctime

参数

struct inode *inode

要更新的 inode

struct timespec64 update

要设置 ctime 的 timespec64

描述

尝试代表委托持有者以原子方式更新 ctime。

nfs 服务器可以回调委托的持有者,以获取更新的 inode 属性,包括 mtime。当更新 mtime 时,将 ctime 更新为至少等于该值的值。

这可能会与 inode 的并发更新竞争,在这种情况下,更新会被跳过。

请注意,即使未启用多粒度时间戳,此方法也有效,因此在两种情况下都会使用。

bool in_group_or_capable(struct mnt_idmap *idmap, const struct inode *inode, vfsgid_t vfsgid)

检查调用者是否具有 CAP_FSETID 特权

参数

struct mnt_idmap *idmap

从挂载的 **inode** 中找到的 idmap

const struct inode *inode

要检查的 inode

vfsgid_t vfsgid

**inode** 的新的/当前的 vfsgid

描述

检查 **vfsgid** 是否在调用者的组列表中,或者调用者是否对 **inode** 具有 CAP_FSETID 特权。这可以用来确定是否可以保留 setgid 位,还是必须删除它。

返回

如果调用者具有足够的特权,则返回 true,否则返回 false。

umode_t mode_strip_sgid(struct mnt_idmap *idmap, const struct inode *dir, umode_t mode)

处理非目录的 sgid 位

参数

struct mnt_idmap *idmap

创建 inode 的挂载的 idmap

const struct inode *dir

父目录 inode

umode_t mode

要在 **dir** 中创建的文件的模式

描述

如果新文件的 **mode** 同时设置了 S_ISGID 和 S_IXGRP 位,并且 **dir** 设置了 S_ISGID 位,则确保调用者要么在父目录的组中,要么在其用户命名空间中具有 CAP_FSETID,并且对父目录具有特权。在所有其他情况下,从 **mode** 中删除 S_ISGID 位。

返回

要用于该文件的新模式

void make_bad_inode(struct inode *inode)

由于 I/O 错误,将 inode 标记为坏

参数

struct inode *inode

要标记为坏的 Inode

当由于介质或远程网络故障而无法读取 inode 时,此函数会将 inode 标记为“坏”,并导致从此点开始对它的 I/O 操作失败。

bool is_bad_inode(struct inode *inode)

inode 是否发生错误

参数

struct inode *inode

要测试的 inode

如果所讨论的 inode 已被标记为坏,则返回 true。

void iget_failed(struct inode *inode)

将正在构建中的 inode 标记为死并释放它

参数

struct inode *inode

要丢弃的 inode

描述

将正在构建中的 inode 标记为死并释放它。

注册和超级块

void deactivate_locked_super(struct super_block *s)

删除对超级块的活动引用

参数

struct super_block *s

要停用的超级块

删除对超级块的活动引用,如果没有其他活动引用,则将其转换为临时引用。在这种情况下,我们告诉 fs 驱动程序关闭它并删除我们刚刚获得的临时引用。

调用者持有超级块的独占锁;该锁被释放。

void deactivate_super(struct super_block *s)

删除对超级块的活动引用

参数

struct super_block *s

要停用的超级块

deactivate_locked_super() 的变体,除了超级块 _不_ 由调用者锁定。如果我们打算删除最后一个活动引用,则会在此之前获取锁。

void retire_super(struct super_block *sb)

防止超级块被重用

参数

struct super_block *sb

要停用的超级块

此函数将超级块标记为在超级块测试中忽略,这会阻止它被重用于任何新的挂载。如果超级块具有私有的 bdi,它也会取消注册,但不会减少超级块的引用计数,以防止潜在的竞争。引用计数由 generic_shutdown_super() 减少。此函数不能与 generic_shutdown_super() 并发调用。多次调用该函数是安全的,后续调用无效。

该标记仅会影响基于块设备的超级块的重用。如果使用此函数,其他超级块仍会被标记,但这不会影响它们的可重用性。

void generic_shutdown_super(struct super_block *sb)

用于 ->kill_sb() 的通用辅助函数

参数

struct super_block *sb

要终止的超级块

generic_shutdown_super() 对超级块关闭执行所有与 fs 无关的工作。典型的 ->kill_sb() 应该从超级块中选取所有需要销毁的 fs 特定对象,调用 generic_shutdown_super() 并释放上述对象。注意:dentry 和 inode _是_ 被处理的,不需要特别处理。

在调用此函数后,文件系统可能不再更改或重新排列属于此超级块的 dentry 集,也不得更改 dentry 到 inode 的附件。

struct super_block *sget_fc(struct fs_context *fc, int (*test)(struct super_block*, struct fs_context*), int (*set)(struct super_block*, struct fs_context*))

查找或创建超级块

参数

struct fs_context *fc

文件系统上下文。

int (*test)(struct super_block *, struct fs_context *)

比较回调函数

int (*set)(struct super_block *, struct fs_context *)

设置回调函数

描述

创建一个新的超级块或查找一个已存在的超级块。

test 回调函数用于查找匹配的已存在超级块。fc 中请求的参数是否被考虑取决于所使用的 test 回调函数。它们甚至可能被完全忽略。

如果匹配到一个已存在的超级块,它将被返回,除非

  1. 文件系统上下文 fc 的命名空间与已存在超级块的命名空间不同

  2. 文件系统上下文 fc 已请求不允许重用已存在的超级块

在这两种情况下,都将返回 EBUSY。

如果没有匹配项,则将分配一个新的超级块并执行基本初始化(将设置 s_type、s_fs_info 和 s_id,并且将调用 set 回调函数),该超级块将被发布,并且它将在部分构造状态下返回,SB_BORN 和 SB_ACTIVE 尚未设置。

返回

成功时,将返回一个已存在或新创建的超级块。

失败时,将返回一个错误指针。

struct super_block *sget(struct file_system_type *type, int (*test)(struct super_block*, void*), int (*set)(struct super_block*, void*), int flags, void *data)

查找或创建超级块

参数

struct file_system_type *type

超级块应属于的文件系统类型

int (*test)(struct super_block *,void *)

比较回调函数

int (*set)(struct super_block *,void *)

设置回调函数

int flags

挂载标志

void *data

传递给它们每一个的参数

void iterate_supers_type(struct file_system_type *type, void (*f)(struct super_block*, void*), void *arg)

为给定类型的超级块调用函数

参数

struct file_system_type *type

文件系统类型

void (*f)(struct super_block *, void *)

要调用的函数

void *arg

传递给它的参数

扫描超级块列表并调用给定函数,传递锁定的超级块和给定参数。

int get_anon_bdev(dev_t *p)

为没有块设备的文件系统分配一个块设备。

参数

dev_t *p

指向 dev_t 的指针。

描述

不使用实际块设备的文件系统可以调用此函数来分配一个虚拟块设备。

上下文

任何上下文。通常在持有 sb_lock 时调用。

返回

成功时返回 0,如果剩余的匿名 bdev 不够则返回 -EMFILE,如果内存分配失败则返回 -ENOMEM。

struct super_block *sget_dev(struct fs_context *fc, dev_t dev)

通过设备号查找或创建超级块

参数

struct fs_context *fc

文件系统上下文。

dev_t dev

设备号

描述

使用提供的设备号查找或创建将存储在 fc->sget_key 中的超级块。

如果匹配到一个已存在的超级块,则将返回该超级块,并且引用计数会增加,调用者必须传输或丢弃该引用计数。

如果没有匹配项,则将分配一个新的超级块并执行基本初始化(将设置 s_type、s_fs_info、s_id、s_dev)。该超级块将被发布,并且它将在部分构造状态下返回,SB_BORN 和 SB_ACTIVE 尚未设置。

返回

成功时返回一个已存在或新创建的超级块,失败时返回一个错误

指针。

int get_tree_bdev_flags(struct fs_context *fc, int (*fill_super)(struct super_block *sb, struct fs_context *fc), unsigned int flags)

基于单个块设备获取超级块

参数

struct fs_context *fc

包含参数的文件系统上下文

int (*fill_super)(struct super_block *sb, struct fs_context *fc)

用于初始化新超级块的助手函数

unsigned int flags

GET_TREE_BDEV_* 标志

int get_tree_bdev(struct fs_context *fc, int (*fill_super)(struct super_block*, struct fs_context*))

基于单个块设备获取超级块

参数

struct fs_context *fc

包含参数的文件系统上下文

int (*fill_super)(struct super_block *, struct fs_context *)

用于初始化新超级块的助手函数

int vfs_get_tree(struct fs_context *fc)

获取可挂载的根

参数

struct fs_context *fc

超级块配置上下文。

描述

调用文件系统以获取或创建一个超级块,该超级块稍后可用于挂载。文件系统将指向用于挂载的根的指针放置在 fc->root 中。

int freeze_super(struct super_block *sb, enum freeze_holder who)

锁定文件系统并强制其进入一致状态

参数

struct super_block *sb

要锁定的超级块

enum freeze_holder who

想要冻结的上下文

描述

同步超级块以确保文件系统的一致性,并调用文件系统的 freeze_fs。在没有先解冻文件系统的情况下,后续调用此函数可能会返回 -EBUSY。

who 应该是: * FREEZE_HOLDER_USERSPACE,如果用户空间想要冻结文件系统; * FREEZE_HOLDER_KERNEL,如果内核想要冻结文件系统; * FREEZE_MAY_NEST,是否允许嵌套冻结和解冻请求。

who 参数区分了内核和用户空间尝试冻结文件系统。尽管在任何给定时间都不能有多个内核冻结或多个用户空间冻结生效,但内核和用户空间都可以保持文件系统冻结。文件系统保持冻结状态,直到没有内核或用户空间冻结生效。

一个文件系统可能持有多个设备,因此一个文件系统可能通过多个块设备通过块层被冻结。在这种情况下,通过传递 FREEZE_MAY_NEST,请求被标记为允许嵌套。文件系统保持冻结状态,直到所有块设备都被解冻。如果在没有 FREEZE_MAY_NEST 的情况下尝试多次冻结,则会返回 -EBUSY。

在此函数执行期间,sb->s_writers.frozen 将经历以下值

SB_UNFROZEN:文件系统正常,所有写入照常进行。

SB_FREEZE_WRITE:文件系统正在被冻结的过程中。应阻止新的写入,但仍允许页面错误。我们等待所有写入完成,然后继续进行下一阶段。

SB_FREEZE_PAGEFAULT:冻结继续进行。现在也阻止了页面错误,但内部文件系统线程仍然可以修改文件系统(尽管它们不应该弄脏新的页面或 inode),回写可以运行等等。在等待所有正在运行的页面错误之后,我们同步文件系统,这将清理所有脏页面和 inode(当同步运行时,不会创建新的脏页面或 inode)。

SB_FREEZE_FS:文件系统已冻结。现在,所有文件系统修改的内部源都被阻止(例如,inode 回收时 XFS 预分配截断)。这通常通过阻止具有它们的并且需要此额外保护的文件系统的新事务来实现。在所有内部写入者完成后,我们调用 ->freeze_fs() 来完成文件系统的冻结。然后,我们转换为 SB_FREEZE_COMPLETE 状态。此状态主要是辅助文件系统验证它们不修改冻结的文件系统。

sb->s_writers.frozen 受 sb->s_umount 保护。

返回

如果冻结成功,则返回零。如果冻结

失败,则返回负错误代码。

int thaw_super(struct super_block *sb, enum freeze_holder who)
  • 解锁文件系统

参数

struct super_block *sb

要解冻的超级块

enum freeze_holder who

想要冻结的上下文

描述

如果在文件系统上没有剩余的冻结,则在 freeze_super() 之后解锁文件系统并将其标记为可写。

who 应该是: * FREEZE_HOLDER_USERSPACE,如果用户空间想要解冻文件系统; * FREEZE_HOLDER_KERNEL,如果内核想要解冻文件系统; * FREEZE_MAY_NEST,是否允许嵌套冻结和解冻请求。

一个文件系统可能持有多个设备,因此一个文件系统可能通过多个块设备通过块层被冻结。文件系统保持冻结状态,直到所有块设备都被解冻。

文件锁

bool locks_owner_has_blockers(struct file_lock_context *flctx, fl_owner_t owner)

检查是否有阻塞的锁请求

参数

struct file_lock_context *flctx

文件锁上下文

fl_owner_t owner

锁所有者

描述

返回值

trueowner 至少有一个阻塞者 falseowner 没有阻塞者

int locks_delete_block(struct file_lock *waiter)

停止等待文件锁

参数

struct file_lock *waiter

正在等待的锁

lockd/nfsd 需要在处理锁时断开连接。

int posix_lock_file(struct file *filp, struct file_lock *fl, struct file_lock *conflock)

将 POSIX 样式的锁应用于文件

参数

struct file *filp

要应用锁的文件

struct file_lock *fl

要应用的锁

struct file_lock *conflock

如果找到冲突的锁,则返回冲突锁副本的位置。

描述

向文件添加 POSIX 样式锁。我们尽可能合并相邻和重叠的锁。POSIX 锁按所有者任务排序,然后按起始地址排序

请注意,如果使用 FL_EXISTS 参数调用,调用者可以通过测试返回值是否为 -ENOENT 来确定是否成功释放了锁。

int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)

撤销文件上的所有未完成租约

参数

struct inode *inode

要返回的文件的 inode

unsigned int mode

O_RDONLY:仅中断写租约;O_WRONLY 或 O_RDWR:中断所有租约

unsigned int type

FL_LEASE:中断租约和委托;FL_DELEG:仅中断委托

break_lease(为了提高速度而内联)已经检查过此文件上至少存在某种锁(可能是一个租约)。租约在调用 open() 或 truncate() 时中断。除非您在 open() 中指定了 O_NONBLOCK,否则此函数可以休眠。

void lease_get_mtime(struct inode *inode, struct timespec64 *time)

使用独占租约更新 inode 的修改时间

参数

struct inode *inode

inode

struct timespec64 *time

指向包含上次修改时间的 timespec 的指针

描述

这是为了强制 NFS 客户端刷新其具有独占租约的文件的缓存。理由是如果有人拥有独占租约,那么他们可能会修改它。

int generic_setlease(struct file *filp, int arg, struct file_lease **flp, void **priv)

在打开的文件上设置租约

参数

struct file *filp

文件指针

int arg

要获取的租约类型

struct file_lease **flp

输入 - 要使用的 file_lock,输出 - 插入的 file_lock

void **priv

lm_setup 的私有数据(如果 lm_setup 不需要,则可能为 NULL)

break_lease() 需要(输入)flp->fl_lmops->lm_break 函数。

int vfs_setlease(struct file *filp, int arg, struct file_lease **lease, void **priv)

在打开的文件上设置租约

参数

struct file *filp

文件指针

int arg

要获取的租约类型

struct file_lease **lease

添加租约时使用的 file_lock

void **priv

添加租约时 lm_setup 的私有信息(如果 lm_setup 不需要,则可能为 NULL)

描述

调用此函数以在文件上建立租约。“lease”参数不用于 F_UNLCK 请求,可以为 NULL。对于设置或更改现有租约的命令,必须设置 (*lease)->fl_lmops->lm_break 操作;否则,此函数将返回 -ENOLCK(并生成一个看起来很吓人的堆栈跟踪)。

“priv” 指针将原样直接传递给 lm_setup 函数。如果 lm_setup 操作不需要,则可以为 NULL。

int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl)

对 inode 应用锁

参数

struct inode *inode

要应用锁的文件的 inode

struct file_lock *fl

要应用的锁

描述

对 inode 应用 POSIX 或 FLOCK 风格的锁请求。

int vfs_test_lock(struct file *filp, struct file_lock *fl)

测试文件字节范围锁

参数

struct file *filp

要测试锁的文件

struct file_lock *fl

要测试的锁;也用于保存结果

描述

失败时返回 -ERRNO。通过将 conf->fl_type 设置为 F_UNLCK 以外的值来指示存在冲突的锁。

int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)

文件字节范围锁

参数

struct file *filp

要应用锁的文件

unsigned int cmd

锁定操作的类型(F_SETLK、F_GETLK 等)

struct file_lock *fl

要应用的锁

struct file_lock *conf

如果找到冲突的锁,则返回冲突锁副本的位置。

描述

不关心冲突锁的调用者可以将 NULL 作为最后一个参数传递。

如果文件系统定义了私有的 ->lock() 方法,则 conf 将保持不变;因此,关心的调用者应将其初始化为某种可接受的默认值。

为了避免阻塞需要获取 POSIX 锁的内核守护进程(例如 lockd),如果设置了 lm_grant,则 ->lock() 接口可能会异步返回,在底层文件系统授予或拒绝锁之前。(并且只有在这种情况下)。此外,需要设置 export_operations 标志中的 EXPORT_OP_ASYNC_LOCK。

期望 ->lock() 异步返回的调用者将仅使用 F_SETLK,而不是 F_SETLKW;如果(并且只有当)请求是用于阻塞锁时,它们将设置 FL_SLEEP。当 ->lock() 异步返回时,它必须返回 FILE_LOCK_DEFERRED,并在锁请求完成时调用 ->lm_grant()。如果请求是非阻塞锁,则文件系统应返回 FILE_LOCK_DEFERRED,然后尝试获取锁,并使用结果调用回调例程。如果请求超时,则回调例程将返回非零返回值,并且文件系统应释放锁。文件系统还负责在授予锁时保留相应的 posix 锁,以便 VFS 可以找出本地持有哪些锁,并在需要时执行正确的锁清理。在以 FILE_LOCK_DEFERRED 返回代码返回到调用者之前,底层文件系统不得放弃内核锁或调用 ->lm_grant()。

int vfs_cancel_lock(struct file *filp, struct file_lock *fl)

文件字节范围解锁

参数

struct file *filp

要应用解锁的文件

struct file_lock *fl

要解锁的锁

描述

由锁管理器用来取消阻塞的请求

bool vfs_inode_has_locks(struct inode *inode)

是否在 inode 上持有任何文件锁?

参数

struct inode *inode

要检查锁的 inode

描述

如果当前在 inode 上设置了任何 FL_POSIX 或 FL_FLOCK 锁,则返回 true。

int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)

将 POSIX 样式的锁应用于文件

参数

struct inode *inode

应该应用锁请求的文件的 inode

struct file_lock *fl

要应用的锁

描述

对 inode 应用 POSIX 风格的锁请求。

int fcntl_getlease(struct file *filp)

询问当前活动的租约是什么

参数

struct file *filp

该文件

此函数返回的值将是以下之一(如果没有任何租约中断挂起)

F_RDLCK 表示持有共享租约。

F_WRLCK 表示持有独占租约。

F_UNLCK 表示未持有任何租约。

(如果租约中断挂起)

F_RDLCK 表示独占租约需要

更改为共享租约(或删除)。

F_UNLCK 表示需要删除租约。

XXX:sfr 和 willy 不同意是否应将 F_INPROGRESS 返回给用户空间。

int check_conflicting_open(struct file *filp, const int arg, int flags)

查看给定文件是否指向与所需租约冲突的现有打开的 inode。

参数

struct file *filp

要检查的文件

const int arg

我们尝试获取的租约的类型

int flags

当前的锁定标志

描述

检查此文件上是否存在与我们尝试设置的租约冲突的现有打开的 fd。

int fcntl_setlease(unsigned int fd, struct file *filp, int arg)

在打开的文件上设置租约

参数

unsigned int fd

打开的文件描述符

struct file *filp

文件指针

int arg

要获取的租约类型

调用此 fcntl 以在文件上建立租约。请注意,当租约中断时,您还需要调用 F_SETSIG 以接收信号。

int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl)

对文件应用 FLOCK 风格的锁

参数

struct inode *inode

要应用锁的文件的 inode

struct file_lock *fl

要应用的锁

描述

对 inode 应用 FLOCK 风格的锁请求。

long sys_flock(unsigned int fd, unsigned int cmd)
  • flock() 系统调用。

参数

unsigned int fd

要锁定的文件描述符。

unsigned int cmd

要应用的锁的类型。

对打开的文件描述符应用 FL_FLOCK 风格的锁。cmd 可以是以下之一:

  • LOCK_SH -- 共享锁。

  • LOCK_EX -- 排他锁。

  • LOCK_UN -- 移除已存在的锁。

  • LOCK_MAND -- ‘强制’ flock。(已弃用)

LOCK_MAND 支持已从内核中移除。

pid_t locks_translate_pid(struct file_lock_core *fl, struct pid_namespace *ns)

将 file_lock 的 fl_pid 号码转换为命名空间

参数

struct file_lock_core *fl

需要转换 fl_pid 的 file_lock

struct pid_namespace *ns

pid 需要被转换到的命名空间

描述

用于将 fl_pid 转换为命名空间虚拟 pid 号码

其他函数

void mpage_readahead(struct readahead_control *rac, get_block_t get_block)

开始针对页面的读取

参数

struct readahead_control *rac

描述要读取的页面。

get_block_t get_block

文件系统的块映射器函数。

描述

此函数遍历页面和每个页面内的块,构建并发出大的 BIO。

如果发生任何不寻常的事情,例如:

  • 遇到有缓冲区的页面

  • 遇到一个孔之后有一个非孔的页面

  • 遇到具有不连续块的页面

那么此代码只会放弃并调用基于 buffer_head 的读取函数。它确实处理了末尾有孔的页面 - 这是一个常见的情况:块大小 < PAGE_SIZE 设置的文件末尾。

BH_Boundary 解释

这里有一个问题。mpage 读取代码汇集了几个页面,获取它们的所有磁盘映射,然后全部提交。这很好,但是获取磁盘映射可能需要 I/O。例如,读取间接块。

因此,对 ext2 文件的前 16 个块进行 mpage 读取将导致按以下顺序提交 I/O

12 0 1 2 3 4 5 6 7 8 9 10 11 13 14 15 16

因为必须读取间接块才能获得块 13、14、15、16 的映射。显然,这会影响性能。

因此,我们所做的是允许文件系统的 get_block() 函数在映射块 11 时设置 BH_Boundary。BH_Boundary 表示:此块之后的块的映射将需要针对可能靠近此块的块进行 I/O。因此,你应该推送你当前累积的 I/O。

这一切都会导致磁盘请求以正确的顺序发出。

int mpage_writepages(struct address_space *mapping, struct writeback_control *wbc, get_block_t get_block)

遍历给定地址空间的脏页面列表,并 writepage() 所有这些页面

参数

struct address_space *mapping

要写入的地址空间结构

struct writeback_control *wbc

*wbc->nr_to_write 中减去写入页面的数量

get_block_t get_block

文件系统的块映射器函数。

描述

这是一个库函数,它实现了 writepages() address_space_operation。

int generic_permission(struct mnt_idmap *idmap, struct inode *inode, int mask)

检查类 Posix 文件系统的访问权限

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

struct inode *inode

要检查访问权限的 inode

int mask

要检查的权限(MAY_READMAY_WRITEMAY_EXECMAY_NOT_BLOCK ...)

描述

用于检查文件的读取/写入/执行权限。我们为此使用“fsuid”,这使我们可以为文件系统访问设置任意权限,而无需更改用于其他事情的“正常” uid。

generic_permission 是 rcu-walk 感知的。如果无法满足 rcu-walk 请求(例如,需要阻塞或过于复杂),则返回 -ECHILD。然后,将在 ref-walk 模式下再次调用它。

如果通过 idmapped 挂载找到 inode,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

int inode_permission(struct mnt_idmap *idmap, struct inode *inode, int mask)

检查给定 inode 的访问权限

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

struct inode *inode

要检查权限的 inode

int mask

要检查的权限(MAY_READMAY_WRITEMAY_EXEC

描述

检查 inode 的读取/写入/执行权限。我们为此使用 fs[ug]id,这使我们可以为文件系统访问设置任意权限,而无需更改用于其他事情的“正常” UID。

在检查 MAY_APPEND 时,还必须在 mask 中设置 MAY_WRITE。

void path_get(const struct path *path)

获取对路径的引用

参数

const struct path *path

要获取引用的路径

描述

给定路径,递增对 dentry 和 vfsmount 的引用计数。

void path_put(const struct path *path)

释放对路径的引用

参数

const struct path *path

要释放引用的路径

描述

给定路径,递减对 dentry 和 vfsmount 的引用计数。

int vfs_path_parent_lookup(struct filename *filename, unsigned int flags, struct path *parent, struct qstr *last, int *type, const struct path *root)

查找相对于 dentry-vfsmount 对的父路径

参数

struct filename *filename

文件名结构

unsigned int flags

查找标志

struct path *parent

指向要填充的 struct path 的指针

struct qstr *last

最后一个组件

int *type

最后一个组件的类型

const struct path *root

指向基本目录的 struct path 的指针

int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, const char *name, unsigned int flags, struct path *path)

查找相对于 dentry-vfsmount 对的文件路径

参数

struct dentry *dentry

指向基本目录的 dentry 的指针

struct vfsmount *mnt

指向基本目录的 vfs 挂载的指针

const char *name

指向文件名的指针

unsigned int flags

查找标志

struct path *path

指向要填充的 struct path 的指针

struct dentry *try_lookup_one_len(const char *name, struct dentry *base, int len)

文件系统助手,用于查找单个路径名组件

参数

const char *name

要查找的路径名组件

struct dentry *base

从中查找的基本目录

int len

要解释的最大长度 len

描述

通过名称在 dcache 中查找 dentry,如果当前不存在则返回 NULL。该函数不会尝试创建 dentry。

请注意,此例程纯粹是文件系统使用的助手,不应由通用代码调用。

调用者必须持有 base->i_mutex。

struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)

文件系统助手,用于查找单个路径名组件

参数

const char *name

要查找的路径名组件

struct dentry *base

从中查找的基本目录

int len

要解释的最大长度 len

描述

请注意,此例程纯粹是文件系统使用的助手,不应由通用代码调用。

调用者必须持有 base->i_mutex。

struct dentry *lookup_one(struct mnt_idmap *idmap, const char *name, struct dentry *base, int len)

文件系统助手,用于查找单个路径名组件

参数

struct mnt_idmap *idmap

执行查找的挂载的 idmap

const char *name

要查找的路径名组件

struct dentry *base

从中查找的基本目录

int len

要解释的最大长度 len

描述

请注意,此例程纯粹是文件系统使用的助手,不应由通用代码调用。

调用者必须持有 base->i_mutex。

struct dentry *lookup_one_unlocked(struct mnt_idmap *idmap, const char *name, struct dentry *base, int len)

文件系统助手,用于查找单个路径名组件

参数

struct mnt_idmap *idmap

执行查找的挂载的 idmap

const char *name

要查找的路径名组件

struct dentry *base

从中查找的基本目录

int len

要解释的最大长度 len

描述

请注意,此例程纯粹是文件系统使用的助手,不应由通用代码调用。

与 lookup_one_len 不同,它应该在不持有父 i_mutex 的情况下调用,并且如果需要将自行获取 i_mutex。

struct dentry *lookup_one_positive_unlocked(struct mnt_idmap *idmap, const char *name, struct dentry *base, int len)

文件系统助手,用于查找单个路径名组件

参数

struct mnt_idmap *idmap

执行查找的挂载的 idmap

const char *name

要查找的路径名组件

struct dentry *base

从中查找的基本目录

int len

要解释的最大长度 len

描述

此助手将在负数上产生 ERR_PTR(-ENOENT)。该助手返回已知的正数或 ERR_PTR()。这是大多数用户想要的。

请注意,带有未锁定父级的固定负数_可以_随时变为正数,因此 lookup_one_unlocked() 的调用者需要非常小心;固定的正数具有 >d_inode 稳定,因此这一个避免了此类问题。

请注意,此例程纯粹是文件系统使用的助手,不应由通用代码调用。

助手应该在不持有 i_mutex 的情况下调用。

struct dentry *lookup_one_len_unlocked(const char *name, struct dentry *base, int len)

文件系统助手,用于查找单个路径名组件

参数

const char *name

要查找的路径名组件

struct dentry *base

从中查找的基本目录

int len

要解释的最大长度 len

描述

请注意,此例程纯粹是文件系统使用的助手,不应由通用代码调用。

与 lookup_one_len 不同,它应该在不持有父 i_mutex 的情况下调用,并且如果需要将自行获取 i_mutex。

int vfs_create(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, bool want_excl)

创建新文件

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

struct inode *dir

父目录的 inode

struct dentry *dentry

子文件的 dentry

umode_t mode

子文件的模式

bool want_excl

文件是否必须尚不存在

描述

创建一个新文件。

如果通过 idmapped 挂载找到 inode,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

struct file *kernel_tmpfile_open(struct mnt_idmap *idmap, const struct path *parentpath, umode_t mode, int open_flag, const struct cred *cred)

为内核内部使用打开一个临时文件

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

const struct path *parentpath

基本目录的路径

umode_t mode

新临时文件的模式

int open_flag

flags

const struct cred *cred

打开的凭据

描述

创建并打开一个临时文件。该文件不计入 nr_files,因此仅供内核内部使用,不得安装到文件表等中。

int vfs_mknod(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)

创建设备节点或文件

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

struct inode *dir

父目录的 inode

struct dentry *dentry

子设备节点的 dentry

umode_t mode

子设备节点的模式

dev_t dev

要创建的设备号

描述

创建一个设备节点或文件。

如果通过 idmapped 挂载找到 inode,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode)

创建目录

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

struct inode *dir

父目录的 inode

struct dentry *dentry

子目录的 dentry

umode_t mode

子目录的模式

描述

创建一个目录。

如果通过 idmapped 挂载找到 inode,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry)

移除目录

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

struct inode *dir

父目录的 inode

struct dentry *dentry

子目录的 dentry

描述

移除一个目录。

如果通过 idmapped 挂载找到 inode,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

取消文件系统对象的链接

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

struct inode *dir

父目录

struct dentry *dentry

受害者

struct inode **delegated_inode

如果 inode 被委托,则返回受害者的 inode。

描述

调用者必须持有 dir->i_mutex。

如果 vfs_unlink 发现委托,它将返回 -EWOULDBLOCK 并在 delegated_inode 中返回对 inode 的引用。然后,调用者应在该 inode 上中断委托并重试。由于中断委托可能需要很长时间,因此调用者应在执行此操作之前删除 dir->i_mutex。

或者,调用者可以为 delegated_inode 传递 NULL。这可能适用于期望底层文件系统不被 NFS 导出的调用者。

如果通过 idmapped 挂载找到 inode,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

创建符号链接

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

struct inode *dir

父目录的 inode

struct dentry *dentry

子符号链接文件的 dentry

const char *oldname

要链接到的文件的名称

描述

创建一个符号链接。

如果通过 idmapped 挂载找到 inode,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

创建一个新链接

参数

struct dentry *old_dentry

要链接的对象

struct mnt_idmap *idmap

挂载的 idmap

struct inode *dir

新的父级

struct dentry *new_dentry

在何处创建新链接

struct inode **delegated_inode

返回需要委托中断的 inode

描述

调用者必须持有 dir->i_mutex

如果 vfs_link 发现要链接的文件上存在需要打破的委托,它将返回 -EWOULDBLOCK 并返回 delegated_inode 中的 inode 引用。 调用者应该打破委托并重试。 由于打破委托可能需要很长时间,调用者应该在执行此操作之前放弃 i_mutex。

或者,调用者可以为 delegated_inode 传递 NULL。这可能适用于期望底层文件系统不被 NFS 导出的调用者。

如果通过 idmapped 挂载找到 inode,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

int vfs_rename(struct renamedata *rd)

重命名文件系统对象

参数

struct renamedata *rd

指向 struct renamedata 信息的指针

描述

调用者必须持有多个互斥锁--参见 lock_rename()。

如果 vfs_rename 在源或目标处发现需要打破的委托,它将返回 -EWOULDBLOCK 并返回 delegated_inode 中的 inode 引用。 调用者应该打破委托并重试。 由于打破委托可能需要很长时间,调用者应该在执行此操作之前放弃所有锁。

或者,调用者可以为 delegated_inode 传递 NULL。这可能适用于期望底层文件系统不被 NFS 导出的调用者。

最糟糕的命名空间操作 - 重命名目录。“变态”甚至不足以形容它。 加州大学伯克利分校的某人经历了一段糟糕的旅程... 问题

  1. 我们可能会陷入循环创建。

  2. 竞争潜力 - 两个无辜的重命名操作可能会一起创建循环。 这就是 4.4BSD 搞砸的地方。 当前修复:在 sb->s_vfs_rename_mutex 上进行序列化。 我们可能会更准确,但那是另一个故事。

  3. 我们可能必须锁定多达 _四个_ 对象 - 父对象和受害者(如果存在),以及源对象(如果它是一个非目录或移动到不同父目录的子目录)。 并且 - 在我们在父对象上获得 ->i_mutex 之后(在此之前我们不知道目标是否存在)。 解决方案:尝试在 inode 的锁定顺序方面做到聪明。 我们依赖于树拓扑只能在 ->s_vfs_rename_mutex _和_ 我们移动的对象父目录将被锁定的情况下改变这一事实。 因此,我们可以按树(祖先优先)对目录进行排序,并将所有非目录排在它们之后。 这是可行的,因为除了重命名之外的所有操作都执行“锁定父目录、查找、锁定子目录”,并且重命名在 ->s_vfs_rename_mutex 下。 然而,它依赖于任何具有 ->lookup() 的对象都只有一个 dentry 的假设。 如果将来出现“混合”对象,我们最好确保它们没有 link(2)。

  4. 从 fhandle 到 dentry 的转换可能在错误的时间发生 - 当我们删除目标时。 解决方案:我们必须在 fhandle_to_dentry 代码中获取 ->i_mutex。 [FIXME - 当前 nfsfh.c 依赖于父目录上的 ->i_mutex,这可行,但会导致一些过度锁定]。

将符号链接主体复制到用户空间缓冲区

参数

struct dentry *dentry

在其上获取符号链接的 dentry

char __user *buffer

用户内存指针

int buflen

缓冲区大小

描述

不触及 atime。 如果需要,这取决于调用者

不调用安全钩子。

获取符号链接主体

参数

struct dentry *dentry

在其上获取符号链接的 dentry

struct delayed_call *done

调用者需要使用此方法释放返回的数据

描述

在提供的 inode 上调用安全钩子和 i_op->get_link()。

它不触及 atime。 如果需要,这取决于调用者。

不适用于“特殊”符号链接,例如 /proc/$$/fd/N

void bio_reset(struct bio *bio, struct block_device *bdev, blk_opf_t opf)

重新初始化 bio

参数

struct bio *bio

要重置的 bio

struct block_device *bdev

要将 bio 用于的块设备

blk_opf_t opf

bio 的操作和标志

描述

在调用 bio_reset() 之后,bio 将处于与刚刚分配的 bio 返回 bio bio_alloc_bioset() 相同的状态 - 唯一保留的字段是由 bio_alloc_bioset() 初始化的字段。 参见 struct bio 中的注释。

void bio_chain(struct bio *bio, struct bio *parent)

链式 bio 完成

参数

struct bio *bio

目标 bio

struct bio *parent

bio 的父 bio

描述

bio 完成时,调用者不会调用 bi_end_io - 相反,在 parentbio 都完成之前不会调用 parent 的 bi_end_io; 链式 bio 也将在它完成时被释放。

调用者不得在 bio 中设置 bi_private 或 bi_end_io。

struct bio *bio_alloc_bioset(struct block_device *bdev, unsigned short nr_vecs, blk_opf_t opf, gfp_t gfp_mask, struct bio_set *bs)

为 I/O 分配 bio

参数

struct block_device *bdev

为其分配 bio 的块设备(可以是 NULL

unsigned short nr_vecs

要预先分配的 bvec 数量

blk_opf_t opf

bio 的操作和标志

gfp_t gfp_mask

传递给 slab 分配器的 GFP_* 掩码

struct bio_set *bs

从中分配的 bio_set。

描述

bs 中的内存池分配 bio。

如果设置了 __GFP_DIRECT_RECLAIM,则 bio_alloc 将始终能够分配 bio。 这是由于内存池保证。 为了使此工作正常进行,调用者永远不能一次从通用池中分配超过 1 个 bio。 需要分配超过 1 个 bio 的调用者必须始终在尝试分配新 bio 之前提交先前分配的 bio 进行 IO。 否则可能会在内存压力下导致死锁。

请注意,当在 submit_bio_noacct() (即任何块驱动程序)下运行时,bio 不会提交,直到您返回之后 - 请参见 submit_bio_noacct() 中将递归转换为迭代以防止堆栈溢出的代码。

这通常意味着在 submit_bio_noacct() 下分配多个 bio 容易发生死锁,但我们有避免死锁的代码,可以从救援线程重新提交任何被阻塞的 bio。

但是,我们不保证从其他内存池分配的前向进度。 应该避免在 submit_bio_noacct() 下从同一内存池进行多次分配 - 而是使用 bio_set 的 front_pad 进行每个 bio 的分配。

返回

成功时返回指向新 bio 的指针,失败时返回 NULL。

struct bio *bio_kmalloc(unsigned short nr_vecs, gfp_t gfp_mask)

kmalloc 一个 bio

参数

unsigned short nr_vecs

要分配的 bio_vecs 的数量

gfp_t gfp_mask

传递给 slab 分配器的 GFP_* 掩码

描述

使用 kmalloc 分配一个 bio(包括 bvecs)。在使用前必须使用 bio_init() 初始化 bio。要释放从此函数返回的 bio,请在调用 bio_uninit() 后使用 kfree()。 通过在再次调用 bio_init() 之前调用 bio_uninit(),可以重用从此函数返回的 bio。

请注意,与 bio_alloc() 或 bio_alloc_bioset() 不同,从此函数分配的内存不是由内存池支持的,可能会失败。 请勿在文件系统 I/O 路径中使用此函数进行分配。

返回

成功时返回指向新 bio 的指针,失败时返回 NULL。

void bio_put(struct bio *bio)

释放对 bio 的引用

参数

struct bio *bio

要释放引用的 bio

描述

释放对 struct bio 的引用,该引用可以通过 bio_alloc、bio_get 或 bio_clone_* 获得。 bio 的最后一次 put 将释放它。

struct bio *bio_alloc_clone(struct block_device *bdev, struct bio *bio_src, gfp_t gfp, struct bio_set *bs)

克隆一个共享原始 bio 的 biovec 的 bio

参数

struct block_device *bdev

要克隆到的 block_device

struct bio *bio_src

要克隆的 bio

gfp_t gfp

分配优先级

struct bio_set *bs

要从中分配的 bio_set

描述

分配一个新的 bio,它是 bio_src 的克隆。 调用者拥有返回的 bio,但不拥有它指向的实际数据。

调用者必须确保在 bio_src 之前不释放返回的 bio。

int bio_init_clone(struct block_device *bdev, struct bio *bio, struct bio *bio_src, gfp_t gfp)

克隆一个共享原始 bio 的 biovec 的 bio

参数

struct block_device *bdev

要克隆到的 block_device

struct bio *bio

要克隆到的 bio

struct bio *bio_src

要克隆的 bio

gfp_t gfp

分配优先级

描述

在调用者提供的内存中初始化一个新的 bio,它是 bio_src 的克隆。 调用者拥有返回的 bio,但不拥有它指向的实际数据。

调用者必须确保在 bio 之前不释放 bio_src

int bio_add_pc_page(struct request_queue *q, struct bio *bio, struct page *page, unsigned int len, unsigned int offset)

尝试将页面添加到透传 bio

参数

struct request_queue *q

目标队列

struct bio *bio

目标 bio

struct page *page

要添加的页面

unsigned int len

vec 条目长度

unsigned int offset

vec 条目偏移量

描述

尝试将页面添加到 bio_vec 映射列表。 这可能会因多种原因而失败,例如 bio 已满或目标块设备限制。 目标块设备必须允许最大为 PAGE_SIZE 的 bio,因此始终可以将单个页面添加到空的 bio。

这应该只由透传 bio 使用。

void __bio_add_page(struct bio *bio, struct page *page, unsigned int len, unsigned int off)

在新段中将页面添加到 bio

参数

struct bio *bio

目标 bio

struct page *page

要添加的起始页

unsigned int len

要添加的数据的长度,可能会跨页

unsigned int off

数据相对于 page 的偏移量,可能会跨页

描述

page + off 处的数据作为新的 bvec 添加到 bio。 调用者必须确保 bio 有另一个 bvec 的空间。

int bio_add_page(struct bio *bio, struct page *page, unsigned int len, unsigned int offset)

尝试将页面添加到 bio

参数

struct bio *bio

目标 bio

struct page *page

要添加的起始页

unsigned int len

vec 条目长度,可能会跨页

unsigned int offset

相对于 page 的 vec 条目偏移量,可能会跨页

尝试将页面添加到 bio_vec 映射列表。 仅当 bio->bi_vcnt == bio->bi_max_vecs 或它是克隆的 bio 时,此操作才会失败。

bool bio_add_folio(struct bio *bio, struct folio *folio, size_t len, size_t off)

尝试将 folio 的一部分添加到 bio。

参数

struct bio *bio

要添加到的 BIO。

struct folio *folio

要添加的 Folio。

size_t len

从 folio 中添加的字节数。

size_t off

要添加的此 folio 中的第一个字节。

描述

使用 folio 的文件系统可以调用此函数,而不是为 folio 中的每个页面调用 bio_add_page()。如果 off 大于 PAGE_SIZE,此函数可以创建一个在 bv_page 之后的页面中开始的 bio_vec。BIO 不支持 4GiB 或更大的 folio。

返回

添加是否成功。

int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)

将用户或内核页面添加到 bio

参数

struct bio *bio

要向其中添加页面的 bio

struct iov_iter *iter

描述要添加的区域的 iov 迭代器

描述

这需要一个指向用户内存的迭代器,或者一个指向内核页面(BVEC 迭代器)的迭代器。 如果我们添加用户页面,我们会固定它们并将它们映射到内核中。 在 IO 完成时,调用者应该释放这些页面。 对于基于 bvec 的迭代器 bio_iov_iter_get_pages() 使用提供的 bvec,而不是复制它们。 因此,任何发出基于 kiocb 的 IO 的人都需要确保 bvec 和页面保持引用状态,直到提交的 I/O 通过调用 ->ki_complete() 完成或返回除 -EIOCBQUEUED 以外的错误。 调用者需要检查 bio 在 IO 完成时是否被标记为 BIO_NO_PAGE_REF。 如果不是,则应释放页面。

该函数尝试但不保证固定尽可能多的页面,这些页面适合 bio,或在 iter 中请求,无论哪个更小。 如果 MM 在固定请求的页面时遇到错误,它会停止。 仅当无法固定 0 个页面时,才会返回错误。

int submit_bio_wait(struct bio *bio)

提交一个 bio,并等待它完成

参数

struct bio *bio

描述 I/O 的 struct bio

描述

围绕 submit_bio() 的简单包装器。成功时返回 0,或者在失败时返回 bio_endio() 的错误。

警告:与通常使用 submit_bio() 的方式不同,此函数不会导致 bio 引用被消耗。 调用者必须自己放弃引用。

void bio_copy_data(struct bio *dst, struct bio *src)

将数据缓冲区的内容从一个 bio 复制到另一个 bio

参数

struct bio *dst

目标 bio

struct bio *src

源 bio

描述

当它到达 srcdst 的末尾时停止 - 也就是说,复制 min(src->bi_size, dst->bi_size) 个字节(或 bio 列表的等效字节数)。

void bio_endio(struct bio *bio)

结束 bio 上的 I/O

参数

struct bio *bio

bio

描述

bio_endio() 将结束整个 bio 上的 I/O。 bio_endio() 是结束 bio 上 I/O 的首选方法。 除非他们拥有 bio 并因此知道它有一个 end_io 函数,否则任何人都不能直接在 bio 上调用 bi_end_io()。

bio_endio() 可以在使用 bio_chain() 链接的 bio 上调用多次。 ->bi_end_io() 函数将仅在最后一次调用。

struct bio *bio_split(struct bio *bio, int sectors, gfp_t gfp, struct bio_set *bs)

拆分 bio

参数

struct bio *bio

要拆分的 bio

int sectors

要从 bio 的开头拆分的扇区数

gfp_t gfp

gfp 掩码

struct bio_set *bs

从中分配的 bio set

描述

分配并返回一个新的 bio,它表示从 bio 的开头开始的 sectors,并更新 bio 以表示剩余的扇区。

除非这是一个丢弃请求,否则新分配的 bio 将指向 bio 的 bi_io_vec。 调用者有责任确保在拆分 bio 之前不会释放 biobs

void bio_trim(struct bio *bio, sector_t offset, sector_t size)

修剪 bio

参数

struct bio *bio

要修剪的 bio

sector_t offset

要从 bio 的开头修剪的扇区数

sector_t size

我们要将 bio 修剪到的尺寸(以扇区为单位)

描述

此函数通常用于克隆并分部分提交给底层设备的 bio。

int bioset_init(struct bio_set *bs, unsigned int pool_size, unsigned int front_pad, int flags)

初始化一个 bio_set

参数

struct bio_set *bs

要初始化的池

unsigned int pool_size

要在内存池中缓存的 bio 和 bio_vec 的数量

unsigned int front_pad

在返回的 bio 前面分配的字节数

int flags

用于修改行为的标志,当前为 BIOSET_NEED_BVECSBIOSET_NEED_RESCUER

描述

设置一个与 bio_alloc_bioset 一起使用的 bio_set。允许调用者请求在 bio 前面分配一定数量的字节。前填充分配对于将 bio 嵌入到另一个结构中非常有用,以避免分配与 bio 一起使用的额外数据。请注意,bio 必须始终嵌入到该结构的末尾,否则会出现严重错误。如果在 flags 中设置了 BIOSET_NEED_BVECS,则会分配一个单独的池来分配 iovec。例如,对于 bio_init_clone(),不需要此池。如果设置了 BIOSET_NEED_RESCUER,则会创建一个工作队列,当内存池空间不足时,可以使用该队列来分派排队的请求。

int seq_open(struct file *file, const struct seq_operations *op)

初始化顺序文件

参数

struct file *file

我们要初始化的文件

const struct seq_operations *op

描述序列的方法表

seq_open() 设置 file,将其与 op 描述的序列关联。op->start() 设置迭代器并返回序列的第一个元素。op->stop() 关闭它。op->next() 返回序列的下一个元素。op->show() 将元素打印到缓冲区中。如果发生错误,->start() 和 ->next() 返回 ERR_PTR(错误)。在序列的末尾,它们返回 NULL。->show() 在成功时返回 0,在发生错误时返回负数。返回 SEQ_SKIP 表示“丢弃此元素并继续前进”。

注意

seq_open() 将分配一个 struct seq_file 并将其

指针存储在 file->private_data 中。此指针不应被修改。

ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)

顺序文件的 ->read() 方法。

参数

struct file *file

要从中读取的文件

char __user *buf

要读取到的缓冲区

size_t size

要读取的最大字节数

loff_t *ppos

文件中当前的位置

现成的 ->f_op->read()

loff_t seq_lseek(struct file *file, loff_t offset, int whence)

顺序文件的 ->llseek() 方法。

参数

struct file *file

有问题的的文件

loff_t offset

新位置

int whence

0 表示绝对位置,1 表示相对位置

现成的 ->f_op->llseek()

int seq_release(struct inode *inode, struct file *file)

释放与顺序文件关联的结构。

参数

struct inode *inode

它的 inode

struct file *file

有问题的的文件

释放与顺序文件关联的结构;如果您没有要销毁的私有数据,则可以用作 ->f_op->release()。

void seq_escape_mem(struct seq_file *m, const char *src, size_t len, unsigned int flags, const char *esc)

将数据打印到缓冲区中,转义某些字符

参数

struct seq_file *m

目标缓冲区

const char *src

源缓冲区

size_t len

源缓冲区的大小

unsigned int flags

要传递给 string_escape_mem() 的标志

const char *esc

需要转义的字符集

描述

将数据放入缓冲区,将给定类(由 flagsesc 定义)中的每个字符替换为可打印的转义序列。

使用 seq_has_overflowed() 检查错误。

char *mangle_path(char *s, const char *p, const char *esc)

整理路径并将其复制到缓冲区开头

参数

char *s

缓冲区开始

const char *p

上述缓冲区中路径的开头

const char *esc

需要转义的字符集

将路径从 p 复制到 s,将 esc 中的每个字符替换为常用的八进制转义符。返回 s 中最后一个写入字符之后的指针,如果失败,则返回 NULL。

int seq_path(struct seq_file *m, const struct path *path, const char *esc)

用于打印路径名的 seq_file 接口

参数

struct seq_file *m

seq_file 句柄

const struct path *path

要打印的 struct path

const char *esc

要在输出中转义的字符集

描述

返回 ‘path’ 的绝对路径,由 path 参数中的 dentry / mnt 对表示。

int seq_file_path(struct seq_file *m, struct file *file, const char *esc)

seq_file 接口,用于打印文件的路径名

参数

struct seq_file *m

seq_file 句柄

struct file *file

要打印的 struct file

const char *esc

要在输出中转义的字符集

描述

返回文件的绝对路径。

int seq_write(struct seq_file *seq, const void *data, size_t len)

将任意数据写入缓冲区

参数

struct seq_file *seq

标识要写入数据的缓冲区的 seq_file

const void *data

数据地址

size_t len

字节数

描述

成功返回 0,否则返回非零值。

void seq_pad(struct seq_file *m, char c)

将填充空格写入缓冲区

参数

struct seq_file *m

标识要写入数据的缓冲区的 seq_file

char c

如果非零,则在填充后追加的字节

struct hlist_node *seq_hlist_start(struct hlist_head *head, loff_t pos)

开始 hlist 的迭代

参数

struct hlist_head *head

hlist 的头部

loff_t pos

序列的起始位置

描述

在 seq_file->op->start() 中调用。

struct hlist_node *seq_hlist_start_head(struct hlist_head *head, loff_t pos)

开始 hlist 的迭代

参数

struct hlist_head *head

hlist 的头部

loff_t pos

序列的起始位置

描述

在 seq_file->op->start() 中调用。如果您想在输出的顶部打印一个标题,请调用此函数。

struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head, loff_t *ppos)

移动到 hlist 的下一个位置

参数

void *v

当前迭代器

struct hlist_head *head

hlist 的头部

loff_t *ppos

当前位置

描述

在 seq_file->op->next() 中调用。

struct hlist_node *seq_hlist_start_rcu(struct hlist_head *head, loff_t pos)

开始一个受 RCU 保护的 hlist 的迭代

参数

struct hlist_head *head

hlist 的头部

loff_t pos

序列的起始位置

描述

在 seq_file->op->start() 中调用。

只要遍历由 rcu_read_lock() 保护,此列表遍历原语可以与 _rcu 列表修改原语(如 hlist_add_head_rcu())安全地并发运行。

struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head, loff_t pos)

开始一个受 RCU 保护的 hlist 的迭代

参数

struct hlist_head *head

hlist 的头部

loff_t pos

序列的起始位置

描述

在 seq_file->op->start() 中调用。如果您想在输出的顶部打印一个标题,请调用此函数。

只要遍历由 rcu_read_lock() 保护,此列表遍历原语可以与 _rcu 列表修改原语(如 hlist_add_head_rcu())安全地并发运行。

struct hlist_node *seq_hlist_next_rcu(void *v, struct hlist_head *head, loff_t *ppos)

移动到受 RCU 保护的 hlist 的下一个位置

参数

void *v

当前迭代器

struct hlist_head *head

hlist 的头部

loff_t *ppos

当前位置

描述

在 seq_file->op->next() 中调用。

只要遍历由 rcu_read_lock() 保护,此列表遍历原语可以与 _rcu 列表修改原语(如 hlist_add_head_rcu())安全地并发运行。

struct hlist_node *seq_hlist_start_percpu(struct hlist_head __percpu *head, int *cpu, loff_t pos)

开始迭代每个 CPU 的 hlist 数组

参数

struct hlist_head __percpu *head

指向 struct hlist_heads 的 percpu 数组的指针

int *cpu

指向 CPU “游标” 的指针

loff_t pos

序列的起始位置

描述

在 seq_file->op->start() 中调用。

struct hlist_node *seq_hlist_next_percpu(void *v, struct hlist_head __percpu *head, int *cpu, loff_t *pos)

移动到 percpu hlist 数组的下一个位置

参数

void *v

指向当前 hlist_node 的指针

struct hlist_head __percpu *head

指向 struct hlist_heads 的 percpu 数组的指针

int *cpu

指向 CPU “游标” 的指针

loff_t *pos

序列的起始位置

描述

在 seq_file->op->next() 中调用。

int register_filesystem(struct file_system_type *fs)

注册一个新的文件系统

参数

struct file_system_type * fs

文件系统结构

将传递的文件系统添加到内核为挂载和其他系统调用所知的的文件系统列表中。 成功返回 0,错误时返回负 errno 代码。

传递的 struct file_system_type 将被链接到内核结构中,在文件系统注销之前不得释放。

int unregister_filesystem(struct file_system_type *fs)

注销文件系统

参数

struct file_system_type * fs

要注销的文件系统

删除先前已成功向内核注册的文件系统。如果找不到文件系统,则返回错误。成功返回零。

一旦此函数返回,struct file_system_type 结构可能会被释放或重用。

void wbc_attach_fdatawrite_inode(struct writeback_control *wbc, struct inode *inode)

关联 wbc 和 inode 用于 fdatawrite

参数

struct writeback_control *wbc

感兴趣的 writeback_control

struct inode *inode

目标 inode

描述

此函数由 __filemap_fdatawrite_range() 使用,它是回写代码的替代入口点,并首先确保 inode 与 bdi_writeback 关联,并将其附加到 wbc

void wbc_detach_inode(struct writeback_control *wbc)

将 wbc 与 inode 解除关联并执行外部检测

参数

struct writeback_control *wbc

刚刚完成的回写的 writeback_control

描述

在 inode 的回写尝试完成后调用,并撤销 wbc_attach_and_unlock_inode()。可以在任何上下文下调用。

由于 inode 的并发写入共享预计非常罕见,并且 memcg 仅在首次使用时跟踪页面所有权,严重限制了此类共享的有用性,因此 cgroup 回写按 inode 跟踪所有权。虽然对 inode 的并发写入共享的支持被认为是没必要的,但在不同的时间点由不同的 cgroup 写入 inode 要常见得多,更重要的是,仅按首次使用收费很容易导致严重不正确的行为(单个外部页面可能导致千兆字节的回写被错误地归因)。

为了解决这个问题,cgroup 回写会检测 inode 的主要脏写者,并将所有权转移给它。为了避免不必要的振荡,检测机制会跟踪历史记录,并且仅当外部使用模式在一定的时间和/或回写尝试中保持稳定时才给出切换结论。

在每次回写尝试时,wbc 尝试使用 Boyer-Moore 多数投票算法检测主要写入者。除了来自多数投票的字节计数之外,它还计算当前 wb 和上一轮获胜者 wb 写入的字节数(上一轮当前 wb、两轮前的获胜者和上一轮多数候选者的最大值)。跟踪历史获胜者有助于算法半可靠地检测最活跃的写入者,即使它不是绝对多数。

一旦确定了该轮的获胜者,该获胜者是否为外部的以及该轮消耗了多少 IO 时间都会记录在 inode->i_wb_frn_history 中。如果记录的外部 IO 时间量超过某个阈值,则给出切换结论。

void wbc_account_cgroup_owner(struct writeback_control *wbc, struct folio *folio, size_t bytes)

记录回写以更新 inode cgroup 所有权

参数

struct writeback_control *wbc

正在进行的回写的 writeback_control

struct folio *folio

正在写出的 folio

size_t bytes

正在写出的字节数

描述

来自 foliobytes 即将在由 wbc 控制的回写期间写出。保留外部 inode 检测的记录。请参阅 wbc_detach_inode()

void __mark_inode_dirty(struct inode *inode, int flags)

用于将 inode 标记为脏的内部函数

参数

struct inode *inode

要标记的 inode

int flags

哪种类型的脏,例如 I_DIRTY_SYNC。这可以是多个 I_DIRTY_* 标志的组合,但 I_DIRTY_TIME 不能与 I_DIRTY_PAGES 组合。

描述

将 inode 标记为脏。我们通知文件系统,然后更新 inode 的脏标志。然后,如果需要,我们将 inode 添加到相应的脏列表中。

大多数调用者应该使用 mark_inode_dirty() 或 mark_inode_dirty_sync() 而不是直接调用此函数。

注意!我们仅在 inode 已哈希或它引用 blockdev 时才将其添加到脏列表中。未哈希的 inode 永远不会添加到脏列表中,即使它们稍后被哈希,因为它们已经被标记为脏。

简而言之,请确保在开始将任何 inode 标记为脏之前先对其进行哈希。

请注意,对于 blockdev,inode->dirtied_when 表示 block-special inode (/dev/hda1) 本身的脏化时间。并且内核内部 blockdev inode 的 ->dirtied_when 字段表示 blockdev 页面的脏化时间。这就是为什么对于 I_DIRTY_PAGES,我们始终使用 page->mapping->host,因此页面脏化时间记录在内部 blockdev inode 中。

void writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr, enum wb_reason reason)

从给定 super_block 回写脏 inode

参数

struct super_block *sb

超级块

unsigned long nr

要写入的页数

enum wb_reason reason

启动某些回写工作的原因

描述

在此超级块上的一些 inode 上开始回写。不对将写入多少(如果有)做出保证,并且此函数不会等待已提交 IO 的 IO 完成。

void writeback_inodes_sb(struct super_block *sb, enum wb_reason reason)

从给定 super_block 回写脏 inode

参数

struct super_block *sb

超级块

enum wb_reason reason

启动某些回写工作的原因

描述

在此超级块上的一些 inode 上开始回写。不对将写入多少(如果有)做出保证,并且此函数不会等待已提交 IO 的 IO 完成。

void try_to_writeback_inodes_sb(struct super_block *sb, enum wb_reason reason)

如果没有正在进行的回写,则尝试启动回写

参数

struct super_block *sb

超级块

enum wb_reason reason

启动某些回写工作的原因

描述

如果没有正在进行的回写,则调用 __writeback_inodes_sb_nr。

void sync_inodes_sb(struct super_block *sb)

同步 sb inode 页面

参数

struct super_block *sb

超级块

描述

此函数写入并等待属于此超级块的任何脏 inode。

int write_inode_now(struct inode *inode, int sync)

将 inode 写入磁盘

参数

struct inode *inode

要写入磁盘的 inode

int sync

写入是否应该同步

描述

如果 inode 是脏的,此函数会立即将其提交到磁盘。这主要是 knfsd 所需的。

调用者必须具有对 inode 的引用,或者必须设置 I_WILL_FREE。

int sync_inode_metadata(struct inode *inode, int wait)

将 inode 写入磁盘

参数

struct inode *inode

要同步的 inode

int wait

等待 I/O 完成。

描述

将 inode 写入磁盘并在完成后调整其脏状态。

注意

仅写入实际的 inode,没有关联的数据或其他元数据。

struct file *anon_inode_getfile(const char *name, const struct file_operations *fops, void *priv, int flags)

通过将其连接到匿名 inode 和描述文件“类”的 dentry 来创建新的文件实例

参数

const char *name

[in] 新文件的“类”的名称

const struct file_operations *fops

[in] 新文件的文件操作

void *priv

[in] 新文件的私有数据(将是文件的 private_data)

int flags

[in] 标志

描述

通过将新文件挂钩到单个 inode 来创建新文件。这对于那些不需要完整 inode 即可正常运行的文件非常有用。所有使用 anon_inode_getfile() 创建的文件都将共享一个 inode,从而节省内存,并避免文件/inode/dentry 设置的代码重复。返回新创建的 file* 或错误指针。

struct file *anon_inode_getfile_fmode(const char *name, const struct file_operations *fops, void *priv, int flags, fmode_t f_mode)

通过将其连接到匿名 inode 和描述文件“类”的 dentry 来创建新的文件实例

参数

const char *name

[in] 新文件的“类”的名称

const struct file_operations *fops

[in] 新文件的文件操作

void *priv

[in] 新文件的私有数据(将是文件的 private_data)

int flags

[in] 标志

fmode_t f_mode

[输入] fmode

描述

通过将新文件挂钩到单个 inode 来创建新文件。这对于那些不需要完整 inode 即可正常运行的文件非常有用。所有使用 anon_inode_getfile() 创建的文件都将共享一个 inode,从而节省内存,并避免文件/inode/dentry 设置的代码重复。允许设置 fmode。返回新创建的 file* 或错误指针。

struct file *anon_inode_create_getfile(const char *name, const struct file_operations *fops, void *priv, int flags, const struct inode *context_inode)

anon_inode_getfile() 类似,但创建一个新的 !S_PRIVATE 匿名 inode,而不是重用单例匿名 inode 并调用 inode_init_security_anon() LSM 钩子。

参数

const char *name

[in] 新文件的“类”的名称

const struct file_operations *fops

[in] 新文件的文件操作

void *priv

[in] 新文件的私有数据(将是文件的 private_data)

int flags

[in] 标志

const struct inode *context_inode

[输入] 与新 inode 的逻辑关系(可选)

描述

创建新的匿名 inode 和文件对。这样做有两个原因

  • 为了让 inode 具有自己的安全上下文,以便 LSM 可以强制执行 inode 创建策略;

  • 如果调用者需要唯一的 inode,例如为了自定义 fstat() 返回的大小

LSM 可以在 inode_init_security_anon() 中使用 context_inode,但不保留对其的引用。

返回新创建的 file* 或错误指针。

int anon_inode_getfd(const char *name, const struct file_operations *fops, void *priv, int flags)

通过将其挂钩到匿名 inode 和描述文件“类”的 dentry 来创建新的文件实例

参数

const char *name

[in] 新文件的“类”的名称

const struct file_operations *fops

[in] 新文件的文件操作

void *priv

[in] 新文件的私有数据(将是文件的 private_data)

int flags

[in] 标志

描述

通过将新文件挂钩到单个 inode 来创建新文件。这对于那些不需要完整 inode 即可正常运行的文件非常有用。所有使用 anon_inode_getfd() 创建的文件都将使用相同的单例 inode,从而减少内存使用并避免文件/inode/dentry 设置的代码重复。返回新创建的文件描述符或错误代码。

int setattr_should_drop_sgid(struct mnt_idmap *idmap, const struct inode *inode)

确定是否需要删除 setgid 位

参数

struct mnt_idmap *idmap

从挂载的 **inode** 中找到的 idmap

const struct inode *inode

要检查的 inode

描述

此函数确定是否需要删除 setgid 位。我们保留向后兼容性,如果设置了 S_IXGRP,则要求无条件删除 setgid 位。否则,我们具有与 setattr_prepare()setattr_copy() 完全相同的要求。

返回

如果需要删除 setgid 位,则为 ATTR_KILL_SGID,否则为 0。

int setattr_should_drop_suidgid(struct mnt_idmap *idmap, struct inode *inode)

确定是否需要删除 set{g,u}id 位

参数

struct mnt_idmap *idmap

从挂载的 **inode** 中找到的 idmap

struct inode *inode

要检查的 inode

描述

此函数确定是否需要删除 set{g,u}id 位。如果需要删除 setuid 位,则返回 ATTR_KILL_SUID。如果需要删除 setgid 位,则返回 ATTR_KILL_SGID。如果需要删除 set{g,u}id 位,则返回两个标志的对应掩码。

返回

指示要删除哪些(如果有)setid 位的 ATTR_KILL_S{G,U}ID 掩码,否则为 0。

int setattr_prepare(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *attr)

检查是否允许对 dentry 进行属性更改

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

struct dentry *dentry

要检查的 dentry

struct iattr *attr

要更改的属性

描述

检查是否允许在给定 dentry 中更改 attr 中包含的属性。这包括正常的 unix 访问权限检查,以及对 rlimits 和其他项的检查。如果用户不允许设置 SGID 位,该函数还会清除模式中的 SGID 位。此外,如果设置了 ATTR_KILL_PRIV,则会清除文件功能和 IMA 扩展属性。

如果通过 idmapped 挂载找到 inode,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

应作为 ->setattr 实现中的第一件事调用,可能在获取其他锁之后。

int inode_newsize_ok(const struct inode *inode, loff_t offset)

此 inode 是否可以截断为给定大小

参数

const struct inode *inode

要截断的 inode

loff_t offset

要分配给 inode 的新大小

描述

inode_newsize_ok 必须在持有 i_mutex 的情况下调用。

inode_newsize_ok 将检查文件系统限制和 ulimit,以检查新的 inode 大小是否在限制范围内。inode_newsize_ok 还将在必要时发送 SIGXFSZ。如果返回失败,则调用者不得继续更改 inode 大小。inode 必须是一个文件(而不是目录),并具有允许截断的适当权限(inode_newsize_ok 不检查这些条件)。

返回

成功时为 0,失败时为 -ve errno

void setattr_copy(struct mnt_idmap *idmap, struct inode *inode, const struct iattr *attr)

将简单的元数据更新复制到通用 inode 中

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

struct inode *inode

要更新的 inode

const struct iattr *attr

新属性

描述

setattr_copy 必须在持有 i_mutex 的情况下调用。

setattr_copy 使用在 idmapped 挂载上在 attr 中指定的元数据更新 inode 的元数据。执行必要的权限检查,以确定是否需要使用正确的 idmapped 挂载权限助手删除 S_ISGID 属性。明显缺少的是 inode 大小更新,它更复杂,因为它需要页面缓存更新。

如果通过 idmapped 挂载找到 inode,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

此操作后,inode 不会标记为脏。理由是对于“简单”文件系统,struct inode 是 inode 存储。如果需要,调用者可以自由地之后将 inode 标记为脏。

int notify_change(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *attr, struct inode **delegated_inode)

修改文件系统对象的属性

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

struct dentry *dentry

受影响的对象

struct iattr *attr

新的属性

struct inode **delegated_inode

如果 inode 被委托,则返回 inode

描述

调用者必须持有受影响对象的 i_mutex。

如果 notify_change 发现需要中断的委托,它将返回 -EWOULDBLOCK,并在 delegated_inode 中返回对 inode 的引用。然后,调用者应该中断委托并重试。由于中断委托可能需要很长时间,调用者应该在执行此操作之前释放 i_mutex。

或者,调用者可以为 delegated_inode 传递 NULL。这可能适用于期望底层文件系统不被 NFS 导出的调用者。此外,对于为写入打开文件的调用者来说,传递 NULL 也是可以的,因为在这种情况下不可能存在冲突的委托。

如果通过 idmapped 挂载找到 inode,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

char *d_path(const struct path *path, char *buf, int buflen)

返回 dentry 的路径

参数

const struct path *path

要报告的路径

char *buf

用于返回值的缓冲区

int buflen

缓冲区长度

描述

将 dentry 转换为 ASCII 路径名。如果条目已被删除,则附加字符串“ (deleted)”。请注意,这是不明确的。

返回指向缓冲区的指针,如果路径太长,则返回错误代码。注意:调用者应使用返回的指针,而不是传入的缓冲区来使用名称!实现通常从缓冲区的偏移量开始,并且可能会在开头留下 0 个字节。

“buflen” 应该是正数。

struct page *dax_layout_busy_page_range(struct address_space *mapping, loff_t start, loff_t end)

mapping 中查找第一个被锁定的页面

参数

struct address_space *mapping

要扫描引用计数 > 1 的页面的地址空间

loff_t start

起始偏移量。包含 'start' 的页面将被包括在内。

loff_t end

结束偏移量。包含 'end' 的页面将被包括在内。如果 'end' 是 LLONG_MAX,则包括从 'start' 到文件末尾的页面。

描述

DAX 需要 ZONE_DEVICE 映射的页面。这些页面永远不会“在线”到页面分配器,因此当 page->count == 1 时,它们被认为是空闲的。文件系统使用此接口来确定映射中的任何页面是否正忙,即用于 DMA 或其他 get_user_pages() 用法。

预计文件系统会持有锁以阻止在此地址空间中建立新的映射。也就是说,它期望能够运行 unmap_mapping_range(),并且随后不会竞争 mapping_mapped() 变为真。

ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter, const struct iomap_ops *ops)

对 DAX 文件执行 I/O

参数

struct kiocb *iocb

此 I/O 的控制块

struct iov_iter *iter

执行 I/O 的源地址或目标地址

const struct iomap_ops *ops

从文件系统传递的 iomap 操作

描述

此函数对直接映射的持久内存执行读写操作。调用者需要注意读/写互斥,并清除 I/O 区域中的任何页面缓存页面。

vm_fault_t dax_iomap_fault(struct vm_fault *vmf, unsigned int order, pfn_t *pfnp, int *iomap_errp, const struct iomap_ops *ops)

处理 DAX 文件上的页面错误

参数

struct vm_fault *vmf

故障的描述

unsigned int order

要故障的页面的阶数

pfn_t *pfnp

如果需要 fsync,则为同步故障插入的 PFN

int *iomap_errp

用于存储发生错误时的详细错误代码

const struct iomap_ops *ops

从文件系统传递的 iomap 操作

描述

当发生页面错误时,文件系统可能会在其 DAX 文件的错误处理程序中调用此帮助程序。dax_iomap_fault() 假设调用者已完成页面错误成功进行所需的所有锁定。

vm_fault_t dax_finish_sync_fault(struct vm_fault *vmf, unsigned int order, pfn_t pfn)

完成同步页面错误

参数

struct vm_fault *vmf

故障的描述

unsigned int order

要插入的条目的阶数

pfn_t pfn

要插入的 PFN

描述

此函数确保页面错误触及的文件范围被永久存储在介质上,并处理插入相应的页表条目。

void simple_rename_timestamp(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry)

更新重命名的各种 inode 时间戳

参数

struct inode *old_dir

旧的父目录

struct dentry *old_dentry

正在重命名的 dentry

struct inode *new_dir

新的父目录

struct dentry *new_dentry

重命名的目标

描述

POSIX 规定旧的和新的父目录的 ctime 和 mtime 都要更新,并且 old_dentrynew_dentry(如果有)的 inode 的 ctime 都要更新。

int simple_setattr(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *iattr)

为简单文件系统设置属性。

参数

struct mnt_idmap *idmap

目标挂载的 ID 映射。

struct dentry *dentry

目录项。

struct iattr *iattr

iattr 结构体。

描述

成功时返回 0,失败时返回 -错误。

simple_setattr 是一个简单的 ->setattr 实现,没有正确实现大小更改。

它可以用于内存文件系统或简单常规文件系统上的特殊文件。任何需要在大小更改时更改磁盘或网络状态的内容都需要自己的 setattr 方法。

ssize_t simple_read_from_buffer(void __user *to, size_t count, loff_t *ppos, const void *from, size_t available)

将数据从缓冲区复制到用户空间。

参数

void __user *to

要读取到的用户空间缓冲区。

size_t count

要读取的最大字节数

loff_t *ppos

缓冲区中的当前位置。

const void *from

要从中读取的缓冲区。

size_t available

缓冲区的大小。

描述

simple_read_from_buffer() 函数从缓冲区 from 的偏移量 ppos 处读取最多 count 个字节,到用户空间地址 to 开始的位置。

成功时,返回读取的字节数,偏移量 ppos 增加该数量,如果发生错误,则返回负值。

ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos, const void __user *from, size_t count)

将数据从用户空间复制到缓冲区。

参数

void *to

要写入的缓冲区。

size_t available

缓冲区的大小。

loff_t *ppos

缓冲区中的当前位置。

const void __user *from

要从中读取的用户空间缓冲区。

size_t count

要读取的最大字节数

描述

simple_write_to_buffer() 函数从用户空间地址 from 开始的位置读取最多 count 个字节,到缓冲区 to 的偏移量 ppos 处。

成功时,返回写入的字节数,偏移量 ppos 增加该数量,如果发生错误,则返回负值。

ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, const void *from, size_t available)

从缓冲区复制数据。

参数

void *to

要读取到的内核空间缓冲区。

size_t count

要读取的最大字节数

loff_t *ppos

缓冲区中的当前位置。

const void *from

要从中读取的缓冲区。

size_t available

缓冲区的大小。

描述

memory_read_from_buffer() 函数从缓冲区 from 的偏移量 ppos 处读取最多 count 个字节,到内核空间地址 to 开始的位置。

成功时,返回读取的字节数,偏移量 ppos 增加该数量,如果发生错误,则返回负值。

int generic_encode_ino32_fh(struct inode *inode, __u32 *fh, int *max_len, struct inode *parent)

通用的 export_operations->encode_fh 函数。

参数

struct inode *inode

要编码的对象。

__u32 *fh

存储文件句柄片段的位置。

int *max_len

存储的最大长度(以 4 字节为单位)。

struct inode *parent

父目录 inode(如果需要)。

描述

这个通用的 encode_fh 函数假设 32 位 inode 号适合用于查找 inode,并且可以使用生成号来检查它是否仍然有效。它将它们放置在文件句柄片段中,export_decode_fh 希望在那里找到它们。

struct dentry *generic_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type, struct inode *(*get_inode)(struct super_block *sb, u64 ino, u32 gen))

fh_to_dentry 导出操作的通用助手函数。

参数

struct super_block *sb

要执行文件句柄转换的文件系统。

struct fid *fid

要转换的文件句柄。

int fh_len

文件句柄的长度(以字节为单位)。

int fh_type

文件句柄的类型。

struct inode *(*get_inode) (struct super_block *sb, u64 ino, u32 gen)

用于检索 inode 的文件系统回调。

描述

此函数解码 fid,只要它具有众所周知的 Linux 文件句柄类型之一,并对其调用 get_inode 来检索文件句柄中指定的对象的 inode。

struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type, struct inode *(*get_inode)(struct super_block *sb, u64 ino, u32 gen))

用于 fh_to_parent 导出操作的通用助手

参数

struct super_block *sb

要执行文件句柄转换的文件系统。

struct fid *fid

要转换的文件句柄。

int fh_len

文件句柄的长度(以字节为单位)。

int fh_type

文件句柄的类型。

struct inode *(*get_inode) (struct super_block *sb, u64 ino, u32 gen)

用于检索 inode 的文件系统回调。

描述

此函数解码 fid,只要它具有一种众所周知的 Linux 文件句柄类型,并在其上调用 get_inode 以检索文件句柄中指定的 _parent_ 对象的 inode(如果在文件句柄中指定),否则返回 NULL。

int __generic_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)

简单文件系统的通用 fsync 实现

参数

struct file *file

要同步的文件

loff_t start

起始字节偏移量

loff_t end

结束字节偏移量(包括)

int datasync

如果为 true,则仅同步必要的元数据

描述

这是简单文件系统的 fsync 方法的通用实现,该文件系统在挂起在 address_space 结构的缓冲区列表中跟踪所有非 inode 元数据。

int generic_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)

具有刷新的简单文件系统的通用 fsync 实现

参数

struct file *file

要同步的文件

loff_t start

起始字节偏移量

loff_t end

结束字节偏移量(包括)

int datasync

如果为 true,则仅同步必要的元数据

int generic_check_addressable(unsigned blocksize_bits, u64 num_blocks)

检查文件系统的可寻址性

参数

unsigned blocksize_bits

文件系统块大小的对数

u64 num_blocks

文件系统中的块数

描述

确定具有 num_blocks 块(以及 2****blocksize_bits** 的块大小)的文件系统是否可通过系统的 sector_t 和页面缓存寻址。如果是,则返回 0,否则返回 -EFBIG。

int simple_nosetlease(struct file *filp, int arg, struct file_lease **flp, void **priv)

用于禁止租约的通用助手

参数

struct file *filp

文件指针

int arg

要获取的租约类型

struct file_lease **flp

为插入提供的新租约

void **priv

lm_setup 操作的私有数据

描述

不希望允许设置租约的文件系统的通用助手。所有参数都会被忽略,它只会返回 -EINVAL。

用于获取“快速”符号链接目标的通用助手

参数

struct dentry *dentry

此处未使用

struct inode *inode

符号链接 inode

struct delayed_call *done

此处未使用

描述

用于文件系统以用于符号链接 inode 的通用助手,其中指向符号链接目标的指针存储在 ->i_link 中。注意:这通常不会被调用,因为作为一种优化,路径查找代码会直接使用任何非 NULL 的 ->i_link,而不会调用 ->get_link()。但是仍然必须设置 ->get_link(),以将 inode_operations 标记为用于符号链接。

返回

符号链接目标

int generic_ci_d_compare(const struct dentry *dentry, unsigned int len, const char *str, const struct qstr *name)

用于不区分大小写的文件系统的通用 d_compare 实现

参数

const struct dentry *dentry

我们要检查其名称的 dentry

unsigned int len

dentry 名称的长度

const char *str

指向 dentry 名称的 str 指针

const struct qstr *name

要比较的名称

返回

如果名称匹配,则为 0,如果失配,则为 1,否则为 -ERRNO

int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str)

用于不区分大小写的文件系统的通用 d_hash 实现

参数

const struct dentry *dentry

父目录的 dentry

struct qstr *str

我们应该填充其哈希的名称的 qstr

返回

如果哈希成功或未更改,则为 0,如果出错,则为 -EINVAL

int generic_ci_match(const struct inode *parent, const struct qstr *name, const struct qstr *folded_name, const u8 *de_name, u32 de_name_len)

将名称(不区分大小写)与目录项匹配。这是用于与目录条目进行比较的文件系统助手。在 VFS 的 ->d_compare 中应使用 generic_ci_d_compare。

参数

const struct inode *parent

正在比较的目录项的父级的 Inode

const struct qstr *name

查找下的名称。

const struct qstr *folded_name

查找下的可选预折叠名称

const u8 *de_name

目录项名称。

u32 de_name_len

目录项名称长度。

描述

测试目录项是否与正在搜索的文件名(不区分大小写)匹配。如果提供了 folded_name,则使用它,而不是重新计算 name 的 casefold。

返回

如果目录项匹配,则 > 0;如果目录项不匹配,则为 0;如果出错,则 < 0。

void generic_set_sb_d_ops(struct super_block *sb)

用于为启用的特性选择文件系统范围的目录项操作集的辅助函数

参数

struct super_block *sb

要配置的超级块

描述

支持大小写折叠和/或 fscrypt 的文件系统可以在挂载时调用此辅助函数来配置 sb->s_d_op 为启用的特性所需的最合适的目录项操作集。必须在配置完这些特性之后,但在创建根目录项之前调用此辅助函数。

bool inode_maybe_inc_iversion(struct inode *inode, bool force)

递增 i_version

参数

struct inode *inode

应该更新 i_version 的 inode

bool force

即使不是必需的也递增计数器?

描述

每次修改 inode 时,任何观察者都必须看到 i_version 字段已更改。

如果设置了 “force” 或设置了 QUERIED 标志,则确保我们递增该值并清除 queried 标志。

在未设置任何标志的常见情况下,我们可以返回 “false” 而不更新 i_version。

如果此函数返回 false,并且没有其他元数据发生更改,那么我们可以避免记录元数据。

u64 inode_query_iversion(struct inode *inode)

读取 i_version 以供后续使用

参数

struct inode *inode

从中读取 i_version 的 inode

描述

读取 inode i_version 计数器。希望存储返回的 i_version 以供后续比较的调用者应该使用此方法。这将保证如果任何内容发生更改,则稍后对 i_version 的查询将导致不同的值。

在此实现中,我们获取当前值,设置 QUERIED 标志,然后尝试使用 cmpxchg 将其交换到位(如果尚未设置)。如果失败,我们使用来自 cmpxchg 的新获取的值重试。

struct timespec64 simple_inode_init_ts(struct inode *inode)

初始化新 inode 的时间戳

参数

struct inode *inode

要初始化的 inode

描述

创建新 inode 时,大多数文件系统会将时间戳设置为当前时间。添加一个辅助函数来执行此操作。

int posix_acl_chmod(struct mnt_idmap *idmap, struct dentry *dentry, umode_t mode)

chmod posix acl

参数

struct mnt_idmap *idmap

从挂载的 **inode** 中找到的 idmap

struct dentry *dentry

要检查权限的目录项

umode_t mode

inode 的新模式

描述

如果已通过 idmapped 挂载找到该目录项,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上,或者如果要对原始 inode 执行权限检查,只需传递 nop_mnt_idmap

int posix_acl_update_mode(struct mnt_idmap *idmap, struct inode *inode, umode_t *mode_p, struct posix_acl **acl)

在 set_acl 中更新模式

参数

struct mnt_idmap *idmap

从挂载的 **inode** 中找到的 idmap

struct inode *inode

目标 inode

umode_t *mode_p

用于更新的模式(指针)

struct posix_acl **acl

acl 指针

描述

设置 ACL 时更新文件模式:根据 ACL 计算新的文件权限位。此外,如果 ACL 等效于新的文件模式,则将 *acl 设置为 NULL 以指示不应设置 ACL。

与 chmod 一样,如果调用者不在所有者组中,或者不具备 CAP_FSETID 的能力,则清除 setgid 位(请参阅 inode_change_ok)。

如果通过 idmapped 挂载找到 inode,则必须通过 idmap 传递 vfsmount 的 idmap。然后,此函数将负责根据 idmap 映射 inode,然后再检查权限。在非 idmapped 挂载上或如果要在原始 inode 上执行权限检查,只需传递 nop_mnt_idmap

从 set_acl inode 操作调用。

struct posix_acl *posix_acl_from_xattr(struct user_namespace *userns, const void *value, size_t size)

将 POSIX ACL 从后备存储转换为 VFS 格式

参数

struct user_namespace *userns

文件系统的 idmapping

const void *value

POSIX ACL 的 uapi 表示形式

size_t size

void 的大小

描述

以未更改的 uapi 格式存储 POSIX ACL 的文件系统在从后备存储读取它们并将其转换为 struct posix_acl VFS 格式时,应使用 posix_acl_from_xattr()。该辅助函数专门用于从 acl inode 操作中调用。

posix_acl_from_xattr() 函数会将 ACL_{GROUP,USER} 条目中存储的原始 {g,u}id 值映射到 userns 中的 idmapping。

请注意,posix_acl_from_xattr() 不考虑 idmapped 挂载。如果考虑,从 get acl inode 操作调用它将返回根据 idmapped 挂载映射的 POSIX ACL,这意味着该值无法为文件系统缓存。idmapped 挂载会在权限检查期间或在 VFS - 用户空间边界处动态考虑,然后再将其报告给用户。

返回

成功时分配的 struct posix_acl,对于有效的标头但

没有实际的 POSIX ACL 条目,则为 NULL,或者为 ERR_PTR() 编码的错误代码。

int vfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name, struct posix_acl *kacl)

设置 posix acls

参数

struct mnt_idmap *idmap

挂载的 idmap

struct dentry *dentry

设置 posix acls 所基于的目录项

const char *acl_name

posix acl 的名称

struct posix_acl *kacl

以适当的 VFS 格式表示的 posix acls

描述

此函数设置 kacl。调用者之后必须对 kacl 调用 posix_acl_release()。

返回

成功时为 0,错误时为负 errno。

struct posix_acl *vfs_get_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name)

获取 posix acls

参数

struct mnt_idmap *idmap

挂载的 idmap

struct dentry *dentry

要检索 posix acls 所基于的目录项

const char *acl_name

posix acl 的名称

描述

此函数从文件系统检索 kacl。调用者必须对 kacl 调用 posix_acl_release()。

返回

成功时为 VFS 格式的 POSIX ACL,错误时为负 errno。

int vfs_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name)

删除 posix ACL

参数

struct mnt_idmap *idmap

挂载的 idmap

struct dentry *dentry

要检索 posix acls 所基于的目录项

const char *acl_name

posix acl 的名称

描述

此函数删除 posix ACL。

返回

成功时为 0,错误时为负 errno。

void fill_mg_cmtime(struct kstat *stat, u32 request_mask, struct inode *inode)

填写 mtime 和 ctime,并将 ctime 标记为已查询 (QUERIED)

参数

struct kstat *stat

存储结果值的位置

u32 request_mask

请求的 STATX_* 值

struct inode *inode

从中获取 c/mtime 的 inode

描述

给定 **inode**,从中提取 ctime 和 mtime,并将结果存储在 **stat** 中。当获取值时,将其标记为已查询(如果尚未标记),以便下次写入时记录一个不同的时间戳。

注意:已查询 (QUERIED) 标志在 ctime 中跟踪,但即使仅请求了 mtime,我们也会将其设置在那里,因为这确保了下次 mtime 更改将是不同的。

void generic_fillattr(struct mnt_idmap *idmap, u32 request_mask, struct inode *inode, struct kstat *stat)

从 inode 结构中填写基本属性

参数

struct mnt_idmap *idmap

从中找到 inode 的挂载的 idmap

u32 request_mask

statx 请求掩码

struct inode *inode

用作源的 Inode

struct kstat *stat

在其中填写属性

描述

从 VFS inode 结构中找到的数据填写 kstat 结构中的基本属性。如果未提供 getattr inode 操作,这是默认行为。

如果通过 idmapped 挂载找到了 inode,则必须通过 **idmap** 传递 vfsmount 的 idmap。然后,此函数将负责在填写 uid 和 gid 字段之前根据 **idmap** 映射 inode。在非 idmapped 挂载上,或者如果要在原始 inode 上执行权限检查,只需传递 **nop_mnt_idmap**。

void generic_fill_statx_attr(struct inode *inode, struct kstat *stat)

从 inode 标志中填写 statx 属性

参数

struct inode *inode

用作源的 Inode

struct kstat *stat

在其中填写属性标志

描述

在 kstat 结构中填写 STATX_ATTR_* 标志,用于 inode 的属性,这些属性在 i_flags 上发布并由 VFS 强制执行。

void generic_fill_statx_atomic_writes(struct kstat *stat, unsigned int unit_min, unsigned int unit_max)

填写原子写入 statx 属性

参数

struct kstat *stat

在其中填写属性标志

unsigned int unit_min

支持的最小原子写入长度(以字节为单位)

unsigned int unit_max

支持的最大原子写入长度(以字节为单位)

描述

从原子写入 unit_min 和 unit_max 值填写 kstat 结构中的 STATX{_ATTR}_WRITE_ATOMIC 标志。

int vfs_getattr_nosec(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int query_flags)

获取属性,不进行安全检查

参数

const struct path *path

从中获取属性的文件

struct kstat *stat

在其中返回属性的结构

u32 request_mask

指示调用者想要什么的 STATX_xxx 标志

unsigned int query_flags

查询模式 (AT_STATX_SYNC_TYPE)

描述

获取属性,而不调用 security_inode_getattr。

目前,除了 vfs_getattr 之外,唯一的调用者是文件句柄查找代码的内部,它仅使用 inode 号并且不向任何用户返回属性。任何其他代码可能都需要 vfs_getattr。

int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync)

辅助函数,用于将数据和元数据的一个范围同步到磁盘

参数

struct file *file

要同步的文件

loff_t start

要同步的数据范围的起始字节偏移量

loff_t end

数据范围的结束字节偏移量(包含在内)

int datasync

仅执行数据同步

描述

将 **file** 中 **start**..**end** 范围内的数据和元数据写回磁盘。如果设置了 **datasync**,则仅写入访问修改后的文件数据所需的元数据。

int vfs_fsync(struct file *file, int datasync)

对文件执行 fsync 或 fdatasync

参数

struct file *file

要同步的文件

int datasync

仅执行 fdatasync 操作

描述

将 **file** 的数据和元数据写回磁盘。如果设置了 **datasync**,则仅写入访问修改后的文件数据所需的元数据。

int __vfs_setxattr_locked(struct mnt_idmap *idmap, struct dentry *dentry, const char *name, const void *value, size_t size, int flags, struct inode **delegated_inode)

在持有 inode 锁的同时设置扩展属性

参数

struct mnt_idmap *idmap

目标 inode 的挂载的 idmap

struct dentry *dentry

在其上执行 setxattr 的对象

const char *name

要设置的 xattr 名称

const void *value

要将 **name** 设置为的值

size_t size

**value** 的大小

int flags

要传递到文件系统操作中的标志

struct inode **delegated_inode

返回时,将包含一个委托被破坏的 inode 指针,如果没有,则为 NULL。

ssize_t vfs_listxattr(struct dentry *dentry, char *list, size_t size)

检索以 0 分隔的 xattr 名称列表

参数

struct dentry *dentry

从中检索 xattr 名称的 inode 的 dentry

char *list

用于存储 xattr 名称的缓冲区

size_t size

缓冲区的大小

描述

此函数返回与 dentry 的 inode 关联的所有 xattr 的名称。

请注意,出于历史原因,vfs_listxattr() 函数也会列出 POSIX ACL。 由于 POSIX ACL 与 IOP_XATTR 解耦,vfs_listxattr() 函数不检查此标志,因为文件系统可以在不实现任何其他 xattr 的情况下实现 POSIX ACL。

但是,由于所有删除 IOP_XATTR 的代码路径也会分配 inode 操作,这些操作要么不实现,要么实现一个存根 ->listxattr() 操作。

返回

成功时,返回已使用的缓冲区的大小。 发生错误时返回

负错误代码。

int __vfs_removexattr_locked(struct mnt_idmap *idmap, struct dentry *dentry, const char *name, struct inode **delegated_inode)

在持有 inode 锁的同时设置扩展属性

参数

struct mnt_idmap *idmap

目标 inode 的挂载的 idmap

struct dentry *dentry

在其上执行 setxattr 的对象

const char *name

要删除的 xattr 的名称

struct inode **delegated_inode

返回时,将包含一个委托被破坏的 inode 指针,如果没有,则为 NULL。

ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)

遍历 dentry 的 xattr list() 操作

参数

struct dentry *dentry

要列出 xattr 的 dentry

char *buffer

结果缓冲区

size_t buffer_size

buffer 的大小

描述

合并 xattr_handler 堆栈中每个 xattr_handler 的 list() 操作的结果。

请注意,这不包括 POSIX ACL 的条目。

const char *xattr_full_name(const struct xattr_handler *handler, const char *name)

从后缀计算完整属性名称

参数

const struct xattr_handler *handler

xattr_handler 操作的处理程序

const char *name

传递给 xattr_handler 操作的名称

描述

在跳过处理程序的前缀后,调用 get 和 set xattr 处理程序操作时会传递属性名称的其余部分:例如,对于前缀为“user.”的处理程序,将“foo”传递给 get 操作,以获取属性“user.foo”。 完整名称仍然在名称中。

注意

从 vfs 调用时,list xattr 处理程序操作会传递 NULL 名称;某些文件系统在内部使用此操作,其语义各不相同。

int mnt_get_write_access(struct vfsmount *m)

获取对挂载的写入权限,而无需冻结保护

参数

struct vfsmount *m

要执行写入操作的挂载

描述

这会告知底层文件系统即将对其执行写入操作,并确保允许写入(mnt 为读写)然后返回成功。此操作不防止文件系统被冻结。当写入操作完成后,必须调用 mnt_put_write_access()。 这实际上是一个引用计数。

int mnt_want_write(struct vfsmount *m)

获取对挂载的写入权限

参数

struct vfsmount *m

要执行写入操作的挂载

描述

这会告知底层文件系统即将对其执行写入操作,并确保允许写入(挂载为读写,文件系统未冻结)然后返回成功。当写入操作完成后,必须调用 mnt_drop_write()。 这实际上是一个引用计数。

int mnt_want_write_file(struct file *file)

获取对文件挂载的写入权限

参数

struct file *file

要在其挂载上执行写入操作的文件

描述

这类似于 mnt_want_write,但是如果文件已打开以进行写入,它会跳过增加 mnt_writers(因为打开的文件已经有引用),而只执行冻结保护和对紧急 r/o 重新挂载的检查。这必须与 mnt_drop_write_file 配对使用。

void mnt_put_write_access(struct vfsmount *mnt)

放弃对挂载的写入权限

参数

struct vfsmount *mnt

要放弃写入权限的挂载

描述

告知底层文件系统我们已完成对其的写入操作。必须与上面的 mnt_get_write_access() 调用匹配。

void mnt_drop_write(struct vfsmount *mnt)

放弃对挂载的写入权限

参数

struct vfsmount *mnt

要放弃写入权限的挂载

描述

告知底层文件系统我们已完成对其的写入操作,并允许文件系统再次冻结。必须与上面的 mnt_want_write() 调用匹配。

struct vfsmount *vfs_create_mount(struct fs_context *fc)

为配置的超级块创建挂载

参数

struct fs_context *fc

带有附加超级块的配置上下文

描述

为已配置的超级块创建挂载。如有必要,调用者应在调用此函数之前调用 vfs_get_tree()

请注意,这不会将挂载附加到任何内容。

bool path_is_mountpoint(const struct path *path)

检查路径是否为当前命名空间中的挂载点。

参数

const struct path *path

要检查的路径

d_mountpoint() 只能可靠地用于确定 dentry 是否未在任何命名空间中挂载,并且该常见情况是内联处理的。 d_mountpoint() 不知道在不同的命名空间中可能会有多个挂载使用给定的 dentry。 此函数检查传入的路径是否为挂载点,而不是单独的 dentry。

int may_umount_tree(struct vfsmount *m)

检查挂载树是否繁忙

参数

struct vfsmount *m

挂载树的根

描述

调用此函数是为了检查挂载树是否有任何打开的文件、pwd、chroot 或子挂载处于繁忙状态。

int may_umount(struct vfsmount *mnt)

检查挂载点是否繁忙

参数

struct vfsmount *mnt

挂载的根

描述

调用此函数是为了检查挂载点是否有任何打开的文件、pwd、chroot 或子挂载。如果挂载有子挂载,则无论子挂载是否繁忙,都将返回繁忙。

不考虑配额和相关内容。换句话说,在某些情况下,它会给出假阴性。它在这里的主要原因是我们需要一种非破坏性的方法来查找易于卸载的文件系统。

struct vfsmount *clone_private_mount(const struct path *path)

创建路径的私有克隆

参数

const struct path *path

要克隆的路径

描述

这将创建一个新的 vfsmount,它是 path 的克隆。新的挂载点不会附加到命名空间中的任何位置,并且是私有的(即,对原始挂载点的更改不会传播到此挂载点)。

使用 mntput() 释放。

void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list)

将挂载点放入到期列表中

参数

struct vfsmount *mnt

要列出的挂载点。

struct list_head *expiry_list

要将挂载点添加到的列表。

proc 文件系统

sysctl 接口

int proc_dostring(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)

读取字符串 sysctl

参数

const struct ctl_table *table

sysctl 表

int write

如果这是对 sysctl 文件的写入,则为 TRUE

void *buffer

用户缓冲区

size_t *lenp

用户缓冲区的大小

loff_t *ppos

文件位置

描述

从/向用户缓冲区读取/写入字符串。如果提供的内核缓冲区不足以容纳该字符串,则该字符串将被截断。复制的字符串以 NULL 结尾。如果该字符串正在被用户进程读取,则会复制该字符串并添加换行符 'n'。如果缓冲区不够大,则会被截断。

成功时返回 0。

int proc_dobool(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)

读取/写入布尔值

参数

const struct ctl_table *table

sysctl 表

int write

如果这是对 sysctl 文件的写入,则为 TRUE

void *buffer

用户缓冲区

size_t *lenp

用户缓冲区的大小

loff_t *ppos

文件位置

描述

从/向用户缓冲区读取/写入一个整数值,将其视为 ASCII 字符串。

table->data 必须指向一个布尔变量,并且 table->maxlen 必须为 sizeof(bool)。

成功时返回 0。

int proc_dointvec(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)

读取整数向量

参数

const struct ctl_table *table

sysctl 表

int write

如果这是对 sysctl 文件的写入,则为 TRUE

void *buffer

用户缓冲区

size_t *lenp

用户缓冲区的大小

loff_t *ppos

文件位置

描述

从/向用户缓冲区读取/写入最多 table->maxlen/sizeof(unsigned int) 个整数值,将其视为 ASCII 字符串。

成功时返回 0。

int proc_douintvec(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)

读取无符号整数向量

参数

const struct ctl_table *table

sysctl 表

int write

如果这是对 sysctl 文件的写入,则为 TRUE

void *buffer

用户缓冲区

size_t *lenp

用户缓冲区的大小

loff_t *ppos

文件位置

描述

从/向用户缓冲区读取/写入最多 table->maxlen/sizeof(unsigned int) 个无符号整数值,将其视为 ASCII 字符串。

成功时返回 0。

int proc_dointvec_minmax(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)

读取具有最小值/最大值的整数向量

参数

const struct ctl_table *table

sysctl 表

int write

如果这是对 sysctl 文件的写入,则为 TRUE

void *buffer

用户缓冲区

size_t *lenp

用户缓冲区的大小

loff_t *ppos

文件位置

描述

从/向用户缓冲区读取/写入最多 table->maxlen/sizeof(unsigned int) 个整数值,将其视为 ASCII 字符串。

此例程将确保这些值在 table->extra1(最小值)和 table->extra2(最大值)指定的范围内。

成功时返回 0,或者在写入时范围检查失败时返回 -EINVAL。

int proc_douintvec_minmax(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)

读取具有最小值/最大值的无符号整数向量

参数

const struct ctl_table *table

sysctl 表

int write

如果这是对 sysctl 文件的写入,则为 TRUE

void *buffer

用户缓冲区

size_t *lenp

用户缓冲区的大小

loff_t *ppos

文件位置

描述

从/向用户缓冲区读取/写入最多 table->maxlen/sizeof(unsigned int) 个无符号整数值,将其视为 ASCII 字符串。不允许负字符串。

此例程将确保这些值在 table->extra1(最小值)和 table->extra2(最大值)指定的范围内。最后有一个针对 UINT_MAX 的健全性检查,以避免必须支持来自用户空间的环绕使用。

成功时返回 0,或者在写入时范围检查失败时返回 -ERANGE。

int proc_dou8vec_minmax(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)

读取具有最小值/最大值的无符号字符向量

参数

const struct ctl_table *table

sysctl 表

int write

如果这是对 sysctl 文件的写入,则为 TRUE

void *buffer

用户缓冲区

size_t *lenp

用户缓冲区的大小

loff_t *ppos

文件位置

描述

从/向用户缓冲区读取/写入最多 table->maxlen/sizeof(u8) 个无符号字符值,将其视为 ASCII 字符串。不允许负字符串。

此例程将确保这些值在 table->extra1(最小值)和 table->extra2(最大值)指定的范围内。

成功时返回 0,或者在写入时范围检查失败时返回错误。

int proc_doulongvec_minmax(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)

读取具有最小值/最大值的长整数向量

参数

const struct ctl_table *table

sysctl 表

int write

如果这是对 sysctl 文件的写入,则为 TRUE

void *buffer

用户缓冲区

size_t *lenp

用户缓冲区的大小

loff_t *ppos

文件位置

描述

从/向用户缓冲区读取/写入最多 table->maxlen/sizeof(unsigned long) 个无符号长整数值,将其视为 ASCII 字符串。

此例程将确保这些值在 table->extra1(最小值)和 table->extra2(最大值)指定的范围内。

成功时返回 0。

int proc_doulongvec_ms_jiffies_minmax(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)

读取具有最小值/最大值的毫秒值向量

参数

const struct ctl_table *table

sysctl 表

int write

如果这是对 sysctl 文件的写入,则为 TRUE

void *buffer

用户缓冲区

size_t *lenp

用户缓冲区的大小

loff_t *ppos

文件位置

描述

从/向用户缓冲区读取/写入最多 table->maxlen/sizeof(unsigned long) 个无符号长整数值,将其视为 ASCII 字符串。这些值被视为毫秒,并在存储时转换为节拍数。

此例程将确保这些值在 table->extra1(最小值)和 table->extra2(最大值)指定的范围内。

成功时返回 0。

int proc_dointvec_jiffies(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)

读取一个整数向量,将其作为秒数处理

参数

const struct ctl_table *table

sysctl 表

int write

如果这是对 sysctl 文件的写入,则为 TRUE

void *buffer

用户缓冲区

size_t *lenp

用户缓冲区的大小

loff_t *ppos

文件位置

描述

从用户缓冲区读取/写入最多 table->maxlen/sizeof(unsigned int) 个整数值,并将其视为 ASCII 字符串。读取的值被假定为秒数,并转换为 jiffies。

成功时返回 0。

int proc_dointvec_userhz_jiffies(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)

读取一个整数向量,将其作为 1/USER_HZ 秒处理

参数

const struct ctl_table *table

sysctl 表

int write

如果这是对 sysctl 文件的写入,则为 TRUE

void *buffer

用户缓冲区

size_t *lenp

用户缓冲区的大小

loff_t *ppos

指向文件位置的指针

描述

从用户缓冲区读取/写入最多 table->maxlen/sizeof(unsigned int) 个整数值,并将其视为 ASCII 字符串。读取的值被假定为 1/USER_HZ 秒,并转换为 jiffies。

成功时返回 0。

int proc_dointvec_ms_jiffies(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)

读取一个整数向量,将其作为 1 毫秒处理

参数

const struct ctl_table *table

sysctl 表

int write

如果这是对 sysctl 文件的写入,则为 TRUE

void *buffer

用户缓冲区

size_t *lenp

用户缓冲区的大小

loff_t *ppos

文件中当前的位置

描述

从用户缓冲区读取/写入最多 table->maxlen/sizeof(unsigned int) 个整数值,并将其视为 ASCII 字符串。读取的值被假定为 1/1000 秒,并转换为 jiffies。

成功时返回 0。

int proc_do_large_bitmap(const struct ctl_table *table, int write, void *buffer, size_t *lenp, loff_t *ppos)

从大型位图读取/写入

参数

const struct ctl_table *table

sysctl 表

int write

如果这是对 sysctl 文件的写入,则为 TRUE

void *buffer

用户缓冲区

size_t *lenp

用户缓冲区的大小

loff_t *ppos

文件位置

描述

位图存储在 table->data 中,位图的长度(以位为单位)存储在 table->maxlen 中。

我们使用范围逗号分隔格式(例如 1,3-4,10-10),以便可以用紧凑的方式表示大型位图。写入文件将清除位图,然后使用给定的输入更新它。

成功时返回 0。

proc 文件系统接口

void proc_flush_pid(struct pid *pid)

从 /proc dcache 中删除 pid 的 dcache 条目。

参数

struct pid *pid

应该被刷新的 pid。

描述

此函数遍历附加到 pid 的 inode 列表(属于任何 proc 文件系统),并将它们从 dentry 缓存中刷新。

在任务退出之前,缓存任务的 /proc 条目是安全合理的。之后,它们只会用无用的条目堵塞 dcache,可能导致有用的 dcache 条目被刷新。当进程被回收时,此例程用于刷新那些无用的 dcache 条目。

注意

此例程只是一种优化,因此不保证

在进程被回收后,不会存在任何 dcache 条目,它只是使其非常不可能存在任何持久的条目。

基于文件描述符的事件

void eventfd_signal_mask(struct eventfd_ctx *ctx, __poll_t mask)

递增事件计数器

参数

struct eventfd_ctx *ctx

[输入] 指向 eventfd 上下文的指针。

__poll_t mask

[输入] poll 掩码

描述

此函数应该由内核在不允许休眠的路径中调用。在此函数中,我们允许计数器达到 ULLONG_MAX 值,并且我们通过向 poll(2) 返回 EPOLLERR 来表示此溢出情况。

void eventfd_ctx_put(struct eventfd_ctx *ctx)

释放对内部 eventfd 上下文的引用。

参数

struct eventfd_ctx *ctx

[输入] 指向 eventfd 上下文的指针。

描述

eventfd 上下文引用必须先前通过 eventfd_ctx_fdget()eventfd_ctx_fileget() 获取。

int eventfd_ctx_remove_wait_queue(struct eventfd_ctx *ctx, wait_queue_entry_t *wait, __u64 *cnt)

读取当前计数器并删除等待队列。

参数

struct eventfd_ctx *ctx

[输入] 指向 eventfd 上下文的指针。

wait_queue_entry_t *wait

[输入] 要删除的等待队列。

__u64 *cnt

[输出] 指向 64 位计数器值的指针。

描述

如果成功,则返回 0,否则返回以下错误代码

-EAGAIN

: 操作将会阻塞。

这用于原子地从 eventfd 等待队列头中删除等待队列条目,并读取/重置计数器值。

struct file *eventfd_fget(int fd)

获取 eventfd 文件描述符的引用。

参数

int fd

[输入] Eventfd 文件描述符。

描述

如果成功,则返回指向 eventfd 文件结构的指针,否则返回以下错误指针

-EBADF

: 无效的 fd 文件描述符。

-EINVAL

: fd 文件描述符不是 eventfd 文件。

struct eventfd_ctx *eventfd_ctx_fdget(int fd)

获取对内部 eventfd 上下文的引用。

参数

int fd

[输入] Eventfd 文件描述符。

描述

返回指向内部 eventfd 上下文的指针,否则返回以下函数返回的错误指针

eventfd_fget

struct eventfd_ctx *eventfd_ctx_fileget(struct file *file)

获取对内部 eventfd 上下文的引用。

参数

struct file *file

[in] Eventfd 文件指针。

描述

返回指向内部 eventfd 上下文的指针,否则返回错误指针

-EINVAL

: fd 文件描述符不是 eventfd 文件。

eventpoll (epoll) 接口

int ep_events_available(struct eventpoll *ep)

检查是否有就绪事件可用。

参数

struct eventpoll *ep

指向 eventpoll 上下文的指针。

返回

如果存在就绪事件,则返回一个非 的值,

否则返回

bool busy_loop_ep_timeout(unsigned long start_time, struct eventpoll *ep)

检查忙轮询是否超时。优先使用 epoll 实例 ep 的超时值,但如果未设置,则回退到通过 busy_loop_timeout 的系统全局值。

参数

unsigned long start_time

用于计算剩余超时时间的起始时间。

struct eventpoll *ep

指向 eventpoll 上下文的指针。

返回

如果超时已过期,则为 true,否则为 false。

int reverse_path_check(void)

tfile_check_list 是 epitem_head 的列表,其中包含提议新添加的链接。我们需要确保这些添加的链接不会添加过多的路径,以致于我们会将所有时间都花费在唤醒 eventpoll 对象上。

参数

void

无参数

返回

如果提议的链接没有创建过多的路径,则返回

否则返回 -1

int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, int maxevents, struct timespec64 *timeout)

检索就绪事件,并将它们传递到调用方提供的事件缓冲区。

参数

struct eventpoll *ep

指向 eventpoll 上下文的指针。

struct epoll_event __user *events

指向用户空间缓冲区的指针,就绪事件应存储在该缓冲区中。

int maxevents

调用方事件缓冲区的大小(以事件数量为单位)。

struct timespec64 *timeout

就绪事件获取操作的最大超时时间,以 timespec 为单位。如果超时时间为零,该函数将不会阻塞;如果 timeout 指针为 NULL,该函数将阻塞,直到至少检索到一个事件(或发生错误)。

返回

已获取的就绪事件数,或者

错误代码(如果发生错误)。

int ep_loop_check_proc(struct eventpoll *ep, int depth)

验证将一个 epoll 文件添加到另一个 epoll 结构中是否违反了约束,包括闭环或过深的链(这可能导致过多的堆栈使用)。

参数

struct eventpoll *ep

当前要检查的 struct eventpoll

int depth

当前正在检查的路径的深度。

返回

如果将 epoll 文件 添加到当前 epoll

结构 ep 中没有违反约束,则返回 ,否则返回 -1

int ep_loop_check(struct eventpoll *ep, struct eventpoll *to)

执行检查以验证将一个 epoll 文件 (to) 添加到另一个 epoll 文件(由 ep 表示)中是否会创建闭环或过深的链。

参数

struct eventpoll *ep

指向我们要插入的 epoll 的指针。

struct eventpoll *to

指向要插入的 epoll 的指针。

返回

如果将 epoll to 添加到 epoll from 中没有违反约束,则返回 ,否则返回 -1

用于导出内核对象的文件系统

int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr, const void *ns)

为具有自定义 ns 的对象创建一个属性文件

参数

struct kobject *kobj

我们正在创建的对象

const struct attribute *attr

属性描述符

const void *ns

新文件应属于的命名空间

int sysfs_add_file_to_group(struct kobject *kobj, const struct attribute *attr, const char *group)

将属性文件添加到预先存在的组中。

参数

struct kobject *kobj

我们正在为其操作的对象。

const struct attribute *attr

属性描述符。

const char *group

组名。

int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, umode_t mode)

更新对象属性上修改的模式值。

参数

struct kobject *kobj

我们正在为其操作的对象。

const struct attribute *attr

属性描述符。

umode_t mode

文件权限。

struct kernfs_node *sysfs_break_active_protection(struct kobject *kobj, const struct attribute *attr)

打破“活动”保护

参数

struct kobject *kobj

内核对象 attr 与之关联。

const struct attribute *attr

要打破“活动”保护的属性。

描述

与 kernfs 一样,使用 sysfs 时,除非调用此函数,否则属性的删除会延迟到所有活动的 .show() 和 .store() 回调完成之后。因此,此函数在实现自删除的方法中很有用。

void sysfs_unbreak_active_protection(struct kernfs_node *kn)

恢复“活动”保护

参数

struct kernfs_node *kn

sysfs_break_active_protection() 返回的指针。

描述

撤消 sysfs_break_active_protection() 的效果。由于此函数在与传递给 sysfs_break_active_protection() 的 'attr' 参数相对应的 kernfs 节点上调用 kernfs_put(),因此该属性可能在 sysfs_break_active_protection()sysfs_unbreak_active_protection() 调用之间被删除,因此在此函数返回后访问 kn 是不安全的。

void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr, const void *ns)

删除具有自定义 ns 标签的对象属性

参数

struct kobject *kobj

我们正在为其执行操作的对象

const struct attribute *attr

属性描述符

const void *ns

要删除的文件的命名空间标签

描述

散列属性名称和命名空间标记,并杀死受害者。

bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr)

从其自身的方法中删除对象属性

参数

struct kobject *kobj

我们正在为其执行操作的对象

const struct attribute *attr

属性描述符

描述

有关详细信息,请参见 kernfs_remove_self()。

void sysfs_remove_file_from_group(struct kobject *kobj, const struct attribute *attr, const char *group)

从组中删除属性文件。

参数

struct kobject *kobj

我们正在为其操作的对象。

const struct attribute *attr

属性描述符。

const char *group

组名。

int sysfs_create_bin_file(struct kobject *kobj, const struct bin_attribute *attr)

为对象创建二进制文件。

参数

struct kobject *kobj

对象。

const struct bin_attribute *attr

属性描述符。

void sysfs_remove_bin_file(struct kobject *kobj, const struct bin_attribute *attr)

删除对象的二进制文件。

参数

struct kobject *kobj

对象。

const struct bin_attribute *attr

属性描述符。

int sysfs_file_change_owner(struct kobject *kobj, const char *name, kuid_t kuid, kgid_t kgid)

更改 sysfs 文件的所有者。

参数

struct kobject *kobj

对象。

const char *name

要更改的文件名。

kuid_t kuid

新所有者的 kuid

kgid_t kgid

新所有者的 kgid

描述

此函数在 kobj 下查找 sysfs 条目 name,并将所有权更改为 kuid/kgid

成功时返回 0,失败时返回错误代码。

int sysfs_change_owner(struct kobject *kobj, kuid_t kuid, kgid_t kgid)

更改给定对象的所有者。

参数

struct kobject *kobj

对象。

kuid_t kuid

新所有者的 kuid

kgid_t kgid

新所有者的 kgid

描述

kobj 的默认目录、文件、组和属性的所有者更改为 kuid/kgid。请注意,sysfs_change_owner 镜像了驱动程序核心如何添加 kobject 的 sysfs 条目。总而言之,sysfs_change_owner() 负责处理 kobj 的默认目录条目、与 kobj 的 ktype 关联的默认属性以及与 kobj 的 ktype 关联的默认属性。驱动程序核心未添加的其他属性必须由创建它们的驱动程序或子系统更改。这与删除驱动程序/子系统特定条目的方式类似。

成功时返回 0,失败时返回错误代码。

int sysfs_emit(char *buf, const char *fmt, ...)

等效于 scnprintf,知道 PAGE_SIZE 缓冲区。

参数

char *buf

PAGE_SIZE 缓冲区的起始位置。

const char *fmt

格式

...

format 的可选参数

描述

返回写入 buf 的字符数。

int sysfs_emit_at(char *buf, int at, const char *fmt, ...)

等效于 scnprintf,知道 PAGE_SIZE 缓冲区。

参数

char *buf

PAGE_SIZE 缓冲区的起始位置。

int at

buf 中开始写入的字节偏移量 at 必须 >= 0 && < PAGE_SIZE

const char *fmt

格式

...

fmt 的可选参数

描述

返回从 &**buf**[at] 开始写入的字符数。

ssize_t sysfs_bin_attr_simple_read(struct file *file, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count)

读取回调以简单地从内存复制。

参数

struct file *file

正在读取的属性文件。

struct kobject *kobj

属性所属的对象。

struct bin_attribute *attr

属性描述符。

char *buf

目标缓冲区。

loff_t off

要从中读取的字节偏移量。

size_t count

要读取的最大字节数。

描述

由内存中的缓冲区支持的 bin_attributes 的简单 ->read() 回调。在 sysfs 中创建 bin_attribute 之前,必须将 struct bin_attribute 中的 privatesize 成员设置为缓冲区的位置和大小。

offcount 的边界检查在 sysfs_kf_bin_read() 中完成。对 off 的负值检查在 vfs_setpos() 和 default_llseek() 中完成。

返回写入 buf 的字节数。

在两个对象之间创建符号链接。

参数

struct kobject *kobj

要在其中创建链接的目录的对象。

struct kobject *target

指向的目标对象。

const char *name

符号链接的名称。

在两个对象之间创建符号链接。

参数

struct kobject *kobj

要在其中创建链接的目录的对象。

struct kobject *target

指向的目标对象。

const char *name

符号链接的名称。

此函数与 sysfs_create_link() 的功能相同,但如果链接已存在,则不会发出警告。

删除对象目录中的符号链接。

参数

struct kobject *kobj

我们正在为其操作的对象。

const char *name

要删除的符号链接的名称。

重命名对象目录中的符号链接。

参数

struct kobject *kobj

我们正在为其操作的对象。

struct kobject *targ

指向的目标对象。

const char *old

符号链接的先前名称。

const char *new

符号链接的新名称。

const void *new_ns

符号链接的新命名空间。

用于常见重命名符号链接习惯的辅助函数。

debugfs 文件系统

debugfs 接口

struct dentry *debugfs_lookup(const char *name, struct dentry *parent)

查找现有的 debugfs 文件

参数

const char *name

指向包含要查找的文件名称的字符串的指针。

struct dentry *parent

指向文件的父 dentry 的指针。

描述

如果函数成功,将返回指向 dentry 的指针。如果文件不存在或发生错误,将返回 NULL。返回的 dentry 在不再需要时必须传递给 dput()。

如果内核中未启用 debugfs,则将返回值 -ENODEV

struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops)

在 debugfs 文件系统中创建一个文件

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限。

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置,这应该是一个目录 dentry。如果此参数为 NULL,则将在 debugfs 文件系统的根目录中创建该文件。

void *data

指向调用者以后想要访问的内容的指针。inode.i_private 指针将在 open() 调用时指向此值。

const struct file_operations *fops

指向应该用于此文件的 struct file_operations 的指针。

描述

debugfs_create_file_unsafe() 与 debugfs_create_file() 完全类似,唯一的区别是它传递的 fops 将不会受到 debugfs 核心的文件删除保护。

您有责任通过 debugfs_file_get()debugfs_file_put() 保护您的 struct file_operation 方法免受文件删除的影响。但是,->open() 仍然受到 debugfs 的保护。

通过 DEFINE_DEBUGFS_ATTRIBUTE() 定义的任何 struct file_operations 都会受到文件删除的保护,因此可以在此处使用。

void debugfs_create_file_size(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops, loff_t file_size)

在 debugfs 文件系统中创建一个文件

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限。

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置,这应该是一个目录 dentry。如果此参数为 NULL,则将在 debugfs 文件系统的根目录中创建该文件。

void *data

指向调用者以后想要访问的内容的指针。inode.i_private 指针将在 open() 调用时指向此值。

const struct file_operations *fops

指向应该用于此文件的 struct file_operations 的指针。

loff_t file_size

初始文件大小

描述

这是用于 debugfs 的基本“创建文件”函数。它允许在创建文件或目录方面具有广泛的灵活性(如果要创建目录,建议使用 debugfs_create_dir() 函数)。

struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)

在 debugfs 文件系统中创建一个目录

参数

const char *name

指向包含要创建的目录名称的字符串的指针。

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置,这应该是一个目录 dentry。如果此参数为 NULL,则将在 debugfs 文件系统的根目录中创建该目录。

描述

此函数在 debugfs 中创建一个具有给定名称的目录。

如果函数成功,将返回指向 dentry 的指针。当要删除该文件时,此指针必须传递给 debugfs_remove() 函数(如果您的模块被卸载,则不会发生自动清理,您有责任在此处进行清理。)如果发生错误,将返回 ERR_PTR(-ERROR)。

如果内核中未启用 debugfs,则将返回值 -ENODEV

注意

预计大多数调用者都应该 _忽略_ 此函数返回的错误。其他 debugfs 函数会处理传递给它们的“dentry”可能是错误的情况,并且它们在这种情况下不会崩溃。即使 debugfs 初始化失败,驱动程序通常也应该可以正常工作。

struct dentry *debugfs_create_automount(const char *name, struct dentry *parent, debugfs_automount_t f, void *data)

在 debugfs 文件系统中创建自动挂载点。

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置,这应该是一个目录 dentry。如果此参数为 NULL,则将在 debugfs 文件系统的根目录中创建该文件。

debugfs_automount_t f

当路径名解析步骤到达该点时要调用的函数。

void *data

传递给 f() 的不透明参数。

描述

f 应该返回 ->d_automount() 的返回值。

在 debugfs 文件系统中创建符号链接。

参数

const char *name

指向一个字符串的指针,该字符串包含要创建的符号链接的名称。

struct dentry *parent

指向此符号链接的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则将在 debugfs 文件系统的根目录中创建符号链接。

const char *target

指向一个字符串的指针,该字符串包含符号链接目标的路径。

描述

此函数在 debugfs 中创建一个具有给定名称的符号链接,该链接指向给定的目标路径。

如果成功,此函数将返回指向 dentry 的指针。当要删除符号链接时,此指针必须传递给 debugfs_remove() 函数(如果您的模块卸载,不会发生自动清理,您需要负责)。如果发生错误,将返回 ERR_PTR(-ERROR)。

如果内核中未启用 debugfs,则将返回值 -ENODEV

void debugfs_remove(struct dentry *dentry)

递归删除目录。

参数

struct dentry *dentry

指向要删除的目录的 dentry 的指针。如果此参数为 NULL 或错误值,则不会执行任何操作。

描述

此函数递归删除 debugfs 中先前通过调用另一个 debugfs 函数(如 debugfs_create_file() 或其变体)创建的目录树。

必须调用此函数才能删除文件,当模块删除时,不会自动清理文件,您需要负责。

void debugfs_lookup_and_remove(const char *name, struct dentry *parent)

查找目录或文件并递归删除它。

参数

const char *name

指向一个字符串的指针,该字符串包含要查找的项的名称。

struct dentry *parent

指向项的父 dentry 的指针。

描述

这相当于执行 debugfs_remove(debugfs_lookup(..)) 之类的操作,但会对正在查找的目录进行正确的引用计数处理。

struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, struct dentry *new_dir, const char *new_name)

在 debugfs 文件系统中重命名文件/目录。

参数

struct dentry *old_dir

指向已重命名对象的父 dentry 的指针。这应该是一个目录 dentry。

struct dentry *old_dentry

要重命名的对象的 dentry。

struct dentry *new_dir

指向应该移动对象的父 dentry 的指针。这应该是一个目录 dentry。

const char *new_name

指向包含目标名称的字符串的指针。

描述

此函数在 debugfs 中重命名文件/目录。目标必须不存在才能成功重命名。

如果成功,此函数将返回指向 old_dentry 的指针(该指针已更新以反映重命名)。如果发生错误,将返回 ERR_PTR(-ERROR)。

如果内核中未启用 debugfs,则将返回值 -ENODEV

bool debugfs_initialized(void)

指示 debugfs 是否已注册。

参数

void

无参数

int debugfs_file_get(struct dentry *dentry)

标记文件数据访问的开始。

参数

struct dentry *dentry

正在访问其数据的 dentry 对象。

描述

在匹配调用 debugfs_file_put() 之前,对文件删除函数 debugfs_remove() 和 debugfs_remove_recursive() 的任何后续调用都将阻塞。由于关联的私有文件数据可能仅在任何删除函数成功返回后才会被释放,因此您可以在成功调用 debugfs_file_get() 后安全地访问它,而无需担心生命周期问题。

如果返回 -EIO,则表示该文件已被删除,因此,访问其任何数据都是不安全的。另一方面,如果允许访问文件数据,则返回零。

void debugfs_file_put(struct dentry *dentry)

标记文件数据访问的结束。

参数

struct dentry *dentry

以前传递给 debugfs_file_get() 的 dentry 对象。

描述

允许之前调用 debugfs_file_get() 阻塞的任何正在进行的对 debugfs_remove() 或 debugfs_remove_recursive() 的并发调用继续进行并返回给其调用者。

void debugfs_enter_cancellation(struct file *file, struct debugfs_cancellation *cancellation)

进入 debugfs 取消。

参数

struct file *file

正在访问的文件。

struct debugfs_cancellation *cancellation

取消对象,其中必须初始化取消回调。

描述

当删除 debugfs 文件时,它需要等待所有活动操作完成。但是,操作本身可能需要等待硬件或某些异步进程的完成,或类似的操作。因此,它可能需要被取消,以避免长时间等待甚至死锁。

此函数可以在可能需要取消的 debugfs 处理程序中使用。一旦调用此函数,可能会调用取消的“cancel”回调,此时调用者应继续调用 debugfs_leave_cancellation() 并尽快离开 debugfs 处理程序函数。请注意,“cancel”回调仅在某种 debugfs_remove() 的上下文中被调用。

此函数必须与 debugfs_leave_cancellation() 配对使用。

void debugfs_leave_cancellation(struct file *file, struct debugfs_cancellation *cancellation)

离开取消部分

参数

struct file *file

正在访问的文件。

struct debugfs_cancellation *cancellation

之前通过 debugfs_enter_cancellation() 注册的取消

描述

请参阅 debugfs_enter_cancellation() 的文档。

void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, u8 *value)

创建一个用于读取和写入无符号 8 位值的 debugfs 文件

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

u8 *value

指向文件应从中读取和写入的变量的指针。

描述

此函数在 debugfs 中创建一个具有给定名称的文件,该文件包含变量 value 的值。如果设置了 mode 变量,则可以从中读取和写入。

void debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent, u16 *value)

创建一个用于读取和写入无符号 16 位值的 debugfs 文件

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

u16 *value

指向文件应从中读取和写入的变量的指针。

描述

此函数在 debugfs 中创建一个具有给定名称的文件,该文件包含变量 value 的值。如果设置了 mode 变量,则可以从中读取和写入。

void debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent, u32 *value)

创建一个用于读取和写入无符号 32 位值的 debugfs 文件

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

u32 *value

指向文件应从中读取和写入的变量的指针。

描述

此函数在 debugfs 中创建一个具有给定名称的文件,该文件包含变量 value 的值。如果设置了 mode 变量,则可以从中读取和写入。

void debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent, u64 *value)

创建一个用于读取和写入无符号 64 位值的 debugfs 文件

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

u64 *value

指向文件应从中读取和写入的变量的指针。

描述

此函数在 debugfs 中创建一个具有给定名称的文件,该文件包含变量 value 的值。如果设置了 mode 变量,则可以从中读取和写入。

void debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, unsigned long *value)

创建一个用于读取和写入无符号长整型值的 debugfs 文件。

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

unsigned long *value

指向文件应从中读取和写入的变量的指针。

描述

此函数在 debugfs 中创建一个具有给定名称的文件,该文件包含变量 value 的值。如果设置了 mode 变量,则可以从中读取和写入。

void debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, u8 *value)

创建一个用于读取和写入无符号 8 位值的 debugfs 文件

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

u8 *value

指向文件应从中读取和写入的变量的指针。

void debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, u16 *value)

创建一个用于读取和写入无符号 16 位值的 debugfs 文件

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

u16 *value

指向文件应从中读取和写入的变量的指针。

void debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent, u32 *value)

创建一个用于读取和写入无符号 32 位值的 debugfs 文件

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

u32 *value

指向文件应从中读取和写入的变量的指针。

void debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent, u64 *value)

创建一个用于读取和写入无符号 64 位值的 debugfs 文件

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

u64 *value

指向文件应从中读取和写入的变量的指针。

void debugfs_create_size_t(const char *name, umode_t mode, struct dentry *parent, size_t *value)

创建一个用于读取和写入 size_t 值的 debugfs 文件

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

size_t *value

指向文件应从中读取和写入的变量的指针。

void debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent, atomic_t *value)

创建一个 debugfs 文件,用于读取和写入 atomic_t 值

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

atomic_t *value

指向文件应从中读取和写入的变量的指针。

void debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent, bool *value)

创建一个 debugfs 文件,用于读取和写入布尔值

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

bool *value

指向文件应从中读取和写入的变量的指针。

描述

此函数在 debugfs 中创建一个具有给定名称的文件,该文件包含变量 value 的值。如果设置了 mode 变量,则可以从中读取和写入。

void debugfs_create_str(const char *name, umode_t mode, struct dentry *parent, char **value)

创建一个 debugfs 文件,用于读取和写入字符串值

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

char **value

指向文件应从中读取和写入的变量的指针。

描述

此函数在 debugfs 中创建一个具有给定名称的文件,该文件包含变量 value 的值。如果设置了 mode 变量,则可以从中读取和写入。

struct dentry *debugfs_create_blob(const char *name, umode_t mode, struct dentry *parent, struct debugfs_blob_wrapper *blob)

创建一个 debugfs 文件,用于读取和写入二进制 blob

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

struct debugfs_blob_wrapper *blob

一个指向 struct debugfs_blob_wrapper 的指针,其中包含指向 blob 数据和数据大小的指针。

描述

此函数在 debugfs 中创建一个具有给定名称的文件,该文件将 blob->data 导出为二进制 blob。如果设置了 mode 变量,则可以读取和写入该文件。

如果函数成功,将返回指向 dentry 的指针。当要删除该文件时,此指针必须传递给 debugfs_remove() 函数(如果您的模块被卸载,则不会发生自动清理,您有责任在此处进行清理。)如果发生错误,将返回 ERR_PTR(-ERROR)。

如果在内核中未启用 debugfs,则将返回 ERR_PTR(-ENODEV) 值。

void debugfs_create_u32_array(const char *name, umode_t mode, struct dentry *parent, struct debugfs_u32_array *array)

创建一个 debugfs 文件,用于读取 u32 数组。

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限。

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

struct debugfs_u32_array *array

包含数据指针和数组大小的包装结构。

描述

此函数在 debugfs 中创建一个具有给定名称的文件,该文件将 array 导出为数据。如果设置了 mode 变量,则可以读取该文件。不支持写入。也不支持在文件中查找。一旦创建数组,其大小就无法更改。

void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, int nregs, void __iomem *base, char *prefix)

使用 seq_print 描述一组寄存器

参数

struct seq_file *s

用于生成输出的 seq_file 结构

const struct debugfs_reg32 *regs

struct debugfs_reg32 结构的数组

int nregs

上述数组的长度

void __iomem *base

用于读取寄存器的基地址

char *prefix

要添加到每个输出行开头的字符串

描述

此函数输出一个文本块,描述某些 32 位硬件寄存器的当前值。它旨在用于基于 seq_file 的 debugfs 文件中,这些文件需要显示寄存器,并与其他信息混合在一起。prefix 参数可用于指定前导字符串,因为某些外围设备具有多个相同的寄存器块,例如 dma 通道的配置

void debugfs_create_regset32(const char *name, umode_t mode, struct dentry *parent, struct debugfs_regset32 *regset)

创建一个 debugfs 文件,该文件返回寄存器值

参数

const char *name

指向包含要创建的文件名称的字符串的指针。

umode_t mode

文件应具有的权限

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

struct debugfs_regset32 *regset

指向 struct debugfs_regset32 的指针,其中包含指向寄存器定义数组、数组大小以及要查找寄存器组的基地址的指针。

描述

此函数在 debugfs 中创建一个具有给定名称的文件,该文件报告一组 32 位寄存器的名称和值。如果设置了 mode 变量,则可以读取该文件。不支持写入。

void debugfs_create_devm_seqfile(struct device *dev, const char *name, struct dentry *parent, int (*read_fn)(struct seq_file *s, void *data))

创建一个绑定到设备的 debugfs 文件。

参数

struct device *dev

与此 debugfs 文件相关的设备。

const char *name

debugfs 文件的名称。

struct dentry *parent

指向此文件的父 dentry 的指针。如果设置了,这应该是一个目录 dentry。如果此参数为 NULL,则该文件将在 debugfs 文件系统的根目录中创建。

int (*read_fn)(struct seq_file *s, void *data)

调用以打印 seq_file 内容的函数指针。