Linux SysFs文件系统分析2(基于Linux6.6)---sysfs相关结构体介绍
一、相关结构体说明
从结构体之间的联系,建立对sysfs文件系统实现框架的感性认识,以便我们更好的理解sysfs文件系统。先来看下这些结构体的关系,如下所示主要包括kset、kobject、kref、sysf_dirent、kobj_type、sys_ops、sysfs_elem_dir、sysfs_elem_symlinks、sysfs_elem_attr、sysfs_elem_bin_attr结构体。主要包括sysfs与设备模型关联的结构体、sysfs文件系统目录及文件建立相关、sysfs文件操作相关的结构体等几大部分。
如上图所示,一个kset结构体变量包括一类kobject的集合,而针对一个kset而言,且也是一个目录,因此其也有相应的kobject,而关于kset的引用计数,直接使用kobject->kref实现引用计数的功能。而针对一个kobject而言,其也有相应的方法,即kobj_type,该方法中包括kobject的释放以及show/store接口,还包括默认的属性参数等。
二、sysfs与设备模型关联的结构体
与设备模型相关的结构体主要为kset、kobject、kref、sysfs_dirent等,其中kobject表示内核对象,定义了内核对象后,则针对每一个设备类型、驱动类型、总线类型等,均可用一个内核对象表示,在sysfs中一个kobject即代表一个目录,针对sysfs的文件,是没有对应的kobject,kobject仅表示目录。而在设备模型中,针对设备、驱动以及总线而言,均会有对应的内核对象,而针对总线而言,其还会包含kset变量,并通过该kset变量的list成员变量,链接bus下所有具体已注册总线的内核对象(kobject)。通过这几个变量,就实现了与设备驱动模型的关联。
这些结构体的关联如下:
struct kobject定义说明
kobject的定义,主要包括对象命令、引用计数、该kobject所属的kset等。
include/linux/kobject.h
struct kobject {
const char *name;
struct list_head entry;
struct kobject *parent;
struct kset *kset;
const struct kobj_type *ktype;
struct kernfs_node *sd; /* sysfs directory entry */
struct kref kref;
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
};
struct kset定义说明
主要包括属于该kset的kobject的链表头、该kset对应的内核对象、kset对应的事件处理接口等
include/linux/kobject.h
struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
} __randomize_layout;
struct kref定义
该结构体就是一个原子变量,用于kobject的引用计数。
include/linux/kref.h
struct kref {
refcount_t refcount;
};
struct kobj_type定义
该结构体主要是kobject对应的释放接口以及属性操作接口(属性操作接口,主要用于该对象下文件的读写操作)
include/linux/kobject.h
struct kobj_type {
void (*release)(struct kobject *kobj);
const struct sysfs_ops *sysfs_ops;
const struct attribute_group **default_groups;
const struct kobj_ns_type_operations *(*child_ns_type)(const struct kobject *kobj);
const void *(*namespace)(const struct kobject *kobj);
void (*get_ownership)(const struct kobject *kobj, kuid_t *uid, kgid_t *gid);
};
struct sysfs_ops定义
include/linux/sysfs.h
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *, char *);
ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t);
};
该结构体主要包括show、store接口指针,其中show、store主要用于属性对应文件的读与写接口,这两个接口需要输入的参数包括kobject、attribute结构体对应的变量。
struct attribute结构体说明
针对上述的结构体变量attribute,系统中各子模块可通过创建包含该结构体变量attribute的私有变量,从而实现针对具体属性的show/store接口的调用。
以struct bus_attribute 结构体变量为例进行简要说明。针对bus目录而言,在进行总线的注册时,其kobject对象的struct kobj_type变量定义为bus_ktype,其中定义了bus目录对应的show/store接口为bus_attr_show/bus_attr_store,而bus对应的属性结构体为bus_attribute,包含了struct attribute成员变量、show/store接口指针(这个show/store接口即为具体文件的处理接口),当在bus目录下创建文件时,则会创建bus_attribute结构体的变量,而在bus_attr_show/bus_attr_store接口中会根据传入的attribute结构体变量,从而获取bus_attribute结构体类型的变量,然后就调用bus_attribute结构体类型变量的show/store接口,从而实现对具体文件的show/store操作。
include/linux/device/bus.h
struct bus_attribute {
struct attribute attr;
ssize_t (*show)(const struct bus_type *bus, char *buf);
ssize_t (*store)(const struct bus_type *bus, const char *buf, size_t count);
};
三、sysfs文件系统目录及文件建立相关
在 Linux 6.x 版本中,sysfs_dirent
结构体确实已经被移除,并且通过重构的方式改进了 sysfs
文件系统的实现。要理解这一点,首先需要了解 Linux 内核在处理 sysfs
时的变动。
1. sysfs_dirent
移除的背景
在早期的 Linux 内核中,sysfs_dirent
结构体是 sysfs
文件系统的一个核心数据结构,它代表 sysfs
文件系统中的文件和目录。这个结构体与内核对象(kobject
)相关联,负责管理文件的操作(如读写)以及维护文件层次结构。
然而,随着内核的发展,特别是内核文件系统架构的不断改进,内核对 sysfs
的实现方式进行了简化和优化。为了减少复杂性和提高效率,sysfs_dirent
结构体被移除,取而代之的是对 dentry
结构体和 kobject
的更紧密结合和改进。
2. sysfs
文件系统在 Linux 6.x 的实现
在 Linux 6.x 中,sysfs
的实现更加直接与 VFS(虚拟文件系统)和 kobject
结合,减少了对专门的 sysfs_dirent
结构体的依赖。其基本思路是利用 dentry
和 kobject
来进行管理,并通过对内核对象的注册与暴露来实现对 sysfs
的支持。
核心概念:
-
dentry
(目录项):dentry
是虚拟文件系统(VFS)中用于表示目录项的结构体。在 Linux 内核中,dentry
是文件路径解析、缓存和访问的核心结构。sysfs
文件系统的目录项(如文件、目录等)通过dentry
来管理,而不再依赖专门的sysfs_dirent
。 -
kobject
(内核对象):kobject
是 Linux 内核中一个通用的对象模型,它提供了内核对象与用户空间的交互方式,包括sysfs
文件的暴露。每个sysfs
文件都与一个kobject
关联,表示该文件对应的内核对象。 -
sysfs
的整合: 在 Linux 6.x 中,sysfs
文件系统的目录结构依然存在,但它是通过kobject
的生命周期管理和dentry
的高效查找机制来实现的。每个kobject
都有一个关联的dentry
,并通过sysfs
文件系统接口暴露其属性。
主要改动:
-
sysfs
通过kobject
和dentry
配合: 在新的实现中,kobject
负责将内核对象暴露给sysfs
,而dentry
负责实际的目录项操作。sysfs
文件不再通过专门的sysfs_dirent
来表示,而是通过dentry
的层次结构与内核对象(kobject
)进行关联。 -
简化操作: 由于
dentry
已经是文件系统中目录项的标准表示方式,因此无需再引入额外的sysfs_dirent
数据结构,这大大简化了内核代码的复杂性,同时也提升了文件系统操作的效率。 -
减少冗余数据结构:
sysfs_dirent
的移除减少了不必要的结构体,减少了内存的占用,并使得内核中sysfs
文件的管理更加高效。
3. 新的 sysfs
管理方式
在 Linux 6.x 中,sysfs
的管理更加直接,主要依靠 kobject
和 dentry
来完成以下任务:
-
内核对象的创建和销毁: 通过
kobject
来创建、销毁内核对象,并通过相应的kobject
接口管理对象生命周期。每个内核对象通常会在/sys
目录下有对应的文件和目录。 -
文件的暴露: 当一个
kobject
被注册到sysfs
时,相应的文件将通过dentry
和kobject
的关联被创建在/sys
目录中。每个文件的内容通过sysfs_ops
中定义的show
和store
方法来处理。 -
目录项层次结构: 使用
dentry
实现sysfs
的目录层次结构。在 Linux 6.x 中,每个目录项都是一个dentry
对象,它代表文件系统中的一个文件或目录。目录项的创建、删除和层次结构的管理通过dentry
来完成,而不再需要额外的sysfs_dirent
。
4. 代码示例
在 Linux 6.x 中,sysfs
文件的创建通常如下:
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/module.h>
static struct kobject *example_kobj;
static ssize_t example_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "Hello, sysfs!\n");
}
static struct kobj_attribute example_attribute = __ATTR(example_file, 0444, example_show, NULL);
static int __init sysfs_example_init(void)
{
int retval;
example_kobj = kobject_create_and_add("example", kernel_kobj);
if (!example_kobj)
return -ENOMEM;
retval = sysfs_create_file(example_kobj, &example_attribute.attr);
if (retval)
kobject_put(example_kobj);
return retval;
}
static void __exit sysfs_example_exit(void)
{
kobject_put(example_kobj);
}
module_init(sysfs_example_init);
module_exit(sysfs_example_exit);
MODULE_LICENSE("GPL");
在这个示例中,内核模块通过 kobject_create_and_add
创建了一个新的内核对象,并通过 sysfs_create_file
创建了一个新的 sysfs
文件。内核对象的属性通过 kobj_attribute
和 show
函数来暴露,而文件本身由 dentry
管理。