sysfs文件系统

avatar
作者
筋斗云
阅读量:3

sysfs系统介绍

📌————本章重点————📌
🔗了解sysfs系统概念;
🔗了解kobject,kest结构体;
🔗了解bus如何管理driver和device;
✨————————————✨

在这里插入图片描述

sysfs系统

sysfs系统是什么?

sysfs是一种虚拟文件系统,旨在提供一种访问内核数据结构的方法,从而允许用户空间程序查看和控制系统的设备和资源。sysfs文件系统通常被挂载在/sys目录下。sysfs提供了一种以树状结构组织的系统信息的方式,其中每个设备都有一个唯一的目录来表示它自己,其中包含有关设备的各种属性和状态信息的文件。这些文件通常是只读的,但有些也可以用于修改设备的某些设置。sysfs还提供了一个机制来通知用户空间程序有关设备状态更改的信息,从而使其能够对这些更改做出反应。sysfs文件系统被广泛用于Linux内核中,它为开发者提供了一种简单的方式来管理和控制系统中的各种设备和资源。

我们知道,在linux系统下一切皆文件,所以设备也是linux下的一个文件。

由mount命令我们可以看到,sysfs挂在在sys目录下
在这里插入图片描述
我们可以进入下面这个文件夹查看设备驱动程序信息
总线都会放到/sys/bus这个目录下,其中设备驱动程序信息在/sys/bus/platform/drivers下
在这里插入图片描述

具体理解我们可以参考以下图表:

在这里插入图片描述
1.Bus(总线)
总线是一种用于连接多个硬件设备的物理或逻辑通道,它是计算机系统中最重要的组成部分之一,负责将各种设备连接到主板上,并通过数据传输来实现这些设备之间的通信。在 Linux 操作系统中,总线是一种抽象的概念,用于描述硬件设备之间的连接方式和通讯协议。常见的总线类型包括 PCI、USB、SATA、I2C 等。Linux 内核通过识别总线来自动发现和配置连接在总线上的硬件设备。

2.Devices(设备)
设备是指连接在总线上的硬件设备,例如磁盘驱动器、网卡、USB 设备等。在 Linux 操作系统中,每个设备都会被分配一个唯一的设备文件(device file),用于表示设备在文件系统中的位置。设备文件通常位于 /dev 目录下,例如硬盘设备文件为 /dev/sda、USB 设备文件为 /dev/usb。

3.Classes(设备类)
设备类是一种用于分类和管理设备的机制。在 Linux 操作系统中,每个设备都会被分配一个设备类,例如磁盘设备属于 block 类、网络设备属于 net 类。设备类用于将相似的设备归类到一起,并提供一组共同的属性和接口。例如,所有 block 类设备都具有读写数据的接口,所有 net 类设备都具有配置网络参数的接口,比如Block 类设备是一种按照固定大小的块(通常为512字节或4KB)来访问的存储设备,例如硬盘、闪存、光盘等。Block 类设备提供了读取和写入块数据的接口,同时也支持块设备缓存、磁盘分区、文件系统等功能。

4.总线、设备和设备类之间的链接方式如下:

每个设备都属于一个设备类,设备类定义了设备的属性和接口。
每个设备都连接到一个总线上,总线通过 ID 来唯一标识每个设备。
每个设备节点都与一个设备相关联,设备节点的名称由设备类决定。

koject的内核对象模型基础

在 Linux 内核中,kobject 是内核对象(Kernel Object)的一种抽象表示。它是内核对象模型的基础,用于表示内核中的各种资源(如设备、驱动程序、进程等),并提供统一的管理和操作接口。是设备模型的核心,引入了通用对象属性的封装概念。kobject 通常用于表示驱动程序中的设备对象,即 struct device 结构体的成员。当设备驱动程序被加载到内核中时,驱动程序会注册一个 struct device_driver 结构体,其中包含了设备对象的信息。内核将创建一个 kobject 对象来表示该设备对象,并将其添加到设备模型中。然后,用户空间可以使用 sysfs 接口来查询和配置设备对象的属性,例如设备状态、驱动程序信息等。头文件:<linux/kobject.h>
在这里插入图片描述
如上图相当于是一种层层封装的结构

kobject结构体定义

struct kobject {     const char              *name;     struct list_head        entry;     struct kobject          *parent;     struct kset             *kset;     struct kobj_type        *ktype;     struct sysfs_dirent     *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:kobject 对象的名称,用于标识该对象在对象树中的位置。
entry:kobject 对象在父对象的子对象链表中的节点。
parent:kobject 对象的父对象,即该对象在对象树中的父节点。
kset:kobject 对象所属的 kset 对象,用于管理该对象的生命周期。
ktype:kobject 对象所属的 kobj_type 对象,用于定义该对象的属性和操作。
sd:sysfs 中与该 kobject 对象对应的 sysfs_dirent 对象。
kref:用于实现 kobject 对象的引用计数,确保该对象在被使用时不被释放。
state_initialized:标识该 kobject 对象是否已经初始化。
state_in_sysfs:标识该 kobject 对象是否已经在 sysfs 中注册。
state_add_uevent_sent:标识该 kobject 对象是否已经发送了添加事件通知。
state_remove_uevent_sent:标识该 kobject 对象是否已经发送了删除事件通知。
uevent_suppress:标识是否禁止该 kobject 对象发送事件通知。

每个内核设备直接或间接嵌入kobject属性。在添加到系统之前,必须使用kobject_ create()函数分配kobject,并将已经分配但尚未初始化的kob ject指针及其kobject_type 指针作为参数。kobject_add()函数用于添加kobject并将其链接到系统,同时根据其层次结构创建目录及其默认属性。功能与之相反的函数是kobject_ del(),将kobject删除链接

kest

kset 是一种特殊的 kobject,它代表一组相关的内核对象,可以通过 sysfs 接口暴露给用户空间。kset 可以看作是 kobject 的容器,它可以包含多个 kobject,并提供了一些方便的接口来管理这些 kobject。设备驱动程序可以创建一个 kset 来表示该驱动程序的设备对象集合,并将每个设备对象表示为一个 kobject,然后将它们添加到 kset 中。头文件:<linux/kobject.h>

struct kset {     struct kobject kobj;  // kset 对应的 kobject     struct list_head list;  // kset 链表     struct kset_uevent_ops *uevent_ops;  // uevent 操作函数指针     const char *subsys;  // kset 所属子系统的名称     struct kobject *kobj_child;  // 子对象的 kobject 指针     struct kobject *kobj_unregister;  // 未注册的 kobject 指针     struct module *module;  // kset 所属的内核模块 }; 

kobj:一个 kobject 对象,表示 kset 对象本身。
list:一个链表,用于将多个 kset 对象连接在一起。
uevent_ops:一个指向 kset_uevent_ops 结构体的指针,表示 kset 对象的 uevent 操作函数集。
subsys:一个字符串,表示 kset 对象所属的子系统名称。
kobj_child:一个指向 kobject 对象的指针,表示 kset 包含的子对象的 kobject。
kobj_unregister:一个指向 kobject 对象的指针,表示未注册的 kobject,用于在 kset 删除时释放该对象。
module:一个指向 struct module 结构体的指针,表示 kset 所属的内核模块。

在这里插入图片描述
在这个目录下的每一个子目录,其实都是相同类型的koject集合,不同的kest组织成树状层次结构,就构成了sysfs子目录

bus如何管理driver和device

在 Linux 内核中,bus 是一种抽象的总线结构,用于管理和控制设备和设备驱动程序之间的交互。每个 bus 对象都有一个相应的 bus_type 结构体,它包含了管理 bus 对象所需的函数和数据。bus 对象还可以包含多个 device 对象和多个 driver 对象。

driver 是一种抽象的设备驱动程序结构,用于实现设备的控制和数据交换。每个 driver 对象都有一个相应的 driver_type 结构体,它包含了实现 driver 所需的函数和数据。driver 对象还可以匹配多个 device 对象,并与之交互。

device 是一种抽象的设备结构,用于表示系统中的物理设备或虚拟设备。每个 device 对象都有一个相应的 device_type 结构体,它包含了描述 device 特性和行为的数据。device 对象还可以与多个 driver 对象匹配,并通过它们来控制和管理设备。

当内核探测到一个新的设备时,它会将设备信息和一些系统信息传递给 bus 对象。bus 对象会根据设备信息匹配合适的 driver 对象,并在匹配成功时将 device 对象与 driver 对象绑定。这样,driver 对象就可以访问 device 对象的属性和方法,并与设备交互。

在设备使用过程中,内核会通过 bus 对象和 driver 对象来控制和管理设备。例如,当设备需要进行初始化、启动、停止、重启或卸载时,内核会调用相应的 driver 函数来完成这些操作。同样,当设备出现故障或需要进行调试时,内核也会通过 bus 对象和 driver 对象来诊断和处理问题。

总之,bus、driver 和 device 是 Linux 内核中用于管理和控制设备和设备驱动程序的重要抽象结构。通过这些结构,内核可以实现设备的自动探测、自动匹配、自动配置和自动管理,从而使设备的使用更加方便和可靠。

在这里插入图片描述
在 Linux 内核中,kobject 和 subsys_private 通常是一一对应的。kobject 结构体表示内核中的对象,而 subsys_private 结构体表示该对象所属的子系统的私有数据。在子系统中,可以通过 kobject 结构体的 kset 成员指针访问该对象所属的 kset 结构体,进而获取子系统的 subsys_private 结构体。一般来说,subsys_private 结构体中包含了与子系统相关的所有数据,如对象列表、状态信息、配置参数等。
例如,在 Linux 设备驱动程序中,一个设备对象的 kobject 结构体中的 kset 成员指针通常指向该设备所属的 bus_type 结构体中的 devices_kset 成员,而 devices_kset 成员又指向设备子系统的 subsys_private 结构体。通过访问 subsys_private 结构体,设备驱动程序可以获取设备子系统的私有数据和状态信息,进而实现设备的初始化、配置和管理。总之,kobject 结构体和 subsys_private 结构体是 Linux 内核中一对重要的结构体,它们通常是一一对应的,表示内核中的对象和该对象所属的子系统的私有数据。通过访问 subsys_private 结构体,内核组件可以获取和修改子系统的私有数据和状态信息,实现对象之间的协同工作。

bus_type 结构体

bus_type 结构体是 Linux 内核中用于表示总线类型的结构体,通常定义在头文件 include/linux/device.h 中。该结构体中包含了一些总线类型的属性和操作方法。

struct bus_type {     const char *name;                       // 总线类型的名称     const char *dev_name;                   // 设备文件名的前缀     struct bus_attribute *bus_attrs;        // 总线类型的属性     struct device_attribute *dev_attrs;     // 设备属性     struct driver_attribute *drv_attrs;     // 驱动程序属性     int (*match)(struct device *dev, struct device_driver *drv);   // 匹配函数     int (*uevent)(struct device *dev, struct kobj_uevent_env *env); // 热插拔事件函数     int (*probe)(struct device *dev);       // 探测函数     int (*remove)(struct device *dev);      // 卸载函数     void (*shutdown)(struct device *dev);   // 关机函数     struct device * (*add_device)(struct device *dev); // 添加设备     void (*remove_device)(struct device *dev); // 移除设备     struct device_driver * (*match_driver)(struct device *dev, struct bus_type *bus); // 匹配驱动程序     const struct dev_pm_ops *pm;            // 电源管理操作函数     struct lock_class_key lock_key;         // 锁的标识符     struct module *owner;                   // 模块的所有者 }; 

name:表示总线类型的名称,通常是一个字符串,如 “pci”、“usb” 等。
dev_name:表示设备文件名的前缀,当设备注册到该总线类型时,内核会为该设备创建一个设备文件,其文件名的前缀为
dev_name,后面会跟上一个数字,如 /dev/ttyUSB0。 bus_attrs:指向一个 bus_attribute
结构体数组,表示总线类型的属性。bus_attribute 结构体用于定义总线类型的属性,通常是一个 sysfs
文件,用于管理总线类型的参数和状态信息。 dev_attrs:指向一个 device_attribute
结构体数组,表示该总线类型下设备的属性。device_attribute 结构体用于定义设备的属性,通常是一个 sysfs
文件,用于管理设备的参数和状态信息。 drv_attrs:指向一个 driver_attribute
结构体数组,表示该总线类型下驱动程序的属性。driver_attribute 结构体用于定义驱动程序的属性,通常是一个 sysfs
文件,用于管理驱动程序的参数和状态信息。
match:用于匹配设备和驱动程序的函数指针,当一个新的设备加入到该总线类型中时,内核会调用该函数来匹配该设备所需的驱动程序。
uevent:用于处理热插拔事件

小知识

什么是挂载

==挂载(Mount)是将文件系统链接到操作系统的目录树上的过程。==具体来说,挂载是将一个文件系统作为一个目录(即挂载点)的内容显示在另一个目录下的过程。通过挂载,用户可以访问该文件系统中的文件和目录,就好像它们是本地文件系统一样。挂载通常用于将磁盘分区、USB设备、网络文件系统等设备链接到操作系统的目录树中。例如,将一个USB闪存驱动器插入计算机时,操作系统可以自动挂载它并将它的文件系统显示在一个目录中。同样,当计算机通过网络连接到另一个计算机的文件系统时,操作系统也可以将该文件系统挂载到本地目录中,以便用户可以访问远程文件系统中的文件。

mount命令

mount命令是一个Linux/Unix命令,它用于将一个文件系统挂载到指定的挂载点(mount point)上,使得该文件系统可以被访问和使用。mount命令可以将本地文件系统、网络文件系统等挂载到指定的挂载点上。单纯的mount是查看已经挂载的详细信息。

最近刚刚接触这个技术,写的有些不足还请各位大佬指出,欢迎各位批评指教!!
在这里插入图片描述

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!