kset

kset总是在sysfs中出现,一旦设置了kset并把它添加到系统中,就会在sysfs中创建一个目录。kset中的每一个kobject成员都会在sysfs中表述。

kset定义:

    /**
     * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
     *
     * A kset defines a group of kobjects. They can be individually
     * different "types" but overall these kobjects all want to be grouped
     * together and operated on in the same manner. ksets are used to
     * define the attribute callbacks and other common events that happen to
     * a kobject.
     *
     * @list: the list of all kobjects for this kset
     * @list_lock: a lock for iterating over the kobjects
     * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
     * @uevent_ops: the set of uevent operations for this kset. These are
     * called whenever a kobject has something happen to it so that the kset
     * can add new environment variables, or filter out the uevents if so
     * desired.
     */
    struct kset {
        struct list_head list;
        spinlock_t list_lock;
        struct kobject kobj;
        const struct kset_uevent_ops *uevent_ops;
    };
创建一个对象kobject时,通常会把kobject添加到kset中去,这个过程分2个步骤:

1. 先把kobject的kset成员,指向目的kset,然后运行kobject_add().

    /**
     * kobject_add - the main kobject add function
     * @kobj: the kobject to add
     * @parent: pointer to the parent of the kobject.
     * @fmt: format to name the kobject with.
     *
     * The kobject name is set and added to the kobject hierarchy in this
     * function.
     *
     * If @parent is set, then the parent of the @kobj will be set to it.
     * If @parent is NULL, then the parent of the @kobj will be set to the
     * kobject associted with the kset assigned to this kobject. If no kset
     * is assigned to the kobject, then the kobject will be located in the
     * root of the sysfs tree.
     *
     * If this function returns an error, kobject_put() must be called to
     * properly clean up the memory associated with the object.
     * Under no instance should the kobject that is passed to this function
     * be directly freed with a call to kfree(), that can leak memory.
     *
     * Note, no "add" uevent will be created with this call, the caller should set
     * up all of the necessary sysfs files for the object and then call
     * kobject_uevent() with the UEVENT_ADD parameter to ensure that
     * userspace is properly notified of this kobject's creation.
     */
    int kobject_add(struct kobject *kobj, struct kobject *parent,
            const char *fmt, ...)
    {
        va_list args;
        int retval;
        if (!kobj)
            return -EINVAL;
        if (!kobj->state_initialized) {
            printk(KERN_ERR "kobject '%s' (%p): tried to add an "
             "uninitialized object, something is seriously wrong.\n",
             kobject_name(kobj), kobj);
            dump_stack();
            return -EINVAL;
        }
        va_start(args, fmt);
        retval = kobject_add_varg(kobj, parent, fmt, args);
        va_end(args);
        return retval;
    }
    EXPORT_SYMBOL(kobject_add);

2. kobject_del(): 把kobject从kset中删除,以清除引用计数。

    /**
     * kobject_del - unlink kobject from hierarchy.
     * @kobj: object.
     */
    void kobject_del(struct kobject *kobj)
    {
        if (!kobj)
            return;
        sysfs_remove_dir(kobj);
        kobj->state_in_sysfs = 0;
        kobj_kset_leave(kobj);
        kobject_put(kobj->parent);   //清除引用记数
        kobj->parent = NULL;
    }

3. kset操作:kset有与kobject相似的初始化和设置接口:

a. kset_init():

    /**
     * kset_init - initialize a kset for use
     * @k: kset
     */
    void kset_init(struct kset*k)
    {
        kobject_init_internal(&k->kobj);
        INIT_LIST_HEAD(&k->list);
        spin_lock_init(&k->list_lock);
    }

b. kset_register()/ kset_unregister():

    /**
     * kset_register - initialize and add a kset.
     * @k: kset.
     */
    int kset_register(struct kset *k)
    {
        int err;
        if (!k)
            return -EINVAL;
        kset_init(k);
        err = kobject_add_internal(&k->kobj);
        if (err)
            return err;
        kobject_uevent(&k->kobj, KOBJ_ADD);
        return 0;
    }
    /**
     * kset_unregister - remove a kset.
     * @k: kset.
     */
    void kset_unregister(struct kset *k)
    {
        if (!k)
            return;
        kobject_put(&k->kobj);
    }

c. kset的引用计数管理:kset_get() / kset_put()

    static inline struct kset *kset_get(struct kset *k)
    {
        return k ? to_kset(kobject_get(&k->kobj)) : NULL;
    }
    static inline void kset_put(struct kset *k)
    {
        kobject_put(&k->kobj);
    }

d. kset的名字,保存在内嵌的kobject中。即 kset->kobj的name 。
e. kset也有一个指针指向kobj_type结构,用来描述kobject。典型应用中,会把kobject中的ktype成员设置为null,因为kset中的ktype成员是实际上被使用的成员。

f. kset中包含了一个子系统指针 subsys. 子系统通常显示在sysfs分层结构中的顶层。


Linux内核中的 `kobject` 和 `kset` 是用于设备模型管理的核心组件,它们为设备和驱动程序提供了一种统一的层次结构表示方式。`kobject` 是 Linux 设备模型的基本构建块,它提供了对象生命周期管理、引用计数、名称和 sysfs 文件系统集成等功能。`kset` 则是 `kobject` 的集合,用于将多个 `kobject` 组织在一起,并提供共同的属性和操作。 ### Kobject 的基本用途 `kobject` 是内核中用于表示设备、驱动程序和总线等实体的通用结构体。它提供了以下核心功能: - **引用计数**:确保对象在使用期间不会被释放。 - **名称管理**:每个 `kobject` 都有一个名称,并且可以在 sysfs 文件系统中表示为一个目录。 - **父子关系**:`kobject` 可以形成层次结构,父对象可以管理子对象的生命周期。 初始化 `kobject` 的典型方式是通过 `kobject_init()` 函数,之后可以调用 `kobject_add()` 将其注册到内核中。例如: ```c struct kobject *kobj; kobj = kobject_create(); if (!kobj) return -ENOMEM; kobject_add(kobj, parent_kobj, "my_kobject"); ``` `kobject_create()` 实际上会调用 `kobject_init()` 和 `kobject_add()` 的组合来创建并注册一个新的 `kobject` [^1]。 ### Kset 的作用 `kset` 是 `kobject` 的容器,它本身也是一个 `kobject`,因此可以嵌入在层次结构中。`kset` 提供了以下功能: - **集合管理**:管理一组具有相同特性的 `kobject`。 - **统一属性**:可以为集合中的所有成员定义统一的属性和操作。 - **热插拔支持**:`kset` 可以提供 uevent 通知机制,用于向用户空间发送设备添加或移除事件。 创建和使用 `kset` 的步骤通常包括: 1. 初始化 `kset` 结构体。 2. 设置 `kset` 的操作函数(如 `uevent` 和 `release`)。 3. 调用 `kset_register()` 将 `kset` 注册到内核中。 示例代码如下: ```c struct kset *my_kset; my_kset = kset_create_and_register("my_kset", &kset_ops, parent_kset); if (!my_kset) return -ENOMEM; ``` ### 实现细节 `kobject` 和 `kset` 的实现位于内核源码的 `lib/kobject.c` 和 `include/linux/kobject.h` 中。`kobject` 的核心操作包括: - `kobject_init()`:初始化 `kobject`。 - `kobject_add()`:将 `kobject` 添加到内核对象层次结构中。 - `kobject_put()`:减少引用计数,当计数为零时释放对象。 - `kobject_unregister()`:取消注册 `kobject`。 `kset` 的操作包括: - `kset_init()`:初始化 `kset`。 - `kset_register()`:注册 `kset`。 - `kset_unregister()`:取消注册 `kset`。 `kobject` 和 `kset` 的设计允许内核开发者构建复杂的设备层次结构,并与用户空间进行交互。它们是 sysfs 文件系统的基础,sysfs 通过 `kobject` 的层次结构将设备和驱动程序的信息导出到用户空间。 ### 示例:创建一个简单的 kobject 并添加属性 以下是一个简单的示例,展示如何创建一个 `kobject` 并添加一个属性文件到 sysfs: ```c #include <linux/kobject.h> #include <linux/sysfs.h> #include <linux/module.h> #include <linux/init.h> static struct kobject *example_kobj; static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "This is a sample value\n"); } static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { pr_info("Writing to foo: %s\n", buf); return count; } static struct kobj_attribute foo_attribute = __ATTR(foo, 0664, foo_show, foo_store); static int __init example_init(void) { int error = 0; pr_info("Example module initializing\n"); example_kobj = kobject_create_and_add("example", kernel_kobj); if (!example_kobj) return -ENOMEM; error = sysfs_create_file(example_kobj, &foo_attribute.attr); if (error) pr_err("Failed to create the foo file in sysfs\n"); return error; } static void __exit example_exit(void) { pr_info("Example module exiting\n"); kobject_put(example_kobj); } module_init(example_init); module_exit(example_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Author Name"); MODULE_DESCRIPTION("A simple example of kobject usage"); ``` 在这个示例中,模块初始化时会创建一个名为 `example` 的 `kobject`,并将其添加到内核的 `kobject` 层次结构中。然后,它会在 sysfs 中创建一个名为 `foo` 的属性文件,用户可以通过读写该文件与内核模块进行交互。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值