• kobject 和 sysfs


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

    设备模型

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

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

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

    kobject

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

    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;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    输出

    clase's kobj name = class
    parent = NULL
    clase's kset is NULL
    
    • 1
    • 2
    • 3

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    leds kobj name = char
    leds's parent kobj name = dev
    name = leds
    parent name = class
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    总结

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

  • 相关阅读:
    ResponseEntity下载包含点的文件名无法下载
    【SpringCloud】微服务技术栈入门8 - 黑马旅游微服务项目实战笔记
    nginx降权+安装php
    微服务网关API Geteway
    将docker镜像打成tar包
    如何编写一份完整的软件测试报告?
    [安洵杯 2019]easy_serialize_php1
    Springboot实战:redisson分布式缓存、分布式锁详细教程(附git源码)
    vue3 antd项目实战——table表格(一文带你快速实现后台管理系统最常用的table表格)
    正则表达式
  • 原文地址:https://blog.csdn.net/lyndon_li/article/details/126372614