41 sysfs 文件系统

发布时间:2023年12月24日

前言

在 linux 中常见的文件系统 有很多, 如下?

基于磁盘的文件系统, ext2, ext3, ext4, xfs, btrfs, jfs, ntfs?
内存文件系统, procfs, sysfs, tmpfs, squashfs, debugfs?
闪存文件系统, ubifs, jffs2, yaffs ?

文件系统这一套体系在 linux 有一层 vfs 抽象, 用户程序不用关心 底层文件系统的具体实现, 用户只用操作 open/read/write/ioctl/close 的相关 系统调用, 这一层系统调用 会操作 vfs 来处理响应的业务?

vfs 会有上面各种文件系统对应的 读写 相关服务, 进而 将操作下沉到 具体的文件系统?

我们这里 来看一下 sysfs 文件系统, 这是一个 基于 内核内存的文件系统, 读写的都是 kobject 的相关信息项, 由内核代码来组织的树形结构?
?

如何分配 inode ?

我们这里的操作是?“cat /sys/module/i8042/parameters/debug”, 访问之前?对应的 inode 还不存在?

sysfs 的?inode 也是懒加载创建的,?当你访问它的时候,才会创建对应的 inode, 这时候?才会在 vfs?中有对应的角色?

sysfs 对应的?iop->lookup 为?kernfs_iop_lookup, 实现如下,?在父级 kernfs_node 下面查询当前文件的?kernfs_node, 然后根据?当前?kernfs_node 去创建,?初始化当前文件对应的?inode

另外就是 kernfs_node 本身会有一套树形结构,?来维护?sysfs?下面各个文件的关系,?以便于这里的?lookup inode 的实现?

kernfs_get_inode 中新建并初始化?inode, ino 取自?kernfs_node 中早就暂存了一个?i_no

iget_locked 中从?super_block 中分配?inode, 并初始化?ino,?将当前?inode?放到了?inode_hashtable 中, 下一次根据?获取直接拿到的是?已有的 inode

kernfs_init_inode 是初始化 inode 的各个函数?

kenfs_init_node 中初始化了?inode->private/i_ops/i_fops 等等,?f_ops 用于后面读写?当前文件的操作?

/sys/xx 是在哪里创建的???

从上面可以看到,?系统首先维护的是?kernfs_node 的树形结构

然后?真正的文件的获取是在访问给定的文件的时候创建的,?比如?cat “/sys/module/i8042/parameters/debug”, “ls /sys/module/i8042/”

上面的例子是一个 “cat /sys/module/i8042/parameters/debug” 访问到具体的文件的例子, 这里我们来测试一个?访问目录,?然后?懒加载创建目录下面的所有的 文件的 inode 的过程?

在新建?inode 的地方打上断点,?可以看到的是?外层在迭代 “/sys/devices/breakpoint” 目录下面的所有文件[基于?kernfs_node], 然后通过?lstat 来访问给定的文件,?进而实现主动触发了?文件夹下面所有的文件的访问

然后具体的根据?kernfs_node 迭代文件夹下面所有目录的地方是在这里,?dir_emit 会访问给定的文件,?访问上面的?lstat?函数?

接下来问题?便是 kernfs_node 的这棵树的初始化的流程了,?内核是先构造了这棵树,?然后用户/内核 访问 的时候,?再根据?kernfs_node 创建了对应的?inode

kernfs_node树?的初始化是在 内核初始化的阶段,?创建了相关的?kobject, 就会注册?kernfs_node, 挂在?kernfs_node 树上面?

如下是注册?sysfs_root, 也就是?“/sys”

如下是注册 “/sys” 下面的?“fs”, 创建?kobject 的时候,?传入?parent?为?NULL, 默认?parent 是?sysfs_root

又比如我们这里的 i8042驱动?下面的 debug 参数?

此参数是属于?i8042驱动?下面的 参数组 下面的 debug?参数

因此这里在?i8042节点 下面创建了?parameters 节点,?然后作为?debug 参数节点的父节点

然后是循环?i8042 的参数列表,?注册对应的参数在?i8042节点?下面的 parameters节点?上面

创建?kernfs_node 的时候, 传入的?ops 为?sysfs_file_kfops_rw

kn->attr->ops 为?sysfs_file_kfops_rw, kn->priv 为当前 attr?

如何分配 存储的空间?

大多数的?sysfs 的?”文件” 是不单独占用存储空间的?

是通过相应的读写函数?去操作对应的 kobject

如何 读写数据?

读取的链路如下?

file->f_ops 为?inode 的?f_ops, 为kernfs_file_ops[初始化是在?kernfs_init_inode], 其中?read?为?kernfs_fop_read

下一层?seq_read 的?m->op 来自于封装?file?对象的时候,?初始化的?seq_file, 默认的?ops 为?kernfs_seq_ops

再下一层 of->kn 为?kernfs_node, kernfs_node->attr.ops 为上面构造?kernfs_node 的时候传入的?ops?为?sysfs_file_kfops_rw, 其中?seq_show 为?sysfs_kf_seq_show

接下来就是根据 kernfs_node 中存放的?attribute 的信息,?定位到?module_attribute, param_attribute, kernel_attribute, 然后通过?kernel_attribute 的?ops?来读写?kernel_attribute

如何根据?path?获取到上下文的数据?

在 kernfs_fop_open 的时候,?根据?inode, kernfs_node 以及上下文?构造?file?

kernfs_fop_open 中的?seq_open 中构造了 seq_file, ops 初始化为上下文传入的?kernfs_seq_ops,?构造之后的?file->private_data 为?新建的 seq_file

在外层的 kernfs_fop_open 封装?file, 新建?kernfs_open_file 并初始化, 作为了?((seq_file)file->private_data)->private_data

seq_open 中新建了?seq_file, 作为?file->private_data

kernfs_fop_open 中?kernfs_node 是来自于?file->f_path.dentry->d_fsdata, 那么这个?d_fsdata 是在哪里填充进去的呢??

来自于根据?path 向下遍历的时候,?i_op->lookup 中在?dentry?中封装了?d_fsdata 为?kernfs_node

完?

文章来源:https://blog.csdn.net/u011039332/article/details/128698174
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。