sysfs文件系統
“sysfs is a ram-based filesystem initially based on ramfs. It provides a means to export kernel data structures, their attributes, and the linkages between them to userspace.”
---documentation/filesystems/sysfs.txt
(ramdisk is also ram-based filesystem。ramdisk是一種磁盤模擬的技術,ramdisk之上實際運行的文件系統是ext2、ext3、ext4,除此之外,還有proc,proc也是基於內存的文件系統,proc文件系統提供一個接口給用戶,讓用戶能夠查看系統運行的一些狀態信息,讓用戶可以修改內核的一些參數,比如說,printk的打印區別可以通過proc來修改。)
Linux2.6內核引入了sysfs文件系統。sysfs被看成是與proc同類別的文件系統。sysfs把連接在系統上的設備和總線組織成分級的文件,使其從用戶空間可以訪問到。sysfs被加載在/sys/目錄下,它的子目錄包括:
·block:在系統中發現的每個塊設備在該目錄下對應一個子目錄。每個子目錄中又包含一些屬性文件,它們描述了這個塊設備的各方面屬性,如:設備大小。(loop塊設備是使用文件來模擬的)
·bus:在內核中注冊的每條總線在該目錄下對應一個子目錄,如:ide pci scsi usb pcmcia。其中每個總線目錄內又包含兩個子目錄:devices和driver,devices目錄包含了在整個系統中發現的屬於該總線類型的設備,drivers目錄包含了注冊到該總線的所有驅動。
·class:將設備按照功能進行的分類,如/sys/class/net目錄下包含了所有網絡接口。
·devices:包含系統所有的設備。
·kernel:內核中的配置參數。
·module:系統中所有模塊的信息。
·firmware:系統中的固件。
·fs:描述系統中的文件系統。
·power:系統中電源選項。
kobject
kboject實現了基本的面向對象管理機制,是構成Linux2.6設備模型的核心結構。它與sysfs文件系統緊密相連,在內核中注冊的每個kobject對象對應sysfs文件系統中的一個目錄。它類似於C++中的基類,kobject常被嵌入於其他類型(即:容器)中。如bus,devices,driver是都是典型的容器。這些容器通過kobject連接起來,形成了一個樹狀接口。
1: struct kobject{
2: const char *name;
3: struct list_head entry;
4: struct kobject *parent; /* 指向父對象 */
5: struct kset *kset;
6: struct kobj_type *ktype;
7: struct sysfs_dirent *sd;
8: struct kref kref; /* 對象引用計數 */
9: unsigned int state_initialized:1;
10: unsigned int state_in_sysfs:1;
11: unsigned int state_add_uevent_sent:1;
12: unsigned int state_remove_uevent_sent:1;
13: };
kobject操作
1: void kobject_init(struct kobject *kobj)
初始化kobject結構
1: int kobject_add(struct kobject *kobj)
將kobject對象注冊到Linux系統
1: int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, stuct kobject *parent, const char *fmt, …)
初始化kobject,並將其注冊到linux系統
1: void kobject_del(struct kobject *kobj)
從Linux系統中刪除kobject對象
1: struct kobject *kobject_get(struct kobject *kobj)
將kobject對象的引用計數加1,同時返回該對象指針
1: void kobjec_put(struct kobject *kobj)
將kobject對象的引用計數減1,如果引用計數降為0,則調用release方法釋放該kobject對象
struct kobj_type
kobject的ktype成員是一個指向kobj_type結構的指針,該結構中記錄了kobject對象的一些屬性。
1: struct kobj_type{
2: void (*release)(struct kobject *kobj);
3: struct sysfs_ops *sysfs_ops;
4: struct attribute **default_attrs;
5: };
release:用於釋放kobject占用的資源,當kobject的引用計數為0時被調用。
struct attribute
1: struct attribute{
2: char *name; /* 屬性文件名 */
3: struct module *owner;
4: mode_t mode; /* 屬性的保護位 */
5: };
struct attribute(屬性):對應於kobject的目錄下的一個文件,name成員就是文件名。
struct sysfs_ops
1: struct sysfs_ops{
2: ssize_t (*show)(struct kobject*, struct attribute *, char *);
3: ssize_t (*store)(struct kobject*, struct attribute *, const char *, size_t);
4: };
show:當用戶讀屬性文件時,該函數被調用,該函數將屬性值存入buffer中返回給用戶態;
store:當用戶寫屬性文件時,該函數被調用,用於存儲用戶傳入的屬性值。
kobject內核模塊代碼:
1: #include <linux/device.h>
2: #include <linux/module.h>
3: #include <linux/kernel.h>
4: #include <linux/init.h>
5: #include <linux/string.h>
6: #include <linux/sysfs.h>
7: #include <linux/stat.h>
8:
9: MODULE_AUTHOR("David Xie");
10: MODULE_LICENSE("Dual BSD/GPL");
11:
12: void obj_test_release(struct kobject *kobject);
13: ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);
14: ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);
15:
16: struct attribute test_attr = {
17: .name = "kobj_config", //②
18: .mode = S_IRWXUGO,
19: };
20:
21: static struct attribute *def_attrs[] = {
22: &test_attr,
23: NULL,
24: };
25:
26:
27: struct sysfs_ops obj_test_sysops =
28: {
29: .show = kobj_test_show,
30: .store = kobj_test_store,
31: };
32:
33: struct kobj_type ktype =
34: {
35: .release = obj_test_release,
36: .sysfs_ops=&obj_test_sysops,
37: .default_attrs=def_attrs,
38: };
39:
40: void obj_test_release(struct kobject *kobject)
41: {
42: printk("eric_test: release .\n");
43: }
44:
45: ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf) //③
46: {
47: printk("have show.\n");
48: printk("attrname:%s.\n", attr->name);
49: sprintf(buf,"%s\n",attr->name);
50: return strlen(attr->name)+2;
51: }
52:
53: ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)
54: {
55: printk("havestore\n");
56: printk("write: %s\n",buf);
57: return count;
58: }
59:
60: struct kobject kobj;
61: static int kobj_test_init()
62: {
63: printk("kboject test init.\n");
64: kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test"); //①
65: return 0;
66: }
67:
68: static int kobj_test_exit()
69: {
70: printk("kobject test exit.\n");
71: kobject_del(&kobj);
72: return 0;
73: }
74:
75: module_init(kobj_test_init);
76: module_exit(kobj_test_exit);
Step 1:檢測/sys/目錄下是否生成kobject_test目錄;(對應於//①)
Step 2:檢測/sys/kobject_test/目錄下是否生成kobj_config文件;(對應//②)
Step 3:檢測當讀kobj_config文件時打印的信息;(對應//③)
kset
kset是具有相同類型的kobject的集合,在sysfs中體現成一個目錄,在內核中用kset數據結構表示,定義為:
1: struct kset{
2: struct list_head list; /* 連接該kset中所有kobject的鏈表頭 */
3: spinlock_t list_lock;
4: struct kobject kobj; /* 內嵌的kobject */
5: struct kset_uevent_ops *uevent_ops; /* 處理熱拔插事件的操作集合 */
6: }
kset操作
1: int kset_register(struct kset *kset)
在內核中注冊一個kset
1: void kset_unregister(struct kset *kset)
從內核中注銷一個kset
熱插拔事件
在Linux系統中,當系統配置發生變化時,如:添加kset到系統、移動kobject,一個通知會從內核空間發送到用戶空間,這就是熱拔插事件。熱拔插事件會導致用戶空間中的處理程序(如udev,mdev)被調用,這些處理程序會通過加載驅動程序,創建設備節點等來響應熱拔插事件。
操作集合
1: struct kset_uevent_ops{
2: int (*filter)(struct kset *kset, struct kobject *kobj);
3: const char *(*name)(struct kset *kset, struct kobject *kobj);
4: int (*uevent)(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env);
5: }
這三個函數什么時候調用?
當該kset所管理的kobject和kset狀態發生變化時(如被加入,移動),這三個函數將被調用。(例:kobject_uevent調用)
這三個函數的功能是什么?
filter:決定是否將事件傳遞到用戶空間。如果filter返回0,將不傳遞事件。(例:uevent_filter)
name:用於將字符串傳遞給用戶空間的熱拔插處理程序。
uevent:將用戶空間需要的參數添加到環境變量中。(例:dev_uevent)
kobject內核模塊代碼:
1: #include <linux/device.h>
2: #include <linux/module.h>
3: #include <linux/kernel.h>
4: #include <linux/init.h>
5: #include <linux/string.h>
6: #include <linux/sysfs.h>
7: #include <linux/stat.h>
8: #include <linux/kobject.h>
9:
10: MODULE_AUTHOR("David Xie");
11: MODULE_LICENSE("Dual BSD/GPL");
12:
13: struct kset kset_p;
14: struct kset kset_c;
15:
16: int kset_filter(struct kset *kset, struct kobject *kobj)
17: {
18: printk("Filter: kobj %s.\n",kobj->name);
19: return 1;
20: }
21:
22: const char *kset_name(struct kset *kset, struct kobject *kobj)
23: {
24: static char buf[20];
25: printk("Name: kobj %s.\n",kobj->name);
26: sprintf(buf,"%s","kset_name");
27: return buf;
28: }
29:
30: int kset_uevent(struct kset *kset, struct kobject *kobj,struct kobj_uevent_env *env)
31: {
32: int i = 0;
33: printk("uevent: kobj %s.\n",kobj->name);
34:
35: while( i < env->envp_idx){
36: printk("%s.\n",env->envp[i]);
37: i++;
38: }
39:
40: return 0;
41: }
42:
43: struct kset_uevent_ops uevent_ops =
44: {
45: .filter = kset_filter,
46: .name = kset_name,
47: .uevent = kset_uevent,
48: };
49:
50: int kset_test_init()
51: {
52: printk("kset test init.\n");
53: kobject_set_name(&kset_p.kobj,"kset_p");
54: kset_p.uevent_ops = &uevent_ops;
55: kset_register(&kset_p);
56:
57: kobject_set_name(&kset_c.kobj,"kset_c");
58: kset_c.kobj.kset = &kset_p;
59: kset_register(&kset_c);
60: return 0;
61: }
62:
63: int kset_test_exit()
64: {
65: printk("kset test exit.\n");
66: kset_unregister(&kset_p);
67: kset_unregister(&kset_c);
68: return 0;
69: }
70:
71: module_init(kset_test_init);
72: module_exit(kset_test_exit);
測試:
/sys/kset_p/kset_c