sysfs是什么? 为什么需要sysfs?
简单说sysfs就是linux下的sys 目录及各级层次的文件/目录. 本质来说, sysfs是一个虚拟文件系统sysfs, 隶属于vfs, 挂载在系统节点/sys下面.
jim@ubt18:sys$ tree -L 1
├── block
├── bus
├── class
├── dev
├── devices
├── firmware
├── fs
├── hypervisor
├── kernel
├── module
└── power
设备模型
2.6内核增加了一个1人注目的新特性一统一设备模型(device model)。设备模型提供了
一个独立的机制专门来表示设备,并描述其在系统中的拓扑结构,从而使得系统具有以下优点:
代码重复最小化
。 //最大程度的对大部分驱动 求同存异, 消除冗余代码, 复用相同的操作
提供诸如引用计数这样的统一机制
。//方便系统remove时候,看是否还有在用资源
可以列举系统中所有的设备,观察它们的状态,并且查看它们连接的总线
。
可以将系统中的全部设备结构以**树的形式**完整、有效地展现出来一包括所有的总线和内 部连接
。
可以将设备和其对应的驱动联系起来,反之亦然
。
可以将设备按照类型加以**归类**,比如分类为输入设备,而无需理解物理设备的拓扑结构
****** 可以沿设备树的叶子向其根的方向依次遍历,以保证能以**正确顺序**关闭各设备的**电源**
最后一点是实现设备模型的最初动机。若想在内核中实现智能的电源管理
,就需要建立表示
系统中设备拓扑关系的树结构。当在树上端的设备关闭电源时,内核必须首先关闭该设备节点以
下的(处于叶子上的)设备电源。比如内核需要先关闭一个USB鼠标,然后才可关闭USB控制
器:同样内核也必须在关闭PCI总线前先关闭USB控制器。简而言之,若要准确而又高效地完 成上述电源管理目标,内核无疑需要一棵设备树
。
构建sysfs的背景:
- 没有sysfs之前,linux系统的驱动都是一个一个单独的,彼此之间没有关联,相互没有层次关系,没有分类,远没有windows系统的"设备管理"页面有层次,方便用户管理使用.
有了sysfs, 新加入系统的设备就有了: 属于哪个bus? 属于哪个class ? 属于block设备还是char设备?同时还可能有power管理的特性,那么用户就可以依据电源管理策略来配置新设备的电源管理模式.
从此, 新设备加入"系统"大家庭, 就有了组织, 可以看sysfs看到他的"组织关系",以及他的驱动, 他的设备节点.
2. 另外一个背景: 没有sysfs之前, 如果想操作一下设备,比如简单的设置gpio的output value, 需要一个完备的app: 打开/dev/xxx, 调用ioctl或者write函数, 设置gpio-value=1. 有了sysfs, 就可以在 /sys/class/gpio目录下,直接通过shell的echo命令设置value=1, 也可以通过cat获得当前gpio的value,大大提高了开发效率.
jim@ubt18:sys$ ls class/gpio/
export unexport
2.6 版的设备模型提供了这样的抽象。现在内核使用该抽象支持了多种不同的任务,其
中包括:
电源管理和系统关机'
完成这些工作需要一些对系统结构的理解。比如一个USB宿主适配器,在处理完
所有与其连接的设备前是不能被关闭的。设备模型使得操作系统能够以正确的顺序
遍历系统硬件。与用户空间通信
sysfs虚拟文件系统的实现与设备模型密切相关,并且向外界展示了它所表述的结
构。向用户空间所提供的系统信息,以及改变操作参数的接口,将越来越多地通过
sysfs实现,也就是说,通过设备模型实现。热插拔设备
越来越多的计算机设备可被动态的热插拔了,也就是说,外围设备可根据用户的需
要安装与卸载。内核中的热插拔机制可以处理热插拔设备,特别是能够与用户空间
进行关于插拔设备的通信,而这种机制也是通过设备模型管理的。设备类型
系统中的许多部分对设备如何连接的信息并不感兴趣,但是它们需要知道哪些类型
的设备是可以使用的。设备模型包括了将设备分类的机制,它会在更高的功能层上
描述这些设备,并使得这些设备对用户空间可见。对象生命周期
上述许多功能,包括热插拔支持和syss,使得内核中创建和管理对象的工作更为
复杂。设备模型的实现需要创建一系列机制以处理对象的生命周期、对象之间的关
系,以及这些对象在用户空间中的表示。
kobject层次结构、kset和子系统
通常,内核用kojbect结构将各个对象连接起来组成一个分层的结构体系,从而与模型
化的子系统相匹配。有两种独立的机制用于连接:parent指针和kset
。
在kobject结构的parent成员中,保存了另外一个kobject结构的指针,这个结构表
示了分层结构中上一层的节点。比如一个kobject结构表示了一个USB设备,它的
parent指针可能指向了表示USB集线器的对象,而USB设备是插在USB集线器上的。
对parent指针最重要的用途是在sysfs分层结构中定位对象
。在后面的“低层sysfs操
作”一节中,读者将会看到它是如何实现的。
sysfs构建基础组件
kobject
核心元数据是kobject, 是所有组件的基础元器件.
struct kobject {
const char *name;
struct list_head entry;
struct kobject *parent;
struct kset *kset;
const struct kobj_type *ktype;
struct kernfs_node *sd; /* sysfs directory entry */
struct kref kref;
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
kobject核心元素有:
name, parent, kset, kref, state_xxx
这些元素表明了 这个kobject 名字是什么, 上级组织在哪里, 属于哪个kset, 是否正在被使用kref, 已经在sysfs的状态. 其中sd就是对应的sysfs目录项.
一级衍生元数据kset, kset = { kobject, uevent-ops, }
struct kset {
struct list_head list;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
} ;
kset意味着一组相似的设备,相互通过 list联系起来, 当需要向用户发送uevent时候,就用大家共享的uevent_ops发送uevent给用户层的udev(函数是kobject_uevent()).
要注意的是
,kset总是在sysfs中出现;一旦设置了kset并把它添加到系统中,将在sysfs
中创建一个目录。kobject不必在sysfs中表示
,但是kset巾的每一个kobject成员都将在
sysfs中得到表述。创建一个对象时,通常要把一个kobject添加到kset中去。这个过程有两个步骤。先把kobject的kset成员要指向目的kset,然后将kobject传递给下面的函数:
int kobject_add(struct kobject *kobj);
和处理相似的函数一样,程序员应该意识到该函数可能会失败(如果失败,将返回一个
负的错误码),并对此做出相应的动作。内核提供了一个方便使用的函数:
extern int kobject_register(struct kobject *kobj);
该函数只是kobject_init和kobject add的简单组合。
当把一个kobject传递给kobject add时,将会增加它的引用计数。在kset中包含的最重
要的内容是对象的引用。在某些时候,可能不得不把kobject从kset中删除,以清除引
用;使用下面的函数达到这个目的:
void kobject_del(struct kobject *kobj);
还有一个kobject unregister函数,它是kobject del和kobject put的组合。
kset中也有一个指针(在ktype成员中)指向kobj_type结构,用来描述它所包含的
kojbect.。该类型的使用优先于kobject中的ktype。因此在典型应用中,kobject中的
k