kobject 和 sysfs

Posted Li-Yongjun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kobject 和 sysfs相关的知识,希望对你有一定的参考价值。

活动地址:CSDN21天学习挑战赛

设备模型

kernel 2.6 增加了一个引人注目得新特性——统一设备模型(device model)。
设备模型是指设备、总线、驱动的系统结构抽象,它的意义在于能够系统地管理所有设备。
设备模型描述设备在系统中的拓扑结构,从而使得系统具有以下优点:

  • 代码重复最小化
  • 提供诸如引用计数这样的统一机制。
  • 可以列举系统中所有的设备,观察它们的状态,并且查看它们连接的总线。
  • 可以将系统中的全部设备结构以树的形式完整、有效地展现出来,包括所有的总线和内部连接
  • 可以将设备和其对应的驱动联系起来,反之亦然。
  • 可以将设备按照类型加以归类,如分类为输入设备,而无需理解物理设备的拓扑结构。
  • 可以沿设备树的叶子向其根的方向依次遍历,以保证能以正确的顺序关闭各设备的电源。

最后一点是实现设备模型的最初动机。若想在内核中实现智能的电源管理,就需要来建立表示系统中设备拓扑关系的树结构。当在树上端的设备关闭电源时,内核必须首先关闭该设备节点以下(处于叶子上的)设备电源。比如内核需要先关闭一个 USB 鼠标,然后才可以关闭 USB 控制器;同样内核也必须在关闭 PCI 总线前先关闭 USB 控制器。简而言之,若要准确又高效地完成上述电源管理目标,内核无疑需要一颗设备树。

kobject

设备模型地核心部分就是 kobject,它由 struct kobject 结构体表示,定义在头文件 <linux/kobject.h> 中。

struct kobject 
	const char		*name;
	struct list_head	entry;
	struct kobject		*parent;
	struct kset		*kset;
	struct kobj_type	*ktype;
	struct kernfs_node	*sd;
	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;
;

name:对应 sysfs 的目录名。
entry:用于将 kobj 挂在 kset->list 中。
parent:指向 kobj 的父结构,形成层次结构,在 sysfs 中表现为父子目录的关系。
kset:表征该 kobj 所属的 kset。kset 可以作为 parent 的“候补”:当注册时,传入的 parent 为空时,可以让 kset 来担当。
ktype:该 kobj 对应的 kobj_type。每个 kobj 或其嵌入的结构对象应该都对应一个 kobj_type。
sd:对应 sysfs 对象。在 3.14 以后的内核中,sysfs 基于 kernfs 来实现。
kref:引用计数对象,支撑 kobj 的引用计数功能。

state_initialized:1---------------------记录初始化与否。调用 kobject_init() 后,会置位。
state_in_sysfs:1-----------------------记录 kobj 是否注册到 sysfs,在 kobject_add_internal() 中置位。
state_add_uevent_sent:1-----------当发送 KOBJ_ADD 消息时,置位。提示已经向用户空间发送 ADD 消息。
state_remove_uevent_sent:1------当发送 KOBJ_REMOVE 消息时,置位。提示已经向用户空间发送 REMOVE 消息。
uevent_suppress:1--------------------如果该字段为 1,则表示忽略所有上报的 uevent 事件。

sysfs

sysfs 是设备模型的意外收获。开发者为了方便调试,决定将设备结构树导出为一个文件系统——sysfs。
sysfs 代替了先前处于 /proc 下的设备相关文件。
sysfs 起初被称为 driverfs。
当前 sysfs 文件系统代替了以前需要由 ioctl() 和 procfs 文件系统完成的功能。
利用在 sysfs 目录中添加一个 sysfs 属性,代替在设备节点上实现一个新的 ioctl()。
sysfs 属性应该保证每个文件只导出一个值,这使得从命令行读写变得简单;该值应该是文本形式而且被映射为简单 C 类型,这使得 C 语言程序可以轻易地将内核数据从 sysfs 导入到自身的变量中。这就比 /proc 好多了,/proc 中的数据混乱而不具有可读性。
sysfs 提供内核到用户空间的服务,这多少有些用户空间的 ABI(应用程序二进制接口)的作用。

示例1

kobject、kset 结构关系还是挺复杂的,这里添加一些打印,直观地了解下其内容。

drivers/base/class.c

int __init classes_init(void)

	int i;
	struct kset *p;
	class_kset = kset_create_and_add("class", NULL, NULL);
	if (!class_kset)
		return -ENOMEM;
printk("clase's kobj name = %s\\n", class_kset->kobj.name);
if (class_kset->kobj.parent)
	printk("clase's parent kobj name = %s\\n", class_kset->kobj.parent->name);
else
	printk("parent = NULL\\n");

if (class_kset->kobj.kset)
	printk("clase's kset kobj name = %s\\n", class_kset->kobj.kset->kobj.name);
else
	printk("clase's kset is NULL\\n");

	return 0;

输出

clase's kobj name = class
parent = NULL
clase's kset is NULL

clase's kobj name = class,和 /sys/class 吻合。并且其 parent 和 kset 均为 NULL,说明 class 在设备模型中处于最顶层,所以 /sys 并不是最顶层,它只是一个目录,/sys 下的一级子目录是一个个顶级 kset

示例2

static int __init leds_init(void)

	int i;
	struct kset *p;

	leds_class = class_create(THIS_MODULE, "leds");
	if (IS_ERR(leds_class))
		return PTR_ERR(leds_class);
	leds_class->pm = &leds_class_dev_pm_ops;
	leds_class->dev_groups = led_groups;


printk("leds kobj name = %s\\n", leds_class->dev_kobj->name);
printk("leds's parent kobj name = %s\\n", leds_class->dev_kobj->parent->name);

printk("name = %s\\n", leds_class->p->subsys.kobj.name);
printk("parent name = %s\\n", leds_class->p->subsys.kobj.parent->name);

	return 0;

leds kobj name = char
leds's parent kobj name = dev
name = leds
parent name = class

得到两种目录结构 dev/char/class/leds/,这两种形式在 /sys 下都有呈现:/sys/dev/char//sys/class/leds/

总结

设备模型还是很复杂、很抽象的,后面还需要深入学习,这里就当做个引子。继续努力!

以上是关于kobject 和 sysfs的主要内容,如果未能解决你的问题,请参考以下文章

kobject 和 sysfs

sysfs文件系统学习

(todo)Linux 内核:设备驱动模型sysfs与kobject基类

linux-sysfs

sysfs.txt 文档翻译

RK3399平台开发系列讲解(内核调试篇)9.17添加Sysfs节点(kobject和kset)