Chinaunix首页 | 论坛 | 博客
  • 博客访问: 766372
  • 博文数量: 370
  • 博客积分: 2334
  • 博客等级: 大尉
  • 技术积分: 3222
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-06 16:56
文章分类

全部博文(370)

文章存档

2013年(2)

2012年(368)

分类: LINUX

2012-05-23 23:22:06

关于kref的操作函数

初始化

void kref_init(struct kref *kref)
{
atomic_set(&kref->refcount, 1);
smp_mb();
}

注意smp_mb以及smp_mb_*的目的是保证在多核SMP机器上的一致性,初始化后引用计数为1。

递增引用计数

void kref_get(struct kref *kref)
{
        WARN_ON(!atomic_read(&kref->refcount));
        atomic_inc(&kref->refcount);
        smp_mb__after_atomic_inc();
}

递减引用计数

int kref_put(struct kref *kref, void (*release)(struct kref *kref))
{
        WARN_ON(release == NULL);
        WARN_ON(release == (void (*)(struct kref *))kfree);
        if (atomic_dec_and_test(&kref->refcount)) {
                release(kref);
                return 1;
        }
        return 0;
}

kref_put使用了回调函数机制。如果引用计数递减后为0,将调用函数release来执行一些释放操作。函数kref_sub与本函数类似,只是kref_sub中引用计数可以减小指定的值,不再局限于1。

int kref_sub(struct kref *kref, unsigned int count,
             void (*release)(struct kref *kref))
{
        WARN_ON(release == NULL);
        WARN_ON(release == (void (*)(struct kref *))kfree);
        if (atomic_sub_and_test((int) count, &kref->refcount)) {
                release(kref);
                return 1;
        }
        return 0;
}



关于kobject的函数

初始化

  1. void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
    {
            char *err_str;
     
            if (!kobj) {
                    err_str = "invalid kobject pointer!";
                    goto error;
            }
            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(kobj);
            kobj->ktype = ktype;
            return;
    //内核中经常使用goto语句进行错误处理
    error:
            printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
            dump_stack();
    }
    EXPORT_SYMBOL(kobject_init);
        该函数首先检测参数的有效性,然后检测该kobject是否已经初始化,然后调用函数kobject_init_internal,最后设置

kobj和ktype之间的映射关系。

static void kobject_init_internal(struct kobject *kobj)
{
        if (!kobj)
                return;
        kref_init(&kobj->kref);
        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的主要工作就是初始化引用计数,链表元素以及各种状态标识。

添加,即将kobject加入驱动模型系统中进行管理

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;
}
EXPORT_SYMBOL(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);
}

这个函数先是设置了kobject的名字,最后建立kobj及其父节点之间的映射关系。

int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
                                  va_list vargs)
{
        const char *old_name = kobj->name;
        char *s;
        if (kobj->name && !fmt)
               return 0;
        kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
        if (!kobj->name)
               return -ENOMEM;
        /* e some of these buggers have '/' in the name ... */
        /* 因为kobject如果通过sysfs导出到用户空间都对应一个目录,所以名称中不能包含‘/’字符 */
        while ((s = strchr(kobj->name, '/')))
                s[0] = '!';
        kfree(old_name);
        return 0;
}

删除,即从驱动设备模型系统中去掉本kobject。

void kobject_del(struct kobject *kobj)
{
        if (!kobj)
                return;
        sysfs_remove_dir(kobj);
        kobj->state_in_sysfs = 0;
        kobj_kset_leave(kobj);
        kobject_put(kobj->parent);
        kobj->parent = NULL;
}

该函数首先从sysfs中去掉响应的目录项,然后从所属kset中去掉本kobject,并修改父节点引用计数。

static void kobj_kset_leave(struct kobject *kobj)
{
       if (!kobj->kset)
                return;
        spin_lock(&kobj->kset->list_lock);
        list_del_init(&kobj->entry);
        spin_unlock(&kobj->kset->list_lock);
        kset_put(kobj->kset);
}

在本函数中,将本kobject从kset的链表中摘下,调用kset_put函数(下面会有介绍)。

函数kobject_get用于递增kobject引用计数。

struct kobject *kobject_get(struct kobject *kobj)
{
        if (kobj)
                kref_get(&kobj->kref);
        return kobj;
}

对应的,函数kobject_put用于递增kobject引用计数,如果kobject引用计数为0,则调用kobject_release。

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

以下函数用于删除时的清理工作。

static void kobject_release(struct kref *kref)
{
        kobject_cleanup(container_of(kref, struct kobject, kref));
}
 
static void kobject_cleanup(struct kobject *kobj)
{
        struct kobj_type *t = get_ktype(kobj);
        const char *name = kobj->name;
        pr_debug("kobject: '%s' (%p): %s\n",
                 kobject_name(kobj), kobj, __func__);
        if (t && !t->release)
                pr_debug("kobject: '%s' (%p): does not have a release() "
                         "function, it is broken and must be fixed.\n",
                         kobject_name(kobj), kobj);
        /* send "remove" if the caller did not do it but sent "add" */
        if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) {
                pr_debug("kobject: '%s' (%p): auto cleanup 'remove' event\n",
                         kobject_name(kobj), kobj);
                kobject_uevent(kobj, KOBJ_REMOVE);
        }
        /* remove from sysfs if the caller did not do it */
        if (kobj->state_in_sysfs) {
                pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n",
                         kobject_name(kobj), kobj);
                kobject_del(kobj);
        }
        if (t && t->release) {
                pr_debug("kobject: '%s' (%p): calling ktype release\n",
                         kobject_name(kobj), kobj);
                t->release(kobj);
        }
        /* free name if we allocated it */
        if (name) {
                pr_debug("kobject: '%s': free name\n", name);
                kfree(name);
        }
}


有关kset的函数操作

初始化

void kset_init(struct kset *k)
{
        kobject_init_internal(&k->kobj);
        INIT_LIST_HEAD(&k->list);
        spin_lock_init(&k->list_lock);
}

本函数中初始化kset结构体内嵌的kobject,然后初始化链表以及自旋锁。由此可以看出,通过内嵌方式,可以实现面向对象中的继承机制。

注册

int kset_register(struct kset *k)
{
        int err;
        if (!k)
                return -EINVAL;
        kset_init(k);
        err = kobject_add_internal(&k->kobj);
        if (err)
                return err;
        kobject_uevent(&k->kobj, KOBJ_ADD);
        return 0;
}

所谓注册,无非是将内嵌的kobject加入设备模型系统中,当然,还要想用户空间到处uevent事件。此处的kobject_add_internal值得一看,从这个函数中可以看出kobject父子节点以及所属kset之间的关系规则。

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) : "",
                 kobj->kset ? kobject_name(&kobj->kset->kobj) : "");
        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的所属kset设定,而其父节点没有设定,则将本kobject加入kset,并将kset作为作为本kobject的父节点。

注销

void kset_unregister(struct kset *k)
{
        if (!k)
                return;
        kobject_put(&k->kobj);
}

仅仅是减少内嵌kobject对象的引用计数

kobject和kset

将某一kobject加入kset

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


将某一Kobject从kset中移除

static void kobj_kset_leave(struct kobject *kobj)
{
        if (!kobj->kset)
                return;
        spin_lock(&kobj->kset->list_lock);
        list_del_init(&kobj->entry);
        spin_unlock(&kobj->kset->list_lock);
        kset_put(kobj->kset);
}



此处仅仅讲解了一些静态数据的操作函数,相应的动态数据操作类似,仅仅是数据不再是静态生命,而是动态创建。

注:在内核中经常可以看到某些函数参数和返回值相同,不光类型,也包括值,这样的做法是为了保证代码调用上的一致性,并没有什么特别作用。

阅读(11843) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

我是一粒糖2012-05-24 10:28:34

kobject父子节点以及所属kset之间的关系规则比较麻烦啊。。