前言
最近在看华为加速引擎KAE的源码,该库通过sysfs文件将设备驱动的一些信息导出到用户态,在用户态代码中通过访问/sys下的文件,获取或者操作加速引擎,而不是使用ioctl的方式。抽空看看内核文档,了解一下sysfs的系统使用及编程。
sysfs
sysfs是一个导出内核对象的文件系统。sysfs是基于ramfs的一个内存文件系统。为用户态提供了一种访问内核数据和属性的方式。
sysfs始终与kobject的底层结构紧密相关。要深入理解的话,还需要了解kobject。
使用sysfs
内核是否编译了sysfs可以通过是否定义宏CONFIG_SYSFS来确定。
一旦有 kobject 在系统中注册,就会有一个目录在sysfs中被创建。这个目录是作为 kobject 的 parent 下的子目录创建的,以准确的传递内核的对象层次到用户空间。比如我们使用class_create创建了一个class,那么对应/sys/class下就会增加一个文件夹,sysfs中的顶层目录代表着内核对象层次的共同祖先;
kobject 的属性能在文件系统中以普通文件的形式导出,Sysfs 为属性定义了面向文件 I/O 操作的方法,以提供对内核属性的读写。属性应为ASCII 码文本文件,以一个文件只存储一个属性值为宜,也可以存一个数组。
后面主要说一下属性的编程使用,属性文件可以方便内核数据的查看及操作。
属性
驱动子系统定义了设备的属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| struct device_attribute { struct attribute attr; ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf); ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); };
int device_create_file(struct device *, const struct device_attribute *); void device_remove_file(struct device *, const struct device_attribute *);
#define DEVICE_ATTR_RW(_name) \ struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
#define DEVICE_ATTR_RO(_name) \ struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
#define DEVICE_ATTR_WO(_name) \ struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
|
通过宏定义可以很方便的设置一个属性,然后实现对应的xxx_show, xxx_store函数,再通过device_create_file创建属性文件,这个文件默认位于/sys/class/xxx_class/xxx/目录下, xxx位设备名。
相应的我们会创建/dev/xxx字符设备。
代码示例
在struct device下有一个groups成员,可以把属性文件聚合成多个组,创建组对应的目录,目录下生成各个属性的文件。
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
| static ssize_t dev_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct test_dev *testdev = dev_get_drvdata(dev); return sprintf(buf, "dev_state %lu\n", testdev->dev_state); }
static ssize_t dev_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct test_dev *testdev = dev_get_drvdata(dev); unsigned long val = 0;
pr_info("dev_state store buf: %s, count %lu\r\n", buf, count); if (kstrtoul(buf, 0, &val) < 0) return -EINVAL;
testdev->dev_state = val;
return count; }
static DEVICE_ATTR_RW(dev_state);
static struct attribute *test_dev_attrs[] = { &dev_attr_id.attr, &dev_attr_dev_state.attr, &dev_attr_api_ver.attr, NULL, };
static const struct attribute_group test_dev_attr_group = { .name = "attrs", .attrs = test_dev_attrs, };
static const struct attribute_group *test_dev_attr_groups[] = { &test_dev_attr_group, NULL };
...
static int test_create_chrdev(struct test_dev *testdev) { int ret;
ret = idr_alloc(&test_idr, testdev, 0, 0, GFP_KERNEL); if (ret < 0) return ret;
cdev_init(&testdev->cdev, &testdev_fops); testdev->dev_id = ret; testdev->cdev.owner = THIS_MODULE;
device_initialize(&testdev->dev); testdev->dev.devt = MKDEV(MAJOR(test_devt), testdev->dev_id); testdev->dev.class = test_class; testdev->dev.groups = test_dev_attr_groups; testdev->dev.release = test_dev_release; dev_set_name(&testdev->dev, "%s", testdev->name); dev_set_drvdata(&testdev->dev, testdev); ret = cdev_device_add(&testdev->cdev, &testdev->dev); if (ret) goto err_with_idr;
dev_dbg(&testdev->dev, "create testdev minior=%d\n", testdev->dev_id); return 0;
err_with_idr: idr_remove(&test_idr, testdev->dev_id); return ret; }
root@Ubuntu:# tree /sys/class/test/testdev/ /sys/class/test/testdev/ |-- attrs // 属性组 | |-- api_ver | |-- dev_state // dev_state属性文件 | `-- id |-- dev |-- power | |-- async | |-- autosuspend_delay_ms | |-- control | |-- runtime_active_kids | |-- runtime_active_time | |-- runtime_enabled | |-- runtime_status | |-- runtime_suspended_time | `-- runtime_usage |-- subsystem -> ../../../../class/test `-- uevent
root@Ubuntu:/sys/class/test/testdev# cat attrs/dev_state dev_state 0 root@Ubuntu:/sys/class/test/testdev# echo 10 > attrs/dev_state root@Ubuntu:/sys/class/test/testdev# [ 6793.317838] dev_state store buf: 10 , count 3
root@Ubuntu:/sys/class/test/testdev# cat attrs/dev_state dev_state 10 root@Ubuntu:/sys/class/test/testdev#
|
完整代码见链接文件:
https://gitee.com/fishmwei/blog_code/blob/master/linux-kernel/chrdev/chrdev.c
更多
又是一个充实的一天,早上八点起床就在刷系分的在线视频,上次写了个论文不及格,好好构思准备再写一遍。
下午休息,带娃去看个电影,回来后倒头睡一觉。然后开始看sysfs,写个blog。
清明节假期给自己的安排也是满满的,太多知识空白需要填补了,循序渐进吧!
相信有付出就会有收获!

行动,才不会被动!
欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。

博客地址: https://fishmwei.github.io
掘金主页: https://juejin.cn/user/2084329776486919