LV065-ktype简介
一、ktype 简介
1. kobj_type 是什么
每个 kobject 对象都有一些属性,这些属性由 kobj_type 表示。kobj_type 就是用于表征 kobject 的的一些属性,指定了删除 kobject 时要调用的函数,kobject 结构体中有 struct kref 字段用于对 kobject 进行引用计数,当计数值为 0 时,就会调用 kobj_type 中的 release 函数对 kobject 进行释放,这个就有点类似于 C++中的智能指针了;它还指定了通过 sysfs 显示或修改有关 kobject 的信息时要处理的操作,实际是调用 show/store 函数。
kobj_type 定义在 struct kobj_type 中:
c
struct kobj_type {
void (*release)(struct kobject *kobj);
const struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs;
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
void (*get_ownership)(struct kobject *kobj, kuid_t *uid, kgid_t *gid);
};- release:通过该回调函数,可以将包含该类型 kobject 的数据结构的内存空间释放掉。
- sysfs_ops:struct sysfs_ops 类型,该种类型的 kobject 的 sysfs 文件系统接口(读属性接口 show 及写属性接口 store)。
- default_attrs:struct attribute 类型,该种类型的 kobject 的 atrribute 列表(所谓 attribute,就是 sysfs 文件系统中的一个文件)。将会在 kobject 添加到内核时,一并注册到 sysfs 中。
- child_ns_type/namespace:和文件系统(sysfs)的命名空间有关,这里不再详细说明。
2. ktype 与 kobject 的关系

- kobject 在创建的时候,默认设置 kobj_type 的值为 dynamic_kobj_ktype(在 kobject_create() 函数中设置的),通常 kobject 会嵌入在其他结构中来使用,因此它的初始化跟特定的结构相关,典型的比如 struct device 和 struct device_driver ;
- 在 /sys 文件系统中,通过 echo/cat 的操作,最终会调用到 show/store 函数,而这两个函数的具体实现可以放置到驱动程序中;
二、ktype demo
1. demo 源码
可以看这里:05_device_model/05_ktype
c
#include <linux/init.h> /* module_init module_exit */
#include <linux/kernel.h>
#include <linux/module.h> /* MODULE_LICENSE */
#include <linux/kobject.h>
#include <linux/slab.h>
#include "./timestamp_autogenerated.h"
#include "./version_autogenerated.h"
#include "./sdrv_common.h"
// #undef PRT
// #undef PRTE
#ifndef PRT
#define PRT printk
#endif
#ifndef PRTE
#define PRTE printk
#endif
struct kobject *skobject1 = NULL; // 定义 kobject 指针变量:skobject1
/**
* @brief dynamic_kobj_release()
* @note 定义 kobject 的释放函数
* @param [in]
* @param [out]
* @retval
*/
static void dynamic_kobj_release(struct kobject *kobj)
{
PRT("kobject: %p\n", kobj);
kfree(kobj);
}
// 定义了一个 kobj_type 结构体变量 stype,用于描述 kobject 的类型。
struct kobj_type stype = {
.release = dynamic_kobj_release,
};
/**
* @brief sdriver_demo_init()
* @note
* @param [in]
* @param [out]
* @retval
*/
static __init int sdriver_demo_init(void)
{
int ret = 0;
printk("*** [%s:%d]Build Time: %s %s, git version:%s ***\n", __FUNCTION__,
__LINE__, KERNEL_KO_DATE, KERNEL_KO_TIME, KERNEL_KO_VERSION);
PRT("sdriver_demo module init!\n");
// 创建 kobject 的第二种方法
// 1.使用 kzalloc 函数分配了一个 kobject 对象的内存
skobject1 = kzalloc(sizeof(struct kobject), GFP_KERNEL);
// 2.初始化并添加到内核中,名为 "skobject1"。
ret = kobject_init_and_add(skobject1, &stype, NULL, "%s", "skobject1");
if(ret < 0)
{
PRTE("kobject_init_and_add fail!ret=%d\n", ret);
goto err_kobject_init_and_add;
}
return 0;
err_kobject_init_and_add:
return ret;
}
/**
* @brief sdriver_demo_exit()
* @note
* @param [in]
* @param [out]
* @retval
*/
static __exit void sdriver_demo_exit(void)
{
// 释放之前创建的 kobject 对象
kobject_put(skobject1);
PRT("sdriver_demo module exit!\n");
}
module_init(sdriver_demo_init); // 将__init 定义的函数指定为驱动的入口函数
module_exit(sdriver_demo_exit); // 将__exit 定义的函数指定为驱动的出口函数
/* 模块信息(通过 modinfo chrdev_led_demo 查看) */
MODULE_LICENSE("GPL v2"); /* 源码的许可证协议 */
MODULE_AUTHOR("sumu"); /* 字符串常量内容为模块作者说明 */
MODULE_DESCRIPTION("Description"); /* 字符串常量内容为模块功能说明 */
MODULE_ALIAS("module's other name"); /* 字符串常量内容为模块别名 */3.2 开发板验证
我们拷贝到开发板,然后加载驱动,卸载驱动,这个实验主要是通过 ktype 自定义了 kobject 对象释放的时候的回调函数:

可以看到,当释放的时候,会出现我们的自定义打印信息。
参考资料
【1】linux 驱动开发—— 6、linux 设备驱动模型_什么是 kobject-CSDN 博客
【2】Linux 设备模型剖析系列一(基本概念、kobject、kset、kobj_type)_device 下的 kobj-CSDN 博客
【4】一张图掌握 Linux platform 平台设备驱动框架!【建议收藏】-CSDN 博客
【5】关于 kobjects、ksets 和 ktypes 的一切你没想过需要了解的东西 — The Linux Kernel documentation