struct object 结构体分析

  • Post author:
  • Post category:其他


为了理解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的目录下创建一个普通文件,权限等属性。



版权声明:本文为u013110721原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。