Kobjects

Kobjects (kernel objects) are the foundation of the Linux device model. They provide reference counting, sysfs representation, and parent-child relationships for kernel data structures.

What is a Kobject?

#include <linux/kobject.h>

struct kobject {
    const char *name;           /* Name in sysfs */
    struct list_head entry;     /* Sibling list */
    struct kobject *parent;     /* Parent kobject */
    struct kset *kset;          /* Containing kset */
    struct kobj_type *ktype;    /* Type operations */
    struct kernfs_node *sd;     /* Sysfs directory */
    struct kref kref;           /* Reference count */
    /* ... */
};

Every kobject corresponds to a directory in sysfs.

Kobject Lifecycle

flowchart TD
    A["kobject_init()"]
    B["kobject_add()"]
    C["Visible in sysfs"]
    D["kobject_put()"]
    E["refcount == 0"]
    F["release() called"]
    G["Memory freed"]

    A --> B
    B --> C
    C --> D
    D --> E
    E --> F
    F --> G

Basic Kobject Usage

Initialization

struct my_object {
    struct kobject kobj;
    int value;
    char name[32];
};

static void my_release(struct kobject *kobj)
{
    struct my_object *obj = container_of(kobj, struct my_object, kobj);
    pr_info("Releasing %s\n", kobject_name(kobj));
    kfree(obj);
}

static struct kobj_type my_ktype = {
    .release = my_release,
    .sysfs_ops = &kobj_sysfs_ops,
    /* .default_groups = my_groups, */
};

Creating and Adding

struct my_object *obj;

obj = kzalloc(sizeof(*obj), GFP_KERNEL);
if (!obj)
    return -ENOMEM;

kobject_init(&obj->kobj, &my_ktype);

ret = kobject_add(&obj->kobj, parent, "my_object");
if (ret) {
    kobject_put(&obj->kobj);  /* Calls release */
    return ret;
}

/* Or use combined init_and_add */
ret = kobject_init_and_add(&obj->kobj, &my_ktype, parent, "my_object");

Reference Counting

/* Get a reference */
kobject_get(&obj->kobj);

/* Release a reference */
kobject_put(&obj->kobj);

/* When refcount hits 0, ktype->release() is called */

Removal

/* Remove from sysfs */
kobject_del(&obj->kobj);

/* Release reference */
kobject_put(&obj->kobj);

/* Or combined */
kobject_put(&obj->kobj);  /* Calls del if needed */

Ksets: Collections of Kobjects

A kset is a collection of kobjects of the same type:

struct kset {
    struct list_head list;      /* List of kobjects */
    spinlock_t list_lock;
    struct kobject kobj;        /* The kset's own kobject */
    const struct kset_uevent_ops *uevent_ops;
};

Creating a Kset

static struct kset *my_kset;

static int __init my_init(void)
{
    /* Create kset under /sys/kernel/ */
    my_kset = kset_create_and_add("my_kset", NULL, kernel_kobj);
    if (!my_kset)
        return -ENOMEM;

    return 0;
}

static void __exit my_exit(void)
{
    kset_unregister(my_kset);
}

Adding Objects to a Kset

struct my_object *obj;

obj = kzalloc(sizeof(*obj), GFP_KERNEL);
kobject_init(&obj->kobj, &my_ktype);

/* Associate with kset */
obj->kobj.kset = my_kset;

/* Add to kset (parent will be kset's kobject) */
ret = kobject_add(&obj->kobj, NULL, "object%d", id);

Sysfs Attributes

Kobjects can have attributes (files in their sysfs directory):

Defining Attributes

/* Attribute show function */
static ssize_t value_show(struct kobject *kobj, struct kobj_attribute *attr,
                          char *buf)
{
    struct my_object *obj = container_of(kobj, struct my_object, kobj);
    return sprintf(buf, "%d\n", obj->value);
}

/* Attribute store function */
static ssize_t value_store(struct kobject *kobj, struct kobj_attribute *attr,
                           const char *buf, size_t count)
{
    struct my_object *obj = container_of(kobj, struct my_object, kobj);
    int val;

    if (kstrtoint(buf, 10, &val))
        return -EINVAL;

    obj->value = val;
    return count;
}

/* Create the attribute */
static struct kobj_attribute value_attr =
    __ATTR(value, 0664, value_show, value_store);

/* Attribute array */
static struct attribute *my_attrs[] = {
    &value_attr.attr,
    NULL,
};

/* Attribute group */
static struct attribute_group my_group = {
    .attrs = my_attrs,
};

static const struct attribute_group *my_groups[] = {
    &my_group,
    NULL,
};

Adding Attributes

/* Method 1: Add to ktype (automatic with kobject_add) */
static struct kobj_type my_ktype = {
    .release = my_release,
    .sysfs_ops = &kobj_sysfs_ops,
    .default_groups = my_groups,
};

/* Method 2: Add manually */
ret = sysfs_create_file(&obj->kobj, &value_attr.attr);

/* Method 3: Add group */
ret = sysfs_create_group(&obj->kobj, &my_group);

Complete Example

#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>

struct my_obj {
    struct kobject kobj;
    int value;
};

static struct kset *my_kset;
static struct my_obj *objects[3];

static ssize_t value_show(struct kobject *kobj, struct kobj_attribute *attr,
                          char *buf)
{
    struct my_obj *obj = container_of(kobj, struct my_obj, kobj);
    return sprintf(buf, "%d\n", obj->value);
}

static ssize_t value_store(struct kobject *kobj, struct kobj_attribute *attr,
                           const char *buf, size_t count)
{
    struct my_obj *obj = container_of(kobj, struct my_obj, kobj);
    int val;

    if (kstrtoint(buf, 10, &val))
        return -EINVAL;

    obj->value = val;
    return count;
}

static struct kobj_attribute value_attr =
    __ATTR(value, 0664, value_show, value_store);

static struct attribute *my_attrs[] = {
    &value_attr.attr,
    NULL,
};

ATTRIBUTE_GROUPS(my);

static void my_release(struct kobject *kobj)
{
    struct my_obj *obj = container_of(kobj, struct my_obj, kobj);
    pr_info("Releasing %s\n", kobject_name(kobj));
    kfree(obj);
}

static struct kobj_type my_ktype = {
    .release = my_release,
    .sysfs_ops = &kobj_sysfs_ops,
    .default_groups = my_groups,
};

static struct my_obj *create_object(int id)
{
    struct my_obj *obj;
    int ret;

    obj = kzalloc(sizeof(*obj), GFP_KERNEL);
    if (!obj)
        return NULL;

    obj->value = id * 10;
    obj->kobj.kset = my_kset;

    ret = kobject_init_and_add(&obj->kobj, &my_ktype, NULL, "object%d", id);
    if (ret) {
        kobject_put(&obj->kobj);
        return NULL;
    }

    kobject_uevent(&obj->kobj, KOBJ_ADD);
    return obj;
}

static void destroy_object(struct my_obj *obj)
{
    if (!obj)
        return;
    kobject_put(&obj->kobj);
}

static int __init kobj_init(void)
{
    int i;

    my_kset = kset_create_and_add("my_kset", NULL, kernel_kobj);
    if (!my_kset)
        return -ENOMEM;

    for (i = 0; i < 3; i++) {
        objects[i] = create_object(i);
        if (!objects[i]) {
            pr_err("Failed to create object %d\n", i);
        }
    }

    pr_info("Kobjects created at /sys/kernel/my_kset/\n");
    return 0;
}

static void __exit kobj_exit(void)
{
    int i;

    for (i = 0; i < 3; i++)
        destroy_object(objects[i]);

    kset_unregister(my_kset);
    pr_info("Kobjects removed\n");
}

module_init(kobj_init);
module_exit(kobj_exit);
MODULE_LICENSE("GPL");

Kobject vs Device

Feature kobject struct device
Purpose Generic sysfs object Hardware representation
Sysfs location Anywhere /sys/devices/
Power management No Yes
Bus integration No Yes
Driver binding No Yes

Use struct device for hardware, raw kobjects for other sysfs objects.

Summary

  • Kobjects provide reference counting and sysfs representation
  • Every kobject is a directory in sysfs
  • Ksets group related kobjects
  • ktype defines operations (release, sysfs_ops)
  • Always use kobject_put() to release references
  • The release() callback is called when refcount hits 0

Next

Learn about platform drivers - the most common driver type.


Back to top

Linux Driver Development Guide is a community resource for learning kernel driver development. Not affiliated with the Linux Foundation. Content provided for educational purposes.

This site uses Just the Docs, a documentation theme for Jekyll.