Linux Kobject

Overview

Linux Driver模型的基础设施就是kobject,我们经常会发现kobject会被内嵌于其它的structure中使用。通过将kobject嵌入其它structure中,可以利用kobject的t特性来达成期望的目的。和kobject相关的结构还有kset和ktype。

Kobject

Kobject有name, reference count和一个特定的type。kobject也有parent pointer,这就使kobject可以组织成一定的层次架构。通常,kobject在sysfs的文件系统中也代表一个目录。一般kobject本身并没有特别的含义,相反它们通常被内嵌于其它的structure中,这样structure就可以利用kboject的特性。一个strucuture中最多只能定义一个kboject。


struct kobject {

    const char *name;   // name

     struct list_head entry;  

    struct kobject *parent;   //pointer to parent

    struct kset *kset;   //pointer to kset

    struct kobj_type *ktype; 

    struct kref kref;   

    ...

}

Ktype

每一个kobject都会有相应的ktype,它是指struct kobject中的ktype成员。ktype控制着如何create/destroy一个kobject。

struct kobj_type { 

    void (*release)(struct kobject *kobj); 

    const struct sysfs_ops *sysfs_ops; 

    struct attribute **default_attrs; 

    ...

}


Kset

Kset代表一组kobjects,这些kobjects可以有相同或不同的ktype. Kset也有自己的kobject。当kobject的parent为NULL的话,那么认为它的parent为kset的kobject,这种关系会体现在sysfs的目录结构中。

struct kset { 

    struct list_head list; 

    spinlock_t list_lock;

    struct kobject kobj; 

    const struct kset_uevent_ops *uevent_ops; 

};   


Kobject API

这里介绍下常见API内部做了哪些动作,为了方便表达,没有把所有的函数语句都贴出来,只列关键语句。

kobject_init()

void kobject_init(struct kobject *kobj, struct kobj_type *ktype)

{

    kobject_init_internal(kobj); 

    kobj->ktype = ktype

    return;  

}

static void kobject_init_internal(struct kobject *kobj)  {

    kref_init(&kobj->kref); 

    INIT_LIST_HEAD(&kobj->entry); 

    kobj->state_in_sysfs = 0; 

    ...

    kobj->state_initialized = 1;     

 }  

static inline void kref_init(struct kref *kref){ 

    atomic_set(&kref->refcount, 1); 

可以看到kobject_init()主要是对kobject的成员做初始化,同时refcount置成1.但同时也要注意,kobject_init()其实并没有对name,parent和kset这些变量赋值

kobject_create()

动态创建一个kobject。

struct kobject *kobject_create(void){ 

    struct kobject *kobj; kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); 

    kobject_init(kobj, &dynamic_kobj_ktype); 

    return kobj;  

}   

static struct kobj_type dynamic_kobj_ktype = {  

    .release = dynamic_kobj_release

    .sysfs_ops = &kobj_sysfs_ops,   

 };

static void dynamic_kobj_release(struct kobject *kobj){ 

    pr_debug("kobject: (%p): %s\n", kobj, __func__);

     kfree(kobj); 

}  

这里可以看到它通过kzalloc()分配memory,会先把kobject的各项成员都赋值成0,然后kobject_init()会再赋值部分成员。

kernel/documentation/kobject.txt有这样提到,建议kobject尽量使用动态分配的。

Because kobjects are dynamic, they must not be declared statically or onthe stack, but instead, always allocated dynamically.  Future versions ofthe kernel will contain a run-time check for kobjects that are createdstatically and will warn the developer of this improper usage.

Kobject_add()

贴上函数注释,描述最为精确

If @parent is set, then the parent of the @kobj will be set to it.If @parent is NULL, then the parent of the @kobj will be set to the kobject associated with the kset assigned to this kobject. If no kset is assigned to the kobject, then the kobject will be located in the root of the sysfs tree.

* * If this function returns an error, kobject_put() must be called to properly clean up the memory associated with the object. Under no instance should the kobject that is passed to this function be directly freed with a call to kfree(), that can leak memory.

* * Note, no "add" uevent will be created with this call, the caller should set up all of the necessary sysfs files for the object and then call kobject_uevent() with the UEVENT_ADD parameter to ensure that userspace is properly notified of this kobject's creation.

int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...){

    va_list args; int retval;

    va_start(args, fmt); 

    retval = kobject_add_varg(kobj, parent, fmt, args); 

    va_end(args);

     return retval;  

}   

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); //set the name of kobject

    kobj->parent = parent;  //set kobject parent

    return kobject_add_internal(kobj);     

}

int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, va_list vargs){

    const char *s; 

    s = kvasprintf_const(GFP_KERNEL, fmt, vargs); //this operation may have malloc operation

    kfree_const(kobj->name);      

    kobj->name = s; 

    return 0;     

}

static int kobject_add_internal(struct kobject *kobj){

    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;  

    }  

    error = create_dir(kobj);  //create dir in the sysfs the parent dir is parent kobject

    kobj->state_in_sysfs = 1;

    return error; 




Kobject_get()

Increase reference count for kobject

struct kobject *kobject_get(struct kobject *kobj){

    kref_get(&kobj->kref); } //only increase the reference count

    return kobj; 

 } 

static inline void kref_get(struct kref *kref){     WARN_ON_ONCE(atomic_inc_return(&kref->refcount) < 2);

 } 

Kobject_put()

Decrement the refcount, and if 0, call kobject_cleanup().

void kobject_put(struct kobject *kobj){ 

    if (kobj) { 

        kref_put(&kobj->kref, kobject_release); 

    }    

static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref)){ 

    return kref_sub(kref, 1, release); 

static inline int kref_sub(struct kref *kref, unsigned int count, void (*release)(struct kref *kref)){

    if (atomic_sub_and_test((int) count, &kref->refcount)) { 

        release(kref);    

        return 1;

     }  

static void kobject_release(struct kref *kref){ 

    struct kobject *kobj = container_of(kref, struct kobject, kref);  

    kobject_cleanup(kobj);

 }  

//free kobject resources

static void kobject_cleanup(struct kobject *kobj){

    struct kobj_type *t = get_ktype(kobj); 

    const char *name = kobj->name;

    /* remove from sysfs if the caller did not do it */

    if (kobj->state_in_sysfs) { 

        kobject_del(kobj);    

    }

    if (t && t->release) { 

        t->release(kobj); 

    } 

    /* free name if we allocated it */ 

    if (name) { 

        kfree_const(name);

     }     

}

kset_register()

Initialize and add a kset.

int kset_register(struct kset *k){ 

    kset_init(k);

    err = kobject_add_internal(&k->kobj); //将kobject挂入parent,同时create dir in sysfs

    kobject_uevent(&k->kobj, KOBJ_ADD);

    return 0;      

}

void kset_init(struct kset *k){ 

    kobject_init_internal(&k->kobj); //初始化kobject成员变量

    INIT_LIST_HEAD(&k->list); 

    spin_lock_init(&k->list_lock);   

 } 

通过上述API的一些理解,可以了解到linux kernel是如何运作kobject的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354