🥇今日学习目标:如何在Linux系统中使用sysfs
🤵♂️ 创作者:JamesBin
⏰预计时间:10分钟
🎉个人主页:嵌入式悦翔园个人主页
🍁专栏介绍:Linux驱动开发100问
一、前言
sysfs是一种文件系统,它允许用户和内核使用文件的方式来交互。sysfs通常用于与设备驱动程序交互,以便用户可以更改驱动程序的行为或访问有关驱动程序状态的信息。在本文中,我们将介绍如何在Linux系统中使用sysfs。
二、sysfs概述
sysfs
是一种虚拟文件系统,它将系统中的设备、驱动程序和其他内核对象表示为文件和目录。sysfs
通常被挂载到/sys
目录中,其中每个设备和驱动程序都具有唯一的目录。每个目录中包含多个文件,用于控制设备的行为或提供有关设备状态的信息。
sysfs
的主要目的是为了方便内核开发人员和设备驱动程序编写者进行交互。sysfs
中的每个文件都有一个相关的内核对象,例如一个设备、一个总线或一个驱动程序。当用户或程序读取或写入sysfs
文件时,内核会相应地更改相关的内核对象。
三、sysfs文件系统的挂载和卸载
sysfs
文件系统是由内核自动挂载的,无需手动挂载。当系统启动时,内核会自动将sysfs
文件系统挂载到/sys
目录中。如果您需要手动卸载sysfs
文件系统,可以使用以下命令:
sudo umount /sys
sysfs
中的文件用于控制设备的行为或提供有关设备状态的信息。sysfs
中的文件通常是只读的,但有些文件也可以被写入以改变设备的状态或行为。sysfs
中的每个文件都有一个唯一的路径,以设备或驱动程序的名称和文件名表示。
例如,要查看/sys
目录下以太网设备的状态信息,可以使用以下命令:
cat /sys/class/net/eth0/operstate
在这个例子中,/sys/class/net/eth0
是以太网设备的目录,operstate
是设备的状态文件。通过读取这个文件,可以获取以太网设备的当前状态,例如 up
或 down
。
另一个示例是要修改设备的状态。要启用或禁用以太网设备,可以使用以下命令:
echo "up" > /sys/class/net/eth0/operstate
这个命令将以太网设备的状态设置为 up
,即启用设备。要禁用设备,只需将 up
更改为 down
。
四、sysfs文件系统的目录结构
sysfs
文件系统提供了一种以层次结构形式组织系统信息的方式。在sysfs
中,每个设备和驱动程序都表示为一个目录,目录中包含一些属性文件和其他目录,这些文件和目录可以用于控制和监视设备。
sysfs
文件系统的根目录位于/sys下,其中的目录结构如下:
/sys/block
: 存放块设备的目录,包括硬盘、U盘等。/sys/bus
: 存放总线类型目录的地方,每种总线都有一个目录,如pci、usb、spi等。/sys/class
: 存放设备类目录的地方,每种设备类都有一个目录,如input、net、sound等。/sys/devices
: 存放设备实例目录的地方,每个设备都有一个唯一的目录。/sys/firmware
: 存放固件文件的目录。/sys/fs
: 存放文件系统相关目录的地方,如cgroup、fuse等。/sys/kernel
: 存放内核相关信息的目录,如调度器、内存管理等。/sys/module
: 存放内核模块的目录。/sys/power
: 存放电源管理相关目录的地方,如休眠、唤醒等。/sys/devices/virtual
: 存放虚拟设备目录的地方,如虚拟终端、虚拟网卡等。
五、sysfs的使用
sysfs
提供了一种可读可写的属性文件接口,可以通过该接口访问设备节点的属性。在/sys
目录下,每个设备节点都有一个对应的目录,其中包含了一些属性文件,例如:
device
:设备节点的名称。driver
:驱动程序的名称。uevent
:当设备节点的状态改变时会触发的事件,可以使用udev工具来处理这些事件。power
:设备的电源管理属性。
例如,要访问一个名为/sys/devices/pci0000:00/0000:00:01.0/usb3/3-1/3-1:1.0/net/eth0
的设备节点,可以使用以下命令:
$ cat /sys/devices/pci0000:00/0000:00:01.0/usb3/3-1/3-1:1.0/net/eth0/operstate
up
这个命令可以显示eth0
接口的状态(up
表示接口已经启用)。
六、在Linux内核模块中使用sysfs
内核模块可以通过sysfs
来暴露自己的参数和状态,以便于用户和应用程序可以访问和配置。在内核模块中,可以使用sysfs_create_file()
函数创建一个属性文件,这个函数的参数包括:
- 一个指向
kobject
结构的指针,这个结构描述了内核对象,例如设备或驱动程序。 - 一个指向
struct attribute
结构的指针,这个结构描述了属性的名称和访问方式。 - 一个指向读取属性的回调函数的指针。
- 一个指向写入属性的回调函数的指针。
在内核模块中创建sysfs
属性文件的一般步骤如下:
定义 kobject
结构体和sysfs_ops
结构体
#include <linux/kobject.h>
#include <linux/sysfs.h>
static struct kobject *my_kobj;
static struct attribute my_attribute = {
.name = "foo",
.mode = 0644,
};
static struct attribute *my_attrs[] = {
&my_attribute,
NULL,
};
static ssize_t my_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
// show函数的具体实现
}
static ssize_t my_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
// store函数的具体实现
}
static struct sysfs_ops my_sysfs_ops = {
.show = my_show,
.store = my_store,
};
在上面的代码中,my_kobj
是一个指向kobject
结构体的指针,my_attribute
是一个attribute
结构体,用于表示foo
属性文件.
my_attrs
是一个指向attribute
结构体指针的数组,用于表示内核对象的所有属性文件,my_show
和my_store
是用于读取和写入属性值的回调函数,my_sysfs_ops
是一个sysfs_ops
结构体,用于表示操作这些属性文件的回调函数集合。
初始化和注册 kobject
static int __init my_init(void)
{
int ret;
my_kobj = kobject_create_and_add("my_kobject", NULL);
if (!my_kobj)
return -ENOMEM;
ret = sysfs_create_file(my_kobj, &my_attribute.attr);
if (ret) {
kobject_put(my_kobj);
return ret;
}
my_kobj->ktype->sysfs_ops = &my_sysfs_ops;
return 0;
}
static void __exit my_exit(void)
{
kobject_put(my_kobj);
}
module_init(my_init);
module_exit(my_exit);
在上面的代码中,kobject_create_and_add
函数用于创建并添加一个名为my_kobject
的内核对象,sysfs_create_file
函数用于将foo
属性文件与my_kobject
关联,my_kobj->ktype->sysfs_ops
用于将my_sysfs_ops
回调函数集合注册到my_kobj
上。
七、结语
在Linux系统中,sysfs
是一个非常重要的文件系统,它提供了一种用户空间与内核空间进行交互的方式,同时也是内核开发中一个非常有用的工具。
在本文中,我们学习了sysfs
的基本概念和目录结构,以及如何使用sysfs
来读取和修改内核对象的属性值,以及在内核模块中如何使用sysfs
来创建属性文件并将其关联到内核对象中。
需要注意的是,sysfs
是一种非常强大的工具,同时也是内核开发中非常重要的一部分。在使用sysfs
时,一定要小心谨慎,遵循最佳实践,并确保正确处理错误情况。只有这样,才能充分利用sysfs
的潜力,从而构建更加稳定和可靠的系统。