【linux kernel】 一文总结linux内核中的kobject、kset和ktype

'# 【linux kernel】 一文总结linux内核中的kobject、kset和ktype

一、背景与问题

在Linux内核开发中,设备驱动和子系统需要管理大量动态创建的内核对象。传统的struct device等结构体难以满足这种动态性需求,于是内核引入了kobject体系作为通用对象管理框架。该体系包含三个核心组件:

  • kobject:基本对象模型,提供统一的引用计数和属性管理
  • kset:对象集合,提供分类管理能力
  • ktype:类型管理,定义对象的属性和操作

这些组件共同构建了内核的设备模型(device model),是sysfs文件系统、热插拔支持、设备属性管理等特性的基础。

二、基本原理

1. kobject核心结构

struct kobject {
    const char *name;
    struct list_head entry;
    struct kobject *parent;
    struct kset *kset;
    struct ktype *ktype;
    struct bin_attribute *bin_attrs;
    struct attribute *attrs;
    struct kobj_attribute *default_attrs;
    struct kref kref;
    unsigned int state;
    void *ptr;
};
  • name:对象名称
  • parent:父对象指针
  • kset:所属集合
  • ktype:类型描述
  • kref:引用计数器
  • state:状态标志(如KOBJ_STATE_IN_TREE)
  • ptr:指向具体对象的指针(如struct device)

2. kset结构

struct kset {
    struct list_head list;
    struct kobject kobj;
    struct kset *parent;
    const struct kset_ops *ops;
};
  • kobj:kset自身的kobject
  • parent:父kset
  • ops:操作函数集合(如kset_add、kset_del)

3. ktype结构

struct ktype {
    const char *name;
    struct attribute_group *default_groups;
    const struct kobj_attribute *attrs;
    const struct bin_attribute *bin_attrs;
    const struct kobj_attribute *default_attrs;
    const struct kobj_attribute *sysfs_ops;
    const struct kobj_attribute *sysfs_ops2;
    const struct kobj_attribute *sysfs_ops3;
    const struct kobj_attribute *sysfs_ops4;
    const struct kobj_attribute *sysfs_ops5;
};
  • name:类型名称
  • default_groups:默认属性组
  • attrs/bin_attrs:属性描述

三、环境准备

#include <linux/kobject.h>
#include <linux/kset.h>
#include <linux/ktype.h>
#include <linux/module.h>
#include <linux/kernel.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");

需要编译为内核模块,使用make构建:

obj-m += kobject_demo.o

四、核心实现

1. 创建kset

static struct kset *my_kset;

static int __init kobject_init(void) {
    my_kset = kset_create("my_kset", &kset_default_ops);
    if (!my_kset)
        return -ENOMEM;
    
    // 注册到内核
    kobject_put(&my_kset->kobj);
    return 0;
}

关键点:

  • 使用kset_create创建kset
  • kset_default_ops是默认操作集合
  • kobject_put将kset注册到sysfs

2. 创建kobject

static struct kobject *my_kobj;

static int __init kobject_init(void) {
    my_kobj = kobject_create_and_add("my_kobj", my_kset->kobj);
    if (!my_kobj)
        return -ENOMEM;
    
    // 添加属性
    static struct attribute *attrs[] = {
        &sysfs_bin_attr("data", 0444, NULL, NULL),
        NULL
    };
    kobject_add_attrs(my_kobj, attrs);
    
    return 0;
}

关键点:

  • kobject_create_and_add创建并注册kobject
  • sysfs_bin_attr创建二进制属性
  • kobject_add_attrs将属性绑定到kobject

3. 实现ktype

static struct ktype my_ktype = {
    .name = "my_ktype",
    .default_groups = NULL,
    .attrs = NULL,
    .bin_attrs = NULL,
};

static int __init kobject_init(void) {
    // 注册ktype
    ktype_register(my_kobj, &my_ktype);
    return 0;
}

关键点:

  • ktype_register将ktype绑定到kobject
  • 需要确保kobject的ktype指针正确指向

五、完整案例:实现一个简单的sysfs接口

#include <linux/kobject.h>
#include <linux/kset.h>
#include <linux/ktype.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sysfs.h>
#include <linux/fs.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");

static struct kset *my_kset;
static struct kobject *my_kobj;
static struct ktype my_ktype;

// 属性操作函数
static ssize_t show_data(struct kobject *kobj, struct kobj_attribute *attr, char *buf) {
    return sprintf(buf, "Sample data\n");
}

static ssize_t store_data(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) {
    printk(KERN_INFO "Received: %s\n", buf);
    return count;
}

// 属性描述
static struct kobj_attribute my_attr = {
    .attr = {
        .name = "data",
        .mode = 0644
    },
    .show = show_data,
    .store = store_data
};

static struct attribute *attrs[] = {
    &my_attr.attr,
    NULL
};

static struct attribute_group my_attr_group = {
    .attrs = attrs
};

// 初始化函数
static int __init kobject_init(void) {
    // 创建kset
    my_kset = kset_create("my_kset", &kset_default_ops);
    if (!my_kset)
        return -ENOMEM;
    
    // 创建kobject
    my_kobj = kobject_create_and_add("my_kobj", my_kset->kobj);
    if (!my_kobj)
        return -ENOMEM;
    
    // 注册属性组
    kobject_add_group(my_kobj, &my_attr_group);
    
    // 注册ktype
    my_ktype.name = "my_ktype";
    ktype_register(my_kobj, &my_ktype);
    
    return 0;
}

// 模块卸载函数
static void __exit kobject_exit(void) {
    kobject_put(my_kobj);
    kset_unregister(my_kset);
}

module_init(kobject_init);
module_exit(kobject_exit);

关键点:

  • 使用kobj_attribute定义属性操作
  • kobject_add_group将属性组绑定到kobject
  • 模块卸载时需要正确释放资源

六、源码解析

1. kobject的引用计数

void kobject_get(struct kobject *kobj) {
    kref_get(&kobj->kref);
}
  • 引用计数器机制确保对象不会被过早释放
  • 当引用计数为0时,调用kobject_put会触发销毁流程

2. kset的注册流程

int kset_register(struct kset *kset) {
    kobject_put(&kset->kobj);
    return 0;
}
  • 确保kset的kobject被正确注册
  • 避免重复注册导致的资源泄漏

3. ktype的绑定过程

void ktype_register(struct kobject *kobj, struct ktype *ktype) {
    kobj->ktype = ktype;
}
  • 将ktype绑定到kobject
  • 实现属性的动态管理

七、进阶使用

1. 多级kset组织

struct kset *parent_kset;
struct kset *child_kset;

child_kset = kset_create("child", &kset_default_ops);
kset_add(child_kset, parent_kset);
  • 用于构建层次化的设备树
  • 适用于USB、PCI等复杂总线架构

2. 事件通知系统

struct kset *my_kset;
struct kobject *my_kobj;

// 注册通知
kobject_add_notifier(my_kobj, KNOTIFY_CREATE | KNOTIFY_REMOVE, my_notifier);
  • 实现对象的动态监控
  • 用于设备热插拔等场景

3. 内存管理优化

struct my_obj {
    struct kobject kobj;
    char data[1024];
};

static int my_init(struct kobject *kobj, const char *name) {
    struct my_obj *obj = to_my_obj(kobj);
    strcpy(obj->data, name);
    return 0;
}
  • 在kobject结构中嵌入自定义数据
  • 优化内存使用,减少内存碎片

八、性能与工程实践

1. 性能优化

  • 减少锁竞争:使用kref_get/kref_put代替全局锁
  • 内存池管理:使用kmem_cache预分配对象
  • 异步处理:将耗时操作放入工作队列

2. 异常处理

void kobject_put(struct kobject *kobj) {
    if (kobj && !kobj->kref.count)
        kobject_put(kobj->parent);
}
  • 确保父对象不会被过早释放
  • 避免悬空指针

3. 安全风险

  • 权限控制:通过mode位控制属性访问权限
  • 数据验证:在store回调中进行输入验证
  • 内存安全:避免kmalloc的内存泄漏

九、常见问题与踩坑

1. 常见错误

错误示例:

kobject_create_and_add("my_kobj", NULL);

问题分析:

  • 父对象为NULL时,kobject会注册到根kset
  • 可能导致sysfs路径混乱

解决方案:

kobject_create_and_add("my_kobj", my_kset->kobj);

2. 内存泄漏

错误示例:

struct kobject *kobj = kobject_create_and_add("my_kobj", NULL);

问题分析:

  • 没有显式调用kobject_put
  • 模块卸载时未释放资源

解决方案:

kobject_put(kobj);

3. 属性未显示

错误示例:

kobject_add_attrs(kobj, NULL);

问题分析:

  • 没有添加任何属性
  • sysfs中不会显示任何内容

解决方案:

static struct attribute *attrs[] = {
    &sysfs_bin_attr("data", 0444, NULL, NULL),
    NULL
};
kobject_add_attrs(kobj, attrs);

十、最佳实践

  1. 统一管理:所有设备对象应通过kobject/kset进行统一管理
  2. 分层设计:使用多级kset构建层次化设备树
  3. 属性分离:将业务属性与系统属性分离管理
  4. 生命周期管理:确保引用计数正确,避免资源泄漏
  5. 安全控制:严格控制属性的访问权限
  6. 性能优化:避免不必要的锁和内存分配

十一、总结

kobject/kset/ktype体系是Linux内核设备模型的核心,提供了统一的内核对象管理机制。通过理解其原理和实现细节,开发者可以构建更健壮的设备驱动和子系统。在实际开发中需要注意:

  • 适用场景:适用于需要动态管理大量对象的场景(如设备驱动、系统子系统)
  • 不适用场景:轻量级对象管理、对性能要求极高的场景

通过合理使用这些机制,可以实现更高效的资源管理、更清晰的系统架构,以及更完善的设备接口。在开发过程中要特别注意引用计数、内存管理、权限控制等关键点,避免常见的陷阱和错误。

最后修改于:2026年09月27日 15:06

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日