当前位置: 首页 > news >正文

[Linux]学习笔记系列 -- [kernel]ksysfs


title: ksysfs
categories:

  • linux
  • kernel
    tags:
  • linux
  • kernel
    abbrlink: d7a8119d
    date: 2025-10-03 09:01:49

文章目录

  • kernel/ksysfs.c Sysfs 内核对象接口(Sysfs Kernel Object Interface) 将内核对象(kobject)层次结构展现为文件系统的核心实现
      • 历史与背景
        • 这项技术是为了解决什么特定问题而诞生的?
        • 它的发展经历了哪些重要的里程碑或版本迭代?
        • 目前该技术的社区活跃度和主流应用情况如何?
      • 核心原理与设计
        • 它的核心工作原理是什么?
        • 它的主要优势体现在哪些方面?
        • 它存在哪些已知的劣势、局限性或在特定场景下的不适用性?
      • 使用场景
        • 在哪些具体的业务或技术场景下,它是首选解决方案?
        • 是否有不推荐使用该技术的场景?为什么?
      • 对比分析
        • 请将其 与 其他相似技术 进行详细对比。
      • 历史与背景
        • 这项技术是为了解决什么特定问题而诞生的?
        • 它的发展经历了哪些重要的里程碑或版本迭代?
        • 目前该技术的社区活跃度和主流应用情况如何?
      • 核心原理与设计
        • 它的核心工作原理是什么?
        • 它的主要优势体现在哪些方面?
        • 它存在哪些已知的劣势、局限性或在特定场景下的不适用性?
      • 使用场景
        • 在哪些具体的业务或技术场景下,它是首选解决方案?
        • 是否有不推荐使用该技术的场景?为什么?
      • 对比分析
        • 请将其 与 其他相似技术 进行详细对比。
    • rcu_expedited: 控制RCU宽限期加急处理的sysfs接口
    • ksysfs_init: 创建 /sys/kernel/ 目录及其文件

在这里插入图片描述

https://github.com/wdfk-prog/linux-study

kernel/ksysfs.c Sysfs 内核对象接口(Sysfs Kernel Object Interface) 将内核对象(kobject)层次结构展现为文件系统的核心实现

历史与背景

这项技术是为了解决什么特定问题而诞生的?

kernel/ksysfs.c 是实现 sysfs 文件系统的核心。sysfs 的诞生是为了解决在它之前的 /proc 文件系统所面临的结构混乱信息冗余问题,并为Linux 2.6内核中引入的全新**统一设备模型(Unified Device Model)**提供一个干净、结构化的视图。

ksysfs.c 旨在解决以下核心问题:

  • 反映内核内部结构:内核的设备模型是一个层次化的树状结构(设备连接在总线上,驱动绑定到设备上)。需要一种机制能将这种内在的、面向对象的层次关系精确地反映到用户空间的文件系统中。
  • 提供稳定的ABI:用户空间工具(最著名的是udev)需要一个稳定、可预测的接口来发现设备、查询其属性并响应设备的热插拔事件。/proc 中杂乱无章的文件和格式使得这项工作非常脆弱。
  • 机制与策略分离ksysfs.c 提供“机制”,即创建目录和属性文件来代表设备。而“策略”(例如,根据这些信息创建 /dev 节点、加载固件)则完全交给用户空间的udev等工具来完成。
  • 设备属性的可调谐性:提供一个简单的、基于文件的接口(读文件获取属性,写文件修改属性),用于查看和调整设备参数。
它的发展经历了哪些重要的里程碑或版本迭代?

sysfsksysfs.c 的发展是与Linux设备模型紧密相连的。

  • 诞生(2.5/2.6内核)sysfs作为新设备模型的一部分被引入,最初名为driverfsksysfs.c从一开始就奠定了其核心设计:将kobject(内核对象)映射为目录,将attribute(属性)映射为文件。
  • kobject模型的成熟sysfs的成功完全建立在kobject之上。kobjectksetktype这套机制的发展,使得内核中任何对象都能方便地在sysfs中获得一个表示。
  • 符号链接(Symbolic Links)的广泛使用:这是一个关键的里程碑。sysfs不仅仅是表示父子关系。它通过符号链接来表示更复杂的关系,例如,一个位于/sys/devices下的设备目录,会通过符号链接指向它所属的总线、驱动程序、子系统等,从而将整个设备模型的关系网络清晰地展现出来。
  • 与uevent的集成ksysfs.c在创建或删除目录/文件时,会生成uevent(内核事件),通过netlink socket广播给用户空间。这是现代Linux热插拔和设备管理(udev)的基石。
目前该技术的社区活跃度和主流应用情况如何?

ksysfs.c是内核最基础、最稳定的部分之一。其核心架构已经非常成熟。社区的活跃度主要体现在:

  • 修复在并发或极端情况下可能出现的细微bug。
  • 进行性能优化,如减少锁竞争、优化路径查找。
  • 配合新的内核子系统,确保它们能够正确、安全地通过sysfs导出其对象。

sysfs是所有现代Linux系统的基础,其应用无处不在:

  • udev/systemd-udevdsysfs的主要消费者,负责设备的动态管理。
  • 电源管理工具:通过读写/sys/class/power_supply//sys/devices/system/cpu/下的文件来监控和控制电源状态。
  • 容器技术cgroups(控制组)通常被挂载为一个类似sysfs的文件系统,用于资源隔离和管理。
  • 系统监控和调优工具

核心原理与设计

它的核心工作原理是什么?

ksysfs.c的核心原理是将内核中的**kobject层次结构翻译成sysfs中的目录和文件结构**。

  1. kobject是基石kobject是内核中用于表示对象的一个嵌入式结构体。它本身不做什么,但提供了引用计数、父子关系指针和一个名字。任何希望在sysfs中出现的内核对象(如struct device, struct bus_type)都必须内嵌一个kobject
  2. kobject -> 目录:当一个kobject通过kobject_add()被添加到内核对象体系中时,kobject_add()会调用ksysfs.c中的sysfs_create_dir_ns()函数。此函数会在sysfs这个内存文件系统中创建一个以kobject的名字命名的目录
  3. attribute -> 文件:每个kobject都关联着一个类型(ktype),这个ktype定义了一组默认的属性(attributes)。每个属性由struct attribute描述,包含一个名字和文件权限。更重要的是,它关联着两个函数指针:
    • show(kobject, attribute, buffer):当用户空间读取此属性文件时,ksysfs.c提供的通用文件操作会最终调用这个函数。驱动开发者在此函数中将内核数据格式化成字符串放入buffer
    • store(kobject, attribute, buffer, size):当用户空间写入此属性文件时,会调用这个函数。驱动开发者在此函数中解析buffer中的字符串,并用它来修改内核中的参数。
  4. 文件创建流程:在sysfs_create_dir_ns()之后,内核会遍历与该kobject关联的所有属性,并为每个属性调用sysfs_create_file()。这个函数在刚刚创建的目录下创建一个以属性名命名的文件,并将其文件操作(file_operations)指向ksysfs.c中预定义的通用read/write实现。
  5. 用户空间交互:当用户cat /sys/.../attribute_file时:
    • VFS(虚拟文件系统)层调用sysfs的文件read操作。
    • sysfsread操作从文件路径中找到对应的kobjectattribute
    • 调用该attributeshow()方法,将结果返回给用户。
它的主要优势体现在哪些方面?
  • 结构清晰:严格的“一个对象一个目录”和“一个属性一个文件”的规则,使得sysfs的结构与内核对象模型完全对应。
  • 高度解耦:设备驱动开发者只需要定义好自己的kobjectattributeshow/store函数),而完全无需关心VFS、文件系统实现等复杂细节。
  • 动态性:与kobject的生命周期管理紧密绑定,kobject被创建,目录就出现;kobject被销毁,目录就消失。完美支持热插拔。
它存在哪些已知的劣势、局限性或在特定场景下的不适用性?
  • “一个值一个文件”的开销:这个设计哲学虽然简单,但在需要导出大量数据时效率低下。获取100个值需要进行100次open/read/close系统调用。
  • 不适合流式数据和事件sysfs是为表示**状态(state)属性(attributes)**而设计的。它不适合传输流式数据(如音频流)或发送连续的事件通知(应使用netlink或字符设备)。
  • ABI稳定性负担:一旦一个属性被加入sysfs,它就成为了内核对用户空间的ABI的一部分。移除或修改它会破坏用户空间程序,因此内核开发者对此非常谨慎,导致sysfs中可能存在一些过时的接口。

使用场景

在哪些具体的业务或技术场景下,它是首选解决方案?

ksysfs.c是内核内部的实现,驱动开发者直接与之交互的是kobjectsysfs_* API。这些API是以下场景的首选:

  • 设备驱动模型集成:任何标准的设备驱动(块设备、网络设备、USB设备等)都必须通过设备模型注册,其struct device中内嵌的kobject会自动被ksysfs.c处理,在/sys/devices下创建目录。
  • 导出可调参数:当驱动需要向用户空间暴露一个可配置的参数时(例如,块设备的I/O调度器、网络接口的MTU),sysfs属性是标准的实现方式。
  • 展示设备状态:向用户空间展示不常变动的设备状态或统计信息(例如,电池电量、风扇转速、网卡收发包统计)。
是否有不推荐使用该技术的场景?为什么?
  • 大量、复杂的数据交换:如果需要一次性向用户空间传递一个大的、复杂的C结构体,或者进行RPC式的复杂交互,应该创建一个字符设备并实现ioctl
  • 开发者调试信息:对于不稳定的、仅用于内核开发者调试的内部状态信息,应该使用debugfsdebugfs没有任何ABI稳定性保证,可以随意修改。
  • 进程相关信息:与进程强相关的信息,其传统和正确的归属地是procfs(例如/proc/<pid>/)。

对比分析

请将其 与 其他相似技术 进行详细对比。
特性Sysfs (ksysfs.c)Procfs (/proc)Debugfsioctl on Char Device
主要用途结构化的内核对象模型视图,特别是设备模型。提供稳定的ABI。进程信息系统状态/统计的混合体。内核开发者调试无ABI保证与特定设备进行双向I/O通信和控制
接口稳定性稳定ABI。一旦添加,极难移除或更改。混合。/proc/<pid>部分稳定,其他部分是历史遗留,新接口不推荐在此添加。完全不稳定。可以随时更改,用户空间程序不应依赖它。稳定ABIioctl命令集一旦定义,就不应改变。
数据模型一个值一个文件。数据是简单的文本字符串。格式化的文本文件。一个文件可能包含多行多列的结构化文本。任意。可以是二进制blob,也可以是文本。二进制命令/数据结构。通过命令码区分操作。
典型场景查看/修改设备参数(/sys/class/net/eth0/mtu),udev集成。ps, top, free, 查看/proc/meminfo, /proc/cpuinfo查看驱动内部数据结构、手动触发调试功能。配置硬件、发送/接收数据块、执行复杂操作(如刷新固件)。

历史与背景

这项技术是为了解决什么特定问题而诞生的?

kernel/ksysfs.c 是实现 sysfs 文件系统的核心。sysfs 的诞生是为了解决在它之前的 /proc 文件系统所面临的结构混乱信息冗余问题,并为Linux 2.6内核中引入的全新**统一设备模型(Unified Device Model)**提供一个干净、结构化的视图。

ksysfs.c 旨在解决以下核心问题:

  • 反映内核内部结构:内核的设备模型是一个层次化的树状结构(设备连接在总线上,驱动绑定到设备上)。需要一种机制能将这种内在的、面向对象的层次关系精确地反映到用户空间的文件系统中。
  • 提供稳定的ABI:用户空间工具(最著名的是udev)需要一个稳定、可预测的接口来发现设备、查询其属性并响应设备的热插拔事件。/proc 中杂乱无章的文件和格式使得这项工作非常脆弱。
  • 机制与策略分离ksysfs.c 提供“机制”,即创建目录和属性文件来代表设备。而“策略”(例如,根据这些信息创建 /dev 节点、加载固件)则完全交给用户空间的udev等工具来完成。
  • 设备属性的可调谐性:提供一个简单的、基于文件的接口(读文件获取属性,写文件修改属性),用于查看和调整设备参数。
它的发展经历了哪些重要的里程碑或版本迭代?

sysfsksysfs.c 的发展是与Linux设备模型紧密相连的。

  • 诞生(2.5/2.6内核)sysfs作为新设备模型的一部分被引入,最初名为driverfsksysfs.c从一开始就奠定了其核心设计:将kobject(内核对象)映射为目录,将attribute(属性)映射为文件。
  • kobject模型的成熟sysfs的成功完全建立在kobject之上。kobjectksetktype这套机制的发展,使得内核中任何对象都能方便地在sysfs中获得一个表示。
  • 符号链接(Symbolic Links)的广泛使用:这是一个关键的里程碑。sysfs不仅仅是表示父子关系。它通过符号链接来表示更复杂的关系,例如,一个位于/sys/devices下的设备目录,会通过符号链接指向它所属的总线、驱动程序、子系统等,从而将整个设备模型的关系网络清晰地展现出来。
  • 与uevent的集成ksysfs.c在创建或删除目录/文件时,会生成uevent(内核事件),通过netlink socket广播给用户空间。这是现代Linux热插拔和设备管理(udev)的基石。
目前该技术的社区活跃度和主流应用情况如何?

ksysfs.c是内核最基础、最稳定的部分之一。其核心架构已经非常成熟。社区的活跃度主要体现在:

  • 修复在并发或极端情况下可能出现的细微bug。
  • 进行性能优化,如减少锁竞争、优化路径查找。
  • 配合新的内核子系统,确保它们能够正确、安全地通过sysfs导出其对象。

sysfs是所有现代Linux系统的基础,其应用无处不在:

  • udev/systemd-udevdsysfs的主要消费者,负责设备的动态管理。
  • 电源管理工具:通过读写/sys/class/power_supply//sys/devices/system/cpu/下的文件来监控和控制电源状态。
  • 容器技术cgroups(控制组)通常被挂载为一个类似sysfs的文件系统,用于资源隔离和管理。
  • 系统监控和调优工具

核心原理与设计

它的核心工作原理是什么?

ksysfs.c的核心原理是将内核中的**kobject层次结构翻译成sysfs中的目录和文件结构**。

  1. kobject是基石kobject是内核中用于表示对象的一个嵌入式结构体。它本身不做什么,但提供了引用计数、父子关系指针和一个名字。任何希望在sysfs中出现的内核对象(如struct device, struct bus_type)都必须内嵌一个kobject
  2. kobject -> 目录:当一个kobject通过kobject_add()被添加到内核对象体系中时,kobject_add()会调用ksysfs.c中的sysfs_create_dir_ns()函数。此函数会在sysfs这个内存文件系统中创建一个以kobject的名字命名的目录
  3. attribute -> 文件:每个kobject都关联着一个类型(ktype),这个ktype定义了一组默认的属性(attributes)。每个属性由struct attribute描述,包含一个名字和文件权限。更重要的是,它关联着两个函数指针:
    • show(kobject, attribute, buffer):当用户空间读取此属性文件时,ksysfs.c提供的通用文件操作会最终调用这个函数。驱动开发者在此函数中将内核数据格式化成字符串放入buffer
    • store(kobject, attribute, buffer, size):当用户空间写入此属性文件时,会调用这个函数。驱动开发者在此函数中解析buffer中的字符串,并用它来修改内核中的参数。
  4. 文件创建流程:在sysfs_create_dir_ns()之后,内核会遍历与该kobject关联的所有属性,并为每个属性调用sysfs_create_file()。这个函数在刚刚创建的目录下创建一个以属性名命名的文件,并将其文件操作(file_operations)指向ksysfs.c中预定义的通用read/write实现。
  5. 用户空间交互:当用户cat /sys/.../attribute_file时:
    • VFS(虚拟文件系统)层调用sysfs的文件read操作。
    • sysfsread操作从文件路径中找到对应的kobjectattribute
    • 调用该attributeshow()方法,将结果返回给用户。
它的主要优势体现在哪些方面?
  • 结构清晰:严格的“一个对象一个目录”和“一个属性一个文件”的规则,使得sysfs的结构与内核对象模型完全对应。
  • 高度解耦:设备驱动开发者只需要定义好自己的kobjectattributeshow/store函数),而完全无需关心VFS、文件系统实现等复杂细节。
  • 动态性:与kobject的生命周期管理紧密绑定,kobject被创建,目录就出现;kobject被销毁,目录就消失。完美支持热插拔。
它存在哪些已知的劣势、局限性或在特定场景下的不适用性?
  • “一个值一个文件”的开销:这个设计哲学虽然简单,但在需要导出大量数据时效率低下。获取100个值需要进行100次open/read/close系统调用。
  • 不适合流式数据和事件sysfs是为表示**状态(state)属性(attributes)**而设计的。它不适合传输流式数据(如音频流)或发送连续的事件通知(应使用netlink或字符设备)。
  • ABI稳定性负担:一旦一个属性被加入sysfs,它就成为了内核对用户空间的ABI的一部分。移除或修改它会破坏用户空间程序,因此内核开发者对此非常谨慎,导致sysfs中可能存在一些过时的接口。

使用场景

在哪些具体的业务或技术场景下,它是首选解决方案?

ksysfs.c是内核内部的实现,驱动开发者直接与之交互的是kobjectsysfs_* API。这些API是以下场景的首选:

  • 设备驱动模型集成:任何标准的设备驱动(块设备、网络设备、USB设备等)都必须通过设备模型注册,其struct device中内嵌的kobject会自动被ksysfs.c处理,在/sys/devices下创建目录。
  • 导出可调参数:当驱动需要向用户空间暴露一个可配置的参数时(例如,块设备的I/O调度器、网络接口的MTU),sysfs属性是标准的实现方式。
  • 展示设备状态:向用户空间展示不常变动的设备状态或统计信息(例如,电池电量、风扇转速、网卡收发包统计)。
是否有不推荐使用该技术的场景?为什么?
  • 大量、复杂的数据交换:如果需要一次性向用户空间传递一个大的、复杂的C结构体,或者进行RPC式的复杂交互,应该创建一个字符设备并实现ioctl
  • 开发者调试信息:对于不稳定的、仅用于内核开发者调试的内部状态信息,应该使用debugfsdebugfs没有任何ABI稳定性保证,可以随意修改。
  • 进程相关信息:与进程强相关的信息,其传统和正确的归属地是procfs(例如/proc/<pid>/)。

对比分析

请将其 与 其他相似技术 进行详细对比。
特性Sysfs (ksysfs.c)Procfs (/proc)Debugfsioctl on Char Device
主要用途结构化的内核对象模型视图,特别是设备模型。提供稳定的ABI。进程信息系统状态/统计的混合体。内核开发者调试无ABI保证与特定设备进行双向I/O通信和控制
接口稳定性稳定ABI。一旦添加,极难移除或更改。混合。/proc/<pid>部分稳定,其他部分是历史遗留,新接口不推荐在此添加。完全不稳定。可以随时更改,用户空间程序不应依赖它。稳定ABIioctl命令集一旦定义,就不应改变。
数据模型一个值一个文件。数据是简单的文本字符串。格式化的文本文件。一个文件可能包含多行多列的结构化文本。任意。可以是二进制blob,也可以是文本。二进制命令/数据结构。通过命令码区分操作。
典型场景查看/修改设备参数(/sys/class/net/eth0/mtu),udev集成。ps, top, free, 查看/proc/meminfo, /proc/cpuinfo查看驱动内部数据结构、手动触发调试功能。配置硬件、发送/接收数据块、执行复杂操作(如刷新固件)。

rcu_expedited: 控制RCU宽限期加急处理的sysfs接口

此代码片段的作用是在 sysfs 中创建一个名为 rcu_expedited 的可读写文件 (/sys/kernel/rcu_expedited), 用于查询和控制RCU (Read-Copy-Update) 的宽限期 (Grace Period) 是否采用 “加急” (expedited) 模式。用户或脚本可以通过读写此文件来动态调整RCU的行为。

RCU是一种内核同步机制, 它允许在不加锁的情况下进行数据读取, 而更新操作则通过创建数据副本、修改副本、然后等待所有已有的读取操作完成后再用新副本替换旧副本来实现。这个等待所有已有读取方完成的阶段被称为"宽限期"。

  • 普通宽限期: 以较低的系统开销为代价, 等待宽限期自然结束。
  • 加急宽限期: 通过更积极的手段 (例如在其它CPU上强制调度) 来尽快结束宽限期, 但会带来更高的系统抖动和性能开销。

在单核抢占式内核中, 宽限期意味着需要等待所有可能在RCU读端临界区内被抢占的任务都经过一个"静止状态" (quiescent state, 例如上下文切换)。启用加急模式可能会更频繁地触发调度器, 以便更快地让这些被抢占的任务执行并退出其RCU临界区。

/** 定义一个整型全局变量 rcu_expedited.* 这个变量是一个标志位, 用于控制RCU宽限期的行为.* 当它的值为 0 时, 内核使用标准的、低开销的RCU宽限期.* 当它的值非 0 时, 内核会触发 "加急" 的RCU宽限期, 这会以更高的系统开销为代价来缩短宽限期的等待时间.*/
int rcu_expedited;
/** rcu_expedited_show: 'rcu_expedited' sysfs 文件的读操作处理函数.* 当用户空间程序执行 'cat /sys/kernel/rcu_expedited' 命令时, 内核会调用此函数.** @kobj:  指向被读取属性所属的kobject的指针, 在这里是 kernel_kobj (/sys/kernel).* @attr:  指向被读取属性的描述符结构体的指针, 在这里是 kobj_attr_rcu_expedited.* @buf:   一个指向用户空间提供的缓冲区的指针, 函数的输出需要写入到这个缓冲区中.* @return: 返回成功写入缓冲区的字节数, 或者一个负值的错误码.*/
static ssize_t rcu_expedited_show(struct kobject *kobj,struct kobj_attribute *attr, char *buf)
{/** 调用 sysfs_emit 函数来安全地格式化字符串并将其写入用户缓冲区 buf.* 这是一个替代 snprintf 的推荐方法, 能更好地处理 sysfs 缓冲区的边界.* @ buf: 目标缓冲区.* @ "%d\n": 格式化字符串, 表示将一个整数以十进制形式输出, 并附加一个换行符.* @ READ_ONCE(rcu_expedited): 这是读取 rcu_expedited 全局变量值的操作.*   READ_ONCE 是一个特殊的宏, 它确保对变量的读取是一个原子操作.*   它会阻止编译器进行可能导致多次读取或读取到陈旧值的优化,*   保证了即使在有并发访问(例如在抢占式单核系统上被其他任务修改)的情况下, 也能获取到该变量在某个时间点的确切值.*/return sysfs_emit(buf, "%d\n", READ_ONCE(rcu_expedited));
}
/** rcu_expedited_store: 'rcu_expedited' sysfs 文件的写操作处理函数.* 当用户空间执行 'echo "1" > /sys/kernel/rcu_expedited' 命令时, 内核会调用此函数.** @kobj:  同上, 指向 /sys/kernel 对应的 kobject.* @attr:  同上, 指向属性的描述符.* @buf:   一个指向用户写入的数据的缓冲区的指针.* @count: 写入数据的字节数.* @return: 返回已成功处理的字节数, 或者一个负值的错误码.*/
static ssize_t rcu_expedited_store(struct kobject *kobj,struct kobj_attribute *attr,const char *buf, size_t count)
{/** 调用 kstrtoint 函数, 尝试将用户传入的字符串 buf 转换为一个整型数,* 并将结果直接存入 rcu_expedited 全局变量.* @ buf: 输入的字符串.* @ 0:   表示基数, 0 意味着函数会自动检测是十进制、八进制还是十六进制.* @ &rcu_expedited: 指向目标整型变量的指针.* 如果转换失败 (例如, 用户输入了 "hello" 这样的非数字字符串), kstrtoint 会返回一个非零的错误码.*/if (kstrtoint(buf, 0, &rcu_expedited))/** 如果转换失败, 就向用户空间返回 -EINVAL (无效参数) 错误.*/return -EINVAL;/** 如果转换成功, 就返回已处理的字节数 count.* 这是向 sysfs 子系统表明写操作成功完成的标准方式.*/return count;
}
/** KERNEL_ATTR_RW 是一个辅助宏, 用于快速定义一个可读写的(RW)内核属性.* 它会展开成一个名为 'kobj_attr_rcu_expedited' 的 static struct kobj_attribute 实例,* 并自动将其 .show 回调设置为 rcu_expedited_show, .store 回调设置为 rcu_expedited_store,* 同时设置文件的权限为 0644 (拥有者可读写, 组用户和其他用户只读).*/
KERNEL_ATTR_RW(rcu_expedited);

ksysfs_init: 创建 /sys/kernel/ 目录及其文件

此函数在内核初始化期间被调用, 其核心职责是在sysfs虚拟文件系统中创建顶层的 /sys/kernel 目录。这个目录作为一个命名空间, 用于向用户空间导出各种内核全局参数、状态信息和控制开关。通过读写该目录下的文件, 用户空间程序或管理员可以查询和调整内核的行为。

/** 此部分代码用于创建一个名为 'notes' 的二进制属性文件,* 其内容直接对应内核镜像中 .notes ELF 段的原始数据.* ELF notes 段通常包含一些元数据, 例如由编译器或构建系统添加的版本信息.*//** extern 声明了两个由链接器脚本定义的符号: __start_notes 和 __stop_notes.* 它们分别标记了内核 .notes 段在内存中的起始和结束地址.* 'const void' 表明这些地址指向的是只读的、类型未知的数据.*/
extern const void __start_notes;
extern const void __stop_notes;
/** 定义一个宏 notes_size, 用于计算 .notes 段的大小.* 这是通过对结束地址和起始地址进行指针运算来实现的.* 结果是这两个地址之间的字节差.*/
#define	notes_size (&__stop_notes - &__start_notes)
/** BIN_ATTR_SIMPLE_RO 是一个辅助宏, 用于快速定义一个只读的二进制 sysfs 属性.* 它会创建一个名为 bin_attr_notes 的静态结构体, 用于描述 'notes' 这个二进制文件.* __ro_after_init 是一个编译器属性, 它告诉编译器这个结构体的数据在内核初始化之后是只读的,* 这有助于进行优化和安全检查.*/
static __ro_after_init BIN_ATTR_SIMPLE_RO(notes);/** 定义一个全局的 struct kobject 指针, kernel_kobj.* 这个 kobject 将代表 sysfs 中的 /sys/kernel 目录.* 它是许多内核全局属性的父对象.*/
struct kobject *kernel_kobj;
/** EXPORT_SYMBOL_GPL 将 kernel_kobj 这个符号导出, 使得其他GPL许可证的内核模块可以使用它.* 这允许其他模块在 /sys/kernel 目录下创建它们自己的 sysfs 文件或目录.*/
EXPORT_SYMBOL_GPL(kernel_kobj);/** 定义一个静态的 struct attribute 指针数组.* 这个数组列出了所有将被创建在 /sys/kernel 目录下的文件的属性.*/
static struct attribute * kernel_attrs[] = {/* fscaps_attr 是与文件能力(File Capabilities)相关的属性. */&fscaps_attr.attr,/* uevent_seqnum_attr 是uevent事件的序列号. */&uevent_seqnum_attr.attr,/* cpu_byteorder_attr 显示CPU的字节序(如: little-endian). 对于STM32H750, 这将是小端序. */&cpu_byteorder_attr.attr,/* address_bits_attr 显示CPU的地址总线宽度. 对于ARMv7M架构, 这将是32位. */&address_bits_attr.attr,
/** #ifdef 是一个预处理指令, 下面的属性只有在定义了相应的宏时才会被编译和创建.* 这使得内核可以根据配置进行裁剪, 移除不需要的功能.*/
#ifdef CONFIG_UEVENT_HELPER/* 仅当配置了uevent助手(CONFIG_UEVENT_HELPER)时, 才创建此文件, 用于显示和设置uevent辅助程序路径. */&uevent_helper_attr.attr,
#endif
#ifdef CONFIG_PROFILING/* 仅当内核编译时启用了性能剖析(CONFIG_PROFILING)选项时, 此属性才会被包含, 用于控制内核剖析. */&profiling_attr.attr,
#endif
#ifdef CONFIG_KEXEC_CORE/* 仅当配置了kexec(CONFIG_KEXEC_CORE)时, 才创建此文件, 用于表示是否已加载一个新的内核准备执行. */&kexec_loaded_attr.attr,
#ifdef CONFIG_CRASH_DUMP/* kexec_crash_loaded_attr 表示是否已加载用于崩溃转储的内核. */&kexec_crash_loaded_attr.attr,/* kexec_crash_size_attr 表示为崩溃转储内核预留的内存大小. */&kexec_crash_size_attr.attr,
#endif
#endif
#ifdef CONFIG_VMCORE_INFO/* 仅当配置了VMCORE_INFO时创建, 用于保存崩溃转储(crash dump)所需的vmcore信息的位置和大小. */&vmcoreinfo_attr.attr,
#ifdef CONFIG_CRASH_HOTPLUG/* crash_elfcorehdr_size_attr 表示崩溃时ELF核心头的大小. */&crash_elfcorehdr_size_attr.attr,
#endif
#endif
#ifndef CONFIG_TINY_RCU/** 仅当没有使用TINY_RCU时, 才创建这两个文件.* 在像STM32这样的单核系统上, 通常会启用 CONFIG_TINY_RCU 这一简化实现,* 因此在这种情况下, 这两个用于控制标准RCU行为的属性将不会被创建.*/&rcu_expedited_attr.attr,&rcu_normal_attr.attr,
#endif/* 数组必须以 NULL 结尾, 作为结束的标记. */NULL
};/** 定义一个静态的、常量属性组结构体 kernel_attr_group.* 它将上面定义的 kernel_attrs 数组包装起来.*/
static const struct attribute_group kernel_attr_group = {/* .attrs 成员指向属性指针数组. */.attrs = kernel_attrs,
};/** ksysfs_init: /sys/kernel 的初始化函数.* 标记为 __init, 表示它仅在内核初始化期间执行, 其占用的内存之后可以被回收.*/
static int __init ksysfs_init(void)
{/* 定义一个整型变量 error, 用于存储错误码. */int error;/** 调用 kobject_create_and_add 函数来创建并注册一个新的 kobject.* @ "kernel": 新创建的 kobject 的名字, 这将成为 sysfs 中的目录名.* @ NULL: 父 kobject 指针. 因为这是在 /sys/ 下的顶级目录之一, 所以没有父 kobject.* 创建的 kobject 地址被赋值给全局指针 kernel_kobj.*/kernel_kobj = kobject_create_and_add("kernel", NULL);/* 检查 kobject 是否创建成功. 如果失败(通常因为内存不足), kernel_kobj 会是 NULL. */if (!kernel_kobj) {/* 将错误码设置为 -ENOMEM (内存不足). */error = -ENOMEM;/* 跳转到 exit 标签进行错误处理. */goto exit;}/** 调用 sysfs_create_group 在 kernel_kobj 代表的目录下创建一组属性文件.* @ kernel_kobj: 父 kobject, 即 /sys/kernel 目录.* @ &kernel_attr_group: 包含所有要创建的文件的属性组.* 如果创建成功, 返回0, 否则返回一个负的错误码.*/error = sysfs_create_group(kernel_kobj, &kernel_attr_group);/* 检查文件组是否创建成功. */if (error)/* 如果失败, 跳转到 kset_exit 标签, 以便清理已创建的 kobject. */goto kset_exit;/* 检查 .notes 段的大小是否大于0, 即该段是否存在且不为空. */if (notes_size > 0) {/** 设置 'notes' 二进制属性的私有数据指针, 让它指向 .notes 段的起始地址.* sysfs 在被读取时会使用这个指针来找到数据源.*/bin_attr_notes.private = (void *)&__start_notes;/** 设置 'notes' 二进制属性的大小.*/bin_attr_notes.size = notes_size;/** 调用 sysfs_create_bin_file 在 /sys/kernel 目录下创建 'notes' 这个二进制文件.* @ kernel_kobj: 父 kobject.* @ &bin_attr_notes: 要创建的二进制文件的属性描述符.*/error = sysfs_create_bin_file(kernel_kobj, &bin_attr_notes);/* 检查二进制文件是否创建成功. */if (error)/* 如果失败, 跳转到 group_exit 标签, 以便清理已创建的属性组. */goto group_exit;}/* 所有操作均成功, 返回0. */return 0;/** 下面是错误处理的 goto 标签, 用于在初始化失败时按相反的顺序清理已分配的资源.*/
group_exit:/* 如果二进制文件创建失败, 就移除之前成功创建的属性文件组. */sysfs_remove_group(kernel_kobj, &kernel_attr_group);
kset_exit:/* 如果属性组创建失败, 就释放并注销之前创建的 kobject. */kobject_put(kernel_kobj);
exit:/* 返回最终的错误码. */return error;
}/** core_initcall 是一个宏, 它将 ksysfs_init 函数注册为一个核心初始化函数.* 这确保了 /sys/kernel 的创建会在内核启动过程中较早地发生.*/
core_initcall(ksysfs_init);
http://www.dtcms.com/a/601482.html

相关文章:

  • 庆阳市建设局网站怎么设置iis默认网站
  • 前端安全展示后端纯文本接口数据的实践:不解析、不危险渲染的结构化方案
  • 【2024年莆田市校园创客节(小学组)初赛】泡泡堂
  • 河南省网站建设电脑网页
  • Doc-Researcher: 多模态文档深度研究系统的技术解析
  • E3Docker,一键解锁E3连接酶配体发现新纪元!
  • 【AI智能体】Coze 基于关键词生成古诗词 + 配图智能体操作详解
  • 百日挑战——单词篇(第二十天)
  • Vue 3组合式API中ref与reactive的核心响应式差异及使用最佳实践是什么?
  • 创意网站推荐智能手机网站模板
  • JAVA学习笔记——集合的概念和习题
  • 商城网站开发方案书导购类网站备案
  • leetcode 290. 单词规律 python
  • D037 vue+django三国演义知识图谱可视化系统
  • 连接一个新的服务器时,打开PyCharm时报错:报错内容是服务器磁盘或配额满了
  • 传媒有限公司免费网站武安市精品网站开发
  • 如何从多源业务表对商家进行综合评估?
  • DELMIA Role: RFE - Operations Experience Manager
  • 灭屏使用对讲,概率性出现无声
  • 问答系统网站模板天津建设工程交易信息网
  • GitHub 热榜项目 - 日榜(2025-11-12)
  • 继续访问这个网站字体安装wordpress
  • Java 进阶:反射机制深度解析
  • 如何开发高性能直播美颜sdk?人脸检测、美型算法与渲染优化详解
  • StreamAPI,取出list中的name属性,返回一个新list
  • SSM基于web的佳茗天香茶品销售平台的设计与实现z2m56(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 请别人做网站需要注意什么问题公司做网站怎么做账
  • 茂名网站制作策划如何查看用wordpress建的站点
  • 【湿地数据集4】基于 TOPMODEL模型的1980–2020年全球湿地动态数据集 GWDD
  • C++重点知识梳理(下)