28struct attribute {
29 const char * name;
30 struct module * owner;
31 mode_t mode;
32};
33
34struct attribute_group {
35 const char * name;
36 struct attribute ** attrs;
37};
struct attribute结构:在这个结构中, name 是属性的名字, owner 是一个指向模块的指针,
模块负责这个属性的实现, 并且 mode 是应用到这个属性的保护位.
mode 常常是 S_IRUGO 对于只读属性;
如果这个属性是可写的, 你可以扔出 S_IWUSR 来只给 root
写权限( modes 的宏定义在 中).
struct attribute_group:属性组,把struct attribute结构的属性,建立成链表
46#define __ATTR(_name,_mode,_show,_store) { \
47 .attr = {.name = __stringify(_name), .mode = _mode }, \
48 .show = _show, \
49 .store = _store, \
50}
51
52#define __ATTR_RO(_name) { \
53 .attr = { .name = __stringify(_name), .mode = 0444 }, \
54 .show = _name##_show, \
55}
56
57#define __ATTR_NULL { .attr = { .name = NULL } }
58
59#define attr_name(_attr) (_attr).attr.name
这些宏可以更方便定义属性。其中赋值用到回调函数的原理。
而其中__stringify(_name)是一个宏, 该宏的作用把#后的x转换成字符串类型的。
1#ifndef __LINUX_STRINGIFY_H
2#define __LINUX_STRINGIFY_H
4/* Indirect stringification. Doing two levels allows the parameter to be a
5 * macro itself. For example, compile with -DFOO=bar, __stringify(FOO)
6 * converts to "bar".
7 */
9#define __stringify_1(x) #x
10#define __stringify(x) __stringify_1(x)
11
12#endif /* !__LINUX_STRINGIFY_H */
sysfs 通常要求所有属性都只包含一个可读文本格式的值,很少需要创建能够处理大量二进制数据的属性。但当在用户空间和设备间传递不可改变的数据时(如上传固件到设备)就需要这个特性。二进制属性使用一个 bin_attribute 结构来描述:
struct bin_attribute {
struct attribute attr;/*属性结构体*/
size_t size;/*这个二进制属性的最大大小(若无最大值则为0)*/
void *private;
ssize_t (*read)(struct kobject *, char *, loff_t, size_t);
ssize_t (*write)(struct kobject *, char *, loff_t, size_t);
/*read 和 write 方法类似字符驱动的读写方法;,在一次加载中可被多次调用,每次调用最大操作一页数据,且必须能以其他方式判断操作数据的末尾*/
int (*mmap)(struct kobject *, struct bin_attribute *attr,
struct vm_area_struct *vma);
};
/*二进制属性必须显式创建,不能以默认属性被创建,创建一个二进制属性调用:*/
int sysfs_create_bin_file(struct kobject *kobj, struct bin_attribute *attr);
/*删除二进制属性调用:*/
int sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
注意:#ifdef CONFIG_SYSFS
.......//代码
#else
CONFIG_SYSFS是默认内核是否支持伪文件系统,这里当然是sysfs文件系统.当支持的话CONFIG_SYSFS就被定义了
本地址有对sysfs文件系统详细介绍:http://blog.chinaunix.net/u1/55599/showart_1089096.html
93extern int sysfs_schedule_callback(struct kobject *kobj,
94 void (*func)(void *), void *data, struct module *owner);
该函数是个回调函数,执行部分在/sysfs/file.h定义
609int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
610 void *data, struct module *owner)
611{
612 struct sysfs_schedule_callback_struct *ss;
613
614 if (!try_module_get(owner))
615 return -ENODEV;
616 ss = kmalloc(sizeof(*ss), GFP_KERNEL);
617 if (!ss) {
618 module_put(owner);
619 return -ENOMEM;
620 }
621 kobject_get(kobj);
622 ss->kobj = kobj;
623 ss->func = func;
624 ss->data = data;
625 ss->owner = owner;
626 INIT_WORK(&ss->work, sysfs_schedule_callback_work);
627 schedule_work(&ss->work);
628 return 0;
629}
其中INIT_WORK(&ss->work, sysfs_schedule_callback_work);(626)
79#define INIT_WORK(_work, _func) \
80 do { \
81 (_work)->data = (atomic_long_t) WORK_DATA_INIT(); \
82 INIT_LIST_HEAD(&(_work)->entry); \
83 PREPARE_WORK((_work), (_func)); \
84 } while (0)
(_work)->data = (atomic_long_t) WORK_DATA_INIT(); 通过宏初始化
INIT_LIST_HEAD(&(_work)->entry), 双向链表的初始化
PREPARE_WORK((_work), (_func)),执行具体回调部分。
schedule_work(&ss->work);加入工作队列中。具体参考/linux/kernel/workqueue.c
现在介绍sysfs文件系统的目录,普通文件,连接等创建过程。
预备知识:struct inode结构,struct file结构,struct dentry结构。kobject结构层次关系有一定的了解。
代码晕了没,下面我举个实例,当然也是源代码的调用关系。
sysfs文件系统中,普通文件对应于kobject中的属性。用sysfs_create_file(),参数如下:
sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
传给它的参数是kobj和attr,其中,kobject对应的是文件夹,attribute对应的是该文件夹下的文件。
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
{
BUG_ON(!kobj || !kobj->dentry || !attr);
return sysfs_add_file(kobj->dentry, attr, SYSFS_KOBJ_ATTR);
}
它直接调用sysfs_add_file()
int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type)
{
struct sysfs_dirent * parent_sd = dir->d_fsdata;
umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
int error = 0;
down(&dir->d_inode->i_sem);
error = sysfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type);
up(&dir->d_inode->i_sem);
return error;
}
int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
void * element, umode_t mode, int type)
{
struct sysfs_dirent * sd;
sd = sysfs_new_dirent(parent_sd, element);
if (!sd)
return -ENOMEM;
sd->s_mode = mode;
sd->s_type = type;
sd->s_dentry = dentry;
if (dentry) {
dentry->d_fsdata = sysfs_get(sd);
dentry->d_op = &sysfs_dentry_ops;
}
return 0;
}
sysfs_create_file()仅仅是调用了sysfs_make_dirent()创建了一个sysfs_dirent结构。与 sysfs_create_dir()不同,它甚至没有在sysfs文件系统下创建inode结构。这项工作被滞后了,在 sysfs_lookup()->sysfs_attach_attr()里面完成的。
这个实例就能反应sysfs文件实际创建文件的调用层次关系。
下面是sysfs文件系统打开文件测层次关系:
open() ->/*用户空间*/
-> 系统调用->
sys_open() -> filp_open()-> dentry_open() -> sysfs_open_file()/*内核空间*/
文件创建可以举个实例,但是sysfs文件系统初始化extern int __must_check sysfs_init(void);
还是一定解析的。源代码在:/linux/fs/sysfs/mount.c
83int __init sysfs_init(void)
84{
85 int err = -ENOMEM;
86
87 sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
88 sizeof(struct sysfs_dirent),
89 0, 0, NULL);
90 if (!sysfs_dir_cachep)
91 goto out;
92
93 err = register_filesystem(&sysfs_fs_type);
94 if (!err) {
95 sysfs_mount = kern_mount(&sysfs_fs_type);
96 if (IS_ERR(sysfs_mount)) {
97 printk(KERN_ERR "sysfs: could not mount!\n");
98 err = PTR_ERR(sysfs_mount);
99 sysfs_mount = NULL;
100 unregister_filesystem(&sysfs_fs_type);
101 goto out_err;
102 }
103 } else
104 goto out_err;
105out:
106 return err;
107out_err:
108 kmem_cache_destroy(sysfs_dir_cachep);
109 sysfs_dir_cachep = NULL;
110 goto out;
111}
kmem_cache_create (const char *name, size_t size, size_t align,
unsigned long flags,void (*ctor)(void*, struct kmem_cache *, unsigned long))
name: 此cache在/proc/slabinfo中显示的名字
size: 此cache中对象的大小 align: 对象对齐方式
flags: SLAB 标志 ctor: 对象构造函数.
成功返回cache的指针,失败返回NULL.此函数不能在中断中调用,但能被中断.
kmem_cache_create()函数, 用来创建一个新缓存。这通常是在内核初始化时执行的,或者在首次加载内核模块时执行。
这里是加载sysfs文件系统这个模块,当然要初始化。
kmem_cache_create是Slab分配器的接口函数,用于创建一个cache,而这里创建了一个cache之后,
你就可以用另一个函数kmem_cache_zalloc来申请内存,不需要用kmem_cache_free来释放内存,
你可以使用kmem_cache_destroy来彻底释放这个内存池.
err = register_filesystem(&sysfs_fs_type);(93)
注册文件系统 ,其中sysfs_fs_type结构用来描述各种特定文件系统类型,这里是sysfs文件。
oh no 说着说着就牵连到这么结构,我实在不想说这个结构了,很简单。可以自己查查file_system_type结构。
既然讲到file_system_type结构,当然得顺便说说vfsmount结构了,
文件系统被安装时,将有一个vfsmount结构体在安装点被安装。构成文件系统链表。
哦,这里就有 sysfs_mount = kern_mount(&sysfs_fs_type);(95)
sysfs文件系统实际被安装了。
vfsmount既然够理清文件系统和所有其他安装点间的关系,且保存安装时指定的标志信息。
注:以上是个人分析,只做参考,禁止复制。欢迎指出其中的错误。
阅读(3180) | 评论(0) | 转发(0) |