The Linux Kernel Module Programming Guide
- Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, Jim Huang
- 译 断水客(WaterCutter)
- 源 LKMPG
8 sysfs: 与模块交互
sysfs
允许用户通过读写模块中的变量实现与内核模块的交互。这个特性在调试时比较有用,有时也用作脚本接口(interface for scripts)。可以用如下命令在系统中的 /sys 目录下找到 sysfs
目录。
ls -l /sys
kobjects
的属性(attributes)可以以文件系统中常规文件的形式导出。sysfs
将文件 I/O 操作转发到为属性定义的方法,从而提供读取和写入内核属性(可以理解为上面提到的“模块中的变量”)的方法。
属性定义形如(definition in simply):
struct attribute {
char *name;
struct module *owner;
umode_t mode;
};
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);
例如,驱动模型将 struct device_attribute
定义为:
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 *);
为了读写属性,声明变量的同时也应该指定对应的 show()
和 store()
方法。include/linux/sysfs.h 中提供了一些宏定义 ( __ATTR
, __ATTR_RO
, __ATTR_WO
, etc.) , 以便提高代码的简洁性和可读性 (making code more concise and readable)。
下面给出了一个hello world模块的示例,其中包括创建可通过sysfs访问的变量。
/*
* hello-sysfs.c sysfs example
*/
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/sysfs.h>
static struct kobject *mymodule;
/* the variable you want to be able to change */
static int myvariable = 0;
static ssize_t myvariable_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", myvariable);
}
static ssize_t myvariable_store(struct kobject *kobj,
struct kobj_attribute *attr, char *buf,
size_t count)
{
sscanf(buf, "%du", &myvariable);
return count;
}
static struct kobj_attribute myvariable_attribute =
__ATTR(myvariable, 0660, myvariable_show, (void *)myvariable_store);
static int __init mymodule_init(void)
{
int error = 0;
pr_info("mymodule: initialised\n");
mymodule = kobject_create_and_add("mymodule", kernel_kobj);
if (!mymodule)
return -ENOMEM;
error = sysfs_create_file(mymodule, &myvariable_attribute.attr);
if (error) {
pr_info("failed to create the myvariable file "
"in /sys/kernel/mymodule\n");
}
return error;
}
static void __exit mymodule_exit(void)
{
pr_info("mymodule: Exit success\n");
kobject_put(mymodule);
}
module_init(mymodule_init);
module_exit(mymodule_exit);
MODULE_LICENSE("GPL");
Make and install the module:
make
sudo insmod hello-sysfs.ko
Check that it exists:
sudo lsmod | grep hello_sysfs
What is the current value of myvariable ?
cat /sys/kernel/mymodule/myvariable
Set the value of myvariable and check that it changed.
echo "32" > /sys/kernel/mymodule/myvariable
cat /sys/kernel/mymodule/myvariable
Finally, remove the test module:
sudo rmmod hello_sysfs
在上面的例子中,我们使用一个简单的 kobject 在 sysfs
下创建了一个目录并与其属性通信。从 Linux v2.6.0 开始,kobject 结构就出现了。它最初旨在作为统一内核代码的简单方法,用于管理引用计数的对象。经过一些任务蠕变,它现在是大部分设备模型与其 sysfs 接口之间的中间件(glue)。
Documentation/driver-api/driver-model/driver.rst and https://lwn.net/Articles/51437/. 有关于 kobject 和 sysfs
的更多信息。