一个初学者对于一个新知识点很难接收和理解,即使文档和视频也很难理解。 这种情况一般各方面原因吧:
- 此知识点相关内容本身自己知道少,是个新的知识点;
- 此知识点关联的基础也不知道,相关阐述说明基础知识点也在自己认知范围外
个人始终认为:基础很重要,千万别囫囵吞枣,不然后面接收起来更难,没法成为自己的知识体系。
文章目录
设备树知识点概要
这里分三部分整理知识点内容:
- 一些目录
/sys/kernel/config/device-tree/overlays//proc/filesystems是做什么的,设备树插件实操演示 - 虚拟文件系统ConfigFS 介绍
- ConfigFS 的核心数据结构
这里整理基础必备知识点目的:打好基础,理解部分核心基础点。
参考资料
Linux驱动开发(速记版)–设备树插件
proc文件系统简介及/proc目录介绍
Linux 下的 /proc 目录介绍
RK3568驱动指南|第八篇 设备树插件-第74章 虚拟文件系统ConfigFS介绍
configfs — 用户空间控制的内核对象配置
备树插件-第75章ConfigFS的核心数据结构
一、 关联目录介绍-device-tree/overlays/ - filesystems
目录 /proc/filesystems 介绍
这里需要了解指令:`cat /proc/filesystems
cat /proc/filesystems 命令用于 列出当前 Linux 内核支持的文件系统类型。
作用如下:
- 显示已注册的文件系统:
输出包含内核编译时支持或运行时动态加载的所有文件系统类型(如 ext4, xfs, btrfs, proc, tmpfs 等)。 - 区分内核原生支持与模块加载的文件系统:
如果一行开头有 nodev,表示该文件系统不需要物理设备(如虚拟文件系统 proc, sysfs, tmpfs)。
没有 nodev 的文件系统(如 ext4)通常需要块设备(如硬盘分区
示例如下:

`这里看到 挂载了一个configfs 文件,并不是所有的Linux 目录挂载了这个configfs , 只有支持了设备数插件功能的kernel 才有这个虚拟文件节点的。
所以在设备树插件相关资料中,开篇都会让 cat /proc/filesystems ,看是否有configfs 节点,目的就是确认你的Linux 内核支持设备树插件的功能。
知识点 configfs
如上获取到的 /proc/filesystems 目录下的 nodev configfs 表示内核支持 configfs 文件系统,并且它是一个 不依赖于物理设备(nodev) 的虚拟文件系统。
configfs 的作用
动态配置内核子系统
-
某些内核模块(如 USB Gadget、SCSI Target、设备树等)允许通过 configfs 动态调整参数,而无需重新加载模块或重启系统。
例如,Android 的 adb(USB 调试)功能就依赖 configfs 来动态切换 USB 模式。 -
替代 sysfs 进行更灵活的对象管理
sysfs(/sys)主要用于展示内核对象(如设备、驱动),而 configfs 允许 用户主动创建和管理对象(类似 “mkdir” 和 “echo” 操作)。 -
常见使用场景
USB Gadget(g_ether, g_mass_storage 等):动态配置 USB 设备模式(如模拟 U 盘、网卡)。
SCSI Target(LIO):iSCSI 或光纤通道存储目标配置。
Android 的 functionfs:配置 USB 功能(如 MTP、PTP、MIDI)。
如何使用 configfs?
configfs 通常挂载在 /sys/kernel/config/(不同发行版可能略有不同),例如如下:

这里我们用之前设备树语法插件里面的.ko 文件来实验下,理解基本使用:

继续看 生产的device-tree目录和该目录下面的子目录的情况:

我们在目录 overlays 目录下 mkdir test 命令,结果如下:在test 目录下面多出了 dtbo 和 status

然后把我们前面写的设备树插件 写入到 dtbo 里面去,同事写入1 到 status 里面去:

见证奇迹的时候: 我们在设备树下面就看到了rk-485-ctl 对应新增的动态节点了。

这里对比一下之前我们写的设备树插件原始内容是什么:Linux驱动-设备树插件语法
/dts-v1/;
/plugin/;
&{/rk-485-ctl}{
overlay_node{
status = "okay";
};
};
那个status 节点不就是动态新增过来的嘛 。我们看看实际这个status 值:

这不就是实际设备树插件里面新增的字段值嘛 。 如果我们修改config 文件系统设备树下面的节点属性值,那么映射到设备树节点下的值也会改变:
/sys/kernel/config/device-tree/overlays/test]# echo 1 > status
/sys/firmware/devicetree/base/rk-485-ctl/overlay_node]# cat status
这样就是实现了修改用户空间的指,映射修改了内核空间设备树的值。
nodev 的含义
- nodev 表示该文件系统 不需要块设备(如硬盘、U 盘),而是纯内存或内核管理的虚拟文件系统(如 procfs、sysfs、tmpfs)。
- 没有 nodev 的文件系统(如 ext4、xfs)需要挂载到实际的存储设备(如 /dev/sda1)
configfs 小结
- configfs 是一个 动态配置内核对象 的虚拟文件系统,主要用于 USB Gadget、SCSI Target 等场景。
- 它在 /proc/filesystems 中标记为 nodev,表示它不依赖物理设备。
- 通常挂载在 /sys/kernel/config/,用户可以通过文件操作(mkdir/echo)动态管理内核配置。
这里通过 device-tree/overlays/ - filesystems 两个目录,了解了设备树插件通过configfs 实现用户空间层修改内核层的逻辑,也初步了解了nodev、挂载相关知识点。
目录 device-tree/overlays 介绍
这个目录是 Linux 设备树(Device Tree)动态覆盖(Overlay)功能的用户空间接口,主要用于在运行时动态修改设备树配置。
功能概述
-
设备树覆盖(Device Tree Overlay):允许在不重新编译内核或重启系统的情况下,动态添加、修改或删除设备树节点和属性。
-
运行时配置:特别适用于嵌入式系统,可以在运行时根据硬件配置变化调整设备树
目录结构和使用
典型的目录结构如下:
/sys/kernel/config/device-tree/overlays/
├── overlay_0/
├── overlay_1/
└── ...
主要操作方式
- 创建新覆盖:
mkdir /sys/kernel/config/device-tree/overlays/my_overlay
- 应用覆盖
# 将设备树blob(.dtbo)写入path属性
cat my_overlay.dtbo > /sys/kernel/config/device-tree/overlays/my_overlay/path
- 检查状态
cat /sys/kernel/config/device-tree/overlays/my_overlay/status
二、虚拟文件系统 ConfigFS
在 Linux 系统中,设备树插件(Device Tree Overlays)选择使用 ConfigFS(Configuration File System,简称 CFS) 作为其虚拟文件系统的原因,主要与 ConfigFS 的设计特性及其在动态设备树管理中的优势有关。以下是详细分析:
ConfigFS 的核心特性
ConfigFS 是一个基于内存的虚拟文件系统,专门用于用户态与内核态的动态配置交互。其核心特点包括:
-
动态对象管理:允许用户态程序通过文件系统接口(创建/删除目录或文件)动态创建、配置和销毁内核对象。
-
与 sysfs 的区别:
sysfs 主要用于展示内核对象的当前状态(如设备信息),通常是只读或有限写入。
configfs 则专注于配置内核对象(如创建设备、加载模块),支持完整的生命周期管理(创建、修改、删除)。
- 事件驱动机制:文件操作(如 mkdir)会直接触发内核中的回调函数,实现配置的实时生效。
设备树插件为何选择 ConfigFS
设备树插件(Overlays)的目的是在运行时动态修改设备树(Device Tree),而 ConfigFS 的设计完美匹配这一需求:
动态加载与卸载
-
传统设备树:需在启动时通过 Bootloader 静态加载,无法运行时修改。
-
设备树插件:通过 ConfigFS 可以动态加载(.dtbo 文件)或卸载,无需重启系统。
示例命令:
mkdir /config/device-tree/overlays/my_overlay # 创建配置节点
cat example.dtbo > /config/device-tree/overlays/my_overlay/dtbo # 加载插件
rmdir /config/device-tree/overlays/my_overlay # 卸载插件
ConfigFS 的 mkdir/rmdir 操作直接对应插件加载/卸载的内核动作。
-
用户态友好接口
ConfigFS 通过标准的文件操作(cat、echo、mkdir)实现配置,无需专用工具或内核模块编程。
用户态工具(如 dtc 编译的 .dtbo)可直接与 ConfigFS 交互,简化开发流程。 -
安全的并发控制
ConfigFS 提供内核级别的锁机制,避免多进程同时修改设备树导致的冲突。 -
与设备树解耦
ConfigFS 作为通用配置框架,不依赖设备树的具体实现。设备树插件仅是其中一种应用场景,未来可扩展其他配置功能。
虚拟文件系统对比
| 文件系统 | 主要用途 | 数据存储 | 动态性 | 典型挂载点 |
|---|---|---|---|---|
| procfs | 进程/内核信息 | 无(动态生成) | 高 | /proc |
| sysfs | 设备/驱动管理 | 无(动态生成) | 高 | /sys |
| devtmpfs | 设备文件管理 | 内存 | 动态创建设备节点 | /dev |
| tmpfs | 临时文件存储 | 内存 | 可读写 | /tmp、/run |
| cgroupfs | 资源限制(cgroups) | 无(配置接口) | 中 | /sys/fs/cgroup |
| debugfs | 内核调试 | 无(动态生成) | 高 | /sys/kernel/debug |
| configfs | 内核对象配置 | 无(动态生成) | 高 | /sys/kernel/config |
三、 ConfigFS 的核心数据结构
这里重点了解ConfigFS 几个结构体,每个结构体是如何关联的,这里给出迅为有个图,方便理解:


核心数据结构
config_group(配置组)
- 作用:表示 ConfigFS 中的一个逻辑分组(目录),可以包含子组或配置项
- 成员:
struct config_group {
struct config_item cg_item; // 继承自 config_item,表示组本身也是一个项
struct list_head cg_children; // 子项(item)链表
struct list_head default_groups; // 默认子组(group)链表
};
- 用途: 设备树插件的根目录 /config/device-tree/overlays/ 就是一个 config_group
config_item(配置项)
- 作用:表示 ConfigFS 中的一个可配置对象(文件或子目录)。
- 成员:
struct config_item {
char *ci_name; // 项的名称(文件名)
struct config_group *ci_group; // 所属的父组
struct list_head ci_entry; // 在父组中的链表节点
struct kref ci_kref; // 引用计数
const struct config_item_type *ci_type; // 项的类型(操作回调)
};
- 用途: 例如,加载一个设备树插件时,会在 /config/device-tree/overlays/ 下创建一个 config_item(如 my_overlay)。
config_item_type(项类型)
- 作用:定义 config_item 的操作回调(如创建、销毁、属性访问)
- 成员:
struct config_item_type {
struct module *ct_owner; // 所属模块
const struct configfs_item_operations *ct_item_ops; // 项操作回调
const struct configfs_group_operations *ct_group_ops; // 组操作回调
struct configfs_attribute **ct_attrs; // 属性(文件)列表
};
- 回调示例:
ct_item_ops->release():当用户态删除项(rmdir)时触发。
ct_attrs:定义可通过文件读写访问的属性(如设备树插件的 dtbo 文件)。
configfs_attribute(属性)
- 作用:表示一个可读写的文件属性。
- 成员:
struct configfs_attribute {
char *ca_name; // 属性文件名(如 `dtbo`)
struct module *ca_owner; // 所属模块
umode_t ca_mode; // 文件权限(如 0644)
};
- **操作:**需实现 show() 和 store() 方法(类似 sysfs 的属性操作)
configfs_subsystem(子系统)
-
**作用:**管理顶级 ConfigFS 组(如 /config/device-tree/)。
-
关键成员:
struct configfs_subsystem {
struct config_group su_group; // 顶级组
struct mutex su_mutex; // 互斥锁(保护并发访问)
};
数据结构的交互流程
用户态操作
mkdir /config/device-tree/overlays/my_overlay
内核响应
- 触发 config_group_operations->make_group(),创建一个新的 config_item。
- 为新项关联 config_item_type,指定其操作回调(如 dtbo 文件的读写)。
加载插件
cat example.dtbo > /config/device-tree/overlays/my_overlay/dtbo
触发 configfs_attribute->store(),将 .dtbo 数据传递给内核解析。
关键设计模式
组合模式(Composite)
-
config_group 可以包含其他 config_item 或 config_group,形成树状结构。
-
例如:/config/device-tree/overlays/ 是组,my_overlay 是项,其下的 dtbo 是属性。
回调驱动
- 所有用户态操作(mkdir/rmdir/read/write)均通过 config_item_type 中的回调函数转发到内核模块。
动态生命周期
- 用户态的 mkdir/rmdir 直接对应内核对象的创建和销毁(通过 kref 引用计数管理)。
代码示例(简化版)
以下是一个简单的 ConfigFS 模块示例,展示如何注册一个组和项:
#include <linux/configfs.h>
static struct configfs_attribute my_attr = {
.ca_name = "value",
.ca_mode = 0644,
.show = my_attr_show, // 实现读回调
.store = my_attr_store, // 实现写回调
};
static struct configfs_attribute *my_attrs[] = {
&my_attr,
NULL,
};
static struct config_item_type my_item_type = {
.ct_attrs = my_attrs,
.ct_owner = THIS_MODULE,
};
static struct config_group my_group = {
.cg_item = {
.ci_name = "my_config",
.ci_type = &my_item_type,
},
};
static struct configfs_subsystem my_subsystem = {
.su_group = my_group,
.su_mutex = __MUTEX_INITIALIZER(my_subsystem.su_mutex),
};
// 注册子系统
configfs_register_subsystem(&my_subsystem);
用户态操作
mkdir /config/my_config
echo 123 > /config/my_config/value
ConfigFS小结
- 这里熟悉了整个ConfigFS 体系,涉及到的几个数据结构,以及每个数据结构是做什么的,之间关联关系
- ConfigFS 的核心数据结构围绕动态配置设计:
config_group 和 config_item 构建层级关系。
config_item_type 提供操作回调。
configfs_attribute 实现具体属性文件。
设备树插件通过这套结构实现动态加载,是 ConfigFS 的典型应用场景。
总结
- 虚拟文件系统的了解
- ConfigFS 关联的基础是指,ConfigFS 里面的几个数据结构
- 设备树插件是如何写属性的流程
最重要的是 夯实基础,基础概念、数据结构、流程 千万不能模棱两可。
1592

被折叠的 条评论
为什么被折叠?



