一、什么是属性
在 Linux 内核中,sysfs 文件系统通过"属性(attribute)"的概念,让内核和用户程序能方便地交换信息。具体来说:
属性是什么? 它就是内核对象(比如设备、驱动)的某个可读写的数据点。例如:
- 设备的名称
- 驱动的内部参数
- 开关状态等
为什么需要属性? 内核对象在 sysfs 里对应一个目录,而目录里的每个文件就是一个属性。用户程序通过读写这些文件,就能直接查看或修改内核里的数据。比如:
- 用户想调整某个硬件的亮度,只需写入对应的 sysfs 文件
- 程序可以读取设备状态,无需修改内核代码
核心作用 属性就像内核和用户程序之间的"开关"和"显示器"。开发者把需要暴露给用户的内核变量,通过属性变成 sysfs 里的普通文件,用户直接操作这些文件就能控制内核行为。
简单来说
属性 = 内核数据的"可视化接口",让用户无需进入内核就能自由读写关键参数。
二、attribute 结构体
Linux 内核中,attribute 分为普通的 attribute 和二进制 attribute,位于:include\linux\sysfs.h


c
struct attribute {
const char *name;
umode_t mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
bool ignore_lockdep:1;
struct lock_class_key *key;
struct lock_class_key skey;
#endif
};1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9

三、实验
源代码下载
git clone git@gitee.com:yangxuesong314/linux-driver.git (若之前已git拉取代码可以忽略)
代码位于:linux-driver/02.Linux设备模型/04.属性文件
c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/configfs.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
// 自定义的kobject结构体,包含一个kobject对象和两个整型值
struct mykobj
{
struct kobject kobj;
int value1;
int value2;
};
// 定义了mykobj结构体指针变量mykobject01
struct mykobj *mykobject01;
// 自定义的kobject释放函数
static void dynamic_kobj_release(struct kobject *kobj)
{
struct mykobj *mykobject01 = container_of(kobj, struct mykobj, kobj);
printk("kobject: (%p): %s\n", kobj, __func__);
kfree(mykobject01);
}
// 自定义的attribute对象value1和value2
struct attribute value1 = {
.name = "value1",
.mode = 0666,
};
struct attribute value2 = {
.name = "value2",
.mode = 0666,
};
// 将attribute对象放入数组中
struct attribute *myattr[] = {
&value1,
&value2,
NULL,
};
// 自定义的show函数,用于读取属性值
ssize_t myshow(struct kobject *kobj, struct attribute *attr, char *buf)
{
ssize_t count;
struct mykobj *mykobject01 = container_of(kobj, struct mykobj, kobj);
if (strcmp(attr->name, "value1") == 0)
{
count = sprintf(buf, "%d\n", mykobject01->value1);
}
else if (strcmp(attr->name, "value2") == 0)
{
count = sprintf(buf, "%d\n", mykobject01->value2);
}
else
{
count = 0;
}
return count;
}
// 自定义的store函数,用于写入属性值
ssize_t mystore(struct kobject *kobj, struct attribute *attr, const char *buf, size_t size)
{
struct mykobj *mykobject01 = container_of(kobj, struct mykobj, kobj);
if (strcmp(attr->name, "value1") == 0)
{
sscanf(buf, "%d\n", &mykobject01->value1);
}
else if (strcmp(attr->name, "value2") == 0)
{
sscanf(buf, "%d\n", &mykobject01->value2);
}
return size;
}
// 自定义的sysfs_ops结构体,包含show和store函数指针
struct sysfs_ops myops = {
.show = myshow,
.store = mystore,
};
// 自定义的kobj_type结构体,包含释放函数、默认属性和sysfs_ops
static struct kobj_type mytype = {
.release = dynamic_kobj_release,
.default_attrs = myattr,
.sysfs_ops = &myops,
};
// 模块的初始化函数
static int mykobj_init(void)
{
int ret;
// 分配并初始化mykobject01
mykobject01 = kzalloc(sizeof(struct mykobj), GFP_KERNEL);
mykobject01->value1 = 1;
mykobject01->value2 = 1;
// 初始化并添加mykobject01到内核中,名为"mykobject01"
ret = kobject_init_and_add(&mykobject01->kobj, &mytype, NULL, "%s", "mykobject01");
return 0;
}
// 模块的退出函数
static void mykobj_exit(void)
{
// 释放mykobject01
kobject_put(&mykobject01->kobj);
}
module_init(mykobj_init); // 指定模块的初始化函数
module_exit(mykobj_exit); // 指定模块的退出函数
MODULE_LICENSE("GPL"); // 模块使用的许可证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
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
驱动进行加载 insmod attr.ko
bash
insmod attr.ko1
然后进入 cd /sys/ 目录下, 可以看到创建生成的 myobject01
bash
cd /sys/
ls1
2
2
接着进入到 cd myobject01 目录下, 可以看到创建的属性文件 value1 和 value2。