struct object 结构体分析

来源:互联网 发布:矩阵的零次方等于一吗 编辑:程序博客网 时间:2024/05/22 10:45

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



1 0
原创粉丝点击