bus_register源码研究

kobject和kset

学习bus前需要先了解kobj和kset

kobject

kobj可以理解为内核设备模型中的一个最小对象(所有sysfs中的实体都需要直接或者间接内嵌继承它),其对应一个sysfs中的目录

name---kobject的名字,也就是sysfs中对应目录的名字

entry---作为kset中的节点,让所属的kset串联kobj的时候用
*parent---kobject的父指针,这样就可以支持层级关系了,sysfs创建目录的时候就是按照这个创建的

kset---当前kobject所属的kset
*ktype---这个kobject的"类型",决定syfs属性文件如何读写,释放时会怎么处理等等
*sd---指向kernfs层真实节点,内核维护,用户不填

kref---引用计数,参与kobject的生命周期,即有人还在用,就不会释放这个kobj

release---用于调试:延迟释放,方便捕获使用后释放的bug

最后是五个状态标志位

c 复制代码
    unsigned int state_initialized:1;       // 是否已经完成初始化(kobject_init() 或 kobject_init_and_add())
    unsigned int state_in_sysfs:1;          // 是否已经成功注册到 sysfs 中(目录已创建)
    unsigned int state_add_uevent_sent:1;   // 是否已经发送过 KOBJ_ADD uevent(创建时通知)
    unsigned int state_remove_uevent_sent:1;// 是否已经发送过 KOBJ_REMOVE uevent(删除时通知)
    unsigned int uevent_suppress:1;         // 是否抑制发送 uevent(用于批量操作时避免刷屏)

kobject_init

对kobject做了一些检查,然后给其内部的一些变量进行了缺省配置

kobject_add

该函数负责将一个已经初始化好的kobject加入到sysfs体系结构中(也就是真正创建sysfs里的目录)

其使用可变参数的方式设置kobject的名字,并且完成添加操作和创建对应目录操作

kset

kset可以理解为对一批kobject的集合,其本身也是内嵌继承了kobject,所以也会有自己的目录

其往往是给一个子系统(bus,class)等使用,可以在kobj假如到kset的时候很方便的设置kobj的parent为自己内嵌的kobj

也更方便子系统访问自己下属的kobj

kset实际上是 内嵌继承kobject的结构体

除了通过list记录自己下面的kobject外,其最重要的作用是统一管理和发送uevent

list:记录属于当前kset的kobjects的链表

lisk_lock:对于list访问的自旋锁,防止遍历过程中节点被修改

kobject:内嵌到当前kset的kobject

uevent_ops:简单说,它是内核用来"定制"某个 kset 下所有 kobject 发出 uevent 时额外携带哪些环境变量的一个回调机制。
uevent 是内核通知用户空间设备事件的机制

kset_init

主要部分体现在kobject_init_internal

初始化了kset的链表和自旋锁

kobject_init_internal

对kobject进行了缺省配置,并初始化了引用计数ref和其插入到链表中的节点entry

kset_register

初始化并且添加一个ketset

其会为当前kset创建一个目录(实际上目录是属于其内嵌的kobject的)

kobject_add_internal

这是对kset内嵌kobject处理的函数

该函数做的事情大概如下:

1.如果该kobject没有指定parent,就把它的父亲指定为其所属kset的内嵌kobj,并且添加该kobj到所属kset的链表中去

2.然后给该kobject创建目录(在parent的kobj对应目录下)

3.修改state_in_sysfs=1,表示该kobj已经是sysfs中的一份子了

kobject_uevent

向用户空间发送一个kobject被添加到内核中的uevent事件,让用户空间程序,如udev知道这个新对象出现了,并且进行处理

这个事件如何理解呢?

比如device_create函数,它可不是自己直接就创建/dev下面的设备节点的,而是也要在创建并注册device所内嵌的kobj到sysfs上,然后使用kobject_uevent(&dev->kobj, KOBJ_ADD);通过用户空间,udev才会去在/dev下面创建新的设备节点

bus_type源码

subsys_private源码

首先bus_type内部定义了一个重要的struct subsys_private类型的指针,该结构体内部成员如下

subsys---为一个kset集合,其中将需要用到的kobject串联起来

devices_kset---为指向设备kset集合的一个指针,即指向代表当前总线下devices目录对应的kset

interfaces---总线支持的接口链表

drivers_kset---为指向设备kset集合的一个指针,即指向代表当前总线下drivers目录对应的kset

klist_devices和klist_drivers这两个变量是为了对注册进bus的device和driver进行记录的链表(该链表提供了引用计数以及锁)
关于这里的kset和klist是否多次一举的理解

kset负责在sysfs中维护用户可见和层次结构

klist通过引用计数+锁的机制 提供了并发安全性

二者并不冲突,kobj提供的引用计数是为了管理device或者driver的生命周期

kilst中knode提供的引用计数是为了提供并发安全的遍历机制

bus_notifier--uevent通知头,热插拔,绑定,解绑等事件会通过这里通知用户空间

drivers_autoprobe---自动匹配并调用驱动中probe的开关,设置为1表示开启

bus_type---为指向总线类型的指针

glue_dirs---为了防止命名空间冲突的一个变量

class---当前总线和某个class绑定的时候用到

bus_type源码

name---总线名字

dev_name---用于枚举总线上设备的变量,比如spi1,spi2等等

dev_root---设置一个device作为总线的根设备

dev_attrs---总线上设备的默认属性

match---如何匹配总线上的driver和device

uevent---影响给用户空间的uevent事件

probe---添加device或者driver时候调用,并且会回调总线上driver中的probe函数来初始化device

remove到resume均为总线上设备的状态发生对应变化的时候会调用的函数

pm---总线上默认的电源管理操作,内部会回调对应的驱动的电源管理函数

iommu_ops---设置总线上的内存映射操作

struct subsys_private*---指向总线的子系统(总线的私有结构体)的指针

综上,bus_type结构体是对总线上设备或者驱动变化的时候,做的对应的操作做了一个规定

而总线上设备在sysfs中的对应结构,需要通过bus_type的私有结构体subsys_private中的成员来实现

bus_register源码

上面提到的subsys.kset指向的kset为在内核加载时就创建好的一个kset,名为bus,并且其内嵌kobj没有(parent),然后在下面的kset_register,会将当前spi_bus对应的subsys内嵌kobj的parent设置为这个名为bus的kset内嵌的kobj,这样就实现了,/sys/bus/下面是spi的目录结构了
由上面的过程引申,kset之间的包含关系是通过内嵌kobj来实现的

这里创建了devices和drivers对应的kset,该kset的内嵌kobj的parent当然就会是当前subsys这个kset的内嵌kobj了

klist_init初始化了两个链表,这两个链表通过独特的引用机制,提供并发安全的对knode所对应结构体(如device或者driver)的访问-----即假如一个进程在移出链表中的元素,需要等待ref为0才可以,这样就不会导致正在链表上迭代的进程的pre或者next指针变成野指针

add_probe_files会添加一个drivers_autoprobe文件到spi_bus的目录下,其值默认为1,即添加device或者driver会自动执行probe函数并在内部回调driver的probe函数

相关推荐
wdfk_prog1 小时前
[Linux]学习笔记系列 -- [drivers][base]dd
linux·笔记·学习
程序员zgh2 小时前
C语言 弱定义机制 解读
c语言·开发语言·c++
AOwhisky2 小时前
iSCSI 网络存储服务从入门到精通
linux·运维·网络
刘叨叨趣味运维2 小时前
服务器硬件全面解析:从CPU到网卡的运维必备知识
linux
宵时待雨2 小时前
数据结构(初阶)笔记归纳6:双向链表的实现
c语言·开发语言·数据结构·笔记·算法·链表
不会代码的小猴2 小时前
Linux环境编程第二天笔记
linux·笔记
Channing Lewis2 小时前
linux进入重启了如何阻止
linux·运维·服务器
Koma_zhe2 小时前
【文本转语音工具VibeVoice】告别单调配音,VibeVoice+cpolar 让多角色音频创作随时随地搞定
linux·人工智能·ai·音视频·语音识别
负二代0.02 小时前
Linux下文件管理
linux·运维·服务器