sysfs文件系统

 
linux中所有文件都由一 一对应的inode表示。
sysfs中每个结点由于一个sysfs_dirent表示,这样每个kobject就对应一个sysfs_dirent.
所以要注意 inode <==> sysfs_dirent间的关系转换。
生成过程:  先有sysfs_dirent, 然后根据其 生成对应的实际文件 inode 与之关联。



//分配并初始化一个sysfs_dirent: 目录
sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
//创建一个新的sysfs_dirent.对应的名称为attr->name.即属性的名称: 属性文件
sd = sysfs_new_dirent(attr->name, mode, type);  type = SYSFS_KOBJ_ATTR


//在sysfs中创建二进制属性文件。二制制属性通常用于firmware 中.它用来更新firmware 的固件.它的接口为 (实现中会调用上面的那个接口:sysfs_new_dirent)
int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
然后生成:
int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, int type)

//创建一般属性文件:创建一般属性的接口为sysfs_create_file().代码如下: (实现中会调用上面的那个接口:sysfs_new_dirent)
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
然后会调用sysfs_add_file().参数attr.是要生成文件的属性值.
int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,int type)


//创建链接文件的接口为: sysfs_create_link().代码如下: (实现中会调用上面的那个接口:sysfs_new_dirent)
int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name)

//在为kobject创建sysfs目录时,会根据kobject中的parent 及 kset来设定 父目录,若都没设置,则使用根目录 /sys,  所以在进入create_dir时,已有父dirent.
int sysfs_create_dir(struct kobject * kobj)
{
struct sysfs_dirent *parent_sd, *sd;
int error = 0;

BUG_ON(!kobj);

if (kobj->parent)
parent_sd = kobj->parent->sd;
else
parent_sd = &sysfs_root;

error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
if (!error)
kobj->sd = sd;
return error;
}


//***********所有的实际sysfs的  一般属性文件  的inode中的 file_operation 是一致的,系统定义:转 调用 kobj_type中的 ops的函数 *********************//
回忆一下,在sysfs文件系统中,inode的初始化:
static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
{
       ……
       case SYSFS_KOBJ_ATTR:
      inode->i_size = PAGE_SIZE;
      inode->i_fop = &sysfs_file_operations;
       ……
}
sysfs_file_operations的定义如下:
const struct file_operations sysfs_file_operations = {
       .read              = sysfs_read_file, //调用kobj_type中的 ops 的 show
       .write             = sysfs_write_file, //调用 kobj_type 中的 ops 的 write
       .llseek            = generic_file_llseek,
       .open             = sysfs_open_file,
       .release    = sysfs_release,
       .poll        = sysfs_poll,
};
linux中,所有的实际文件都一 一对应一个 inode。而sysfs的文件的inode在生成时,自动绑定了统一的:sysfs_file_operations,而这里面的运作是系统自定义的,其会根据这个sysfs文件的kobj_type中的ops 的方法来进行访问。

//对属性文件 的读:
最终会调用kobject->ktype->ops->show()方法
//对属性文件的写
调用了kobject->ktype->ops->store()
//******************************************************************//


/*
先分配内存,再注册,再挂载文件系统sysfs. 生成sysfs里的根目录。

//*************挂载sysfs文件系统********************************************
sys_mount()
==> sysfs_get_sb() 
==> get_sb_single() :它对super_block.以及挂载的dentry和inode的赋值是在回调函数sysfs_fill_super, mnt()中完成的:
inode = sysfs_get_inode(&sysfs_root); 
==> 创建一个新的 inode
struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
{
      struct inode *inode;
      //以super_block和sd->s_ino为哈希值,到哈希表中寻找相应的inode.如果不存在,则新建
      inode = iget_locked(sysfs_sb, sd->s_ino);
      //对新生成的inode进行初始化
      if (inode && (inode->i_state & I_NEW))
     sysfs_init_inode(sd, inode);
 
      return inode;
}
==> 显然.在mount的时候是不会生成inode的.必定会进入sysfs_init_inode()函数*/
static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
{
      struct bin_attribute *bin_attr;
 
      inode->i_blocks = 0;
      inode->i_mapping->a_ops = &sysfs_aops;
      inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
      inode->i_op = &sysfs_inode_operations;
      inode->i_ino = sd->s_ino;
      lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
 
      if (sd->s_iattr) {
     /* sysfs_dirent has non-default attributes
      * get them for the new inode from persistent copy
      * in sysfs_dirent
      */
     set_inode_attr(inode, sd->s_iattr);
      } else
     set_default_inode_attr(inode, sd->s_mode);
 
 
      /* initialize inode according to type*/ 
//这里有四种sysfs文件类型, 根据类型给定其inode上可用的操作。 file_operations
      switch (sysfs_type(sd)) {
      case SYSFS_DIR:
     inode->i_op = &sysfs_dir_inode_operations;
     inode->i_fop = &sysfs_dir_operations;
     inode->i_nlink = sysfs_count_nlink(sd);
     break;
      case SYSFS_KOBJ_ATTR:
     inode->i_size = PAGE_SIZE;
     inode->i_fop = &sysfs_file_operations;
     break;
      case SYSFS_KOBJ_BIN_ATTR:
     bin_attr = sd->s_bin_attr.bin_attr;
     inode->i_size = bin_attr->size;
     inode->i_fop = &bin_fops;
     break;
      case SYSFS_KOBJ_LINK:
     inode->i_op = &sysfs_symlink_inode_operations;
     break;
      default:
     BUG();
      }
 
      unlock_new_inode(inode);
}
//在这里,我们可以看到sysfs文件系统中的各种操作函数了..


/*  **********************************************************************************      */
一:前言
在设备模型中,sysfs文件系统用来表示设备的结构.将设备的层次结构形象的反应到用户空间中.用户空间可以修改sysfs中的文件属性来修改设备的属性值,今天我们就来详细分析一下,sysfs的实现.
2:
二:sysfs的初始化和挂载
Sysfs文件系统的初始化是在sysfs_init()中完成的,代码如下:
/*
 * sysfs_dirent - the building block of sysfs hierarchy.  Each and
 * every sysfs node is represented by single sysfs_dirent.
 *
 * As long as s_count reference is held, the sysfs_dirent itself is
 * accessible.  Dereferencing s_elem or any other outer entity
 * requires s_active reference.
 */
struct sysfs_dirent {
atomic_t s_count;
atomic_t s_active;
struct sysfs_dirent *s_parent;
struct sysfs_dirent *s_sibling;
const char *s_name;

union {
struct sysfs_elem_dir s_dir;
struct sysfs_elem_symlink s_symlink;
struct sysfs_elem_attr s_attr;
struct sysfs_elem_bin_attr s_bin_attr;
};

unsigned int s_flags;
ino_t s_ino;
umode_t s_mode;
struct iattr *s_iattr;
};
/*
 * Context structure to be used while adding/removing nodes.
 */
struct sysfs_addrm_cxt {
struct sysfs_dirent *parent_sd;
struct inode *parent_inode;
struct sysfs_dirent *removed;
int cnt;
};

int __init sysfs_init(void)
{
   int err = -ENOMEM;
//创建一个分配 sysfs_dirent 的cache
       sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache", sizeof(struct sysfs_dirent), 0, 0, NULL);
       if (!sysfs_dir_cachep)
              goto out;
 
       err = sysfs_inode_init();
       if (err)
              goto out_err;
       //注册sysfs文件系统s
       err = register_filesystem(&sysfs_fs_type);
       if (!err) {
              //挂载sysfs文件系统
              sysfs_mount = kern_mount(&sysfs_fs_type);
              if (IS_ERR(sysfs_mount)) {
                     printk(KERN_ERR "sysfs: could not mount!\n");
                     err = PTR_ERR(sysfs_mount);
                     sysfs_mount = NULL;
                     unregister_filesystem(&sysfs_fs_type);
                     goto out_err;
              }
       } else
              goto out_err;
out:
       return err;
out_err:
       kmem_cache_destroy(sysfs_dir_cachep);
       sysfs_dir_cachep = NULL;
       goto out;
}

每个kobject对应sysfs中的一个目录,kobject的每个属性对应sysfs文件系统中的文件.
struct sysfs_dirent就是用来做kobject与dentry的互相转换用的.它们的关系如下图所示:
///********************************************//
Sysfs文件系统的file_system_type定义如下:
static struct file_system_type sysfs_fs_type = {
       .name           = "sysfs",
       .get_sb          = sysfs_get_sb,
       .kill_sb    = kill_anon_super,
};

在sys_mount()中最终会调用struct file_system_type的get_sb函数来实现文件系统的挂载.它的代码如下:
static int sysfs_get_sb(struct file_system_type *fs_type,
       int flags, const char *dev_name, void *da ta, struct vfsmount *mnt)
{
       return get_sb_single(fs_type, flags, da ta, sysfs_fill_super, mnt);
}

在这里要注意几个全局量. sysfs_sb表示sysfs文件系统的super_block. sysfs_root表示sysfs文件系统根目录的struct sysfs_dirent.
sysfs_get_inode(&sysfs_root)用来将sysfs_root导出相应的inode.代码如下:
struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
{
       struct inode *inode;
       //以super_block和sd->s_ino为哈希值,到哈希表中寻找相应的inode.如果不存在,则新建
       inode = iget_locked(sysfs_sb, sd->s_ino);
       //对新生成的inode进行初始化
       if (inode && (inode->i_state & I_NEW))
              sysfs_init_inode(sd, inode);
 
       return inode;
}
在mount的时候是不会生成inode的.必定会进入sysfs_init_inode()函数.代码如下:
static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
{
       struct bin_attribute *bin_attr;
 
       inode->i_blocks = 0;
       inode->i_mapping->a_ops = &sysfs_aops;
       inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
       inode->i_op = &sysfs_inode_operations;
       inode->i_ino = sd->s_ino;
       lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
 
       if (sd->s_iattr) {
              /* sysfs_dirent has non-default attributes
               * get them for the new inode from persistent copy
               * in sysfs_dirent
               */
              set_inode_attr(inode, sd->s_iattr);
       } else
              set_default_inode_attr(inode, sd->s_mode);
 
 
       /* initialize inode according to type */
       switch (sysfs_type(sd)) {
       case SYSFS_DIR:
              inode->i_op = &sysfs_dir_inode_operations;
              inode->i_fop = &sysfs_dir_operations;
              inode->i_nlink = sysfs_count_nlink(sd);
              break;
       case SYSFS_KOBJ_ATTR:
              inode->i_size = PAGE_SIZE;
              inode->i_fop = &sysfs_file_operations;
              break;
       case SYSFS_KOBJ_BIN_ATTR:
              bin_attr = sd->s_bin_attr.bin_attr;
              inode->i_size = bin_attr->size;
              inode->i_fop = &bin_fops;
              break;
       case SYSFS_KOBJ_LINK:
              inode->i_op = &sysfs_symlink_inode_operations;
              break;
       default:
              BUG();
       }
 
       unlock_new_inode(inode);
}
在这里,我们可以看到sysfs文件系统中的各种操作函数了..
在syfs文件系统中,怎么样判断一个目录下是否有这个文件呢?
在前面有关文件系统的分析中我们可以看.有关文件的查找实际上都会由inod->i_op-> lookup()函数进行判断.在sysfs中,这个函数对应为sysfs_lookup().代码如下:
static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)

//******************************************************//
三:在sysfs文件系统中创建目录
在linux设备模型中,每注册一个kobject.就会为之创建一个目录.
int sysfs_create_dir(struct kobject * kobj)
{
       struct sysfs_dirent *parent_sd, *sd;
       int error = 0;
 
       BUG_ON(!kobj);
 
       //如果kobject没有指定父结点,则将其父结点指定为sysfs的根目录syfs_root
       if (kobj->parent)
              parent_sd = kobj->parent->sd;
       else
              parent_sd = &sysfs_root;
 
       //创建目录
       error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
       //kobj->sd 指向对应的sysfs_dirent
       if (!error)
              kobj->sd = sd;
       return error;
}
在这里,先为结点指定父目录,然后调用create_dir()在父目录下生成结点.代码如下:
static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
                    const char *name, struct sysfs_dirent **p_sd)
{
       //指定目录的模式
       umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
       struct sysfs_addrm_cxt acxt;
       struct sysfs_dirent *sd;
       int rc;
 
       /* allocate */
       //分配并初始化一个sysfs_dirent
       sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
       if (!sd)
              return -ENOMEM;
       //初始化sd->s_dir.kobj字段
       sd->s_dir.kobj = kobj;
 
       /* link in */
       //acxt是一个临时变量.它用来存放父结点的相关信息
 
       //设置acxt->parent_sd  为父结点的sysfs_dirent.acxt->parent_inode为父结点的inode
       sysfs_addrm_start(&acxt, parent_sd);
       //设置sd->s_parent.并按inod值按顺序链入父结点的children链表
       rc = sysfs_add_on e(&acxt, sd);
       sysfs_addrm_finish(&acxt);
 
       if (rc == 0)
              *p_sd = sd;
       else
              sysfs_put(sd);
 
       return rc;
}在这里,为子节点生成了对应的sysfs_dirent.设置了它的父结点域,并将其链入到父结点的children链表.这样,在文件系统中查找父目录下面的子结点了

//******************************************************//
四:在sysfs中创建一般属性文件
Kobject的每一项属性都对应在sysfs文件系统中,kobject对应的目录下的一个文件.文件名称与属性名称相同.创建一般属性的接口为sysfs_create_file().代码如下:
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
{
       BUG_ON(!kobj || !kobj->sd || !attr);
 
       //kobject->sd: 为kobject表示目录的struct sysfs_dirent结构
       return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);
 
}
最终会调用sysfs_add_file().参数attr.是要生成文件的属性值.
int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
                 int type)
{
       //文件对应的属性
       umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
       struct sysfs_addrm_cxt acxt;
       struct sysfs_dirent *sd;
       int rc;
 
       //创建一个新的sysfs_dirent.对应的名称为attr->name.即属性的名称
       sd = sysfs_new_dirent(attr->name, mode, type);
       if (!sd)
              return -ENOMEM;
       //设置属性值
       sd->s_attr.attr = (void *)attr;
 
       //将子结点的struct sysfs_dirent结构关链到父结点
       sysfs_addrm_start(&acxt, dir_sd);
       rc = sysfs_add_on e(&acxt, sd);
       sysfs_addrm_finish(&acxt);
 
       if (rc)
              sysfs_put(sd);
 
       return rc;
}
这个流程与创建目录的流程大部份相同.不相同的只是创建目录时,它的父目录为上一层结点,创建文件时,它的父目录就是kobject对应的struct sysfs_dirent.
这样,在kobject对应的目录下面就可以看到这个文件了.^_^

//***************************************************//
文件建好之后,要怎么样去读写呢?
回忆一下,在sysfs文件系统中,inode的初始化:
static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
{
       ……
       …….
       case SYSFS_KOBJ_ATTR:
       inode->i_size = PAGE_SIZE;
       inode->i_fop = &sysfs_file_operations;
       ……
}
sysfs_file_operations的定义如下:
const struct file_operations sysfs_file_operations = {
       .read              = sysfs_read_file,
       .write             = sysfs_write_file,
       .llseek            = generic_file_llseek,
       .open             = sysfs_open_file,
       .release    = sysfs_release,
       .poll        = sysfs_poll,
};
 
文件的操作全部都在这里了,我们从打开文件说起.
sysfs_open_file()代码如下:
static int sysfs_open_file(struct inode *inode, struct file *file)
{
       struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
       struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
       struct sysfs_buffer *buffer;
       struct sysfs_ops *ops;
       int error = -EACCES;
 
       /* need attr_sd for attr and ops, its parent for kobj */
       if (!sysfs_get_active_two(attr_sd))
              return -ENODEV;
 
       /* every kobject with an attribute needs a ktype assigned */
       //将buffer->ops设置为kobj->ktype->sysfs_ops
       if (kobj->ktype && kobj->ktype->sysfs_ops)
              ops = kobj->ktype->sysfs_ops;
       else {
              printk(KERN_ERR "missing sysfs attribute operations for "
                     "kobject: %s\n", kobject_name(kobj));
              WARN_ON(1);
              goto err_out;
       }
 
       /* File needs write support.
        * The inode's perms must say it's ok,
        * and we must have a store method.
        */
       if (file->f_mode & FMODE_WRITE) {
              if (!(inode->i_mode & S_IWUGO) || !ops->store)
                     goto err_out;
       }
 
       /* File needs read support.
        * The inode's perms must say it's ok, and we there
        * must be a show method for it.
        */
       if (file->f_mode & FMODE_READ) {
              if (!(inode->i_mode & S_IRUGO) || !ops->show)
                     goto err_out;
       }
 
       /* No error? Great, allocate a buffer for the file, and store it
        * it in file->private_da ta for easy access.
        */
       error = -ENOMEM;
       buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
       if (!buffer)
              goto err_out;
 
       mutex_init(&buffer->mutex);
       buffer->needs_read_fill = 1;
       buffer->ops = ops;
       file->private_da ta = buffer;
 
       /* make sure we have open dirent struct */
       //将buffer链至attr_sd->s_attr.open链表上
       error = sysfs_get_open_dirent(attr_sd, buffer);
       if (error)
              goto err_free;
 
       /* open succeeded, put active references */
       sysfs_put_active_two(attr_sd);
       return 0;
 
 err_free:
       kfree(buffer);
 err_out:
       sysfs_put_active_two(attr_sd);
       return error;
}
在这段代码中,需要注意以下几个操作,
1:buffer链接在file-> private_da ta.具buffer还被链接在sysfs_dirent->s_attr.open.这样.VFS通过file.设备模型通过kobject->sd->s_attr.open都能找到这个要操作的 buffer
2:buffer->ops被设置为了kobject->ktype->sysfs_ops
//***************************************************//
文件的写操作入口如下:
static ssize_t
sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
       struct sysfs_buffer * buffer = file->private_da ta;
       ssize_t len;
 
       mutex_lock(&buffer->mutex);
       //将buf中的内容copy到了buffer->page
       len = fill_write_buffer(buffer, buf, count);
       //与设备模型的交互
       if (len > 0)
              len = flush_write_buffer(file->f_path.dentry, buffer, len);
       //更新ppos
       if (len > 0)
              *ppos += len;
       mutex_unlock(&buffer->mutex);
       return len;
}
首先,调用fill_write_buffer()将用户空间传值下来的数值copy到buffer->page.然后再调用flush_write_buffer()与设备模型进行交互.
Flush_wirte_buffer()代码如下:
static int
flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count)
{
       struct sysfs_dirent *attr_sd = dentry->d_fsdata;
       struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
       struct sysfs_ops * ops = buffer->ops;
       int rc;
 
       /* need attr_sd for attr and ops, its parent for kobj */
       if (!sysfs_get_active_two(attr_sd))
              return -ENODEV;
 
       rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count);
 
       sysfs_put_active_two(attr_sd);
 
       return rc;
}
我们在分析open()操作的时候曾分析到.buffer的ops是kobject->ktype->ops.在这里,它相当于调用了kobject->ktype->ops->store().参数分别为:操作的kobject.文件对应的属性.写入的值和值的长度.
Sysfs这样设计,主要是在VFS保持一个统一的接口,因为每一个kobject对应的属性值都不相同,.相应的,操作方法也不一样,这样,在ktype中就区别开来了.
 
文件的读操作
相应接口为sysfs_read_file().代码如下:
static ssize_t
sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
       struct sysfs_buffer * buffer = file->private_da ta;
       ssize_t retval = 0;
 
       mutex_lock(&buffer->mutex);
       //从设备模型中将值取出.并存入buffer->page中
       if (buffer->needs_read_fill) {
              retval = fill_read_buffer(file->f_path.dentry,buffer);
              if (retval)
                     goto out;
       }
       //将buffer->page中的值copy到用户空间的buf
       pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
               __FUNCTION__, count, *ppos, buffer->page);
       retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
                                    buffer->count);
out:
       mutex_unlock(&buffer->mutex);
       return retval;
}
读操作的流程刚好和写操作流程相反.它先从设备模型中取值,然后再copy到用户空间.
fill_read_buffer的代码如下:
static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
{
       struct sysfs_dirent *attr_sd = dentry->d_fsdata;
       struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
       struct sysfs_ops * ops = buffer->ops;
       int ret = 0;
       ssize_t count;
 
       if (!buffer->page)
              buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
       if (!buffer->page)
              return -ENOMEM;
 
       /* need attr_sd for attr and ops, its parent for kobj */
       if (!sysfs_get_active_two(attr_sd))
              return -ENODEV;
 
       buffer->event = atomic_read(&attr_sd->s_attr.open->event);
       count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page);
 
       sysfs_put_active_two(attr_sd);
 
       /*
        * The co de works fine with PAGE_SIZE return but it's likely to
        * indicate truncated result or overflow in normal use cases.
        */
       if (count >= (ssize_t)PAGE_SIZE) {
              print_symbol("fill_read_buffer: %s returned bad count\n",
                     (unsigned long)ops->show);
              /* Try to struggle along */
              count = PAGE_SIZE - 1;
       }
       if (count >= 0) {
              buffer->needs_read_fill = 0;
              buffer->count = count;
       } else {
              ret = count;
       }
       return ret;
}
在这里,我们看到,最终会调用kobject->ktype->ops->show()方法.参数含义同写操作中是一样的.

//*************************************//

五:在sysfs中创建二进制属性文件
二制制属性通常用于firmware 中.它用来更新firmware 的固件.它的接口为sysfs_create_bin_file()
代码如下:
int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
{
       BUG_ON(!kobj || !kobj->sd || !attr);
 
       return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR);
}
Sysfs_add_file()这个函数我们在之前已经分析过.在这个地方,可能会引起迷糊.因为在sysfs_add_file()中.有:
int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
                 int type)
{
       ……
       sd->s_attr.attr = (void *)attr;
       ……
}
这里为什么是sd->a_attr呢?应该是sd-> s_bin_attr才对吧!
仔细观察struct sysfs_dirent的结构,如下:
struct sysfs_dirent {
       atomic_t         s_count;
       atomic_t         s_active;
       struct sysfs_dirent  *s_parent;
       struct sysfs_dirent  *s_sibling;
       const char             *s_name;
 
       union {
              struct sysfs_elem_dir            s_dir;
              struct sysfs_elem_symlink    s_symlink;
              struct sysfs_elem_attr           s_attr;
              struct sysfs_elem_bin_attr     s_bin_attr;
       };
 
       unsigned int           s_flags;
       ino_t                     s_ino;
       umode_t                s_mode;
       struct iattr             *s_iattr;
};
注意中间是一个union 结构,实际上只占用一个内存空间.而且s_attr与s_bin_arre的第一个属性都为struct attribute.所以在这里, sd->a_attr与sd-> s_bin_attr;的效果是一样的.内核这样处理,又少用了一个接口.看来作者在设计的时候,花了很多的心思.
 
二进制的文件读写与普通属性的文件读写方式大部份都一样,所不同的是.二进制文件的读写接口分别是: sysfs_dirent ->s_bin_attr.bin_attr->read和sysfs_dirent ->s_bin_attr.bin_attr->write

//**********************************//
struct file_system_type {
const char *name;
int fs_flags;
int (*get_sb) (struct file_system_type *, int,
      const char *, void *, struct vfsmount *);
void (*kill_sb) (struct super_block *);
struct module *owner;
struct file_system_type * next;
struct list_head fs_supers;

struct lock_class_key s_lock_key;
struct lock_class_key s_umount_key;

struct lock_class_key i_lock_key;
struct lock_class_key i_mutex_key;
struct lock_class_key i_mutex_dir_key;
struct lock_class_key i_alloc_sem_key;
};

你可能感兴趣的:(struct,File,System,buffer,attributes,symlink)