加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

Linux内核之设备驱动-sysfs

(2016-08-21 21:00:32)
标签:

linux

设备驱动

sysfs

分类: linux

Linux内核之设备驱动-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
可 以先把documentation/filesystems/sysfs.txt读一遍。文档这种东西,真正读起来就嫌少了。Sysfs文件系统是一个类 似于proc文件系统的特殊文件系统,用于将系统中的设备组织成层次结构,并向用户模式程序提供详细的内核数据结构信息。


去/sys看一看,
localhost:/sys#ls /sys/
block/ bus/ class/ devices/ firmware/ kernel/ module/ power/
Block目录:包含所有的块设备
Devices目录:包含系统所有的设备,并根据设备挂接的总线类型组织成层次结构
Bus目录:包含系统中所有的总线类型
Drivers目录:包括内核中所有已注册的设备驱动程序
Class目录:系统中的设备类型(如网卡设备,声卡设备等) 

sys下面的目录和文件反映了整台机器的系统状况。比如bus,
localhost:/sys/bus#ls
i2c/ ide/ pci/ pci express/ platform/ pnp/ scsi/ serio/ usb/
里面就包含了系统用到的一系列总线,比如pci, ide, scsi, usb等等。比如你可以在usb文件夹中发现你使用的U盘,USB鼠标的信息。

我们要讨论一个文件系统,首先要知道这个文件系统的信息来源在哪里。所谓信息来源是指文件组织存放的地点。比如,我们挂载一个分区,

mount -t vfat /dev/hda2 /mnt/C

我们就知道挂载在/mnt/C下的是一个vfat类型的文件系统,它的信息来源是在第一块硬盘的第2个分区。

但是,你可能根本没有去关心过sysfs的挂载过程,她是这样被挂载的。

mount -t sysfs sysfs /sys

ms看不出她的信息来源在哪。sysfs是一个特殊文件系统,并没有一个实际存放文件的介质。断电后就玩完了。简而言之,sysfs的信息来源是kobject层次结构,读一个sysfs文件,就是动态的从kobject结构提取信息,生成文件。

文件系统

文件系统是个很模糊广泛的概念,"文件"狭义地说,是指磁盘文件,广义理解,可以是有组织有次序地存储与任何介质(包括内存)的一组信息。 linux把所有的资源都看成是文件,让用户通过一个统一的文件系统操作界面,也就是同一组系统调用,对属于不同文件系统的文件进行操作。这样,就可以对 用户程序隐藏各种不同文件系统的实现细节,为用户程序提供了一个统一的,抽象的,虚拟的文件系统界面,这就是所谓"VFS(Virtual Filesystem Switch)"。这个抽象出来的接口就是一组函数操作。

我们要实现一种文件系统就是要实现VFS所定义的一系列 接口,file_operations, dentry_operations, inode_operations等,供上层调用。file_operations是对每个具体文件的读写操作,dentry_operations, inode_operations则是对文件的属性,如改名字,建立或删除的操作。

struct file_operations {
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
int (*open) (struct inode *, struct file *);
...
};
struct dentry_operations {
...
};
struct inode_operations {
int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
int (*link) (struct dentry *,struct inode *,struct dentry *);
int (*mkdir) (struct inode *,struct dentry *,int);
int (*rmdir) (struct inode *,struct dentry *);
...}

举个例子,我们写C程序,open(“hello.c”, O_RDONLY),它通过系统调用的流程是这样的

open() ->      
-> 系统调用->
sys_open() -> filp_open()-> dentry_open() ->  file_operations->open()          

不同的文件系统,调用不同的file_operations->open(),在sysfs下就是sysfs_open_file()。

 

 

我们在进程中要怎样去描述一个文件呢?我们用目录项(dentry)和索引节点(inode)。它们的定义如下:

struct dentry {
struct inode                                *d_inode;
struct list_head                          d_child;
struct dentry_operations          *d_op;
struct super_block                     *d_sb;
void                                     *d_fsdata;
unsigned char                  d_iname[DNAME_INLINE_LEN_MIN];
......
};
struct inode {
unsigned long                     i_ino;
atomic_t                               i_count;
umode_t                               i_mode;
unsigned int                        i_nlink;
uid_t                                      i_uid;
gid_t                                      i_gid;
dev_t                                     i_rdev;
loff_t                                      i_size;
struct timespec                   i_atime;
unsigned long                     i_blocks;
unsigned short                    i_bytes;
unsigned char                      _sock;
12
struct inode_operations *i_op;
struct file_operations *i_fop;
struct super_block *i_sb;
......
}; 

        所谓"文件", 就是按一定的形式存储在介质上的信息,所以一个文件其实包含了两方面的信息,一是存储的数据本身,二是有关该文件的组织和管理的信息。在内存中, 每个文件都有一个dentry(目录项)和inode(索引节点)结构,dentry记录着文件名,上级目录等信息,正是它形成了我们所看到的树状结构; 而有关该文件的组织和管理的信息主要存放inode里面,它记录着文件在存储介质上的位置与分布。同时dentry->d_inode指向相应的 inode结构。dentry与inode是多对一的关系,因为有可能一个文件有好几个文件名(硬链接, hard link, 可以参考这个网页 http://www.ugrad.cs.ubc.ca/~cs219/CourseNotes/Unix/commands-links.html )。

所有的dentry用d_parent和d_child连接起来,就形成了我们熟悉的树状结构。

inode代表的是物理意义上的文件,通过inode可以得到一个数组,这个数组记录了文件内容的位置,如该文件位于硬盘的第3,8,10块,那么 这个数组的内容就是3,8,10。其索引节点号inode->i_ino,在同一个文件系统中是唯一的,内核只要根据i_ino,就可以计算出它对 应的inode在介质上的位置。就硬盘来说,根据i_ino就可以计算出它对应的inode属于哪个块(block),从而找到相应的inode结构。但 仅仅用inode还是无法描述出所有的文件系统,对于某一种特定的文件系统而言,比如ext3,在内存中用ext3_inode_info描述。他是一个 包含inode的"容器"。

struct ext3_inode_info {
               __le32 i_data[15];
               ......
               struct inode vfs_inode;
};

le32 i data[15]这个数组就是上一段中所提到的那个数组。

注意,在遥远的2.4的古代,不同文件系统索引节点的内存映像 (ext3_inode_info,reiserfs_inode_info,msdos_inode_info ...)都是用一个union内嵌在inode数据结构中的. 但inode作为一种非常基本的数据结构而言,这样搞太大了,不利于快速的分配和回收。但是后来发明了container_of(...)这种方法后,就 把union移到了外部,我们可以用类似container of(inode, struct ext3_inode_info, vfs_inode),从inode出发,得到其的"容器"。

dentry和inode终究都是在内存中的,它们的原始信息必须要有一个载体。否则断电之后岂不是玩完了?且听我慢慢道来。

文件可以分为磁盘文件,设备文件,和特殊文件三种。设备文件暂且不表。

磁盘文件 
就磁盘文件而言,dentry和inode的载体在存储介质(磁盘)上。对于像ext3这样的磁盘文件来说,存储介质中的目录项和索引节点载体如下,
struct ext3_inode {
__le16 i_mode;
__le16 i_uid;
__le32 i_size;
__le32 i_atime;
__le32 i_ctime;
__le32 i_mtime;

__le32 i_dtime;
__le16 i_gid;
__le16 i_links_count;
......
__le32 i_block[EXT2_N_BLOCKS];
......
}
struct ext3_dir_entry_2 {
__u32 inode;
__u16 rec_len;
__u8 name_len;
__u8 file_type;
char name[EXT3_NAME_LEN];
};

le32 i block[EXT2 N BLOCKS];
i_block数组指示了文件的内容所存放的地点(在硬盘上的位置)。

ext3_inode是放在索引节点区,而ext3_dir_entry_2是以文件内容的形式存放在数据区。我们只要知道了ino,由于 ext3_inode大小已知,我们就可以计算出ext3_inode在索引节点区的位置( ino * sizeof(ext3_inode) ),而得到了ext3_inode,我们根据i_block就可以知道这个文件的数据存放的地点。将磁盘上ext3_inode的内容读入到 ext3_inode_info中的函数是ext3_read_inode()。以一个有100 block的硬盘为例,一个文件系统的组织布局大致如下图。位图区中的每一位表示每一个相应的对象有没有被使用。

http://p.blog.csdn.net/images/p_blog_csdn_net/fudan_abc/ext.jpg

特殊文件 
特殊文件在内存中有inode和dentry数据结构,但是不一定在存储介质上有"索引节 点",它断电之后的确就玩完了,所以不需要什么载体。当从一个特殊文件读时,所读出的数据是由系统内部按一定的规则临时生成的,或从内存中收集,加工出来 的。sysfs里面就是典型的特殊文件。它存储的信息都是由系统动态的生成的,它动态的包含了整个机器的硬件资源情况。从sysfs读写就相当于向 kobject层次结构提取数据。

还请注意, 我们谈到目录项和索引节点时,有两种含义。一种是在存储介质(硬盘)中的(如ext3_inode),一种是在内存中的,后者是根据在前者生成的。内存中 的表示就是dentry和inode,它是VFS中的一层,不管什么样的文件系统,最后在内存中描述它的都是dentry和inode结构。我们使用不同 的文件系统,就是将它们各自的文件信息都抽象到dentry和inode中去。这样对于高层来说,我们就可以不关心底层的实现,我们使用的都是一系列标准 的函数调用。这就是VFS的精髓,实际上就是面向对象。

我们在进程中打开一个文件F,实际上就是要在内存中建立F的dentry,和inode结构,并让它们与进程结构联系来,把VFS中定义的接口给接起来。我们来看一看这个经典的图。这张图之于文件系统,就像每天爱你多一些之于张学友,番茄炒蛋之于复旦南区食堂,刻骨铭心。

http://p.blog.csdn.net/images/p_blog_csdn_net/fudan_abc/fs.jpg

 

 

 

前面说过,只要知道文件的索引节点号,就可以得到那个文件。但是我们在操作文件时,从没听说谁会拿着索引节点号来操作文件,我们只知道文件名而已。 它们是如何"和谐"起来的呢?linux把目录也看成一种文件,里面记录着文件名与索引节点号的对应关系。比如在ext3文件系统中,如果文件是一个目 录,那么它的内容就是一系列ext3_dir_entry_2的结构


struct ext3_dir_entry_2 {
__u32 inode;
__u16 rec_len;
__u8 name_len;
__u8 file_type;
char name[EXT3_NAME_LEN];
};


举个例子,比如要打开/home/test/hello.c。首先,找到‘/’,读入其内容,找到名为"home"的文件的索引节点号,打 开/home这个"文件",读入内容,找到名为 "test" 的的文件的索引节点号,同理,再打开文件"/home/test",找到找到名为"hello.c”的文件的索引节点号,最后就得到 /home/test/hello.c了。这就是path_walk()函数的原理。

其中,根据一个文件夹的inode,和一个文件名来获取该文件的inode结构的函数,就叫lookup,它是inode_operations里面的函数。
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
lookup, 顾名思义,就是查找,比如查查在test这个文件夹下,有没有叫hello.c的文件,有的话,就从存储介质中读取其inode结构。并用 dentry->d_inode指向它。所以,我们只要知道了文件的路径和名字,总可以从根目录开始,一层一层的往下走,定位到某一个文件。 

superblock与vfsmount

接下来还要介绍两个数据结构,superblock和vfsmount。super_block结构是从所有具体的文件系统所抽象出来的一个结构, 每一个文件系统实例都会有一对应super_block结构。比如每一个ext2的分区就有一个super_block结构,它记录了该文件系统实例(分 区)的某些描述性的信息,比如该文件系统实例的文件系统类型,有多大,磁盘上每一块的大小, 还有就是super_operations。它与inode,dentry一样,只是某些内容在内存中的映像。就ext2文件系统而言,设备上的超级块为 ext2_super_block。由于sysfs是虚拟的文件系统,独一无二, 并且只能被mount一次,sysfs的super_block结构是sysfs_sb。sysfs_sb也是动态的从内存中生成的。


还有要提一下super_operations,它也算是VFS的一个接口。实现一个文件系统file_operations, dentry_operations, inode_operations, super_operations这四个结构都要实现。

把一个设备安装到一个目录节点时要用一个vfsmount的作为连接件。vfsmount结构定义如下:

struct vfsmount {
              struct list_head mnt_hash;
              struct vfsmount *mnt_parent; 
              struct dentry *mnt_mountpoint; 
              struct dentry *mnt_root; 
              struct super_block *mnt_sb; 
              ..........
}

对于某个文件系统实例,内存中super_block和vfsmount都是唯一的。比如,我们将某个挂载硬盘分区mount -t vfat /dev/hda2 /mnt/d。实际上就是新建一个vfsmount结构作为连接件,vfsmount->mnt_sb = /dev/hda2的超级块结构;vfsmount->mntroot = /dev/hda2的"根"目录的dentry;vfsmount->mnt_mountpoint = /mnt/d的dentry; vfsmount->mnt_parent = /mnt/d所属的文件系统的vfsmount。并且把这个新建的vfsmount连入一个全局的hash表mount_hashtable中。

从而我们就可以从总根’/’开始,沿着dentry往下找。假如碰到一个某个目录的dentry是被mount了的,那么我们就从 mount_hashtable表中去寻找相应的vfsmount结构 (函数是lookup_mnt())。然后我们得到vfsmount ->mnt_root,就可以找到mount在该目录的文件系统的"根"dentry结构。然后又继续往下走,就可以畅通无阻了。

关于path_walk()的代码我就不贴了,太长了。其实懂了原理后再去看,很简单,跟看故事会差不多。我当年就是看完这个函数后,信心倍增阿。pathwalk,不管前面是高速公路,或是泥泞的乡间小路,我们都要走到底。

 

 

最近Linus炮轰C++,“C++是一种糟糕的(horrible)语言。而且因为有大量不够标准的程序员在使用而使许多真正懂得底层问题,而不会折腾那些白痴‘对象模型’”。牛人就是牛气冲天阿。

在fs/sysfs/下面,除去makefile,还有8个文件。其中, bin.c, file.c, dir.c, symblink.c分别代表了在sysfs文件系统中当文件类型为二进制文件,普通文件,目录,符号连接时的各自的file operations结构体的实现。inode.c则是inode oprations的实现,还有创建和删除inode。mount.c包括了sysfs的初始化函数。sysfs.h就是头文件,里面有函数的原形,并将 其extern出去。 

sysfs的文件系统的所读写的信息是存放在kobject当中,那么dentry是如何与kobject联系起来的呢?是通过sysfs_dirent。

sysfs_dirent

sysfs文件系统有自己的dirent结构,dirent = directory entry (目录实体)。sysfs中,每一个dentry对应了一个dirent结构,dentry->d _fsdata是一个void的指针,它指向sysfs_dirent结构。

struct sysfs_dirent {
            atomic_t               s_count;
            struct list_head  s_sibling;
            struct list_head  s_children;
            void *                    s_element;
            int                          s_type;
            umode_t             s_mode;
            struct dentry *     s_dentry;
            struct iattr *         s_iattr;
            atomic_t              s_event;
};

s_count是引用计数,s_sibling,s_children指针是这些sysfs_dirent 连成一个树状结构。s_type则说明了这个dirent具体的类型:
#define SYSFS_ROOT 0x0001
#define SYSFS_DIR 0x0002
#define SYSFS_KOBJ_ATTR 0x0004
#define SYSFS_KOBJ_BIN_ATTR 0x0008
#define SYSFS_KOBJ_LINK 0x0020

s_element就是指向相应与s_type类型的数据结构。如DIR(就是kobject,一个kobject对应一个 DIR),KOBJ_ATTR(attribute属性,代表一个文件)。sysfs_dirent是kobject和sysfs联系的一个中间连接结 构。它通过s_sibling,s_children连接成一个层次结构。而且它的层次结构与sysfs完全一致的,它就是一个连接kobject和 dentry结构的连接件。

举个例子总结一下这些数据结构的连接关系。在sysfs中的文件结构如下
/sys/bus/ldd/
|--device
|--driver
`--version

它对应的dentry,dirent,kobject的连接图如图1,2,3

http://p.blog.csdn.net/images/p_blog_csdn_net/fudan_abc/dentry.jpg

图1: dentry连接图
http://p.blog.csdn.net/images/p_blog_csdn_net/fudan_abc/dirent.jpg 
图2: dirent连接图
http://p.blog.csdn.net/images/p_blog_csdn_net/fudan_abc/kobj.jpg 
图3: kobject连接图

对比一下可以发现不同之处。向version这样用bus_create_file()创建的文件,或曰属性,只停留在sysfs_dirent这一层。


对于sysfs下的文件夹而言,denrty, dirent, kobject之间通过指针相互联系起来。
dentry->d_fsdata = &dirent;
dirent->element = &kobject;
kobject->dentry = &dentry;

 

 

每当我们新增一个kobject结构的时候,同时会在/sys下创建一个目录。

kobject_add()  ->  create_dir() -> sysfs_create_dir()

此时,我还想重申,kernel代码的更新换代是很快的,我们的目的是懂得代码背后的原理,知识,或曰哲学。我不想讲的太细,因为关于sysfs的 部分从2.6.10到现在2.6.22已经改了很多了。但其总体架构没变。写此文的目的是让您跟着我的思路走一遍,对sysfs有了一个总体上的认识。然 后自己就可以去看最新的代码了。最新的代码肯定是效率更高,条理逻辑更清晰。

sysfs_create_dir()流程图如下:
                     -> create_dir()
                                          -> *d = sysfs_get_dentry()
                                                               -> lookup_hash()
                                                                                    -> __lookup_hash()
                                                                                    -> cached_lookup()
                                                                                    -> new = d_alloc(base, name);
                                                                                    -> inode->i_op->lookup(inode, new, nd)
                                          -> sysfs_create(*d, mode, init_dir)
                                                               -> sysfs_new_inode(mode)
                                                               -> init_dir(inode); // Call back function
                                          -> sysfs_make_dirent()
                                                               -> sysfs_new_dirent()
                                                               -> dentry->d_fsdata = sysfs_get(sd);
                                                               -> dentry->d_op = &sysfs_dentry_ops;
                                          -> (*d)->d_op = &sysfs_dentry_ops;

    135 int sysfs_create_dir(struct kobject * kobj)
    136 {
    137         struct dentry * dentry = NULL;
    138         struct dentry * parent;
    139         int error = 0;
    140 
    141         BUG_ON(!kobj);
    142 
    143         if (kobj->parent)
    144                 parent = kobj->parent->dentry;
    145         else if (sysfs_mount && sysfs_mount->mnt_sb)
    146                 parent = sysfs_mount->mnt_sb->s_root;
    147         else
    148                 return -EFAULT;
    149 
    150         error = create_dir(kobj,parent,kobject_name(kobj),&dentry);
    151         if (!error)
    152                 kobj->dentry = dentry;
    153         return error;
    154 }
143-148就是找到父辈的kobject,再调用create_dir();

     95 static int create_dir(struct kobject * k, struct dentry * p,
     96                       const char * n, struct dentry ** d)
     97 {
     98         int error;
     99         umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
    100 
    101         down(&p->d_inode->i_sem);
    102         *d = sysfs_get_dentry(p,n);
    103         if (!IS_ERR(*d)) {
    104                 error = sysfs_create(*d, mode, init_dir);
    105                 if (!error) {
    106                         error = sysfs_make_dirent(p->d_fsdata, *d, k, mode,
    107                                                 SYSFS_DIR);
    108                         if (!error) {
    109                                 p->d_inode->i_nlink++;
    110                                 (*d)->d_op = &sysfs_dentry_ops;
    111                                 d_rehash(*d);
    112                         }
    113                 }
    114                 if (error && (error != -EEXIST))
    115                         d_drop(*d);
    116                 dput(*d);
    117         } else
    118                 error = PTR_ERR(*d);
    119         up(&p->d_inode->i_sem);
    120         return error;
    121 }
99行,设置‘文件’ 属性,101获取信号量。

(1)sysfs_get_dentry()
102行sysfs_get_dentry()。它的作用是根据父辈dentry和文件名得到 dentry结构。首先在缓存中找,如果找到就返回,找不到就用d_alloc()新建一个dentry结构。我们是新建文件夹,缓存中自然是没有的,所 以要用d_alloc()来新建一个。接着我们调用lookup函数,它定义如下。

struct inode_operations sysfs_dir_inode_operations = {
             .lookup = sysfs_lookup,
};

    204 static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
    205                                 struct nameidata *nd)
    206 {
    207         struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
    208         struct sysfs_dirent * sd;
    209         int err = 0;
    210 
    211         list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
    212                 if (sd->s_type & SYSFS_NOT_PINNED) {
    213                         const unsigned char * name = sysfs_get_name(sd);
    214 
    215                         if (strcmp(name, dentry->d_name.name))
    216                                 continue;
    217 
    218                         if (sd->s_type & SYSFS_KOBJ_LINK)
    219                                 err = sysfs_attach_link(sd, dentry);
    220                         else
    221                                 err = sysfs_attach_attr(sd, dentry);
    222                         break;
    223                 }
    224         }
    225 
    226         return ERR_PTR(err);
    227 }

前 面讲过lookup函数的作用。它在inode代表的文件夹下查找有没有名为dentry.d name.name的文件。如果有,就将其对应的inode结构从信息的载体中读出来。由于是新建的文件夹,所以lookup函数在我们这个故事里根本没 做事。但是我还是忍不住想分析一下lookup函数。

sysfs文件系统中,文件夹的inode和dentry结构一直都是存在于内存中的,所以不用再进行读取了。而文件,链接的inode事先是没有的,需要从载体中读出。这就是212行这个判断的作用。可以看出,如果是文件夹,循环里面啥都没做。

#define SYSFS_NOT_PINNED /
(SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR | SYSFS_KOBJ_LINK)

但是sysfs的lookup还有它不同之处。其他文件系统像ext3格式中普通文件的inode,在文件创建之时就已经创建了。但是,sysfs 不一样,它在创建普通文件时,只是先创建一个sysfs_dirent结构。创建inode的工作是推迟到lookup函数来完成的。在下一节 sysfs_create_file()会看到这一点。

sysfs_attach_attr()和sysfs_attach_link()的作用就是根据dentry和sysfs_dirent新建一个inode。

总之,我们通过sysfs_get_dentry()得到了一个新建的dentry结构。

(2)sysfs_create()分析 (104行)
sysfs_create()->sysfs_new_inode(mode) -> new_inode(sysfs_sb)
创建一个新的索引节点inode。sysfs_sb是sysfs的超级块(super_block)结构。mode则是inode的属性,它记录了如下信息,比如,文件类型(是文件夹,链接,还是普通文件),inode的所有者,创建时间等等。

(3)sysfs make dirent()分析 (104行)
至此,我们得到了一个dirent结构,初始化,再把它连接到上层目录的sysfs_dirent的s_children链表里去。sysfs_make_dirent()为刚刚新建出来的dentry建立一个dirent结构。并将dentry和dirent联系起来。

(4)总结
在sysfs下创建一个目录,提供的函数是sysfs_create_dir()。创建了dentry, dirent, inode
结构, 它们之间的连接关系见图1http://p.blog.csdn.net/images/p_blog_csdn_net/fudan_abc/sysfs.jpg

 

 

最近彭宇的案件炒得沸沸扬扬,究竟这个社会怎么了?

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中,inode并不那么重要。这是因为我们所要读写的信息已经就在内存中,并且已经形 成了层次结构。我们只需有dentry,就可以dentry->fsdata,就能找到我们读些信息的来源 ---  sysfs_dirent结构。这也是我觉得有必要研究 sysfs的原因之一,因为它简单,而且不涉及具体的硬件驱动,但是从这个过程中,我们可以把文件系统中的一些基本数据结构搞清楚。接下来,我以读取 sysfs文件和文件夹的内容为例子,讲讲文件读的流程。那么关于写,还有关于symblink的东西完全可以以此类推了。

我们新建文件夹时,设置了
 inode->i_op = &sysfs_dir_inode_operations;
 inode->i_fop = &sysfs_dir_operations;

struct file_operations sysfs_dir_operations = {
        .open = sysfs_dir_open,
        .release = sysfs_dir_close,
        .llseek = sysfs_dir_lseek,
        .read = generic_read_dir,
        .readdir = sysfs_readdir,
};

用一个简短的程序来做实验。

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif #include sys types.h 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif #include dirent.h 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif #include unistd.h 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif int  main() {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               DIR   dir;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                struct  dirent  ptr;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               dir   opendir( /sys/bus/ );
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif                while ((ptr   readdir(dir)) != NULL) {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                             printf( d_name :%s ,ptr -> d_name);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif               

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               closedir(dir);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                return   ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif }

在用户空间,用gcc编译执行即可。我们来看看它究竟做了什么。

(1)sysfs_dir_open()

这是个用户空间的程序。opendir()是glibc的函数,glibc也就是著名的标准c库。至于opendir ()是如何与sysfs dir open ()接上头的,那还得去看glibc的代码。我就不想分析了...glibc可以从gnu的网站上自己下载源代码,编译。再用gdb调试,就可以看得跟清 楚。
函数流程如下:
opendir("/sys/bus/") ->
-> 系统调用->
sys_open() -> filp_open()-> dentry_open() -> sysfs_dir_open()

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif static   int  sysfs_dir_open( struct  inode  inode,  struct  file  file)
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif              struct  dentry   dentry   file -> f_dentry;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif              struct  sysfs_dirent   parent_sd   dentry -> d_fsdata;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif             down( dentry -> d_inode -> i_sem);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif             file -> private_data   sysfs_new_dirent(parent_sd, NULL);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif             up( dentry -> d_inode -> i_sem);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif              return  file -> private_data      ENOMEM;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif }

内核空间:新建一个dirent结构,连入父辈的dentry中,并将它地址保存在file->private_data中。这个dirent的具体作用待会会讲。
用户空间:新建了一个DIR结构,DIR结构如下。

#define __dirstream DIR
struct __dirstream
{
             int fd;
             char *data;
             size_t allocation;
             size_t size;
             size_t offset;
             off_t filepos;
             __libc_lock_define (, lock)
};

(2)sysfs_readdir()

流程如下:


readdir(dir) -> getdents() ->
-> 系统调用->
sys32 readdir() -> vfs readdir() -> sysfs readdir()

readdir(dir)这个函数有点复杂,虽然在main函数里的while循环中,readdir被执行了多次,我们看看glibc里面的代码

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif readdir(dir) {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                 ......
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif                  if  (dirp -> offset  >=  dirp -> size) {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                 ......
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                 getdents()
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                 ......
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif                 

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif ......
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif }

实际上,getdents() -> ... -> sysfs_readdir()只被调用了两次,getdents()一次就把所有的内容都读完,存在DIR结构当中,readdir()只是从DIR结 构当中每次取出一个。DIR(dirstream)结构就是一个流。而回调函数filldir的作用就是往这个流中填充数据。第二次调用 getdents()是用户把DIR里面的内容读完了,所以它又调用getdents()但是这次getdents()回返回NULL。

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif static   int  sysfs_readdir( struct  file   filp,  void    dirent, filldir_t filldir)
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               struct  dentry  dentry   filp -> f_dentry;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               struct  sysfs_dirent   parent_sd   dentry -> d_fsdata;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               struct  sysfs_dirent  cursor   filp -> private_data;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               struct  list_head  p,     cursor -> s_sibling;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif              ino_t ino;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               int    filp -> f_pos;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif               switch  (i)  {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                            case   :
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                           ino   dentry -> d_inode -> i_ino;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                            if  (filldir(dirent,   i, ino, DT_DIR)    )
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                         break ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                           filp -> f_pos ++ ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                           ++ ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif                             
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                            case   :
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                           ino   parent_ino(dentry);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                            if  (filldir(dirent,  ..  i, ino, DT_DIR)    )
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                         break ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                           filp -> f_pos ++ ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                           ++ ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif                             
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                            default :
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif                            if  (filp -> f_pos  ==    {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                        list_del(q);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                        list_add(q,  parent_sd -> s_children);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif                           

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif                            for  (p -> next; !=   parent_sd -> s_children; -> next)  {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                         struct  sysfs_dirent  next;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                         const   char    name;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                         int  len;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                        next   list_entry(p,  struct  sysfs_dirent, s_sibling);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                         if  next -> s_element)
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                                      continue ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                        name   sysfs_get_name(next);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                        len   strlen(name);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                         if  (next -> s_dentry)
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                                     ino   next -> s_dentry -> d_inode -> i_ino;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                         else 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                                     ino   iunique(sysfs_sb,  );
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                         if  (filldir(dirent, name, len, filp -> f_pos, ino,dt_type(next))    )
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                                      return   ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                        list_del(q);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                        list_add(q, p);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                          q;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                                        filp -> f_pos ++ ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif                           

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif              

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif return   ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif }

看sysfs_readdir()其实很简单,它就是从我们调用sysfs_dir_open()时新建的一个sysfs_dirent结构开始, 便利当前dentry->dirent下的所有子sysfs_dirent结构。读出名字,再回调函数filldir()将文件名,文件类型等信 息,按照一定的格式写入某个缓冲区。

一个典型的filldir()就是filldir64(),它的作用的按一定格式向缓冲区写数据,再把数据复制到用户空间去。

 

跟上回一样,我用这个小程序来读

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif #include  stdio.h 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif #include  fcntl.h 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif #include  unistd.h 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif int  main() {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                char   name    /sys/bus/ldd/version ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                char  buf[ 500 ];
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                int  fd;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                int  size;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               fd   open(name, O_RDONLY);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               printf( fd:%d ,fd);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               size   read(fd,buf, sizeof (buf));
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               printf( size:%d ,size);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               printf( %s ,buf);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif               close(fd);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif                return   ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif }

(1)sysfs_open_file() 

open() ->
-> 系统调用->
sys_open() -> filp_open()-> dentry_open() -> sysfs_open_file()

static int sysfs_open_file(struct inode * inode, struct file * filp)
{
             return check_perm(inode,filp);
}

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif static   int  check_perm( struct  inode   inode,  struct  file   file)
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      struct  kobject  kobj   sysfs_get_kobject(file -> f_dentry -> d_parent);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      struct  attribute   attr   to_attr(file -> f_dentry);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      struct  sysfs_buffer   buffer;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      struct  sysfs_ops   ops   NULL;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      int  error    ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      if  kobj  ||   attr)
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif          goto  Einval;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif       
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif      if  try_module_get(attr -> owner))  {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif         error    ENODEV;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif          goto  Done;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif     

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif       
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      if  (kobj -> kset  &&  kobj -> kset -> ktype)
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif         ops   kobj -> kset -> ktype -> sysfs_ops;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      else   if  (kobj -> ktype)
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif         ops   kobj -> ktype -> sysfs_ops;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      else 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif         ops    subsys_sysfs_ops;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif       
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      if  ops)
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif          goto  Eaccess;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif       
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif      if  (file -> f_mode   FMODE_WRITE)  {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif          if  (inode -> i_mode   S_IWUGO)  ||   ops -> store)
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif              goto  Eaccess;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif     

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif       
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif      if  (file -> f_mode   FMODE_READ)  {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif          if  (inode -> i_mode   S_IRUGO)  ||   ops -> show)
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif              goto  Eaccess;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif     

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif       
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif     buffer   kmalloc( sizeof struct  sysfs_buffer),GFP_KERNEL);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif      if  (buffer)  {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif         memset(buffer, sizeof struct  sysfs_buffer));
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif         init_MUTEX( buffer -> sem);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif         buffer -> needs_read_fill    ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif         buffer -> ops   ops;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif         file -> private_data   buffer;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif     
  else 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif         error    ENOMEM;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      goto  Done;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif  Einval:
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif     error    EINVAL;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      goto  Done;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif  Eaccess:
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif     error    EACCES;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif     module_put(attr -> owner);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif  Done:
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      if  (error  &&  kobj)
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif         kobject_put(kobj);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      return  error;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif }

check_perm()检查一下权限,创建一个sysfs的缓冲区sysfs_buffer buffer,并设置其sysfs_ops sysfs_buffer->ops。在我们这个故事里,sysfs_buffer->ops被设置成bus_sysfs_ops。最后让 file->private_data = buffer。

(2)sysfs read file() 

流程如下:
read()->
-> 系统调用->
sys_read() -> vfs_read() -> sysfs_read_file()

看看sysfs_read_file()函数,

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif static  ssize_t
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif sysfs_read_file( struct  file  file,  char  __user  buf, size_t count, loff_t  ppos)
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      struct  sysfs_buffer   buffer   file -> private_data;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif     ssize_t retval    ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif 
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif     down( buffer -> sem);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockStart.gif      if  (buffer -> needs_read_fill)  {
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif          if  ((retval   fill_read_buffer(file -> f_dentry,buffer)))
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif              goto   out ;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedSubBlockEnd.gif     

http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif     pr_debug( %s: count %d, ppos %lld, buf %s ,
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif          __FUNCTION__,count, ppos,buffer -> page);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif     retval   flush_read_buffer(buffer,buf,count,ppos);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif out :
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif     up( buffer -> sem);
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif      return  retval;
http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif }

顺着sysfs_read_file()往下走:
sysfs_read_file()
              ---> fill_read_buffer()
                            ---> sysfs_buffer->bus_sysfs_ops->bus_attr_show()
                                        ---> bus_attribute->show_bus_version() //注意这个函数是我们在lddbus.c里面定义的
              ---> flush_read_buffer()

fill_read_buffer()的是真正的读,它把内容读到sysfs定义的缓冲区sysfs_buffer。flush_read_buffer()是把缓冲区copy到用户空间。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有