Chinaunix首页 | 论坛 | 博客
  • 博客访问: 512684
  • 博文数量: 68
  • 博客积分: 5011
  • 博客等级: 大校
  • 技术积分: 806
  • 用 户 组: 普通用户
  • 注册时间: 2007-11-30 22:06
文章分类
文章存档

2011年(1)

2009年(8)

2008年(59)

我的朋友

分类: LINUX

2008-07-24 17:56:15

  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既然够理清文件系统和所有其他安装点间的关系,且保存安装时指定的标志信息。
 
 
 注:以上是个人分析,只做参考,禁止复制。欢迎指出其中的错误。
 




   


 
 
阅读(3204) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~