前言
最近在看华为加速引擎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 码文本文件,以一个文件只存储一个属性值为宜,也可以存一个数组。
后面主要说一下属性的编程使用,属性文件可以方便内核数据的查看及操作。
属性
驱动子系统定义了设备的属性:
c
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成员,可以把属性文件聚合成多个组,创建组对应的目录,目录下生成各个属性的文件。
c
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;
// device_create_file(&testdev->dev, &dev_attr_dev_state);
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#
完整代码见链接文件:
更多
又是一个充实的一天,早上八点起床就在刷系分的在线视频,上次写了个论文不及格,好好构思准备再写一遍。
下午休息,带娃去看个电影,回来后倒头睡一觉。然后开始看sysfs,写个blog。
清明节假期给自己的安排也是满满的,太多知识空白需要填补了,循序渐进吧!
相信有付出就会有收获!

行动,才不会被动!
欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。
博客地址: fishmwei.github.io
掘金主页: juejin.cn/user/208432...