07、创建多个属性文件 *
我们创建了一个属性文件, 但是在情况中, 我们可能需要创建 N 个属性文件。
一、sysfs_create_group 函数
sysfs_create_group
函数的作用是:在系统文件系统(sysfs)中创建一个文件组,把相关的配置或状态文件集中到一个目录下,方便统一管理和查看。
目录:/include/linux/sysfs.h
C
int __must_check sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp);
1
2
2
这个函数需要两个参数:
第一个参数kobj:指向你要绑定属性组的内核对象的指针。 第二个参数grp:指向属性组的指针,这个结构体里包含了要创建的所有属性文件列表。
attribute_group
结构体的作用是: 它是一个容器,里面列出了所有要生成的属性文件(比如sysfs中的文件),方便一次性将这些属性关联到指定的内核对象上。
C
/**
* struct attribute_group - data structure used to declare an attribute group.
* @name: Optional: Attribute group name
* If specified, the attribute group will be created in
* a new subdirectory with this name.
* @is_visible: Optional: Function to return permissions associated with an
* attribute of the group. Will be called repeatedly for each
* non-binary attribute in the group. Only read/write
* permissions as well as SYSFS_PREALLOC are accepted. Must
* return 0 if an attribute is not visible. The returned value
* will replace static permissions defined in struct attribute.
* @is_bin_visible:
* Optional: Function to return permissions associated with a
* binary attribute of the group. Will be called repeatedly
* for each binary attribute in the group. Only read/write
* permissions as well as SYSFS_PREALLOC are accepted. Must
* return 0 if a binary attribute is not visible. The returned
* value will replace static permissions defined in
* struct bin_attribute.
* @attrs: Pointer to NULL terminated list of attributes.
* @bin_attrs: Pointer to NULL terminated list of binary attributes.
* Either attrs or bin_attrs or both must be provided.
*/
struct attribute_group {
const char *name;
umode_t (*is_visible)(struct kobject *,
struct attribute *, int);
umode_t (*is_bin_visible)(struct kobject *,
struct bin_attribute *, int);
struct attribute **attrs;
struct bin_attribute **bin_attrs;
};
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
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
这个结构体包含三个主要部分:
- 名称(name):组的名字,用来创建对应的 sysfs 文件夹。
- 属性列表(attrs):指向一组属性文件的位置列表。
- 可见性检查(is_visible):可选的判断函数,用来决定是否显示每个属性文件。如果没设置这个函数(设为 NULL),所有属性文件都会默认显示。
其中 attrs 详细说明:
属性文件数组就是一串指向属性结构体(struct attribute)的指针列表,最后一个位置放NULL表示结束。每个结构体对应一个属性文件。
要将某个属性对象(比如struct kobject_attribute)的.attr成员加入数组,只需要:
- 用&符号获取该成员的内存地址
- 把这个地址存进数组里
这样数组就按顺序存放了所有属性的指针,最后用NULL标记结尾。
案例:
下面展示使用 sysfs_create_group 创建一个组并添加属性文件
C++
struct attribute *attrs[] = {
&attr1.attr,
&attr2.attr,
NULL,
};
const struct attribute_group attr_group = {
.name = "my_group",
.attrs = attrs,
};
sysfs_create_group(kobj, &attr_group);
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
在上述示例中, 我们创建了一个名叫“my_group” 的组, 并将属性文件 attr1 和 attr2 添加到该组中, 然后使用 sys_create_group 将该组添加到指定的 kobject kobj 中。 接下来我们开始做实验。
二、实验
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