Linux设备模型基础---操作函数

关于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;
         /* ewww... 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) : "<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)
                         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);
}



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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值