快乐虾
http://blog.csdn.net/lights_joy/
本文适用于
ADI bf561 DSP
uclinux-2008r1.5-rc3 (smp patch)
Visual DSP++ 5.0(update 5)
欢迎转载,但请保留作者信息
内核中使用了kobject来表示与管理一些内核对象,从documentation/kobject的描述可知,kobject兼有以下几个作用:
- Object reference counting.
- Maintaining lists (sets) of objects.
- Object set locking.
- Userspace representation.
kobject与sysfs文件系统有着密切的关系,所有注册到kobject核心的对象都将在sysfs文件系统中拥有一个目录,从而达到导出内核对象的目的。
这个结构体的定义位于include/linux/kref.h,用于表示一个kobject对象的引用计数。
struct kref {
atomic_t refcount;
};
就是一个atomic_t类型的数据。
通常使用kref_init函数对它进行初始化:
/**
* kref_init - initialize object.
* @kref: object in question.
*/
void kref_init(struct kref *kref)
{
atomic_set(&kref->refcount,1);
smp_mb();
}
即将refcount的初值设置为1。
这个结构体用于表示一个内核对象,其定义在include/linux/kobject.h:
#define KOBJ_NAME_LEN 20
struct kobject {
const char * k_name;
char name[KOBJ_NAME_LEN];
struct kref kref;
struct list_head entry;
struct kobject * parent;
struct kset * kset;
struct kobj_type * ktype;
struct dentry * dentry;
wait_queue_head_t poll;
};
l entry
每个kset下面都可有一长串的kobject列表,此成员即用于此目的。
l dentry
由于每个kobject都将在sysfs文件系统中创建一个目录,这个值就是指向它的目录节点,因为sysfs是在内存中实现的,因而需要用一个dentry来表示,而不是一个inode。
l k_name
这个成员可以单独指定一个名称,如果没有单独指定,它将指向此结构体的name成员。而且k_name不允许为空字符串。
kobject结构体使用kobject_init函数进行初始化:
/**
* kobject_init - initialize object.
* @kobj: object in question.
*/
void kobject_init(struct kobject * kobj)
{
if (!kobj)
return;
kref_init(&kobj->kref);
INIT_LIST_HEAD(&kobj->entry);
init_waitqueue_head(&kobj->poll);
kobj->kset = kset_get(kobj->kset);
}
通过此函数,引用计数设置为1。
当要引用一个kobject对象时,通常使用kobject_get函数:
/**
* kobject_get - increment refcount for object.
* @kobj: object.
*/
struct kobject * kobject_get(struct kobject * kobj)
{
if (kobj)
kref_get(&kobj->kref);
return kobj;
}
/**
* kref_get - increment refcount for object.
* @kref: object.
*/
void kref_get(struct kref *kref)
{
WARN_ON(!atomic_read(&kref->refcount));
atomic_inc(&kref->refcount);
smp_mb__after_atomic_inc();
}
即kobject_get函数将此kobject对象的引用加1后返回此对象。
这个结构体用于表示某一类对象(用kobject表示)的集合,其定义为:
/**
* kset - a set of kobjects of a specific type, belonging
* to a specific subsystem.
*
* All kobjects of a kset should be embedded in an identical
* type. This type may have a descriptor, which the kset points
* to. This allows there to exist sets of objects of the same
* type in different subsystems.
*
* A subsystem does not have to be a list of only one type
* of object; multiple ksets can belong to one subsystem. All
* ksets of a subsystem share the subsystem's lock.
*
* Each kset can support specific event variables; it can
* supress the event generation or add subsystem specific
* variables carried with the event.
*/
struct kset_uevent_ops {
int (*filter)(struct kset *kset, struct kobject *kobj);
const char *(*name)(struct kset *kset, struct kobject *kobj);
int (*uevent)(struct kset *kset, struct kobject *kobj, char **envp,
int num_envp, char *buffer, int buffer_size);
};
struct kset {
struct kobj_type * ktype;
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
struct kset_uevent_ops * uevent_ops;
};
从list这个成员可以很容易知道每个kset下面都将有许多的kobject。从kobj这个成员也可以猜测出内核是将kset也当成一个对象来看待的,呵呵。
通常使用kset_init函数进行此结构体的初始化:
/**
* kset_init - initialize a kset for use
* @k: kset
*/
void kset_init(struct kset * k)
{
kobject_init(&k->kobj);
INIT_LIST_HEAD(&k->list);
spin_lock_init(&k->list_lock);
}
注意在此并不改变uevent_ops成员的值,此值通常在定义kset的全局变量时初始化(可以初始化为NULL)。Ktype的值同样在全局变量定义时进行初始化,也可以设置为NULL。
这个类型用以表示对某一类kobject的操作:
struct kobj_type {
void (*release)(struct kobject *);
struct sysfs_ops * sysfs_ops;
struct attribute ** default_attrs;
};
内核中使用了decl_subsys这个宏来定义一类对象集:
#define decl_subsys(_name,_type,_uevent_ops) \
struct kset _name##_subsys = { \
.kobj = { .name = __stringify(_name) }, \
.ktype = _type, \
.uevent_ops =_uevent_ops, \
}
比如在fs/namespace.c中就定义了这么一个对象集:
decl_subsys(fs, NULL, NULL);
这个对象集在mnt_init函数中进行注册:
err = subsystem_register(&fs_subsys);
在内核中搜索,可以发现有不少的decl_subsys:
F:\embed\uClinux\uClinux-dist-2008R1.5-RC3\linux-2.6.x\block\genhd.c(611):decl_subsys(block, &ktype_block, &block_uevent_ops);
F:\embed\uClinux\uClinux-dist-2008R1.5-RC3\linux-2.6.x\drivers\base\bus.c(147):static decl_subsys(bus, &ktype_bus, NULL);
F:\embed\uClinux\uClinux-dist-2008R1.5-RC3\linux-2.6.x\drivers\base\class.c(75):static decl_subsys(class, &ktype_class, NULL);
F:\embed\uClinux\uClinux-dist-2008R1.5-RC3\linux-2.6.x\drivers\base\class.c(481):static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);
F:\embed\uClinux\uClinux-dist-2008R1.5-RC3\linux-2.6.x\drivers\base\core.c(431):decl_subsys(devices, &ktype_device, &device_uevent_ops);
F:\embed\uClinux\uClinux-dist-2008R1.5-RC3\linux-2.6.x\drivers\base\firmware.c(19):static decl_subsys(firmware, NULL, NULL);
F:\embed\uClinux\uClinux-dist-2008R1.5-RC3\linux-2.6.x\drivers\base\sys.c(135):static decl_subsys(system, &ktype_sysdev_class, NULL);
F:\embed\uClinux\uClinux-dist-2008R1.5-RC3\linux-2.6.x\fs\namespace.c(44):decl_subsys(fs, NULL, NULL);
F:\embed\uClinux\uClinux-dist-2008R1.5-RC3\linux-2.6.x\kernel\ksysfs.c(66):decl_subsys(kernel, NULL, NULL);
F:\embed\uClinux\uClinux-dist-2008R1.5-RC3\linux-2.6.x\kernel\params.c(697):decl_subsys(module, &module_ktype, &module_uevent_ops);
这些kset的共同特点是它们都没有parent。
此函数用于注册一个kset,其实现在fs/kobject.c中:
int subsystem_register(struct kset *s)
{
return kset_register(s);
}
跟踪kset_register:
/**
* kset_register - initialize and add a kset.
* @k: kset.
*/
int kset_register(struct kset * k)
{
if (!k)
return -EINVAL;
kset_init(k);
return kset_add(k);
}
挺简单的,先初始化kset结构体,再将它加入到内核中kset的链表中。
跟踪kset_add:
/**
* kset_add - add a kset object to the hierarchy.
* @k: kset.
*/
int kset_add(struct kset * k)
{
return kobject_add(&k->kobj);
}
从这里可以明显看出kset本身的确也是一个kobject。
跟踪kobject_add:
/**
* kobject_add - add an object to the hierarchy.
* @kobj: object.
*/
int kobject_add(struct kobject * kobj)
{
return kobject_shadow_add(kobj, NULL);
}
跟踪kobject_shadow_add:
/**
* kobject_shadow_add - add an object to the hierarchy.
* @kobj: object.
* @shadow_parent: sysfs directory to add to.
*/
int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
{
int error = 0;
struct kobject * parent;
if (!(kobj = kobject_get(kobj)))
return -ENOENT;
if (!kobj->k_name)
kobj->k_name = kobj->name;
if (!*kobj->k_name) {
pr_debug("kobject attempted to be registered with no name!\n");
WARN_ON(1);
kobject_put(kobj);
return -EINVAL;
}
parent = kobject_get(kobj->parent);
pr_debug("kobject %s: registering. parent: %s, set: %s\n",
kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>",
kobj->kset ? kobj->kset->kobj.name : "<NULL>" );
if (kobj->kset) {
spin_lock(&kobj->kset->list_lock);
if (!parent)
parent = kobject_get(&kobj->kset->kobj);
list_add_tail(&kobj->entry,&kobj->kset->list);
spin_unlock(&kobj->kset->list_lock);
kobj->parent = parent;
}
error = create_dir(kobj, shadow_parent);
if (error) {
/* unlink does the kobject_put() for us */
unlink(kobj);
kobject_put(parent);
/* be noisy on error issues */
if (error == -EEXIST)
printk(KERN_ERR "kobject_add failed for %s with "
"-EEXIST, don't try to register things with "
"the same name in the same directory.\n",
kobject_name(kobj));
else
printk(KERN_ERR "kobject_add failed for %s (%d)\n",
kobject_name(kobj), error);
dump_stack();
}
return error;
}
此时shadow_parent参数为NULL。
在此函数中,如果kobject有指定的kset,则将此object添加到kset的对象链表中,如果没有显式指定parent,则取kset做为它的parent。
然后调用create_dir函数在sysfs文件系统中创建此kobject的入口。
此函数的定义在lib/kobject.c:
static int create_dir(struct kobject * kobj, struct dentry *shadow_parent)
{
int error = 0;
if (kobject_name(kobj)) {
error = sysfs_create_dir(kobj, shadow_parent);
if (!error) {
if ((error = populate_dir(kobj)))
sysfs_remove_dir(kobj);
}
}
return error;
}
两步走,先用sysfs_create_dir创建目录,如果没有发生错误,它将正确设置好kobject::dentry,使其指向正确的目录指针。如果此kobject有指定的parent<span s