Linux 設備模型 --- Kset


Kset :

Kset 定義:

Kset 是具有相同類型的 kobject 的集合,在 sysfs 中體現成一個目錄kobject 不能包含目錄,只能包含文件;而 Kset 可以包含子目錄



在內核中用 Kset 數據結構表示,

Kset 結構:

struct Kset
{
	struct  list_head list;    //連接該 Kset 中所有 kobject 的鏈表頭;
 	soinlock_t   list_lock;
	struct  kobject  kobj;    //內嵌的 kobject ;
	struct  kset_uevent_ops *uevent_ops;  //處理 熱插拔事件的操作集合;
}

Kset 操作:

int  kset_register (struct kset  *  kset)   在內核註冊一個 Kset;

void  kset_unregister (struct kset * kset)  從內核註銷一個 Kset;


熱插拔 事件:

在 Linux 系統中,當系統配置發生變化時

如:添加 Kset 到系統;移動 kobject ,一個通知會從內核空間發送到用戶空間,這就是熱插拔事件.

熱插拔事件 會導致用戶空間中相應的處理程序 ( 如 udev,mdev ) 被調用,這些處理程序會通過加載驅動程序,

創建設備節點來響應 熱插拔事件.


熱插拔 - 操作集合結構 - 包含三個函數:

Struct  kset_uevent_ops
{
	int (*filter) (struct kset *set, struct kobject *kobject );
	const char *(*name) (struct kset *kset, struct kobject *kobj);
	int (*uevent) ( struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env);
}

三個函數什麼時候被調用:

當該 Kset 所管理的 kobject 和 kset 狀態發生變化時 ( 如:被加入,被移動) ,這三個函數將被調用;( 例: kobject _uevent 調用).


三個函數功能:

filter :決定是否將事件傳遞到用戶空間,如果 filter 返回 0 ,將不傳遞事件 (例:uevent_filter).

name :用於將字符串傳遞給用戶空間的熱插拔處理程序.

uevent :將用戶空間需要的參數添加到環境變量中 (例:dev_uevent).


程序例子Kset . c :

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/stat.h>
#include <linux/kobject.h>
 
MODULE_AUTHOR("David Xie");
MODULE_LICENSE("Dual BSD/GPL");
 
struct kset kset_p;
struct kset kset_c;

int kset_filter(struct kset *kset, struct kobject *kobj)
{
        printk("Filter: kobj %s.\n",kobj->name);
        return 1;
}
 
const char *kset_name(struct kset *kset, struct kobject *kobj)
{
        static char buf[20];
        printk("Name: kobj %s.\n",kobj->name);
        sprintf(buf,"%s","kset_name");
        return buf;
}
 
int kset_uevent(struct kset *kset, struct kobject *kobj,struct kobj_uevent_env *env)
{
        int i = 0;
        printk("uevent: kobj %s.\n",kobj->name);

        while( i < env->envp_idx){
                printk("%s.\n",env->envp[i]);
                i++;
        }

        return 0;
}

struct kset_uevent_ops uevent_ops = 
{
        .filter = kset_filter,
        .name   = kset_name,
        .uevent = kset_uevent,
};
 
int kset_test_init()
{
        printk("kset test init.\n");
        kobject_set_name(&kset_p.kobj,"kset_p");
        kset_p.uevent_ops = &uevent_ops;
        kset_register(&kset_p);
 
        kobject_set_name(&kset_c.kobj,"kset_c");
        kset_c.kobj.kset = &kset_p; // kset_c  與 kset_p 關係;
        kset_register(&kset_c);
        return 0;
}
 
int kset_test_exit()
{
        printk("kset test exit.\n");
        kset_unregister(&kset_p);
        kset_unregister(&kset_c);
        return 0;
}
 
module_init(kset_test_init);
module_exit(kset_test_exit);


運行 insmod 程序:

編譯,加載 insmod 模塊程序,可以看到6,7行打印信息.

還可以看出 kset_p 目錄 包含 kset_c 目錄:這是因爲 :kset_c.kobj.kset = &kset_p; // kset_c  與 kset_p 關係;



修改一下程序,將 int kset_test_init() 函數的下半部分註釋掉 , 

如下:

int kset_test_init()
{
        printk("kset test init.\n");
        kobject_set_name(&kset_p.kobj,"kset_p");
        kset_p.uevent_ops = &uevent_ops;
        kset_register(&kset_p);
 /*
        kobject_set_name(&kset_c.kobj,"kset_c");
        kset_c.kobj.kset = &kset_p;
        kset_register(&kset_c);                      */
        return 0;                      
}

再編譯 ismod 模塊


可以看到,相比於前一次的 insmod 加載模塊程序,這次的打印信息,少了很多,這是爲什麼呢?

因爲:

struct kset_uevent_ops uevent_ops = {
	.filter = kset_filter,
        .name   = kset_name,
        .uevent = kset_uevent,
}

這個結構是用來處理熱插拔事件的,那什麼時候處理熱插拔事件呢,

當我們 kset_p 目錄下的包含發生變化時,kset_p 所對應的熱插拔函數將被調用 ,即是我們上面的結構體中的三個函數.

我們註釋掉的代碼正好是在 kset_p 目錄下添加子目錄,所有產生了熱插拔事件.


rmmod 卸載模塊:












發佈了115 篇原創文章 · 獲贊 21 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章