宜兰县网站建设_网站建设公司_JavaScript_seo优化
2026/1/10 19:54:08 网站建设 项目流程

Linux 设备模型与 sysfs 机制深度分析

前言

本文档基于 Linux 内核源码(RK3588 平台),系统梳理 Linux 设备模型的核心机制,重点讲解kobject、kset、ktype以及sysfs 文件系统的工作原理。内容面向初学者,结合源码示例和流程图,帮助理解内核如何通过/sys暴露设备属性。


目录

  1. 概述
  2. kobject 机制
  3. kset 机制
  4. kobj_type 机制
  5. sysfs 文件系统
  6. 设备属性暴露机制
  7. 完整示例

1. 概述

1.1 为什么需要设备模型?

Linux 设备模型是为了解决以下问题:

  • 统一管理:所有设备(CPU、内存、外设)用统一的数据结构表示
  • 层次组织:设备之间有父子关系(如 PCI 总线下的设备)
  • 用户空间可见:通过/sys暴露设备信息和配置接口
  • 热插拔支持:设备动态添加/删除时自动通知用户空间
  • 电源管理:统一的设备电源状态管理

1.2 核心组件关系图

┌─────────────────────────────────────────────────────────────┐ │ Linux 设备模型架构 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ kobject │────▶│ kset │────▶│ ktype │ │ │ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ │ │ │ │ 内嵌 │ 包含 │ 描述 │ │ ▼ ▼ ▼ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ device │ │bus_type │ │sysfs_ops│ │ │ └─────────┘ └─────────┘ └─────────┘ │ │ │ │ │ │ │ └───────────────┴───────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────┐ │ │ │ sysfs │ │ │ │ (/sys 文件) │ │ │ └─────────────────┘ │ └─────────────────────────────────────────────────────────────┘

关系说明

  • kobject是所有设备对象的基础结构
  • ksetkobject集合,提供统一的 uevent 处理
  • ktype定义kobject行为(如何释放、如何处理属性)
  • devicekobject扩展,代表实际设备
  • sysfskobject树暴露到用户空间

2. kobject 机制

2.1 kobject 结构定义

文件位置:kernel/include/linux/kobject.h:65-86

structkobject{constchar*name;// 对象名称(对应 sysfs 目录名)structlist_headentry;// 链表节点(用于加入 kset)structkobject*parent;// 父对象(形成层次结构)structkset*kset;// 所属的 ksetstructkobj_type*ktype;// 对象类型(定义行为)structkernfs_node*sd;// sysfs 目录项指针structkrefkref;// 引用计数// 状态标志位unsignedintstate_initialized:1;// 是否已初始化unsignedintstate_in_sysfs:1;// 是否已在 sysfs 中unsignedintstate_add_uevent_sent:1;// 是否已发送 ADD 事件unsignedintstate_remove_uevent_sent:1;// 是否已发送 REMOVE 事件unsignedintuevent_suppress:1;// 是否抑制 uevent};

字段详解

字段作用类比
name对象名称文件名
parent父对象父目录
kset所属集合文件夹分组
ktype类型描述文件类型定义
sdsysfs 目录项实际的目录 inode
kref引用计数使用计数

2.2 kobject 生命周期

流程图

┌──────────────┐ │ 定义 kobject │ └──────┬───────┘ │ ▼ ┌──────────────┐ │kobject_init()│ ◀── 必须先初始化 │ 设置 ktype │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ kobject_add() │ ◀── 添加到层次结构 │ 创建 sysfs │ └──────┬───────┘ │ ┌──────┴───────┐ │ │ ▼ ▼ ┌───────────┐ ┌───────────┐ │正常使用期间 │ │ 引用计数 │ │ 通过 get/put│ │ 管理 │ └─────┬─────┘ └─────┬─────┘ │ │ └───────┬───────┘ │ ▼ ┌──────────────┐ │kobject_put() │ ◀── 引用计数归零 │ 调用 release │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ 自动释放 │ │ (由 ktype │ │ 的 release) │ └──────────────┘

2.3 核心函数源码分析

2.3.1 kobject_init()

文件位置:kernel/lib/kobject.c:349-376

voidkobject_init(structkobject*kobj,structkobj_type*ktype){if(!kobj){pr_err("invalid kobject pointer!\n");return;}if(!ktype){pr_err("must have a ktype!\n");return;}if(kobj->state_initialized){pr_err("tried to init an initialized object!\n");dump_stack();}// 1. 初始化引用计数kobject_init_internal(kobj);// kref_init(&kobj->kref)// 2. 关联类型kobj->ktype=ktype;}

要点

  • 必须提供ktype,定义了对象的行为
  • 初始化引用计数为 1
  • 不能重复初始化
2.3.2 kobject_add()

文件位置:kernel/lib/kobject.c:426-447

intkobject_add(structkobject*kobj,structkobject*parent,constchar*fmt,...){if(!kobj->state_initialized){pr_err("tried to add an uninitialized object!\n");return-EINVAL;}// 设置名称(支持 printf 格式)va_start(args,fmt);retval=kobject_set_name_vargs(kobj,fmt,args);va_end(args);// 内部添加逻辑returnkobject_add_internal(kobj);}

内部添加流程(kobject_add_internal):

staticintkobject_add_internal(structkobject*kobj){structkobject*parent=kobj->parent;// 1. 如果有 kset,加入 kset 的链表if(kobj->kset){if(!parent)parent=&kobj->kset->kobj;// 用 kset 的 kobject 作为父对象kobj_kset_join(kobj);// 加入 kset->list}// 2. 创建 sysfs 目录error=create_dir(kobj);// sysfs_create_dir_ns()if(error)gotoerr_out;// 3. 标记已加入 sysfskobj->state_in_sysfs=1;return0;}
2.3.3 kobject_put()

文件位置:kernel/lib/kobject.c:746-756

voidkobject_put(structkobject*kobj){if(kobj){if(!kobj->state_initialized)WARN(1,"kobject is not initialized!\n");kref_put(&kobj->kref,kobject_release);// 减少引用计数}}

释放流程

staticvoidkobject_release(structkref*kref){structkobject*kobj=container_of(kref,structkobject,kref);// 1. 如果还在 sysfs 中,先删除if(kobj->state_in_sysfs)__kobject_del(kobj);// 删除 sysfs 目录// 2. 调用 ktype 的 release 函数if(kobj->ktype&&kobj->ktype->release)kobj->ktype->release(kobj);// 3. 释放名称字符串kfree_const(kobj->name);}

2.4 kobject 路径获取

函数kobject_get_path()→ 返回完整路径(如/devices/platform/serial8250

示例

char*path=kobject_get_path(my_kobj,GFP_KERNEL);printk("Path: %s\n",path);// 输出: /sys/devices/...kfree(path);

3. kset 机制

3.1 kset 结构定义

文件位置:kernel/include/linux/kobject.h:203-213

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询