Linux设备驱动模型二 kobject

来源:互联网 发布:sinx幂级数展开知乎 编辑:程序博客网 时间:2024/05/29 16:32

kobject


1.1 kobject数据结构

kobjectsysfs文件系统的基础数据结构,它定义在include/linux/kobjec.h

struct kobject {      /*名称*/   const char     *name;   /*与与所属的kset(list成员)组成链表*/   struct list_head   entry;   /*父kobject;此成员未指定时,默认指向所属kset的kobject成员;在/sys文件系统中表示目录的上一层*/   struct kobject     *parent;   /*指向所属的kset,可为NULL*/   struct kset        *kset;   /*提供操作kobject属性特征(attribute)的接口*/   struct kobj_type   *ktype;   /*sys文件信息*/   struct sysfs_dirent    *sd;   /*kobject的引用计数*/   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;};   


kset的定义如下:

struct kset {/*与子kobject的entry成员组成链表*/struct list_head list;/*自旋锁*/spinlock_t list_lock;/*kobject*/struct kobject kobj;const struct kset_uevent_ops *uevent_ops;}; 


kobj_type的定义如下:

struct kobj_type {/*释放函数*/void (*release)(struct kobject *kobj);/*sys文件操作函数*/const struct sysfs_ops *sysfs_ops;/*文件属性*/struct attribute **default_attrs;const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);const void *(*namespace)(struct kobject *kobj);}; 

sysfs_direct被定义在fs/sysfs/sysfs.h,它的定义如下:

struct sysfs_dirent {atomic_ts_count;atomic_ts_active;#ifdef CONFIG_DEBUG_LOCK_ALLOCstruct lockdep_mapdep_map;#endif/*上级目录*/struct sysfs_dirent*s_parent;struct sysfs_dirent*s_sibling;/*名称*/const char*s_name;const void*s_ns; /* namespace tag */union {struct sysfs_elem_dirs_dir;struct sysfs_elem_symlinks_symlink;struct sysfs_elem_attrs_attr;struct sysfs_elem_bin_attrs_bin_attr;};unsigned ints_flags;unsigned shorts_mode;ino_ts_ino;struct sysfs_inode_attrs *s_iattr;}; 


1.2 Kobject创建流程


我们看一下kobject的初始化过程。

初始化kobject有两种方式,分别是用kobject_init_and_addkobject_create_and_add函数,他们的区别是:

1)kobject_init_and_add传入一个kobject指针和kobj_type指针,然后进行初始化

2)kobject_create_and_add创建一个kobject变量,并返回其指针,它不用传入kobj_type指针

1.2.1 kobject_init_and_add


下面看kobject_init_and_add函数的实现:

/** * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy * @kobj: pointer to the kobject to initialize * @ktype: pointer to the ktype for this kobject. * @parent: pointer to the parent of this kobject. * @fmt: the name of the kobject. * * This function combines the call to kobject_init() and * kobject_add().  The same type of error handling after a call to * kobject_add() and kobject lifetime rules are the same here. */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;} 

它首先调用了kobject_init函数,再调用kobject_add_varg函数。先看kobject_init函数的实现:

/** * kobject_init - initialize a kobject structure * @kobj: pointer to the kobject to initialize * @ktype: pointer to the ktype for this kobject. * * This function will properly initialize a kobject such that it can then * be passed to the kobject_add() call. * * After this function is called, the kobject MUST be cleaned up by a call * to kobject_put(), not by a call to kfree directly to ensure that all of * the memory is cleaned up properly. */void kobject_init(struct kobject *kobj, struct kobj_type *ktype){    char *err_str;    if (!kobj) {        err_str = "invalid kobject pointer!";        goto error;    }    /*ktype不能为NULL*/    if (!ktype) {        err_str = "must have a ktype to be initialized properly!\n";        goto error;    }    if (kobj->state_initialized) {        /* do not error out as sometimes we can recover */        printk(KERN_ERR "kobject (%p): tried to init an initialized "               "object, something is seriously wrong.\n", kobj);        dump_stack();    }    /*调用kobject_init_internal函数*/    kobject_init_internal(kobj);    /*设置ktype*/    kobj->ktype = ktype;    return;error:    printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);    dump_stack();} 

从上面的代码可以看到,它调用了kobject_init_internal函数,并设置了kobject所指向的ktypektype必须不能为NULL

再看kobject_init_internal函数的实现:

static void kobject_init_internal(struct kobject *kobj){    if (!kobj)        return;    /*初始化引用计数器为1*/    kref_init(&kobj->kref);    /*初始化entry链表结点,用于与所属的kset的list成员组成链表*/    INIT_LIST_HEAD(&kobj->entry);    kobj->state_in_sysfs = 0;    kobj->state_add_uevent_sent = 0;    kobj->state_remove_uevent_sent = 0;    kobj->state_initialized = 1;} 

kobject_init_internal函数初始化引用计数器为1,并初始化entry链表结点。

 

  • 我们再次回到kobject_init_and_add函数中,它接着调用了kobject_add_varg函数:

static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,                            const char *fmt, va_list vargs){    int retval;    /*设置kobject的名称*/    retval = kobject_set_name_vargs(kobj, fmt, vargs);    if (retval) {        printk(KERN_ERR "kobject: can not set name properly!\n");        return retval;    }    /*设置父kobject*/    kobj->parent = parent;    /*调用kobject_add_internal函数*/    return kobject_add_internal(kobj);} 

kobject_add_varg函数主要做了以下3个工作:

1)动过kobject_set_name_vargs设置kobject的名称

2)设置kobjectparent成员,即所指向的父kobject,可以为NULL

3)调用kobject_add_internal函数


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,这里调用了kobject_get,结束的时候必须用kobject_put*/    parent = kobject_get(kobj->parent);    /* join kset if set, use it as parent if we do not already have one */    if (kobj->kset) {        /*如果parent没有设置,把parent指向所属ket的kobj成员*/        if (!parent)            parent = kobject_get(&kobj->kset->kobj);        /*把kobject的entry成员添加到kset的list链表中*/        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>");    /*创建sys目录*/    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",                   __func__, kobject_name(kobj));        else            printk(KERN_ERR "%s failed for %s (%d)\n",                   __func__, kobject_name(kobj), error);        dump_stack();    } else        kobj->state_in_sysfs = 1;    return error;} 

kobject_add_internal函数有几个关键点:

1)如果kobjectkset成员不为NULL,它会调用kobj_kset_join函数把kobjectentry成员添加到ksetlist链表中

2)如果kobjectparent成员为NULL,则把它指向ksetkobject成员。

3)最后调用create_dir函数创建sys目录,关于create_dir,在上一章中有描述。

 

接着看kobj_kset_join函数的实现:

/* add the kobject to its kset's list */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);} 

很清楚地看到,此段代码把kobjectentry成员添加到以ksetlist成员为头结点的链表中。


1.2.2 创建流程图



1.2.3 kobject_create_and_add

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;} 

它调用了kobject_createkobject_add函数。

 

Kobject_create的实现如下:

struct kobject *kobject_create(void){struct kobject *kobj;kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);if (!kobj)return NULL;kobject_init(kobj, &dynamic_kobj_ktype);return kobj;

可以看到,和之前的kobject_init_and_add函数一样,它也调用了kobject_init函数来初始化kobject,但此时传入的kobj_type指针是系统定义的kobj_type变量:

static struct kobj_type dynamic_kobj_ktype = {.release= dynamic_kobj_release,.sysfs_ops= &kobj_sysfs_ops,}; 

所以,我们应该明白:通过kobject_init_and_add初始化的kobject,其ktype成员是外部指定的,而通过kobject_create_and_add初始化的kobject,其ktype成员是系统定义的。

  • 再看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;} 

可以看到,它调用了kobject_add_varg函数,此函数的实现在之前已描述过。


1.2.4 创建流程图





1.2.5 代码示例1

  •  文件kobject_demo1.c

#include <linux/device.h>#include <linux/module.h>#include <linux/init.h>#include <linux/sysfs.h>#include <linux/kernel.h>#include <linux/stat.h>#include <linux/slab.h>#include <linux/string.h>/*kobject变量*/static struct kobject *mp_kobj;/*struct attribute {const char*name;mode_tmode;#ifdef CONFIG_DEBUG_LOCK_ALLOCstruct lock_class_key*key;struct lock_class_keyskey;#endif};*//*struct attribute变量*/static struct attribute m_attr = {    .name = "name",    .mode = S_IRWXUGO,};/*struct attribute数组*/static struct attribute *m_attrs[] = {    &m_attr,    NULL,/*末尾必须为NULL*/};/**********************************************************///sysfs_ops/*struct sysfs_ops {ssize_t(*show)(struct kobject *, struct attribute *,char *);ssize_t(*store)(struct kobject *,struct attribute *,const char *, size_t);};*//*sysfs_ops的show函数实现*/static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,                              char *buf){    ssize_t count = 0;    printk("%s\n", __FUNCTION__);    count = sprintf(buf, "%s\n", kobject_name(kobj) );    return count;}/*sysfs_ops的store函数实现*/static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,                               const char *buf, size_t count){    printk("%s\n", __FUNCTION__);    return 0;}/*struct sysfs_ops变量 */static struct sysfs_ops m_sys_ops = {    .show = kobj_attr_show,    .store = kobj_attr_store,};/**********************************************************//*模块加载函数*/static int __init kobj_init(void){    int error = 0;    /*struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)    if use kobject_create_and_add, it will auto bind ktype to dynamic_kobj_ktype    so we can not set ktype member*/    mp_kobj = kobject_create_and_add("kobj_demo1_1", NULL);    if (!mp_kobj) {        goto out;    }    printk("%s success.\n", __FUNCTION__);    return 0;out:    printk("%s failed!\n", __FUNCTION__);    return error;}/*模块退出函数*/static void __exit kobj_exit(void){    //删除kobject    kobject_del(mp_kobj);    //使引用计数减1并调用kobj_type的release函数    kobject_put(mp_kobj);    printk("%s\n", __FUNCTION__);}module_init(kobj_init);module_exit(kobj_exit);MODULE_AUTHOR("tonny");MODULE_DESCRIPTION("kobject demo");MODULE_LICENSE("GPL"); 

 

  • 文件Makefile

FILE=kobject_demo1obj-m:=$(FILE).oKERNELBUILD :=/lib/modules/$(shell uname -r)/builddefault:make -C $(KERNELBUILD) M=$(shell pwd) modulesecho insmod/rmmod ./$(FILE).ko to load or uninstallclean:rm -rf *.o *.ko *.mod.c .*.cmd *.markers *.order *.symvers .tmp_versions 

  • 编译及运行:

$ make#编译模块$ sudo dmesg -c            #清除内核日志$ sudo insmod ./kobject_demo1.ko   #加载内核模块$ sudo dmesg                #察看内核日志[ 1954.839828] kobj_init success.$ cd /sys/kobj_demo1/           #进入/sys目录$ pwd/sys/kobj_demo1$ lsname$ cat name              #察看kobject属性kobj_demo1$ sudo rmmod ./kobject_demo1.ko        #卸载内核模块$ sudo dmesg[ 3609.041498] kobj_release[ 3609.041501] kobj_exit 

  • kobject_demo1.c的关键地方:

1)通过kobject_init_and_add函数初始化kobject,同时传入了ktype变量。

2)因为没有设置父kobjectkset,所以kobject_demo1出现在/sys顶层目录下

3)在删除kobject的时候,必须调用kobject_put函数,以便清除kobject所有相关的内存,kobject_put函数的实现如下:

/** * kobject_put - decrement refcount for object. * @kobj: object. * * Decrement the refcount, and if 0, call kobject_cleanup(). */void kobject_put(struct kobject *kobj){    if (kobj) {        if (!kobj->state_initialized)            WARN(1, KERN_WARNING "kobject: '%s' (%p): is not "                 "initialized, yet kobject_put() is being "                 "called.\n", kobject_name(kobj), kobj);        kref_put(&kobj->kref, kobject_release);    }} 

1.2.6 代码示例2

通过kobject_create_and_add函数创建kobject

  •  文件kobject_demo1_1.c

#include <linux/device.h>#include <linux/module.h>#include <linux/init.h>#include <linux/sysfs.h>#include <linux/kernel.h>#include <linux/stat.h>#include <linux/slab.h>#include <linux/string.h>/*kobject变量*/static struct kobject *mp_kobj;/*struct attribute {const char*name;mode_tmode;#ifdef CONFIG_DEBUG_LOCK_ALLOCstruct lock_class_key*key;struct lock_class_keyskey;#endif};*//*struct attribute变量*/static struct attribute m_attr = {    .name = "name",    .mode = S_IRWXUGO,};/*struct attribute数组*/static struct attribute *m_attrs[] = {    &m_attr,    NULL,/*末尾必须为NULL*/};/**********************************************************///sysfs_ops/*struct sysfs_ops {ssize_t(*show)(struct kobject *, struct attribute *,char *);ssize_t(*store)(struct kobject *,struct attribute *,const char *, size_t);};*//*sysfs_ops的show函数实现*/static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,                              char *buf){    ssize_t count = 0;    printk("%s\n", __FUNCTION__);    count = sprintf(buf, "%s\n", kobject_name(kobj) );    return count;}/*sysfs_ops的store函数实现*/static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,                               const char *buf, size_t count){    printk("%s\n", __FUNCTION__);    return 0;}/*struct sysfs_ops变量 */static struct sysfs_ops m_sys_ops = {    .show = kobj_attr_show,    .store = kobj_attr_store,};/**********************************************************//*模块加载函数*/static int __init kobj_init(void){    int error = 0;    /*struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)    if use kobject_create_and_add, it will auto bind ktype to dynamic_kobj_ktype    so we can not set ktype member*/    mp_kobj = kobject_create_and_add("kobj_demo1_1", NULL);    if (!mp_kobj) {        goto out;    }    printk("%s success.\n", __FUNCTION__);    return 0;out:    printk("%s failed!\n", __FUNCTION__);    return error;}/*模块退出函数*/static void __exit kobj_exit(void){    //删除kobject    kobject_del(mp_kobj);    //使引用计数减1并调用kobj_type的release函数    kobject_put(mp_kobj);    printk("%s\n", __FUNCTION__);}module_init(kobj_init);module_exit(kobj_exit);MODULE_AUTHOR("tonny");MODULE_DESCRIPTION("kobject demo");MODULE_LICENSE("GPL"); 

kobject_demo1.c不同的是,kobject_demo1_1.c并没有创建kobj_type变量

1.2.7 代码示例3


前面两个示例并没有指定父kobjectparent成员,下面指定其parent成员

  • kobject_demo2.c

#include <linux/device.h>#include <linux/module.h>#include <linux/init.h>#include <linux/sysfs.h>#include <linux/kernel.h>#include <linux/stat.h>#include <linux/slab.h>#include <linux/string.h>#define ATTR_NAME "name"#define ATTR_VALUE"value"struct my_object {    struct kobject kobj;    int value;};static struct my_object *m_obj1;static struct my_object *m_obj2;/**********************************************************///attrubutestatic struct attribute m_attr_name = {    .name = ATTR_NAME,    .mode = S_IRWXUGO,};static struct attribute m_attr_value = {    .name = ATTR_VALUE,    .mode = S_IRWXUGO,};static struct attribute *m_attrs[] = {    &m_attr_name,    &m_attr_value,    NULL,};/**********************************************************///sysfs_opsstatic ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,                              char *buf){    ssize_t count = 0;    struct my_object *mobj;    printk("%s\n", __FUNCTION__);    if (!strcmp(attr->name, ATTR_NAME)) {        count = sprintf(buf, "%s\n", kobject_name(kobj) );    } else if (!strcmp(attr->name, ATTR_VALUE)) {        mobj = container_of(kobj, struct my_object, kobj);        count = sprintf(buf, "%d\n", mobj->value);    }    return count;}static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,                               const char *buf, size_t count){    struct my_object *mobj;    printk("%s\n", __FUNCTION__);    if (!strcmp(attr->name, ATTR_VALUE)) {        mobj = container_of(kobj, struct my_object, kobj);        sscanf(buf, "%d", &mobj->value);    }    return count;}static struct sysfs_ops m_sys_ops = {    .show = kobj_attr_show,    .store = kobj_attr_store,};/**********************************************************///kobj_typevoid kobj_release(struct kobject *kobj){    struct my_object *mobj = container_of(kobj, struct my_object, kobj);    if (mobj) {        //释放my_object内存        kfree(mobj);    }    printk("%s\n", __FUNCTION__);}static struct kobj_type m_ktype = {    .release = kobj_release,    .sysfs_ops = &m_sys_ops,    .default_attrs = m_attrs,};/**********************************************************/static int __init kobj_init(void){    int error = 0;    //申请m_obj1内存    m_obj1 = (struct my_object *)kzalloc(sizeof(struct my_object), GFP_KERNEL);    if (!m_obj1) {        error = -ENOMEM;        goto out;    }    //申请m_obj2内存    m_obj2 = (struct my_object *)kzalloc(sizeof(struct my_object), GFP_KERNEL);    if (!m_obj2) {        error = -ENOMEM;        goto out1;    }    //初始化m_obj1的kobject    error = kobject_init_and_add(&m_obj1->kobj, &m_ktype, NULL, "kobj_demo1");    if (error) {        goto out2;    }    ////初始化m_obj2的kobject,并指定其parent为m_obj1->kobj    error = kobject_init_and_add(&m_obj2->kobj, &m_ktype, &m_obj1->kobj, "kobj_demo2");    if (error) {        goto out2;    }    //初始化value值    m_obj1->value = 1;    m_obj2->value = 2;    printk("%s success.\n", __FUNCTION__);    return 0;out2:    kfree(m_obj2);out1:    kfree(m_obj1);out:    printk("%s failed!\n", __FUNCTION__);    return error;}static void __exit kobj_exit(void){    //删除kobject    kobject_del(&m_obj2->kobj);    //使引用计数减1并调用kobj_type的release函数    kobject_put(&m_obj2->kobj);    kobject_del(&m_obj1->kobj);    kobject_put(&m_obj1->kobj);    printk("%s\n", __FUNCTION__);}module_init(kobj_init);module_exit(kobj_exit);MODULE_AUTHOR("tonny");MODULE_DESCRIPTION("kobject demo");MODULE_LICENSE("GPL"); 









0 0
原创粉丝点击