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