kobject在字符设备中的使用

作者:linuxer 发布于:2014-12-4 18:14

一、前言

关于kobject的基本概念的描述请参考Linux设备模型(2)_Kobject中的描述。本文主要以字符设备为例,描述内核中使用kobject的一个场景,以便加深对kobject这个内核神器的理解。

 

二、定义

内核中用struct cdev来表示一个字符设备,具体数据结构定义如下:

struct cdev {
    struct kobject kobj;
    struct module *owner;
    const struct file_operations *ops;
    struct list_head list;
    dev_t dev;
    unsigned int count;
};

在linux kernel中大量使用了面向对象的思想(虽然c语言不是一种面向对象的语言,但是,仍然可以体现一些面向对象的思想)。对于c++而言,有基类和派生类,派生类可以继承基类的一些接口和属性。对于c而言,我们将kobject嵌入到其他数据结构中的方式来实现继承。

 

三、初始化

1、driver动态分配struct cdev的场景

register_chrdev接口函数是2.4 kernel时代的API,到了2.6时代,为了兼容之前的旧的driver,内核仍然提供了这个接口函数,但是底层已经是使用新的字符设备的接口函数了,具体如下:

int __register_chrdev(……)
{
    ……

    cdev = cdev_alloc();-------------------动态分配struct cdev

    ……
    kobject_set_name(&cdev->kobj, "%s", name); -------设定kobject的名字

    err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);---将字符设备加入系统

    ……
}

动态分配struct cdev的过程如下:

struct cdev *cdev_alloc(void)
{
    struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);--------(1)
    if (p) {
        INIT_LIST_HEAD(&p->list);
        kobject_init(&p->kobj, &ktype_cdev_dynamic);-------------(2)
    }
    return p;
}

(1)分配了struct cdev,也就分配了kobject的memory,他们是共存亡的。

(2)初始化kobject,注意:这里的ktype_cdev_dynamic非常关键,和消耗cdev这个对象(也就是销毁kobject这个对象相关),可以参考第四章的描述。

 

2、driver静态定义struct cdev的场景

有的时候,我们的字符设备的cdev是静态定义的,例如:

static struct cdev xxx_cdev;

当然,也有可能cdev这个数据结构是嵌入到你自己定义的数据结构struct xxx_cdev中,然后静态定义一个struct xxx_cdev的变量。当然,它们本质上是一样的。对于这样静态定义的cdev,我们使用cdev_init来初始化。我们来看一看cdev_init中如何初始化kobject:

void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
    memset(cdev, 0, sizeof *cdev);
    INIT_LIST_HEAD(&cdev->list);
    kobject_init(&cdev->kobj, &ktype_cdev_default);-----------(1)
    cdev->ops = fops;
}

和cdev_alloc一样,调用kobject_init初始化内嵌的kobject,不过ktype是不一样的,这里是ktype_cdev_default。

 

三、将kobject加入系统

通过cdev_add可以将cdev注册到系统中:

int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
    ……

    kobject_get(p->kobj.parent);

    return 0;
}

期待的kobject_add没有出现,只有增加了cdev中kobject的parent的引用计数,当然,如果在你的driver中不设定parent,其实这个调用也是没有意义的。

 

四、注销

对于静态定义的cdev(因此kobject也是静态定义),无所谓销毁,因此该kobject的ktype的release函数不需要释放内存,大家可以去看看cdev_default_release函数。对于动态分配的cdev(因此kobject也是动态分配),其ktype是:

static struct kobj_type ktype_cdev_dynamic = {
    .release    = cdev_dynamic_release,
};

在函数中会释放内存,具体如下:

static void cdev_dynamic_release(struct kobject *kobj)
{
    struct cdev *p = container_of(kobj, struct cdev, kobj);----找到kobject对应的cdev对象
    struct kobject *parent = kobj->parent;

    cdev_purge(p);
    kfree(p);--------------释放内存
    kobject_put(parent);
}

标签: kobject cdev

评论:

puppypyb
2014-12-09 12:26
good!!!!!

我觉得这段解释有必要加入到正文中去,说起来,bbs怎么没有编辑功能呢?
linuxer
2014-12-09 12:43
@puppypyb:讨论区的文章可以编辑的,如果你是这份文档的作者。其实和其他板块的文章是类似的。
puppypyb
2014-12-09 09:45
kobject是组成设备模型的基本结构。

前面你和wowo已经论证过cdev与设备模型无关,那么你是怎么理解cdev中出现的kobject? 没看出来它在这里的作用。
linuxer
2014-12-09 12:14
@puppypyb:设备模型中大量使用了kobject,但是kobject并不是仅仅for设备模型的。
对于cdev这个场景,kobject主要是应用两点:
1、reference count。
2、ktype中的release函数

基本上可以这么认为,cdev中的kobject没有完全发挥其功能,假设其全部功能有10条,实际只用了2条。是不是很浪费?当然是很浪费了,如果有可能,最好定义一个基类,只包括上面的那两点功能,kobject派生于此基类,cdev也是派生于此基类。当然,是否定义这样的基类应该是内核中的应用场景相关,如果有大量类似cdev这样的场景,我们相信内核人员有可能定义这样的基类
wowo
2014-12-09 22:09
@linuxer:这两点功能,其中一点(reference count),kernel中已经有一个基类了,即struct kref,kobject也正是派生于kref。
至于第二点,应该就是kobject诞生的初衷。
linuxer
2014-12-04 18:23
看了蜗窝同学的kobject的文章,准备找几个实际使用的案例分析一下,首先是最简单的一个场景,慢慢深入吧

发表评论:

Copyright @ 2013-2015 蜗窝科技 All rights reserved. Powered by emlog