天天看點

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    3staticssize_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_opsstaticstructsysfs_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);      

繼續閱讀