sysfs属性文件使用

前言

最近在看华为加速引擎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#

完整代码见链接文件:

gitee.com/fishmwei/bl...

更多

又是一个充实的一天,早上八点起床就在刷系分的在线视频,上次写了个论文不及格,好好构思准备再写一遍。

下午休息,带娃去看个电影,回来后倒头睡一觉。然后开始看sysfs,写个blog。

清明节假期给自己的安排也是满满的,太多知识空白需要填补了,循序渐进吧!

相信有付出就会有收获!


行动,才不会被动!

欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。

博客地址: fishmwei.github.io

掘金主页: juejin.cn/user/208432...


相关推荐
wuxuanok1 小时前
Web后端开发-分层解耦
java·笔记·后端·学习
31535669131 小时前
ClipReader:一个剪贴板英语单词阅读器
前端·后端
ladymorgana1 小时前
【Spring Boot】HikariCP 连接池 YAML 配置详解
spring boot·后端·mysql·连接池·hikaricp
neoooo1 小时前
别慌,Java只有值传递——一次搞懂“为啥我改了它还不变”!
java·后端·spring
用户7785371836962 小时前
一力破万法:从0实现一个http代理池
后端·爬虫
拖孩2 小时前
微信群太多,管理麻烦?那试试接入AI助手吧~
前端·后端·微信
Humbunklung2 小时前
Rust枚举:让数据类型告别单调乏味
开发语言·后端·rust
radient2 小时前
Golang-GMP 万字洗髓经
后端·架构
蓝倾2 小时前
如何使用API接口实现淘宝商品上下架监控?
前端·后端·api
舂春儿2 小时前
如何快速统计项目代码行数
前端·后端