首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

linux装置模型之内核集合、内核对象

2013-10-19 
linux设备模型之内核集合、内核对象引言:最近上班特无聊,发发牢骚,特地对内核对象、内核集合进行了了解,写此

linux设备模型之内核集合、内核对象

引言:最近上班特无聊,发发牢骚,特地对内核对象、内核集合进行了了解,写此文章,方便日后一目了然

设备模型构成:①内核对象②内核集合

 

一:内核对象

定义:内核对象是设备模型中最基本的数据类型,内核对象与sysfs(伪文件系统,通常挂载/sys目录下)文件系统中的目录一一对应,其父子关系对应着目录的层次关系,属性对应着目录中的文件(文件名、以及文件属性)

内核对象的数据类型

structkobject{

    constchar*name;  //内核对象的名称

    structlist_headentry;//把属于同一个集合的多个内核对象组成链表

    structkobject*parent;//维护内核对象的父子关系

    structkset*kset; //指向所属内核集合

    structkobj_type*ktype;  //指向一个用于描述内核对象内型的结构体(包括:文件名,文件属性,以及文件的读写)

    structkrefkref;  //引用计数

    unsignedintuevent_suppress:1;//内核用户态事件是否被抑制

    //...

};

内核对象的类型

structkobj_type{

    void(*release)(structkobject*kobj); //内核对象的释放函数

    structsysfs_ops*sysfs_ops;   //sysfs文件操作(读、写)

    structattribute**default_attrs;  //内核对象的默认属性(文件的名称、文件的访问权限)

}; 

内核对象的属性

structattribute{

    constchar*name;

    mode_tmode;

};

内核对象的操作

structsysfs_ops{

    ssize_t(*show)(structkobject*kobj,structattribute*attr,char*buf);

    ssize_t(*store)(structkobject*kobj,structattribute*attr,constchar*buf,size_tsize));

};

内核对象的名称
    内核对象的名称属性(即文件名)
    intkobject_set_name(structkobject*kobj,constchar*fmt,...);
    内核对象的改名函数
    intkobject_rname(structkobject*kobj,contchar*name);
    内核对象的名称获取
    intkobject_name(conststructkobject*kobj);
内核对象的初始化与注册
    初始化
    voidkobject_init(structkobject*kobj,structkobj_type*ktype);
    注册
    intkobject_add(structkobject*kobj,structkobject*parent,constchar*fmt,...);
    初始化与注册(以上两者合并)
    intkobject_init_and_add(structkobject*kobj,structkobj_type*ktype,structkobject*parent,constchar*fmt,...);
    动态创建
    structkobject*kobject_create(void);
    动态创建与注册
    structkobject*kobject_create_and_add(constchar*name,structkobject*parent);
    释放
    voidkobject_del(structkobject*kobj);

 

动态创建属性(属性即名字,包括文件名、访问权限)

    intsysfs_create_file(structkobject*kobj,conststructattribute*attr);

    动态创建的属性被删除

    voidsysfs_remove_file(structkobject*kobj,conststructattribute*attr);

    解释:动态创建属性,相当于在内核目录(/sys)中动态创建一个文件,应用程序读写这个文件时,内核仍然会调用内核对象时提供的show、store函数

   

    考虑到动态创建属性

    structkobj_attribute{

        structattributeattr;

        ssize_t(*show)(structkobject*,structkobj_attribute*attr);

        ssize_t(*store)(structkobject*kobj,structkobj_attribute*attr,constchar*buf,size_tcount);

};

 

然后定义一个通用的show和stroe函数(以下两个函数是内核特有的,可以仿照)

    staticssize_tkobj_attr_show(structkobject*kobj,structattribute*attr,char*buf);

    staticssize_tkobj_attr_store(structkobject*kobj,structattribute*attr,constchar*buf,size_tcount);

    structsysfs_opskobj_sysfs_ops={

        .show=kobj_attr_show,

        .store=kobj_attr_store,

};

内核还定义了一个宏来初始化structkobj_attribute内核对象的属性

            __ATTR(name,mode,show,store)

    例:structkobj_attributeattr_xxx=__ATTR(XXX,S_IRUG0,XXX_show,xxx_store);

二.内核集合

定义:内核集合是基于内核对象而设计的,它可以收纳多个内核对象,并且可以管理内核对象所发送的用户态事件

    内核集合数据内型

    structkset{

        structlist_headlist; //链表头

        spinlock_tlist_lock;  //自旋锁

        structkobjectkobj;   //内嵌的内核对象

        structkset_uevent_ops*uevent_ops;//指向用户态事件操作,uenent_ops指向一个结构体,其中包含各种用户态事件的操作函数指针

    };

    内核集合的注册和注销

    intkset_register(structkset*kset);

    voidkset_ungister(structkset*kset);

    动态创建并注册

    structkset*kset_create_and_add(constchar*name,structkset_uevent_ops*u,structkobject*parent_kobj);

    用户态事件

    intkobject_uevent_env(structkobject*kobj,enumkobject_actionaction,char*envp[]);

    其中第二个参数“枚举”,表示事件类型的参数

    enumkobject_action{

        KOBJ_ADD,  //注册

        KOBJ_REMOVE, //注销

        KOBJ_CHANGE,   //修改

        KOBJ_MOVE, //移动

        KOBJ_ONLINE,   //在线

        KOBJ_OFFLINE,  //离线

        KOBJ_MAX  //不是一种动作,仅用来表示可选取的个数

    };

    用户态事件将以两种方式告知应用程序:

    ①用户态帮手的方式“/sbin/hotplug”(具体细节,找度娘);

    ②NETLINK套接字方法,在应用程序内可以直接用netlink_socket=socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT);

内核集合与内核对象之关系   

总结:内核对象在注册前如果设置了kset指针,则注册时它就会被加入到kset指针所指向的内核集合中,它所发送的用户态事件将接收这个内核集合的过滤操作

 

 

内核集合与对象例程
在加载时,首先创建并注册一个顶级子系统test,然后在这个子系统内注册若干个内核对象,每个对象有两个属性;name属性为可读,string属性为可写
目录树形图:
/sys
|
|
|---test(kset)(内核集合)
        |
        |
        |-------kobj1(内核对象)
        |         |
        |        |------struct sys_ops(读写文件)
        |         |
        |        |------struct attribute(属性名字、访问权限)
        |
        |-------kobj2(内核对象)
        |          |
        |         |------struct sys_ops(读写文件)
        |         |
        |         |------struct attribute(属性名字、访问权限)
 
源码如下:
    #include<linux/module.h>
    #defineSZ_STRING   30
    #defineNR_KOBJS    3
    staticssize_ttest_attr_show(structkobject*kobj,structattribute*attr,char*buf)
    {
        structkobj_attribute*kattr;
        ssize_tret=-EIO;
        kattr=container_of(attr,structkobj_attribute,attr);
        if(kattr->show)
            ret=kattr->show(kobj,kattr,buf);
        returnret;
    }
    staticssize_ttest_attr_restore(structkobject*kobj,structattribute*attr,constchar*buf,size_tcount)
    {
        structkobj_attribute*kattr;
        ssize_tret=-EIO;
        kattr=container_of(attr,structkobj_attribute,attr);
        if(kattr->store)
            ret=kattr->store(kobj,kattr,buf,count);
        returnret;
    }
    //仿照内核的kobj_sysfs_ops
    staticstructsysfs_opstest_sysfs_ops = {
        .show=test_attr_show,
        .store=test_attr_restore,
    };
    staticvoidtest_release(structkobject*kobj)
    {
        kfree(kobj);
    }
    //属性name的show、store函数
    staticssize_ttest_name_show(structkobject*kobj,structkobj_attribute*attr,char*buf)
    {
        returnsprintf(buf,"%s\n",kobject_name(kobj));
    }
    staticssize_ttest_name_restore(structkobject*kobj,structkobj_attribute*attr,constchar*buf,size_tlen)
    {
        return-EACCES;
    }
    //属性name的定义
    staticstructkobj_attributetest_attr_name=
            __ATTR(name,S_IRUGO,test_name_show,test_name_restore);
    //用于保存属性stirng对应的字符串
    staticchartest_string[SZ_STRING]="test\n";
    //属性name的show、store函数
    staticssize_ttest_string_show(structkobject*kobj,structkobj_attribute*attr,char*buf)
    {
        returnsprintf(buf,test_string);
    }
    staticssize_ttest_string_restore(structkobject*kobj,structkobj_attribute*attr,constchar*buf,size_tlen)
    {
        if(len>=SZ_STRING)
            len=SZ_STRING-1;
        memcpy(test_string,buf,len);
        test_string[len]='\0';
        returnlen;
    }
    //属性string的定义
    staticstructkobj_attributetest_attr_string=
            __ATTR(name,S_IWUGO,test_string_show,test_string_restore);
    //对象的默认属性,将string、name属性加入到structattribute结构中
    staticstructattribute*test_default_attr[]={
        &test_attr_name,
        &test_attr_string,
        NULL,
    };
    //对象的类型
    staticstructkobj_typetest_kobj_type={
        .release=test_release,
        .sysfs_ops=&test_sysfs_ops,   //属性操作
        .default_attrs=test_default_attr  //默认属性
    };
    //用于保存动态创建的内核集合的指针
    staticstructkset*kset;
    //模块初始化
    static__initintsys_test_init(void)
    {
        inti;
        interr;
        structkobject*kobj,*next;
        pr_debug("sysfs_test_init:becalled.\n");
        //创建“内核集合”,由于没有父对象,它将成为顶级子系统,即/sys下的目录
        if((kset=kset_create_and_add("test",NULL,NULL))==NULL){
            pr_debug("sysfs_test_init:kset_create_and_addERR\n");
            err=-ENOMEM;
            gotokset_fail;
        }
        //为kset集合创建一个属性,使用name属性的定义
        if(err=sysfs_create_file((&kset->kobj),&test_attr_name.attr)){
            pr_debug("sysfs_test_init:sysfs_create_fileERR\n");
            gotosysfs_fail;
        }
        //注册NR_KOBJS个内核对象
        for(i=0;i<NR_KOBJS;i++){
            kobj=kzalloc(sizeof(structkobject),GFP_KERNEL);
            if(!kobj){
                pr_debug("sysfs_test_init:kzallocERR\n");
                err=-ENOMEM;
                gotokobject_fail;
            }
            //设置所属集合
            kobj->kset=kset;
            //初始化并注册
            err=kobject_init_and_add(kobj,&test_kobj_type,NULL,"obj%d",i);
            if(err){
                pr_debug("sysfs_test_init:kobject_init_and_addERR\n");
                kfree(kobj);
                gotokobject_fail;
            }
            kobject_uevent(kobj,KOBJ_ADD);
        }
        return0;
    kobject_fail:
        list_for_each_entry_safe(kobj,next,&kset->list,entry)kobject_put(kobj);
    sysfs_fail:
        kset_unregister(kset);
    kset_fail:
        returnerr;
    }
    static__exitvoidsysfs_test_exit(void)
    {
        structkobject*kobj,*next;
        pr_debug("sysfs_test_exit:becalled.\n");
        list_for_each_entry_safe(kobj,next,&kset->list,entry)
        kobject_put(kobj);
        kset_unregister(kset);
    }
    MODULE_LICENSE("GPL");
    module_init(sys_test_init);
    module_exit(sysfs_test_exit);

 

热点排行