LDM以kobject和kset为根本,初步了解了kobject后,继续趁热打铁,对kset做下了解,并对kobject和kest的关系做下了解。
内核空间与用户空间的映射关系如下表所示:
内核空间(internel) | 用户空间(externel) |
内核对象 (kernel objects) |
目录 (directories) |
对象属性 (object attributes) |
普通文件 (regular files) |
对象关系 (object relationshiops) |
符号链接 (symbolic links) |
struct kobject {
const char *name;
struct kref kref;
struct list_head entry;
struct kobject *parent;
struct kset *kset; //包含kset,网上说kset是kobject的容器,没懂什么意思。。。
struct kobj_type *ktype;
struct sysfs_dirent *sd;
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;
};
struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;//包含kobject
struct kset_uevent_ops *uevent_ops;
};
先看下kset_example,说不定就明白了
依旧是从module_init(example_init);开始:
static int example_init(void)
{
/*
* Create a kset with the name of "kset_example",
* located under /sys/kernel/
*/
example_kset = kset_create_and_add("kset_example", NULL, kernel_kobj);
if (!example_kset)
return -ENOMEM;
/*
* Create three objects and register them with our kset
*/
foo_obj = create_foo_obj("foo");
if (!foo_obj)
goto foo_error;
bar_obj = create_foo_obj("bar");
if (!bar_obj)
goto bar_error;
baz_obj = create_foo_obj("baz");
if (!baz_obj)
goto baz_error;
return 0;
baz_error:
destroy_foo_obj(bar_obj);
bar_error:
destroy_foo_obj(foo_obj);
foo_error:
return -EINVAL;
}
首先看第一步:
example_kset = kset_create_and_add("kset_example", NULL, kernel_kobj);//这里的kernel_kobj和kobject_example中的一样,还是sys/kernel目录。可参见ksysfs_init函数。
struct kset *kset_create_and_add(const char *name,
struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
{
struct kset *kset;
int error;
kset = kset_create(name, uevent_ops, parent_kobj);
if (!kset)
return NULL;
error = kset_register(kset);
if (error) {
kfree(kset);
return NULL;
}
return kset;
}
第一步是kset = kset_create(name, uevent_ops, parent_kobj);
第二步是error = kset_register(kset);
生成kset:
static struct kset *kset_create(const char *name,
struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
{
struct kset *kset;
kset = kzalloc(sizeof(*kset), GFP_KERNEL);
if (!kset)
return NULL;
kobject_set_name(&kset->kobj, name);
kset->uevent_ops = uevent_ops;
kset->kobj.parent = parent_kobj;
/*
* The kobject of this kset will have a type of kset_ktype and belong to
* no kset itself. That way we can properly free it when it is
* finished being used.
*/
kset->kobj.ktype = &kset_ktype;
kset->kobj.kset = NULL;
return kset;
}
1、给kset分配空间
2、将kset结构体中的kobject的名字设为“kset_example”.
3、将kset->uevent_ops = uevent_ops;
kset->kobj.parent = parent_kobj;
4、 kset->kobj.ktype = &kset_ktype;
static struct kobj_type kset_ktype = {
.sysfs_ops = &kobj_sysfs_ops,
.release = kset_release,
};
5、 kset->kobj.kset = NULL;
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;
}
1、kset_init(k);
void kset_init(struct kset *k)
{
kobject_init_internal(&k->kobj);
INIT_LIST_HEAD(&k->list);
spin_lock_init(&k->list_lock);
}
kset的初始化包括初始化kset中的kobject,将kset的list初始化。
2、 err = kobject_add_internal(&k->kobj);
将kset结构体中kobject做操作,这个操作和kobject_example中的不大一样:
static int kobject_add_internal(struct kobject *kobj)
{
int error = 0;
struct kobject *parent;
if (!kobj)
return -ENOENT;
if (!kobj->name || !kobj->name[0]) {
pr_debug("kobject: (%p): attempted to be registered with empty "
"name!/n", kobj);
WARN_ON(1);
return -EINVAL;
}
parent = kobject_get(kobj->parent);
/* join kset if set, use it as parent if we do not already have one */
if (kobj->kset) {
if (!parent)
parent = kobject_get(&kobj->kset->kobj);
kobj_kset_join(kobj);
kobj->parent = parent;
}
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'/n",
kobject_name(kobj), kobj, __FUNCTION__,
parent ? kobject_name(parent) : "<NULL>",
kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
error = create_dir(kobj);
if (error) {
kobj_kset_leave(kobj);
kobject_put(parent);
kobj->parent = NULL;
/* be noisy on error issues */
if (error == -EEXIST)
printk(KERN_ERR "%s failed for %s with "
"-EEXIST, don't try to register things with "
"the same name in the same directory./n",
__FUNCTION__, kobject_name(kobj));
else
printk(KERN_ERR "%s failed for %s (%d)/n",
__FUNCTION__, kobject_name(kobj), error);
dump_stack();
} else
kobj->state_in_sysfs = 1;
return error;
}
1、parent = kobject_get(kobj->parent);得到kset中的kobject的parent,所以parent指向name为“kernel”的kobject。
2、
if (kobj->kset) {
if (!parent)
parent = kobject_get(&kobj->kset->kobj);
kobj_kset_join(kobj);
kobj->parent = parent;
}
在kobject_example中不用看这个if,在kset_example也不需要看,因为在kset_create中有kset->kobj.kset = NULL;
3、error = create_dir(kobj);//以“kset_example”为名字建立一个目录
4、kobj->state_in_sysfs = 1;//表明该kset中的kobj在sysfs中了
最后,kobject_uevent(&k->kobj, KOBJ_ADD);
int kobject_uevent(struct kobject *kobj, enum kobject_action action)
{
return kobject_uevent_env(kobj, action, NULL);
}
//这个目前看不懂,大致理解为如下:
调用kobject_uevent()把这个(添加新设备的)事件,以及相关信息(包括设备的VendorID,DeviceID等信息。)通过netlink发送到用户态中。在用户态的udevd检测到这个事件,就可以根据这些信息,打开/lib/modules/uname-r/modules.alias文件。
接着是
create_foo_obj("foo");
create_foo_obj("bar");
create_foo_obj("baz");
以create_foo_obj("foo");为例:
struct foo_obj {
struct kobject kobj;
int foo;
int baz;
int bar;
};
static struct foo_obj *foo_obj;
static struct foo_obj *bar_obj;
static struct foo_obj *baz_obj;
static struct foo_obj *create_foo_obj(const char *name)
{
struct foo_obj *foo;
int retval;
/* allocate the memory for the whole object */
foo = kzalloc(sizeof(*foo), GFP_KERNEL);
if (!foo)
return NULL;
/*
* As we have a kset for this kobject, we need to set it before calling
* the kobject core.
*/
foo->kobj.kset = example_kset;
/*
* Initialize and add the kobject to the kernel. All the default files
* will be created here. As we have already specified a kset for this
* kobject, we don't have to set a parent for the kobject, the kobject
* will be placed beneath that kset automatically.
*/
retval = kobject_init_and_add(&foo->kobj, &foo_ktype, NULL, "%s", name);
if (retval) {
kfree(foo);
return NULL;
}
/*
* We are always responsible for sending the uevent that the kobject
* was added to the system.
*/
kobject_uevent(&foo->kobj, KOBJ_ADD);
return foo;
}
1、 struct foo_obj *foo;
foo = kzalloc(sizeof(*foo), GFP_KERNEL);
给新定义的foo_obj分配空间
2、foo->kobj.kset = example_kset;
3、retval = kobject_init_and_add(&foo->kobj, &foo_ktype, NULL, "%s", name);
其中
static struct kobj_type foo_ktype = {
.sysfs_ops = &foo_sysfs_ops,
.release = foo_release,
.default_attrs = foo_default_attrs,
};
而
static struct attribute *foo_default_attrs[] = {
&foo_attribute.attr,
&baz_attribute.attr,
&bar_attribute.attr,
NULL, /* need to NULL terminate the list of attributes */
};
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
struct kobject *parent, const char *fmt, ...)
{
va_list args;
int retval;
kobject_init(kobj, ktype);
va_start(args, fmt);
retval = kobject_add_varg(kobj, parent, fmt, args);
va_end(args);
return retval;
}
1、kobject_init(kobj, ktype);---->kobject_init(foo->kobj, foo_ktype)//初始化foo->kobj
2、retval = kobject_add_varg(kobj, parent, fmt, args);
因为retval = kobject_init_and_add(&foo->kobj, &foo_ktype, NULL, "%s", name);中第三个参数为NULL,所以
parent为NULL。
但是在内核中有这样的注释:
As we have already specified a kset for this
kobject, we don't have to set a parent for the kobject, the kobject
will be placed beneath that kset automatically.
kobject_add_varg中kobj->parent = parent;那就是kobj->parent为NULL
这个时候的kobject_add_varg有些不一样,首先调用kobject_set_name_vargs将名字设为"foo",然后调用
kobject_add_internal(struct kobject *kobj)
1、parent = kobject_get(kobj->parent);
2、
/* join kset if set, use it as parent if we do not already have one */
if (kobj->kset) {
if (!parent)
parent = kobject_get(&kobj->kset->kobj);
kobj_kset_join(kobj);
kobj->parent = parent;
}
这里,这个if就要跑进去了
既然跑进去了,而前面的kobj->parent为NULL,所以
要跑parent = kobject_get(&kobj->kset->kobj);
所以真正的parent还是被赋值为kset_example这个kset结构体包含的kobject中。这个正好印证了上面的英文注释:
As we have already specified a kset for this
kobject, we don't have to set a parent for the kobject, the kobject
will be placed beneath that kset automatically.
所以后面的kobj->parent = parent;就将foo中的kobject和kset_example中的kobject作为父子关系连接起来。
还有一个重要的一环:
kobj_kset_join(kobj);
/* add the kobject to its kset's list */
static void kobj_kset_join(struct kobject *kobj)
{
if (!kobj->kset)
return;
kset_get(kobj->kset);//计数加1
spin_lock(&kobj->kset->list_lock);
list_add_tail(&kobj->entry, &kobj->kset->list);
spin_unlock(&kobj->kset->list_lock);
}
list_add_tail(&kobj->entry, &kobj->kset->list); //就是把kobj自身加入到自身的kset的链表里面
/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
将kobj插入所属的kset的list_head这个双向链表中。
这样就像上图那样,不过kset child list应该就是list_head这个双向链表,就所有的kobject都串起来。
所以会生成下面的目录:
sys/kset_example下有三个目录:
foo、bar和baz
而每个目录下都有三个文件:foo、bar和baz。
show函数和kobect_example中的是一样的。
kobect和kset有了初步的认识,但对sysfs认识不够深,文件夹和文件都是怎么建立的要慢慢了解。