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 卸載模塊: