驱动-ConfigFS-释放资源篇

了解了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

releasedrop_item 和这几个结构体关联,这里还是从结构体的角度再次重温一下这几个结构体知识点,前面的文章知识点其实已经介绍了,这里简单回顾 才能更好理解 drop_itemrelease 函数
驱动-设备数插件-创建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 方法结构体的了解和被调用的结构体的知识点回顾
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值