LV06-12-ConfigFS-02-数据结构与应用
我们来详细了解一下Configfs。若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
PC端开发环境 | Windows | Windows11 |
Ubuntu | Ubuntu20.04.2的64位版本 | |
VMware® Workstation 17 Pro | 17.6.0 build-24238078 | |
终端软件 | MobaXterm(Professional Edition v23.0 Build 5042 (license)) | |
Win32DiskImager | Win32DiskImager v1.0 | |
Linux开发板环境 | Linux开发板 | 正点原子 i.MX6ULL Linux 阿尔法开发板 |
uboot | NXP官方提供的uboot,使用的uboot版本为U-Boot 2019.04 | |
linux内核 | linux-4.19.71(NXP官方提供) |
点击查看本文参考资料
分类 | 网址 | 说明 |
官方网站 | https://www.arm.com/ | ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档 |
https://www.nxp.com.cn/ | NXP官方网站 | |
https://www.nxpic.org.cn/ | NXP 官方社区 | |
https://u-boot.readthedocs.io/en/latest/ | u-boot官网 | |
https://www.kernel.org/ | linux内核官网 |
点击查看相关文件下载
分类 | 网址 | 说明 |
NXP | https://github.com/nxp-imx | NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库 |
nxp-imx/linux-imx/releases/tag/v4.19.71 | NXP linux内核仓库tags中的v4.19.71 | |
nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0 | NXP u-boot仓库tags中的rel_imx_4.19.35_1.1.0 | |
I.MX6ULL | i.MX 6ULL Applications Processors for Industrial Products | I.MX6ULL 芯片手册(datasheet,可以在线查看) |
i.MX 6ULL Applications ProcessorReference Manual | I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网) | |
Source Code | https://elixir.bootlin.com/linux/latest/source | linux kernel源码 |
kernel/git/stable/linux.git - Linux kernel stable tree | linux kernel源码(官网,tag 4.19.71) | |
https://elixir.bootlin.com/u-boot/latest/source | uboot源码 |
这一部分是学习如何创建内核对象, 然后生成对应的文件和目录。
一、核心数据结构
1. 关键数据结构
站在用户的角度来说,一个文件系统里面有目录、文件两种对象。在configfs的内核实现中,对应4个概念。
1.1 configfs_attribute
这里其实还有个configfs_bin_attribute,他们两个都是对应文件。
- configfs_attribute:对应的文件里含有的是可视化的字符串信息
1 | struct configfs_attribute { |
- configfs_bin_attribute:对应的文件里含有的是二进制信息
1 | struct configfs_bin_attribute { |
(1)读写文件时,会导致上述结构体里的show/store或者read/write函数被调用
(2)文件是位于某个目录的: config_item
1.2 config_item
1 | struct config_item { |
这是 ConfigFS 中最基本的数据结构, 用于表示一个配置项。 每个配置项都是一个内核对象, 可以是设备、 驱动程序、 子系统等。 config_item 结构包含了配置项的类型、名称、 属性、 状态等信息, 以及指向父配置项和子配置项的指针。
Tips:configfs中的每个对象都是config_item,后面的config_group、subsystem本质上都属于特殊的config_item
- config_group、configfs_subsystem,config_item都对应一个目录
- 跟config_group、configfs_subsystem对比时, config_item这个目录下不再有目录
- 在 config_item 目录下有属性文件,还可以创建链接文件
- 链接文件的操作结构体是:config_item_type里的 configs_item_operations

1.3 config_group
config_group 是一种特殊类型的配置项, 表示一个配置项组,对应一个目录。 它可以包含一组相关的配置项, 形成一个层次结构。config_group 结构包含了父配置项的指针, 以及指向子配置项的链表。
1 | struct config_group { |
- 普通的config_item :下面不再有子目录。
- config_group:下面还可以创建config_item或者config_group,即:下面可以再创建子目录。
- 在当前目录下操作子目录时,对应的操作结构体是:config_item_type里的 configs_group_operations
1.4 configfs_subsystem
configfs_subsystem 是configfs文件系中的最顶层的数据结构, 用于表示整个 ConfigFS 子系统。 它包含了根配置项组的指针, 以及 ConfigFS 的其他属性和状态信息。
1 | struct configfs_subsystem { |
比如:
/sys/kernel/config/usb_gadget
、/sys/kernel/config/iio
在
drivers/usb/gadget/configfs.c
中调用configfs_register_subsystem(&gadget_subsys)
就会创建subsystem,它对应configfs文件系统中的顶层目录usb_gadget
subsystem也属于config_group。

1.5 总结
这些数据结构之间的关系可以形成一个树形结构, 其中 configfs_subsystem 是根节点, config_group 表示配置项组, config_item 表示单个配置项。 子配置项通过链表连接在一起, 形成父子关系。

2. 子系统、 容器和 config_item
接下来以设备树插件的驱动为例来详细了解一下这三个概念。
2.1 dtbocfg_root_subsys
1 | static struct configfs_subsystem dtbocfg_root_subsys = { |
这段代码定义了一个名为 dtbocfg_root_subsys 的 configfs_subsystem 结构体实例, 表示ConfigFS 中的一个子系统。
- dtbocfg_root_subsys.su_group 是一个 config_group 结构体, 它表示子系统的根配置项组。 在这里, 该结构体的 .cg_item 字段表示根配置项组的基本配置项。
.ci_namebuf = “device-tree”: 配置项的名称设置为”device-tree”, 表示该配置项的名称为”device-tree”。
.ci_type = &dtbocfg_root_type: 配置项的类型设置为 dtbocfg_root_type, 这是一个自定义的配置项类型。
- .su_mutex 字段是一个互斥锁, 用于保护子系统的操作。 在这里, 使用了__MUTEX_INITIALIZER 宏来初始化互斥锁。
通过这段代码, 创建了一个名为”device-tree”的子系统, 它的根配置项组为空。 可以在该子系统下添加更多的配置项和配置项组, 用于动态配置和管理设备树相关的内核对象。 Linux系统下创建了 device-tree 这个子系统,如下图 :
2.2 注册配置项组
接下来继续分析设备树插件驱动代码中注册配置项组的部分 :
1 | static int __init dtbocfg_module_init(void) |
这段代码是一个初始化函数 dtbocfg_module_init(), 用于初始化和注册 ConfigFS 子系统和配置项组。
第 7 行:通过 config_group_init()函数初始化了 dtbocfg_root_subsys.su_group, 即子系统的根配置项组。
第 8 行:使用 config_group_init_type_name()函数初始化了dtbocfg_overlay_group, 表示名为”overlays”的配置项组, 并指定了配置项组的类型为dtbocfg_overlays_type, 这是一个自定义的配置项类型。
第 10 行:调用 configfs_register_subsystem()函数注册了 dtbocfg_root_subsys 子系统。 如果注册失败, 将打印错误信息, 并跳转到register_subsystem_failed 标签处进行错误处理。
第 16 行:调用 configfs_register_group()函数注册了 dtbocfg_overlay_group 配置项组, 并将其添加到 dtbocfg_root_subsys.su_group 下。 如果注册失败, 同样会打印错误信息, 并跳转到 register_group_failed 标签处进行错误处理。
第 22 - 23 行:如果所有的注册过程都成功, 将打印”OK”消息, 并返回 0, 表示初始化成功。
如果在注册配置项组失败时, 会先调用 configfs_unregister_subsystem() 函数注销之前注册的子系统, 然后返回注册失败的错误码 retval。这段代码的作用是初始化和注册一个名为”device-tree”的 ConfigFS 子系统, 并在其下创建一个名为”overlays”的配置项组。 Linux 系统下, 在 device-tree 子系统下创建了 overlays 容器,如下图 :
3. 属性和方法
我们要在容器下放目录或属性文件, 所以我们看一下 config_item结构体 :
1 | struct config_item { |
config_item 结构体中包含了 config_item_type 结构体, config_item_type 结构体如下所示:
1 | struct config_item_type { |
- config_item_type 结构体中包含了 struct configfs_item_operations 结构体:
1 | struct configfs_item_operations { |
- config_item_type 结构体中包含了 struct configfs_group_operations 结构体:
1 | struct configfs_group_operations { |
- config_item_type 结构体中包含了 struct configfs_attribute结构体:
1 | struct configfs_attribute { |
4. 总结



- attribute

当我们使用mkdir dtbo_demo
这个命令创建dtbo_demo这个item的时候,就会调用configfs_group_operations .make_item方法
二、注册configfs子系统
1. demo源码
demo源码可以看这里:12_configfs_demo/01_configfs_subsystem · 苏木/imx6ull-driver-demo - 码云 - 开源中国
2. 开发板测试
- (1)挂载configfs文件系统
1 | mount -t configfs none /sys/kernel/config |
- (2)加载驱动
1 | insmod sdriver_demo.ko |

- (3)查看注册的子系统
1 | ls /sys/kernel/config/ |

- (4)卸载驱动
1 | rmmod sdriver_demo.ko |

三、注册group容器
1. demo源码
源码可以看这里:12_configfs_demo/02_configfs_group · 苏木/imx6ull-driver-demo - 码云 - 开源中国
2. 开发板测试
- (1)挂载configfs文件系统
1 | mount -t configfs none /sys/kernel/config |
- (2)测试效果
1 | insmod sdriver_demo.ko |

我们进入注册生成的 sconfigfs 子系统, 可以看到注册生成的 sgroup 容器。
四、用户空间创建 item
1. demo实例
1.1 demo源码
源码可以看这里:12_configfs_demo/03_configfs_item · 苏木/imx6ull-driver-demo - 码云 - 开源中国
1.2 开发板测试
- (1)挂载configfs文件系统
1 | mount -t configfs none /sys/kernel/config |
- (2)加载驱动
1 | insmod sdriver_demo.ko |

- (3)创建item
1 | cd /sys/kernel/config/sconfigfs/sgroup/ |

- (4)删除item
1 | cd /sys/kernel/config/sconfigfs/sgroup/ |

- (5)卸载驱动
1 | rmmod sdriver_demo.ko |
2. drop_item 和 release
当我们在命令行使用 rmdir 命令删除 item 时, 会执行configfs_item_operations.release 函数,
1 | struct configfs_item_operations { |
.release 成员字段是在 struct config_item_type结构体中成员configfs_item_operations里面定义的一个回调函数指针。 它指向一个函数, 当 configfs 中的配置项被释放或删除时, 内核会调用该函数来执行相应的资源释放操作。 它通常用于释放与配置项相关的资源, 比如释放动态分配的内存、 关闭打开的文件描述符等。
还有一个 drop_item 函数,它是定义在 configfs_group_operations 中:
1 | struct configfs_group_operations { |
drop_item 一个回调函数指针。 它指向一个函数, 当 configfs 中的配置组(group) 被删除时, 内核会调用该函数来处理与配置组相关的操作。 这个函数通常用于清理配置组的状态、 释放相关的资源以及执行其他必要的清理操作。 .drop_item 函数在删除配置组时被调用, 而不是在删除单个配置项时被调用。
.release 成员字段用于配置项的释放操作, 而 .drop_item 成员字段用于配置组的删除操作。它们分别在不同的上下文中执行不同的任务, 但都与资源释放和清理有关。
3. drop_item实例
2.1 demo源码
源码可以看这里:12_configfs_demo/04_drop_and_release · 苏木/imx6ull-driver-demo - 码云 - 开源中国
3.2 开发板测试
- (1)挂载configfs文件系统
1 | mount -t configfs none /sys/kernel/config |
- (2)加载驱动
1 | insmod sdriver_demo.ko |
- (3)创建item
1 | cd /sys/kernel/config/sconfigfs/sgroup/ |
- (4)删除item
1 | cd /sys/kernel/config/sconfigfs/sgroup/ |

输入“ rmdir test” 命令删除 item, 执行 rmdir 命令之后, 依次执行了 sdrv_group_delete_item() 函数和sdrv_item_release()函数。
- (5)卸载驱动
1 | rmmod sdriver_demo.ko |
五、注册attribute
1. demo源码
源码可以看这里:12_configfs_demo/05_attribute · 苏木/imx6ull-driver-demo - 码云 - 开源中国
2. 开发板测试
- (1)挂载configfs文件系统
1 | mount -t configfs none /sys/kernel/config |
- (2)加载驱动
1 | insmod sdriver_demo.ko |
- (3)创建item
1 | cd /sys/kernel/config/sconfigfs/sgroup/ |

- (4)属性操作
1 | cd item_demo |

- (5)删除item
1 | cd /sys/kernel/config/sconfigfs/sgroup/ |

- (5)卸载驱动
1 | rmmod sdriver_demo.ko |
六、实现多级目录
经过前面的学习, 我们了解到一个配置组也就是(group) 可以包含多个配置项(item)和子配置组。 配置项和配置组都是作为配置组的成员存在的。 配置项和配置组之间通过指针进行关联, 以形成一个层次结构。
配置项(item)是最后一级目录了,它下面不可以再有目录:

我们可以在配置项组中创建目录,那么我们能否实现这样的结构:
1 | /sys/kernel/config/sconfigfs/sgroup/a_dir/item_name_dir |
下面就来了解一下多级目录的创建。其实吧,学到这里的时候我也不知道这里有什么用,后面用到了再补充吧。
1. demo源码
源码可以看这里:12_configfs_demo/06_multilevel_dir · 苏木/imx6ull-driver-demo - 码云 - 开源中国
2. 开发板测试
- (1)挂载configfs文件系统
1 | mount -t configfs none /sys/kernel/config |
- (2)加载驱动
1 | insmod sdriver_demo.ko |
- (3)创建目录
1 | cd /sys/kernel/config/sconfigfs/sgroup/ |
然后输入“mkdir group_demo” 命令创建 config_item ,创建成功之后 会打印这个项的名称:

然后进入group_demo目录下, 此时可以在 test 目录下创建 item —— item_demo:

但由于在驱动中我们并没有实现在 group 下创建 item 功能, 所以会提示创建 item_demo 没有权限。后面没有深入去搞了,这里就了解到这里吧。
- (5)删除刚才的group_demo
1 | cd /sys/kernel/config/sconfigfs/sgroup/ |

- (5)卸载驱动
1 | rmmod sdriver_demo.ko |
参考资料
configfs-用户空间控制的内核对象配置 - abin在路上 - 博客园