本文主要呈现一个使用sysfs编写代码的样例
准备属性和回调接口
我们知道,呈现在sysfs中的文件名其实都是内核中ktype的属性值,而从用户空间对这些属性值进行读写其实就是回调了我们在ktype结构中注册读写函数,所以,这里我们准备了两个函数,值得注意的是,内核会将用户空间的buf转换到内核空间并当作参数传入回调函数,所以我们就不用再进行这个转换。这里由于没有实际的属性,我就只是打印一下信息,实际使用的时候这两个函数要对内核中的真实属性进行读写。
static char kbuf[1024] = {0}; static ssize_t my_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { char info[]="my_show is called\n"; return scnprintf(buf,sizeof(info),info); } static ssize_t my_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { printk("%s is called\n",__func__); strncpy(kbuf,buf,count); printk("user_buf:%s,count:%ld|after copy,kbuf:%s\n",buf,count,kbuf); return count; }
构造kobj_attribute
准备好了原材料,第一道工序就是将属性和回调接口封装到一个kobj_attribute结构对象中,当然对这个属性的读写权限等信息也应该进行封装,我们来回顾一下这个结构
//linux/kobject.h 139 struct kobj_attribute { 140 struct attribute attr; 141 ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, 142 char *buf); 143 ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, 144 const char *buf, size_t count); 145 }; //linux/sysfs.h 29 struct attribute { 30 const char *name; 31 umode_t mode; //权限 32 ... 37 };
当然,内核也给我们提供了相应的宏来快速的构造这个结构
//linux/sysfs.h 100 #define __ATTR(_name, _mode, _show, _store) { \ 101 .attr = {.name = __stringify(_name), \ 102 .mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \ 103 .show = _show, \ 104 .store = _store, \ 105 }
使用了这个宏,我们就可以快速的构造我们的kobj_attribute结构
//show是name,就是sys中的文件名 static struct kobj_attribute my_sysfs_read =__ATTR(show, S_IRUSR, my_show, NULL); static struct kobj_attribute my_sysfs_write =__ATTR(write, S_IWUSR, NULL,my_store);
构造attribute数组
一个kobject网完对应多个attribute,此时就需要将这些attribute封装成一个结构体数组,注意这个数组最后一个元素一定要是NULL。
static struct attribute *my_sysfs_attr[] = { &my_sysfs_read.attr, &my_sysfs_write.attr, NULL, };
如果这些属性直接放到kobject的目录中,我们可以直接使用sysfs_create_file(),但通常情况下,我们更多的将上述的struct attribute进行进一步的封装,并使用sysfs_create_group()来创建一个名为attribute_group.name的、包含struct attribute中的属性目录,这种方式更加的灵活,因为如果我们不指定目录的名字,那么效果个sysfs_create_file()是一样的。
static struct attribute_group my_sysfs_attr_group = { .name = "sub_my_attr", //不写这个成员就不会创建子文件夹 .attrs = my_sysfs_attr, }; struct kobject *my_kobj = NULL;
int mysys_init(void) { ... my_kobj = kobject_create_and_add("my_sysfs", NULL); sysfs_create_group(my_kobj, &my_sysfs_attr_group); ... } void mysys_exit(void) { ... sysfs_remove_group(my_kobj, &my_sysfs_attr_group); kobject_put(my_kobj); }
输出

将上述的程序编译成模块,我们就可以观察到下面的输出结果。
感谢博主,帮助很大!还想请教一下:sysfs已经存在了一些文件和目录,要如何把kobject添加已有的路径中呢
可以找到已有路径的 kobject 对象, 然后让新的 kobject.parent 指向该已有路径的 kobject