1 概念
kobj 是内核抽象出来的通用对象模型,用于表示内核中的实体.
结构体: https://elixir.bootlin.com/linux/v6.17.1/source/include/linux/kobject.h#L64.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| struct kobject { const char *name; struct list_head entry; struct kobject *parent; struct kset *kset; const struct kobj_type *ktype; struct kernfs_node *sd; struct kref kref;
unsigned int state_initialized:1; unsigned int state_in_sysfs:1; unsigned int state_add_uevent_sent:1; unsigned int state_remove_uevent_sent:1; unsigned int uevent_suppress:1;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE struct delayed_work release; #endif };
struct kobj_type { void (*release)(struct kobject *kobj); const struct sysfs_ops *sysfs_ops; const struct attribute_group **default_groups; const struct kobj_ns_type_operations *(*child_ns_type)(const struct kobject *kobj); const void *(*namespace)(const struct kobject *kobj); void (*get_ownership)(const struct kobject *kobj, kuid_t *uid, kgid_t *gid); };
struct kset { struct list_head list; spinlock_t list_lock; struct kobject kobj; const struct kset_uevent_ops *uevent_ops; } __randomize_layout;
struct kobj_attribute { struct attribute attr; ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf); ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); };
struct attribute { const char *name; umode_t mode; #ifdef CONFIG_DEBUG_LOCK_ALLOC bool ignore_lockdep:1; struct lock_class_key *key; struct lock_class_key skey; #endif };
|
关系图.

2 Demo
2.1 最小的 kobject demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include <linux/init.h> #include <linux/module.h> #include <linux/kobject.h> #include <linux/sysfs.h>
MODULE_LICENSE("GPL");
static struct kobject *demo_kobj;
static int __init kobj_demo_init(void) { demo_kobj = kobject_create_and_add("kobj_demo", kernel_kobj); if (!demo_kobj) return -ENOMEM;
pr_info("kobj_demo created at /sys/kernel/kobj_demo\n"); return 0; }
static void __exit kobj_demo_exit(void) { kobject_put(demo_kobj); pr_info("kobj_demo removed\n"); }
module_init(kobj_demo_init); module_exit(kobj_demo_exit);
|
这是一个空的 kobj,成功 insmod 之后会出现.
1
| ls /sys/kernel/kobj_demo
|
2.2 带属性文件的 demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| #include <linux/init.h> #include <linux/module.h> #include <linux/kobject.h> #include <linux/sysfs.h>
MODULE_LICENSE("GPL");
static struct kobject *demo_kobj; static int demo_value = 0;
static ssize_t value_show(struct kobject *kobj, struct attribute *attr, char *buf) { return sprintf(buf, "%d\n", demo_value); }
static ssize_t value_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) { sscanf(buf, "%d", &demo_value); return count; }
static struct attribute value_attr = { .name = "value", .mode = 0664, };
static const struct sysfs_ops demo_sysfs_ops = { .show = value_show, .store = value_store, };
static struct kobj_type demo_ktype = { .sysfs_ops = &demo_sysfs_ops, };
static int __init kobj_demo_init(void) { int ret; demo_kobj = kobject_create_and_add("kobj_demo", kernel_kobj); if (!demo_kobj) return -ENOMEM;
demo_kobj->ktype = &demo_ktype;
ret = sysfs_create_file(demo_kobj, &value_attr); if (ret) kobject_put(demo_kobj);
pr_info("kobj_demo with attribute(created via struct attribute) created\n"); return ret; }
static void __exit kobj_demo_exit(void) { kobject_put(demo_kobj); pr_info("kobj_demo removed\n"); }
module_init(kobj_demo_init); module_exit(kobj_demo_exit);
|
同样 insmod 之后我们会看到.
1 2 3 4 5 6 7 8
| cat /sys/kernel/kobj_demo/value 0
echo 42 > /sys/kernel/kobj_demo/value cat /sys/kernel/kobj_demo/value 42
|
2.3 多属性的 kobj
我们也可以用 kobj_arrtibute 是对 attribute 的一层封装.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| #include <linux/init.h> #include <linux/module.h> #include <linux/kobject.h> #include <linux/sysfs.h>
MODULE_LICENSE("GPL");
static int foo, bar;
static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "%d\n", foo); } static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { sscanf(buf, "%d", &foo); return count; }
static struct kobj_attribute foo_attr = __ATTR(foo, 0664, foo_show, foo_store);
static ssize_t bar_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "%d\n", bar); } static ssize_t bar_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { sscanf(buf, "%d", &bar); return count; } static struct kobj_attribute bar_attr = __ATTR(bar, 0664, bar_show, bar_store);
static struct attribute *demo_attrs[] = { &foo_attr.attr, &bar_attr.attr, NULL, };
static const struct attribute_group demo_attr_group = { .attrs = demo_attrs, };
static struct kobject *demo_kobj;
static int __init kobj_demo_init(void) { int ret; demo_kobj = kobject_create_and_add("kobj_demo", kernel_kobj); if (!demo_kobj) return -ENOMEM;
ret = sysfs_create_group(demo_kobj, &demo_attr_group); if (ret) kobject_put(demo_kobj);
pr_info("kobj_demo with foo and bar created\n"); return ret; }
static void __exit kobj_demo_exit(void) { kobject_put(demo_kobj); }
module_init(kobj_demo_init); module_exit(kobj_demo_exit);
|
同理.
1 2
| cat /sys/kernel/kobj_demo/foo echo 99 > /sys/kernel/kobj_demo/bar
|