了解了ConfigFS 关联的基本知识,创建子系统、group、item。 这里补充一个知识点,回收资源相关的。
文章目录
前言
这里对ConfigFS 体系资源回收知识点做一个了解、熟悉。 主要涉及到两个 函数:drop_item 、release
。 这里就是具体去了解 这两个api 关联的知识点。
参考资料
重温一下前面的知识点,其中创建Item 篇有release api 的调用,可以看一下针对性知识点模块知识
Linux驱动-设备树插件语法
设备树插件基础必备
设备树插件注册子系统
驱动-设备树插件-注册group
RK3568驱动指南|第八篇 设备树插件-第78章 用户空间创建item实验
驱动-设备数插件-创建Item
设备树插件-第79章 完善drop和release函数实验
一、实际案例
源码程序
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/configfs.h>
// 定义一个名为"mygroup"的config_group结构体
static struct config_group mygroup;
// 自定义的配置项结构体
struct myitem
{
struct config_item item;
};
// 配置项释放函数
void myitem_release(struct config_item *item)
{
struct myitem *myitem = container_of(item, struct myitem, item);
kfree(myitem);
printk("%s\n", __func__);
}
// 配置项操作结构体
struct configfs_item_operations myitem_ops = {
.release = myitem_release,
};
// 配置项类型结构体
static struct config_item_type mygroup_item_type = {
.ct_owner = THIS_MODULE,
.ct_item_ops = &myitem_ops,
};
// 创建配置项函数
struct config_item *mygroup_make_item(struct config_group *group, const char *name)
{
struct myitem *myconfig_item;
printk("%s\n", __func__);
myconfig_item = kzalloc(sizeof(*myconfig_item), GFP_KERNEL);
config_item_init_type_name(&myconfig_item->item, name, &mygroup_item_type);
return &myconfig_item->item;
}
// 删除配置项函数
void mygroup_delete_item(struct config_group *group, struct config_item *item)
{
struct myitem *myitem = container_of(item, struct myitem, item);
config_item_put(&myitem->item);
printk("%s\n", __func__);
}
// 配置组操作结构体
struct configfs_group_operations mygroup_ops = {
.make_item = mygroup_make_item,
.drop_item = mygroup_delete_item,
};
// 定义名为"mygroup_config_item_type"的config_item_type结构体,用于描述配置项类型。
static const struct config_item_type mygroup_config_item_type = {
.ct_owner = THIS_MODULE,
.ct_group_ops = &mygroup_ops,
};
// 定义名为"myconfig_item_type"的配置项类型结构体
static const struct config_item_type myconfig_item_type = {
.ct_owner = THIS_MODULE,
.ct_group_ops = NULL,
};
// 定义一个configfs_subsystem结构体实例"myconfigfs_subsystem"
static struct configfs_subsystem myconfigfs_subsystem = {
.su_group = {
.cg_item = {
.ci_namebuf = "myconfigfs",
.ci_type = &myconfig_item_type,
},
},
};
// 模块的初始化函数
static int myconfig_group_init(void)
{
// 初始化配置组
config_group_init(&myconfigfs_subsystem.su_group);
// 注册子系统
configfs_register_subsystem(&myconfigfs_subsystem);
// 初始化配置组"mygroup"
config_group_init_type_name(&mygroup, "mygroup", &mygroup_config_item_type);
// 在子系统中注册配置组"mygroup"
configfs_register_group(&myconfigfs_subsystem.su_group, &mygroup);
return 0;
}
// 模块退出函数
static void myconfig_group_exit(void)
{
// 注销子系统
configfs_unregister_subsystem(&myconfigfs_subsystem);
}
module_init(myconfig_group_init); // 指定模块的初始化函数
module_exit(myconfig_group_exit); // 指定模块的退出函数
MODULE_LICENSE("GPL"); // 模块使用的许可证
MODULE_AUTHOR("fangchen"); // 模块的作者
源码分析
这个源码程序完全基于上一篇 驱动-设备数插件-创建Item 基础上来修改了几行代码。
回顾 config_item_type-configfs_group_operations-configfs_item_operations
release
和 drop_item
和这几个结构体关联,这里还是从结构体的角度再次重温一下这几个结构体知识点,前面的文章知识点其实已经介绍了,这里简单回顾 才能更好理解 drop_item
和release
函数
在 驱动-设备数插件-创建Item 和 设备树插件基础必备 篇中有相关介绍了 可以看看以前知识点,做了详细分析:
问题点分析
上面的结构体知识是基本的知识点,特别重要。 现在的问题是:
configfs_item_operations
结构体配置了在这里插入代码片
函数 和 configfs_group_operations
结构体配置了drop_item
,一个是项的操作,一个是组的操作。 比如如下代码这样写:
// 配置项释放函数
void myitem_release(struct config_item *item)
{
struct myitem *myitem = container_of(item, struct myitem, item);
kfree(myitem);
printk("%s\n", __func__);
}
// 配置项操作结构体
struct configfs_item_operations myitem_ops = {
.release = myitem_release,
};
// 配置项类型结构体
static struct config_item_type mygroup_item_type = {
.ct_owner = THIS_MODULE,
.ct_item_ops = &myitem_ops,
};
// 创建配置项函数
struct config_item *mygroup_make_item(struct config_group *group, const char *name)
{
struct myitem *myconfig_item;
printk("%s\n", __func__);
myconfig_item = kzalloc(sizeof(*myconfig_item), GFP_KERNEL);
config_item_init_type_name(&myconfig_item->item, name, &mygroup_item_type);
return &myconfig_item->item;
}
// 删除配置项函数
void mygroup_delete_item(struct config_group *group, struct config_item *item)
{
struct myitem *myitem = container_of(item, struct myitem, item);
// config_item_put(&myitem->item);
printk("%s\n", __func__);
}
// 配置组操作结构体
struct configfs_group_operations mygroup_ops = {
.make_item = mygroup_make_item,
.drop_item = mygroup_delete_item,
};
// 定义名为"mygroup_config_item_type"的config_item_type结构体,用于描述配置项类型。
static const struct config_item_type mygroup_config_item_type = {
.ct_owner = THIS_MODULE,
.ct_group_ops = &mygroup_ops,
};
也就是在 configfs_group_operations
结构体的组操作中的配置了drop_item
函数结构体,在实现里面 不去执行 config_item_put(&myitem->item); api
函数。 结果是什么呢?
在 ConfigFS 体系里面执行了 rmdir+内核模块名,configfs_group_operations 结构体配置的drop_item 结构体函数会执行,但是 configfs_item_operations 中的release 方法就不会执行了。 这就会导致内存资源无法释放出去。
所以要想实现 configfs_item_operations 中的结构体 release 方法回调,就在configfs_group_operations 结构体配置的drop_item 结构体函数中去执行 config_item_put(&myitem->item); 函数。
知识点扩充-release -drop_item
在 Linux 内核的 configfs
子系统中,configfs_item_operations
中的 release
函数和 configfs_group_operations
中的 drop_item
API 都与 configfs
对象的生命周期管理相关,但它们的职责和调用时机有所不同。以下是它们的区别和联系:
函数解析
release 函数 (configfs_item_operations)
作用:
release 是一个内存释放回调,当 configfs
对象(config_item
)的引用计数降至零时被调用。它的主要职责是释放该对象占用的内存和资源。
调用时机:
当内核不再需要该 config_item
(例如,用户空间删除 configfs
属性文件或卸载模块时),kobject
的引用机制会触发 release
。
典型实现:
void my_item_release(struct config_item *item) {
struct my_struct *p = to_my_struct(item);
kfree(p);
}
关键点:
- 纯粹的内存管理角色,不涉及逻辑操作(如清理其他资源)。
- 由
kobject
的引用计数机制自动触发,开发者无需直接调用。
drop_item 函数 (configfs_group_operations)
作用:
drop_item
是一个逻辑回调,当用户空间通过 rmdir
删除 configfs
目录(表示一个子对象)时被调用。它负责断开父对象与子对象的关系,并可能触发引用计数递减。
调用时机:
用户显式删除 configfs
目录(如 rmdir /config/parent/child
)时,由 VFS 层调用。
典型实现:
void my_group_drop_item(struct config_group *group, struct config_item *item) {
struct my_parent *parent = to_my_parent(group);
struct my_child *child = to_my_child(item);
// 1. 解除父子关系
list_del(&child->sibling_list);
// 2. 递减引用计数(最终可能触发 release)
config_item_put(item);
}
关键点:
- 处理对象间的逻辑关系(如从父对象的链表中移除子项)。
- 必须手动调用
config_item_put
来递减引用计数,否则release
不会被触发。 - 可以包含额外的清理逻辑(如通知其他模块)。
联系与协作
调用顺序:
用户删除一个 configfs
目录时,内核会先调用 drop_item
解除父子关系,然后在引用计数降至零后调用 release 释放内存。
依赖关系:
drop_item
通常需要显式调用 config_item_put
来触发 release
;如果忘记调用,会导致内存泄漏。
分工明确:
drop_item
:处理逻辑关系(如断开父子链接、通知其他模块)。release
:处理物理资源(如释放内存、销毁私有数据结构)。
图示流程
用户执行 `rmdir /config/parent/child`
↓
VFS 调用 configfs 的 `drop_item`
↓
drop_item 逻辑:
1. 从父组中移除子项
2. 调用 config_item_put(item)
↓
如果引用计数为零 → 触发 `release`
↓
release 释放 item 的内存
区别与联系
特性 | release 函数 | drop_item API |
---|---|---|
目的 | 释放 config_item 的资源 | 处理从父组中移除子项的逻辑 |
调用者 | 内核(通过 config_item_put) | 内核(在用户 rmdir 时触发) |
是否直接释放资源 | 是 | 否(需调用 config_item_put 间接触发) |
返回值 | 无(void) | 返回被移除的 config_item |
典型操作 | 释放内存、关闭文件等 | 解除父子关系、检查引用计数 |
联系:
drop_item
通常会在返回 config_item
后,由内核调用 config_item_put
,从而可能触发 release
函数(如果引用计数归零)。
即:rmdir → drop_item → config_item_put → release
(若引用为 0)。
总结
- 这里其实就是讲了一个知识点:ConfigFS 里面资源释放机制,针对性的对drop_item和release 方法结构体的了解和被调用的结构体的知识点回顾