[TOC]
kernfs 伪文件系统核心框架(Pseudo Filesystem Core Framework) sysfs和cgroupfs的底层基石 历史与背景 这项技术是为了解决什么特定问题而诞生的? kernfs (Kernel File System) 是一个为了解决在实现伪文件系统(pseudo filesystem)时遇到的内部复杂性和锁竞争问题 而被创造出来的内核核心框架。它的诞生主要源于其前身及主要用户——sysfs
——所暴露出的设计缺陷:
锁机制复杂且易于死锁 :在 kernfs 出现之前,sysfs
的实现与 VFS(虚拟文件系统)层紧密耦合。sysfs
中的目录和文件直接对应于内核的 dentry
和 inode
对象。VFS 自身的锁机制(特别是 d_lock
和 i_mutex
)非常复杂,当 sysfs
的属性文件读写操作需要回调到驱动程序,而驱动程序又可能需要获取其他与 VFS 相关的锁时,就极易形成复杂的锁依赖链,导致死锁(deadlock)。这是 sysfs
长期以来最头疼的问题之一。
数据结构臃肿 :直接使用 dentry
和 inode
来表示 sysfs
中的每一个节点,对于这种只有元数据、没有实际数据的伪文件系统来说,是一种浪费。这些 VFS 结构体包含了大量 sysfs
根本用不到的字段,增加了内存消耗。
生命周期管理困难 :sysfs
节点的生命周期与 VFS 对象的生命周期紧密绑定,而 VFS 的缓存机制(dcache)使得节点的销毁时机变得不确定,这给需要精确控制节点创建和移除的驱动开发者带来了困难。
缺乏清晰的抽象 :sysfs
的实现混杂了通用逻辑和 VFS 的特定实现细节,使得代码难以理解和维护,也无法方便地被其他需要类似功能的伪文件系统(如 cgroupfs)复用。
kernfs 的诞生就是为了将伪文件系统的内部逻辑实现 与VFS 的表现层 彻底分离开,从而解决上述所有问题。
它的发展经历了哪些重要的里程碑或版本迭代? kernfs 的发展是一个典型的内核重构过程:
构思与实现 :由内核开发者 Tejun Heo 主导,旨在创建一个通用的、轻量级的框架来构建层次化的伪文件系统,其首要目标就是修复 sysfs
的锁问题。
内核引入 :kernfs 在 Linux 内核 3.14 版本中被正式引入。这是一个重要的里程碑,标志着内核拥有了一个专门用于构建伪文件系统的标准工具集。
sysfs 迁移 :在引入 kernfs 之后,一个庞大的工程就是将现有的 sysfs
实现完全迁移到 kernfs 之上。这意味着 sysfs
不再直接操作 dentry
和 inode
,而是通过 kernfs 作为中间层。这个迁移工作跨越了多个内核版本。
cgroupfs v2 的采用 :在统一的 cgroup 层次结构(cgroup v2)的设计和实现中,kernfs 被选为其底层的文件系统实现。这证明了 kernfs 作为一个通用框架的成功,不再仅仅是 sysfs
的“后台”。
目前该技术的社区活跃度和主流应用情况如何? kernfs 是一个非常稳定和成熟的内核核心组件。它不是一个用户可以直接挂载或使用的文件系统,而是一个内部框架 。它的活跃度体现在其用户的活跃度上:
sysfs :作为 Linux 设备模型的核心部分,sysfs
遍布于所有现代 Linux 系统中,因此 kernfs 也在所有这些系统上稳定运行。
cgroupfs v2 :作为现代容器技术(如 Docker, systemd)和资源管理的基础,cgroup v2 的普及也意味着 kernfs 被广泛部署在服务器和数据中心环境中。
社区对 kernfs 的维护主要集中在细微的优化和修复上,其核心架构已无需大的改动。
核心原理与设计 它的核心工作原理是什么? kernfs 的核心设计思想是分离 :将伪文件系统的内部数据结构和层次关系 (由 kernfs 自己管理)与它在用户空间所呈现的VFS 视图 (标准的目录和文件)分离开来。
独立的内部数据结构 :kernfs 定义了自己的核心节点结构 struct kernfs_node
。这个结构体非常轻量,只包含维护层次结构所必需的信息,如父节点、子节点和兄弟节点的指针、节点名称、类型(目录或文件)以及访问权限等。所有 sysfs
或 cgroupfs
的节点在内部都表现为一个 kernfs_node
树。
解耦的锁机制 :kernfs 实现了一个非常简单的全局读写信号量(kernfs_rwsem
)。所有改变 kernfs 树结构的操作(如创建、删除、重命名节点)都需要获取这个信号量的写锁。而所有遍历或查找操作只需要获取读锁。这种“一个锁管所有结构变化”的模式,虽然看起来粗暴,但彻底切断了与 VFS 锁的复杂依赖,从根本上消除了死锁的风险。属性文件的读写操作则不触及这个锁。
按需实例化的VFS对象 :kernfs 节点树独立存在于内核中。只有当用户空间的进程通过 ls
, cat
等命令实际访问到某个 sysfs
路径时,VFS 层才会回调到 kernfs,kernfs 此时才会按需 地为被访问的 kernfs_node
创建一个对应的 inode
和 dentry
,从而在用户面前呈现为一个正常的文件或目录。这些 VFS 对象仅仅是 kernfs 内部节点的“视图”或“代理”。
操作的委托 :当用户对 sysfs
文件进行读写时,VFS 调用会通过实例化的 inode
找到其背后的 kernfs_node
,kernfs 再将操作委托给当初创建这个节点时所注册的回调函数(struct kernfs_ops
),最终调用到设备驱动中相应的 show
/store
函数。
它的主要优势体现在哪些方面?
死锁免疫 :简单而独立的锁模型从根本上解决了与VFS纠缠不清导致的死锁问题,这是其最大的优势。
轻量高效 :使用专用的 kernfs_node
代替通用的 inode
/dentry
来管理内部结构,减少了内存占用。
清晰的抽象和复用 :提供了一套清晰的API(如 kernfs_create_dir
, kernfs_create_file
),将伪文件系统的实现细节封装起来,使得 sysfs
和 cgroupfs
的实现都变得更加简洁,并且逻辑可以复用。
精确的生命周期控制 :由于内部结构独立于VFS缓存,驱动程序可以精确地控制节点的创建和销毁,其生命周期变得确定。
它存在哪些已知的劣势、局限性或在特定场景下的不适用性?
性能瓶颈 :单一的全局写锁在某些极端情况下可能会成为性能瓶颈。例如,如果有大量CPU核心同时、高频率地在 sysfs
中创建和删除文件,它们将会因为竞争这个锁而相互等待。但在绝大多数实际使用场景中,sysfs
的结构变化并不频繁,因此这不是一个普遍问题。
非通用文件系统 :kernfs 是一个高度特化的框架,它只适用于实现层次化的、主要用于展示内核状态或接收简单输入的伪文件系统。它不能用于实现存储持久化数据的常规磁盘文件系统。
使用场景 在哪些具体的业务或技术场景下,它是首选解决方案?请举例说明。 kernfs 作为内核内部框架,是实现特定类型伪文件系统的唯一且标准 的解决方案。
sysfs :这是 kernfs 诞生和存在的首要理由。sysfs
将内核中的设备驱动模型层次化地暴露到用户空间。例如,/sys/class/net/eth0/
目录下的所有文件和子目录,在内核内部都是一棵由 kernfs_node
组成的树,由 kernfs 负责管理。
cgroupfs (v2) :统一的 cgroup 层次结构(通常挂载在 /sys/fs/cgroup
)也是基于 kernfs 实现的。用户通过在这个文件系统中创建目录来创建新的 cgroup,通过读写目录中的文件(如 cpu.max
, memory.high
)来配置资源限制。所有这些文件系统操作都被 kernfs 转换为对内部 cgroup 数据结构的调用。
是否有不推荐使用该技术的场景?为什么? 任何需要实现通用目的 或存储持久化数据 的文件系统,都绝不应该考虑 kernfs。
磁盘文件系统(ext4, xfs, btrfs) :这些文件系统需要管理磁盘块的分配、日志、数据一致性等,功能集与 kernfs 完全不同。
网络文件系统(NFS, CIFS) :这些文件系统需要处理网络协议、缓存、认证等,也与 kernfs 无关。
其他伪文件系统(procfs, debugfs) :procfs
和 debugfs
有其自身的、历史悠久的实现方式,虽然它们在功能上与 sysfs
有相似之处,但它们并没有被迁移到 kernfs 上,主要是因为迁移成本巨大且收益不明显。
对比分析 请将其 与 其他相似技术 进行详细对比。 kernfs 最直接的对比对象就是它所取代的旧的、直接基于VFS的sysfs实现方法 。
特性
kernfs 框架
旧的直接基于VFS的实现
核心数据结构
使用轻量级的 struct kernfs_node
管理内部层次结构。inode
和dentry
仅作为按需创建的视图。
直接使用 VFS 的 struct inode
和 struct dentry
作为核心数据结构。
锁模型
一个独立的全局读写信号量(kernfs_rwsem
)保护所有结构性变更,与 VFS 锁完全解耦。
严重依赖并交织于 VFS 的锁,如 dcache_lock
, inode->i_mutex
等,极易导致死锁。
抽象层次
高 。提供了清晰的API,将伪文件系统逻辑与VFS表现层分离。
低 。伪文件系统的实现逻辑与VFS的实现细节紧密耦合。
内存占用
较低 。kernfs_node
比 inode
+dentry
的组合更小。
较高 。通用VFS数据结构中存在大量未被使用的字段。
生命周期管理
确定 。节点的创建和销毁由驱动程序通过API精确控制。
不确定 。受VFS的dcache缓存策略影响,销毁时机不可预测。
可复用性
高 。作为一个通用框架,被 sysfs
和 cgroupfs
共同使用。
低 。实现与 sysfs
的特定需求绑定,难以复用。
include/linux/kernfs.h kernfs_ns_enabled 测试是否启用了命名空间 1 2 3 4 5 6 7 8 9 10 static inline bool kernfs_ns_enabled (struct kernfs_node *kn) { return kn->flags & KERNFS_NS; }
kernfs_type 获取 kernfs_node 的类型 1 2 3 4 static inline enum kernfs_node_type kernfs_type (struct kernfs_node *kn) { return kn->flags & KERNFS_TYPE_MASK; }
fs/kernfs/kernfs-internal.h kernfs_rcu_name 获取 kernfs_node 的名称 1 2 3 4 static inline const char *kernfs_rcu_name (const struct kernfs_node *kn) { return rcu_dereference_check(kn->name, kernfs_root_is_locked(kn)); }
kernfs_inc_rev 增加 kernfs_node 的版本号 1 2 3 4 static inline void kernfs_inc_rev (struct kernfs_node *parent) { parent->dir.rev++; }
fs/kernfs/mount.c kernfs_initkernfs_init 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 static void __init kernfs_mutex_init (void ) { int count; for (count = 0 ; count < NR_KERNFS_LOCKS; count++) mutex_init(&kernfs_locks->open_file_mutex[count]); } static void __init kernfs_lock_init (void ) { kernfs_locks = kmalloc(sizeof (struct kernfs_global_locks), GFP_KERNEL); WARN_ON(!kernfs_locks); kernfs_mutex_init(); } void __init kernfs_init (void ) { kernfs_node_cache = kmem_cache_create("kernfs_node_cache" , sizeof (struct kernfs_node), 0 , SLAB_PANIC, NULL ); kernfs_iattrs_cache = kmem_cache_create("kernfs_iattrs_cache" , sizeof (struct kernfs_iattrs), 0 , SLAB_PANIC, NULL ); kernfs_lock_init(); }
fs/kernfs/inode.c __kernfs_setattr 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr){ struct kernfs_iattrs *attrs ; unsigned int ia_valid = iattr->ia_valid; attrs = kernfs_iattrs(kn); if (!attrs) return -ENOMEM; if (ia_valid & ATTR_UID) attrs->ia_uid = iattr->ia_uid; if (ia_valid & ATTR_GID) attrs->ia_gid = iattr->ia_gid; if (ia_valid & ATTR_ATIME) attrs->ia_atime = iattr->ia_atime; if (ia_valid & ATTR_MTIME) attrs->ia_mtime = iattr->ia_mtime; if (ia_valid & ATTR_CTIME) attrs->ia_ctime = iattr->ia_ctime; if (ia_valid & ATTR_MODE) kn->mode = iattr->ia_mode; return 0 ; }
fs/kernfs/dir.c __kernfs_new_node 创建一个新的 kernfs_node 节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 static struct kernfs_node *__kernfs_new_node (struct kernfs_root *root , struct kernfs_node *parent , const char *name , umode_t mode , kuid_t uid , kgid_t gid , unsigned flags ) { struct kernfs_node *kn ; u32 id_highbits; int ret; name = kstrdup_const(name, GFP_KERNEL); if (!name) return NULL ; kn = kmem_cache_zalloc(kernfs_node_cache, GFP_KERNEL); if (!kn) goto err_out1; idr_preload(GFP_KERNEL); spin_lock(&kernfs_idr_lock); ret = idr_alloc_cyclic(&root->ino_idr, kn, 1 , 0 , GFP_ATOMIC); if (ret >= 0 && ret < root->last_id_lowbits) root->id_highbits++; id_highbits = root->id_highbits; root->last_id_lowbits = ret; spin_unlock(&kernfs_idr_lock); idr_preload_end(); if (ret < 0 ) goto err_out2; kn->id = (u64)id_highbits << 32 | ret; atomic_set (&kn->count, 1 ); atomic_set (&kn->active, KN_DEACTIVATED_BIAS); RB_CLEAR_NODE(&kn->rb); rcu_assign_pointer(kn->name, name); kn->mode = mode; kn->flags = flags; if (!uid_eq(uid, GLOBAL_ROOT_UID) || !gid_eq(gid, GLOBAL_ROOT_GID)) { struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID, .ia_uid = uid, .ia_gid = gid, }; ret = __kernfs_setattr(kn, &iattr); if (ret < 0 ) goto err_out3; } if (parent) {. ret = security_kernfs_init_security(parent, kn); if (ret) goto err_out3; } return kn; err_out3: spin_lock(&kernfs_idr_lock); idr_remove(&root->ino_idr, (u32)kernfs_ino(kn)); spin_unlock(&kernfs_idr_lock); err_out2: kmem_cache_free(kernfs_node_cache, kn); err_out1: kfree_const(name); return NULL ; }
kernfs_leftmost_descendant 找到指定 kernfs_node 节点的最左后代节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 static struct kernfs_node *kernfs_leftmost_descendant (struct kernfs_node *pos) { struct kernfs_node *last ; while (true ) { struct rb_node *rbn ; last = pos; if (kernfs_type(pos) != KERNFS_DIR) break ; rbn = rb_first(&pos->dir.children); if (!rbn) break ; pos = rb_to_kn(rbn); } return last; }
kernfs_active 检查 kernfs_node 是否处于激活状态 1 2 3 4 5 6 7 8 9 10 static bool __kernfs_active(struct kernfs_node *kn){ return atomic_read (&kn->active) >= 0 ; } static bool kernfs_active (struct kernfs_node *kn) { lockdep_assert_held(&kernfs_root(kn)->kernfs_rwsem); return __kernfs_active(kn); }
kernfs_activate_one 激活一个 kernfs_node 节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 static void kernfs_activate_one (struct kernfs_node *kn) { lockdep_assert_held_write(&kernfs_root(kn)->kernfs_rwsem); kn->flags |= KERNFS_ACTIVATED; if (kernfs_active(kn) || (kn->flags & (KERNFS_HIDDEN | KERNFS_REMOVING))) return ; WARN_ON_ONCE(rcu_access_pointer(kn->__parent) && RB_EMPTY_NODE(&kn->rb)); WARN_ON_ONCE(atomic_read (&kn->active) != KN_DEACTIVATED_BIAS); atomic_sub (KN_DEACTIVATED_BIAS, &kn->active); }
kernfs_next_descendant_post 实现 kernfs_node 的后序遍历(post-order traversal)
后序遍历是一种树结构遍历方式,按照“左子树 -> 右子树 -> 根节点”的顺序访问节点。该函数在 kernfs 文件系统中用于遍历指定节点的所有后代节点,并最终访问根节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 static struct kernfs_node *kernfs_next_descendant_post (struct kernfs_node *pos, struct kernfs_node *root) { struct rb_node *rbn ; lockdep_assert_held_write(&kernfs_root(root)->kernfs_rwsem); if (!pos) return kernfs_leftmost_descendant(root); if (pos == root) return NULL ; rbn = rb_next(&pos->rb); if (rbn) return kernfs_leftmost_descendant(rb_to_kn(rbn)); return kernfs_parent(pos); }
kernfs_activate 显式激活一个 kernfs_node 及其子树节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 void kernfs_activate (struct kernfs_node *kn) { struct kernfs_node *pos ; struct kernfs_root *root = kernfs_root(kn); down_write(&root->kernfs_rwsem); pos = NULL ; while ((pos = kernfs_next_descendant_post(pos, kn))) kernfs_activate_one(pos); up_write(&root->kernfs_rwsem); }
kernfs_create_root 创建和初始化 kernfs 的层级结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 struct kernfs_root *kernfs_create_root (struct kernfs_syscall_ops *scops, unsigned int flags, void *priv) { struct kernfs_root *root ; struct kernfs_node *kn ; root = kzalloc(sizeof (*root), GFP_KERNEL); if (!root) return ERR_PTR(-ENOMEM); idr_init(&root->ino_idr); init_rwsem(&root->kernfs_rwsem); init_rwsem(&root->kernfs_iattr_rwsem); init_rwsem(&root->kernfs_supers_rwsem); INIT_LIST_HEAD(&root->supers); if (sizeof (ino_t ) >= sizeof (u64)) root->id_highbits = 0 ; else root->id_highbits = 1 ; kn = __kernfs_new_node(root, NULL , "" , S_IFDIR | S_IRUGO | S_IXUGO, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, KERNFS_DIR); if (!kn) { idr_destroy(&root->ino_idr); kfree(root); return ERR_PTR(-ENOMEM); } kn->priv = priv; kn->dir.root = root; root->syscall_ops = scops; root->flags = flags; root->kn = kn; init_waitqueue_head(&root->deactivate_waitq); if (!(root->flags & KERNFS_ROOT_CREATE_DEACTIVATED)) kernfs_activate(kn); return root; }
kernfs_new_node 创建一个新的 kernfs_node 节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 struct kernfs_node *kernfs_new_node (struct kernfs_node *parent, const char *name, umode_t mode, kuid_t uid, kgid_t gid, unsigned flags) { struct kernfs_node *kn ; if (parent->mode & S_ISGID) { if (parent->iattr) gid = parent->iattr->ia_gid; if (flags & KERNFS_DIR) mode |= S_ISGID; } kn = __kernfs_new_node(kernfs_root(parent), parent, name, mode, uid, gid, flags); if (kn) { kernfs_get(parent); rcu_assign_pointer(kn->__parent, parent); } return kn; }
kernfs_name_hash 计算命名空间(ns)和名称字符串(name)的哈希值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 static unsigned int kernfs_name_hash (const char *name, const void *ns) { unsigned long hash = init_name_hash(ns); unsigned int len = strlen (name); while (len--) hash = partial_name_hash(*name++, hash); hash = end_name_hash(hash); hash &= 0x7fffffffU ; if (hash < 2 ) hash += 2 ; if (hash >= INT_MAX) hash = INT_MAX - 1 ; return hash; }
kernfs_sd_compare 比较两个 kernfs_node 节点的名称和命名空间 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 static int kernfs_name_compare (unsigned int hash, const char *name, const void *ns, const struct kernfs_node *kn) { if (hash < kn->hash) return -1 ; if (hash > kn->hash) return 1 ; if (ns < kn->ns) return -1 ; if (ns > kn->ns) return 1 ; return strcmp (name, kernfs_rcu_name(kn)); } static int kernfs_sd_compare (const struct kernfs_node *left, const struct kernfs_node *right) { return kernfs_name_compare(left->hash, kernfs_rcu_name(left), left->ns, right); }
kernfs_link_sibling 将一个新的 kernfs_node 节点插入到其父节点的红黑树(rbtree)中 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 static int kernfs_link_sibling (struct kernfs_node *kn) { struct rb_node *parent = NULL ; struct kernfs_node *kn_parent ; struct rb_node **node ; kn_parent = kernfs_parent(kn); node = &kn_parent->dir.children.rb_node; while (*node) { struct kernfs_node *pos ; int result; pos = rb_to_kn(*node); parent = *node; result = kernfs_sd_compare(kn, pos); if (result < 0 ) node = &pos->rb.rb_left; else if (result > 0 ) node = &pos->rb.rb_right; else return -EEXIST; } rb_link_node(&kn->rb, parent, node); rb_insert_color(&kn->rb, &kn_parent->dir.children); down_write(&kernfs_root(kn)->kernfs_iattr_rwsem); if (kernfs_type(kn) == KERNFS_DIR) kn_parent->dir.subdirs++; kernfs_inc_rev(kn_parent); up_write(&kernfs_root(kn)->kernfs_iattr_rwsem); return 0 ; }
kernfs_add_one 添加 kernfs_node 到父节点 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 int kernfs_add_one (struct kernfs_node *kn) { struct kernfs_root *root = kernfs_root(kn); struct kernfs_iattrs *ps_iattr ; struct kernfs_node *parent ; bool has_ns; int ret; down_write(&root->kernfs_rwsem); parent = kernfs_parent(kn); ret = -EINVAL; has_ns = kernfs_ns_enabled(parent); if (WARN(has_ns != (bool )kn->ns, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n" , has_ns ? "required" : "invalid" , kernfs_rcu_name(parent), kernfs_rcu_name(kn))) goto out_unlock; if (kernfs_type(parent) != KERNFS_DIR) goto out_unlock; ret = -ENOENT; if (parent->flags & (KERNFS_REMOVING | KERNFS_EMPTY_DIR)) goto out_unlock; kn->hash = kernfs_name_hash(kernfs_rcu_name(kn), kn->ns); ret = kernfs_link_sibling(kn); if (ret) goto out_unlock; down_write(&root->kernfs_iattr_rwsem); ps_iattr = parent->iattr; if (ps_iattr) { ktime_get_real_ts64(&ps_iattr->ia_ctime); ps_iattr->ia_mtime = ps_iattr->ia_ctime; } up_write(&root->kernfs_iattr_rwsem); up_write(&root->kernfs_rwsem); if (!(kernfs_root(kn)->flags & KERNFS_ROOT_CREATE_DEACTIVATED)) kernfs_activate(kn); return 0 ; out_unlock: up_write(&root->kernfs_rwsem); return ret; }
kernfs_put 减少 kernfs_node 的引用计数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 void kernfs_put (struct kernfs_node *kn) { struct kernfs_node *parent ; struct kernfs_root *root ; if (!kn || !atomic_dec_and_test(&kn->count)) return ; root = kernfs_root(kn); repeat: parent = kernfs_parent(kn); WARN_ONCE(atomic_read (&kn->active) != KN_DEACTIVATED_BIAS, "kernfs_put: %s/%s: released with incorrect active_ref %d\n" , parent ? rcu_dereference(parent->name) : "" , rcu_dereference(kn->name), atomic_read (&kn->active)); if (kernfs_type(kn) == KERNFS_LINK) kernfs_put(kn->symlink.target_kn); spin_lock(&kernfs_idr_lock); idr_remove(&root->ino_idr, (u32)kernfs_ino(kn)); spin_unlock(&kernfs_idr_lock); call_rcu(&kn->rcu, kernfs_free_rcu); kn = parent; if (kn) { if (atomic_dec_and_test(&kn->count)) goto repeat; } else { idr_destroy(&root->ino_idr); kfree_rcu(root, rcu); } } EXPORT_SYMBOL_GPL(kernfs_put);
kernfs_create_dir_ns 创建一个目录 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 struct kernfs_node *kernfs_create_dir_ns (struct kernfs_node *parent, const char *name, umode_t mode, kuid_t uid, kgid_t gid, void *priv, const void *ns) { struct kernfs_node *kn ; int rc; kn = kernfs_new_node(parent, name, mode | S_IFDIR, uid, gid, KERNFS_DIR); if (!kn) return ERR_PTR(-ENOMEM); kn->dir.root = parent->dir.root; kn->ns = ns; kn->priv = priv; rc = kernfs_add_one(kn); if (!rc) return kn; kernfs_put(kn); return ERR_PTR(rc); }
fs/kernfs/file.c __kernfs_create_file: kernfs内部的文件创建函数 该函数是kernfs
(内核文件系统)的内部核心功能,是sysfs
等伪文件系统中所有文件创建操作的最终执行者。它的根本作用是:分配一个新的kernfs_node
(内核文件节点)结构体,用调用者提供的所有元数据(名称、权限、所有者、大小、操作回调函数等)来填充它,然后将这个新创建的节点原子地链接到父目录的层级结构中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 struct kernfs_node *__kernfs_create_file (struct kernfs_node *parent , const char *name , umode_t mode , kuid_t uid , kgid_t gid , loff_t size , const struct kernfs_ops *ops , void *priv , const void *ns , struct lock_class_key *key ) { struct kernfs_node *kn ; unsigned flags; int rc; flags = KERNFS_FILE; kn = kernfs_new_node(parent, name, (mode & S_IALLUGO) | S_IFREG, uid, gid, flags); if (!kn) return ERR_PTR(-ENOMEM); kn->attr.ops = ops; kn->attr.size = size; kn->ns = ns; kn->priv = priv; #ifdef CONFIG_DEBUG_LOCK_ALLOC if (key) { lockdep_init_map(&kn->dep_map, "kn->active" , key, 0 ); kn->flags |= KERNFS_LOCKDEP; } #endif if (ops->seq_show) kn->flags |= KERNFS_HAS_SEQ_SHOW; if (ops->mmap) kn->flags |= KERNFS_HAS_MMAP; if (ops->release) kn->flags |= KERNFS_HAS_RELEASE; rc = kernfs_add_one(kn); if (rc) { kernfs_put(kn); return ERR_PTR(rc); } return kn; }