01int __init devices_init(void)
02{
03 devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
04 if (!devices_kset)
05 return -ENOMEM;
06 dev_kobj = kobject_create_and_add("dev", NULL);
07 if (!dev_kobj)
08 goto dev_kobj_err;
09 sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
10 if (!sysfs_dev_block_kobj)
11 goto block_kobj_err;
12 sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
13 if (!sysfs_dev_char_kobj)
14 goto char_kobj_err;
15
16 return 0;
17
18 char_kobj_err:
19 kobject_put(sysfs_dev_block_kobj);
20 block_kobj_err:
21 kobject_put(dev_kobj);
22 dev_kobj_err:
23 kset_unregister(devices_kset);
24 return -ENOMEM;
25}
第3行使用kset_create_and_add函数创建一个全局的kset对象,来初始化devices_kset指针。也就是sys目录下创建device目录
第4行如果值为真,说明创建失败,返回。
第6行使用kobject_create_and_add函数创建一个kobject对象,来初始化dev_kobj指针。在sys目录下创建dev目录。
第7行如果if条件为真,说明创建不成功。
第9行创建块设备的kobject对象,其kobject为dev_kobj,也就是在dev目录下创建一个block目录。
第10行如果条件为真,创建不成功,中转到block_koj_err地方处理。
第12行创建字符设备的kobject对象,其kobject为dev_kobj,也就是在dev目录下创建一个char目录。
01struct kset *kset_create_and_add(const char *name,
02 struct kset_uevent_ops *uevent_ops,
03 struct kobject *parent_kobj)
04{
05 struct kset *kset;
06 int error;
07
08 kset = kset_create(name, uevent_ops, parent_kobj);
09 if (!kset)
10 return NULL;
11 error = kset_register(kset);
12 if (error) {
13 kfree(kset);
14 return NULL;
15 }
16 return kset;
17}
这个函数,动态的产生一个kset结构,然后注册它到sysfs文件系统
第8行创建一个kset对象。
第11行注册一个kset对象。
static struct kset *kset_create(const char *name,
struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
01{
02 struct kset *kset;
03
04 kset = kzalloc(sizeof(*kset), GFP_KERNEL);
05 if (!kset)
06 return NULL;
07 kobject_set_name(&kset->kobj, name);
08 kset->uevent_ops = uevent_ops;
09 kset->kobj.parent = parent_kobj;
10
11 /*
12 * The kobject of this kset will have a type of kset_ktype and belong to
13 * no kset itself. That way we can properly free it when it is
14 * finished being used.
15 */
16 kset->kobj.ktype = &kset_ktype;
17 kset->kobj.kset = NULL;
18
19 return kset;
20}
第4行动态的分配空间给kset指针。
第7行设置kset的名字,其实是通过kset中的kobject对象,来设置名字的。每一个文件夹对应一个kobject对象。
第9行kset对象中的kobject对象的父指针指向parent_kobj,在这里是空指针的,因为它是第一个kset对象,他的kobject也是最顶层的目录
第16行kset对象的kobj.ktype对对象指向kset_ktype.
第17行kset对象的kobj.kset设置为空。
int kset_register(struct kset *k)
01{
02 int err;
03
04 if (!k)
05 return -EINVAL;
06
07 kset_init(k);
08 err = kobject_add_internal(&k->kobj);
09 if (err)
10 return err;
11 kobject_uevent(&k->kobj, KOBJ_ADD);
12 return 0;
13}
第7行使用kset_init函数初始化一个kset对象
第8行增加kset 的kobject对象。
static int kobject_add_internal(struct kobject *kobj)
{
01 int error = 0;
02 struct kobject *parent;
03
04 if (!kobj)
05 return -ENOENT;
06
07 if (!kobj->name || !kobj->name[0]) {
08 WARN(1, "kobject: (%p): attempted to be registered with empty "
09 "name!\n", kobj);
10 return -EINVAL;
11 }
12
13 parent = kobject_get(kobj->parent);
14
15 /* join kset if set, use it as parent if we do not already have one */
16 if (kobj->kset) {
17 if (!parent)
18 parent = kobject_get(&kobj->kset->kobj);
19 kobj_kset_join(kobj);
20 kobj->parent = parent;
21 }
22
23 pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
24 kobject_name(kobj), kobj, __func__,
25 parent ? kobject_name(parent) : "<NULL>",
26 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
27
28 error = create_dir(kobj);
29 if (error) {
30 kobj_kset_leave(kobj);
31 kobject_put(parent);
32 kobj->parent = NULL;
33
34 /* be noisy on error issues */
35 if (error == -EEXIST)
36 printk(KERN_ERR "%s failed for %s with "
37 "-EEXIST, don't try to register things with "
38 "the same name in the same directory.\n",
39 __func__, kobject_name(kobj));
40 else
41 printk(KERN_ERR "%s failed for %s (%d)\n",
42 __func__, kobject_name(kobj), error);
43 dump_stack();
44 } else
45 kobj->state_in_sysfs = 1;
46
47 return error;
48}
第13行增加对kobject对象父节点的引用。
第28行创建一个kobject目录
第29-44行如果创建目录出错,减少对父kobject对象的引用。
struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
{
01 struct kobject *kobj;
02 int retval;
03
04 kobj = kobject_create();
05 if (!kobj)
06 return NULL;
07
08 retval = kobject_add(kobj, parent, "%s", name);
09 if (retval) {
10 printk(KERN_WARNING "%s: kobject_add error: %d\n",
11 __func__, retval);
12 kobject_put(kobj);
13 kobj = NULL;
14 }
15 return kobj;
16}
第4行创建一个kobject对象
第8行把这个kobject对象,加入到层次架构中,也就是sysfs文件系统中。
struct kobject *kobject_create(void)
{
01 struct kobject *kobj;
02
03 kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
04 if (!kobj)
05 return NULL;
06
07 kobject_init(kobj, &dynamic_kobj_ktype);
08 return kobj;
09}
第3行分配kobject对象空间
第7行初始kobject对象
int kobject_add(struct kobject *kobj, struct kobject *parent,
const char *fmt, ...)
{
01 va_list args;
02 int retval;
03
04 if (!kobj)
05 return -EINVAL;
06
07 if (!kobj->state_initialized) {
08 printk(KERN_ERR "kobject '%s' (%p): tried to add an "
09 "uninitialized object, something is seriously wrong.\n",
10 kobject_name(kobj), kobj);
11 dump_stack();
12 return -EINVAL;
13 }
14 va_start(args, fmt);
15 retval = kobject_add_varg(kobj, parent, fmt, args);
16 va_end(args);
17
18 return retval;
19}
kobject对象的名字会被加到kobject的层次树中。如果出错的话,会减少对kobject的引用。
下面的函数分别是增加char和block的目录。和dev目录的增加是类似的。