为了理解struct object 结构体,查看了很多资料,阅读了内核源码,总算对struct object 结构体有一点了解。不足之处,请指出。。。
(1)、为了便于了解struct object 结构体,先从例子出发:
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/init.h>
static int foo;
static int baz;
static int 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, “%du”, &foo);
return count;
}
static struct kobj_attribute foo_attribute =
__ATTR(foo, 0666, foo_show, foo_store);
static ssize_t b_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
int var;
if (strcmp(attr->attr.name, “baz”) == 0)
var = baz;
else
var = bar;
return sprintf(buf, “%d\n”, var);
}
static ssize_t b_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
int var;
sscanf(buf, “%du”, &var);
if (strcmp(attr->attr.name, “baz”) == 0)
baz = var;
else
bar = var;
return count;
}
static struct kobj_attribute baz_attribute =
__ATTR(baz, 0666, b_show, b_store);
static struct kobj_attribute bar_attribute =
__ATTR(bar, 0666, b_show, b_store);
static struct attribute *attrs[] = {
&foo_attribute.attr,
&baz_attribute.attr,
&bar_attribute.attr,
NULL, /* need to NULL terminate the list of attributes */
};
static struct attribute_group attr_group = {
.attrs = attrs,
};
static struct kobject *example_kobj;
static int __init example_init(void)
{
int retval;
example_kobj = kobject_create_and_add(“kobject_example”, kernel_kobj);
if (!example_kobj)
return -ENOMEM;
retval = sysfs_create_group(example_kobj, &attr_group);
if (retval)
kobject_put(example_kobj);
return retval;
}
static void __exit example_exit(void)
{
kobject_put(example_kobj);
}
module_init(example_init);
module_exit(example_exit);
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“Greg Kroah-Hartman <greg@kroah.com>”);
编译成模块,加载内核后,可以在/sys/kernel/目录下有一个kobject_example目录,目录下3个普通文件,权限为666,分别是foo,baz,bar。从模块入口函数kobject_create_and_add参数可知(struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)),第一个参数是name字符串,第二个参数是parent的一个struct kobject类型指针,返回值是一个指struct kobject类型。从中可以猜出第一个参数是一个目录名字,挂载在第二个参数目录下,返回一个指抽当前指向的目录指针。接下来看sysfs_create_group函数(int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)),第一个参数是指向一个struct kobject指针,第二个参数是指向一个struct attribute_group指针。可以猜出,在本函数作用是在struct kobjec指向的目录下创建自已的属性,分别是foo,baz,bar等属性。从中可以初步了解struct kobject结构体的作用。
(2)、对struct kobject了解,必需要对如下几个结构体了解
struct kobject {
const char *name;
struct list_head entry;
struct kobject *parent;
struct kset *kset;
struct kobj_type *ktype;
struct sysfs_dirent *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;
};
在struct kobject中,name是名字,entry是用于kobject所属kset下的子kobject链表,parent指向kobject的父节点,kset指向kobject所属的kset,ktype定义了kobject所属的类型,sd指向kobject对应的sysfs目录,kref记录kobject的引用计数,之后是一系列标志。
struct
kobj_type {
void
(*release)(
struct
kobject *kobj);
struct
sysfs_ops *sysfs_ops;
struct
attribute **default_attrs;
};
struct kobj_type就是定义了kobject的公共类型,其中既有操作的函数,也有公共的属性。其中release()是在kobject释放时调用的,sysfs_ops中定义了读写属性文件时调用的函数。default_attrs中定义了这类kobject公共的属性。
struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
};
struct kset可以看成在kobject上的扩展,它包含一个kobject的链表,可以方便地表示sysfs中目录与子目录的关系。其中,list是所属kobject的链表头,list_lock用于在访问链表时加锁,kobj是kset的内部kobject,要表现为sysfs中的目录就必须拥有kobject的功能,最后的kset_uevent_ops定义了对发往用户空间的uevent的处理。我对uevent不了解,会尽量忽略。
(2)、了解几个结构体后,就可以情境分析模块函数了
模块入口函数:
<0>example_init
static int __init example_init(void)
{
int retval;
example_kobj = kobject_create_and_add(“kobject_example”, kernel_kobj);
if (!example_kobj)
return -ENOMEM;
retval = sysfs_create_group(example_kobj, &attr_group);
if (retval)
kobject_put(example_kobj);
return retval;
}
<1> example_init->kobject_create_and_add
struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
{
struct kobject *kobj;
int retval;
kobj = kobject_create();
if (!kobj)
return NULL;
retval = kobject_add(kobj, parent, “%s”, name);
if (retval) {
printk(KERN_WARNING “%s: kobject_add error: %d\n”,
__func__, retval);
kobject_put(kobj);
kobj = NULL;
}
return kobj;
}
先分配一个 struct kobject *kobj结构体 kobj = kobject_create(),把分配结构体加入/sys的parent父目录下,并设置名字为name.
<2>example_init->kobject_create_and_add->kobject_add
int kobject_add(struct kobject *kobj, struct kobject *parent,
const char *fmt, …)
{
va_list args;
int retval;
if (!kobj)
return -EINVAL;
if (!kobj->state_initialized) {
printk(KERN_ERR “kobject ‘%s’ (%p): tried to add an ”
“uninitialized object, something is seriously wrong.\n”,
kobject_name(kobj), kobj);
dump_stack();
return -EINVAL;
}
va_start(args, fmt);
retval = kobject_add_varg(kobj, parent, fmt, args);
va_end(args);
return retval;
}
<3>example_init->kobject_create_and_add->kobject_add->kobject_add_varg
static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
const char *fmt, va_list vargs)
{
int retval;
retval = kobject_set_name_vargs(kobj, fmt, vargs);
if (retval) {
printk(KERN_ERR “kobject: can not set name properly!\n”);
return retval;
}
kobj->parent = parent;
return kobject_add_internal(kobj);
}
设置kobj中 name,并把父 kobj->parent 指向parent。然后添加和初始化kobj
<4>example_init->kobject_create_and_add->kobject_add->kobject_add_varg->kobject_add_internal
static int kobject_add_internal(struct kobject *kobj)
{
int error = 0;
struct kobject *parent;
if (!kobj)
return -ENOENT;
if (!kobj->name || !kobj->name[0]) {
WARN(1, “kobject: (%p): attempted to be registered with empty ”
“name!\n”, kobj);
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, __func__,
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)
WARN(1, “%s failed for %s with ”
“-EEXIST, don’t try to register things with ”
“the same name in the same directory.\n”,
__func__, kobject_name(kobj));
else
WARN(1, “%s failed for %s (error: %d parent: %s)\n”,
__func__, kobject_name(kobj), error,
parent ? kobject_name(parent) : “‘none'”);
} else
kobj->state_in_sysfs = 1;
return error;
}
首先判断kobj是否存在,kobj的name是否初始化,接下来从kobj引用parent,kobj的parent的引用计算加1,如果存在kobj的kset的集合,下一章介绍。如果在kset的集合中存在,并kobj的父parent不存在,那么引用kset集合中的kobj当父parent。然后把kobj加入kset集合中。否则在/sysfs当做父parent
<6>example_init->kobject_create_and_add->kobject_add->kobject_add_varg->kobject_add_internal->kobject_get
struct kobject *kobject_get(struct kobject *kobj)
{
if (kobj)
kref_get(&kobj->kref);
return kobj;
}
kobj的引用计数,每一次引用,kobj->kref的值加1.
<6>example_init->kobject_create_and_add->kobject_add->kobject_add_varg->kobject_add_internal->kobj_kset_join
static void kobj_kset_join(struct kobject *kobj)
{
if (!kobj->kset)
return;
kset_get(kobj->kset);
spin_lock(&kobj->kset->list_lock);
list_add_tail(&kobj->entry, &kobj->kset->list);
spin_unlock(&kobj->kset->list_lock);
}
把kobj的entry加入kobj->kset->list链表中
<7>example_init->kobject_create_and_add->kobject_add->kobject_add_varg->kobject_add_internal->create_dir
static int create_dir(struct kobject *kobj)
{
int error = 0;
if (kobject_name(kobj)) {
error = sysfs_create_dir(kobj);
if (!error) {
error = populate_dir(kobj);
if (error)
sysfs_remove_dir(kobj);
}
}
return error;
}
接下来就是在kobj的父parent目录下创建一个kobj的name的目录的属性。
<8>example_init->kobject_create_and_add->kobject_add->kobject_add_varg->kobject_add_internal->create_dir->sysfs_create_dir
int sysfs_create_dir(struct kobject * kobj)
{
enum kobj_ns_type type;
struct sysfs_dirent *parent_sd, *sd;
const void *ns = NULL;
int error = 0;
BUG_ON(!kobj);
if (kobj->parent)
parent_sd = kobj->parent->sd;
else
parent_sd = &sysfs_root;
if (!parent_sd)
return -ENOENT;
if (sysfs_ns_type(parent_sd))
ns = kobj->ktype->namespace(kobj);
type = sysfs_read_ns_type(kobj);
error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);
if (!error)
kobj->sd = sd;
return error;
}
如果kobj的parent存在,就获得parent的sd,否把sysfs_root当做当前的sd,也就是/sysfs目录,然后创建一个目录。
<9>example_init->kobject_create_and_add->kobject_add->kobject_add_varg->kobject_add_internal->create_dir->populate_dir
static int populate_dir(struct kobject *kobj)
{
struct kobj_type *t = get_ktype(kobj);
struct attribute *attr;
int error = 0;
int i;
if (t && t->default_attrs) {
for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {
error = sysfs_create_file(kobj, attr);
if (error)
break;
}
}
return error;
}
目录创建成功后,接下来如果默认属性存在就创建目录下创建默认的的属性,就用到了 struct kobj_type,供用户调用。
<10>example_init->sysfs_create_group
int sysfs_create_group(struct kobject *kobj,
const struct attribute_group *grp)
{
return internal_create_group(kobj, 0, grp);
}
<11>example_init->sysfs_create_group->internal_create_group
static int internal_create_group(struct kobject *kobj, int update,
const struct attribute_group *grp)
{
struct sysfs_dirent *sd;
int error;
BUG_ON(!kobj || (!update && !kobj->sd));
/* Updates may happen before the object has been instantiated */
if (unlikely(update && !kobj->sd))
return -EINVAL;
if (!grp->attrs) {
WARN(1, “sysfs: attrs not set by subsystem for group: %s/%s\n”,
kobj->name, grp->name ? “” : grp->name);
return -EINVAL;
}
if (grp->name) {
error = sysfs_create_subdir(kobj, grp->name, &sd);
if (error)
return error;
} else
sd = kobj->sd;
sysfs_get(sd);
error = create_files(sd, kobj, grp, update);
if (error) {
if (grp->name)
sysfs_remove_subdir(sd);
}
sysfs_put(sd);
return error;
}
可以知道在kobj的目录下创建一个普通文件,权限等属性。