Linux那些事儿之我是Sysfs(12)举例三:sysfs读入文件夹内容

原创 2007年09月13日 16:24:00

上回我们说到,如何创建文件夹和文件。我们发现,在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,
};

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

#include<sys/types.h>
#include
<dirent.h>
#include
<unistd.h>
int main()...{
              DIR 
* dir;
              
struct dirent *ptr;
              dir 
= opendir("/sys/bus/");
              
while((ptr = readdir(dir))!=NULL)...{
                            printf(
"d_name :%s ",ptr->d_name);
              }

              closedir(dir);
              
return -1;
}

在用户空间,用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()/*内核空间*/

static int sysfs_dir_open(struct inode *inode, struct file *file)
...{
            
struct dentry * dentry = file->f_dentry;
            
struct sysfs_dirent * parent_sd = dentry->d_fsdata;
            down(
&dentry->d_inode->i_sem);
            file
->private_data = sysfs_new_dirent(parent_sd, NULL);
            up(
&dentry->d_inode->i_sem);
            
return file->private_data ? 0 : -ENOMEM;
}

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

#define __dirstream DIR
struct __dirstream
{
             int fd; /* File descriptor. */
             char *data; /* Directory block. */
             size_t allocation; /* Space allocated for the block. */
             size_t size; /* Total valid data in the block. */
             size_t offset; /* Current offset into the block. */
             off_t filepos; /* Position of next entry to read. */
             __libc_lock_define (, lock) /* Mutex lock for this structure. */
};

(2)sysfs_readdir()

流程如下:


readdir(dir) -> getdents() ->/*用户空间*/
-> 系统调用->
sys32 readdir() -> vfs readdir() -> sysfs readdir()/*内核空间*/

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

readdir(dir)...{
                ......
                
if (dirp->offset >= dirp->size)...{
                ......
                getdents()
                ......
                }

......
}

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

static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
...{
             
struct dentry *dentry = filp->f_dentry;
             
struct sysfs_dirent * parent_sd = dentry->d_fsdata;
             
struct sysfs_dirent *cursor = filp->private_data;
             
struct list_head *p, *= &cursor->s_sibling;
             ino_t ino;
             
int i = filp->f_pos;
             
switch (i) ...{
                          
case 0:
                          ino 
= dentry->d_inode->i_ino;
                          
if (filldir(dirent, "."1, i, ino, DT_DIR) < 0)
                                       
break;
                          filp
->f_pos++;
                          i
++;
                          
/**//* fallthrough */
                          
case 1:
                          ino 
= parent_ino(dentry);
                          
if (filldir(dirent, ".."2, i, ino, DT_DIR) < 0)
                                       
break;
                          filp
->f_pos++;
                          i
++;
                          
/**//* fallthrough */
                          
default:
                          
if (filp->f_pos == 2...{
                                       list_del(q);
                                       list_add(q, 
&parent_sd->s_children);
                          }

                          
for (p=q->next; p!= &parent_sd->s_children; p=p->next) ...{
                                       
struct sysfs_dirent *next;
                                       
const char * name;
                                       
int len;
                                       next 
= list_entry(p, struct sysfs_dirent, s_sibling);
                                       
if (!next->s_element)
                                                    
continue;
                                       name 
= sysfs_get_name(next);
                                       len 
= strlen(name);
                                       
if (next->s_dentry)
                                                    ino 
= next->s_dentry->d_inode->i_ino;
                                       
else
                                                    ino 
= iunique(sysfs_sb, 2);
                                       
if (filldir(dirent, name, len, filp->f_pos, ino,dt_type(next)) < 0)
                                                    
return 0;
                                       list_del(q);
                                       list_add(q, p);
                                       p 
= q;
                                       filp
->f_pos++;
                          }

             }

return 0;
}

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

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

版权声明:本文为博主原创文章,未经博主允许不得转载。

Linux那些事儿 之 ext4文件系统(0) 引子

曾经以为人生就这样了,浮躁的心拒绝再看代码。然而来到美国两年之后,我于本月初去了一趟拉斯维加斯,发现在那儿找个美国小姐要八百美金,而且还不是包夜。当那个金发美女都已经走进我的房间,我却因为价钱太贵承受...
  • fudan_abc
  • fudan_abc
  • 2012年08月25日 13:47
  • 31512

Linux那些事儿之我是Sysfs(1)sysfs初探

"sysfs is a ram-based filesystem initially based on ramfs. It provides a means to export kernel dat...
  • xie0812
  • xie0812
  • 2016年05月17日 17:36
  • 519

Linux那些事儿之我是Sysfs(11)sysfs 创建普通文件

最近彭宇的案件炒得沸沸扬扬,究竟这个社会怎么了?sysfs文件系统中,普通文件对应于kobject中的属性。用sysfs_create_file(),参数如下:sysfs_create_file(st...
  • fudan_abc
  • fudan_abc
  • 2007年09月12日 21:15
  • 10103

Linux那些事儿之我是Sysfs(4)举例一lddbus

对了,你得把ldd3的examples代码下下来。不然没法继续了。接下来我们从例子着手,localhost:/home/XX/examples/lddbus#insmod lddbus.ko此时再看/...
  • fudan_abc
  • fudan_abc
  • 2007年09月01日 16:12
  • 17936

Linux那些事儿之我是Sysfs(9)sysfs文件系统模型

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

Linux那些事儿之我是Sysfs

  • 2011年01月10日 11:03
  • 758KB
  • 下载

Linux那些事儿之我是Sysfs--引子

        看到复旦人甲热火朝天的写作,我心底不禁暗暗敬佩。话说我进入linux领域也有2年了,我学习linux完全是兴趣。因为我觉得用linux比较酷,比较吊。当年看过一篇捧linux大骂win...
  • fudan_abc
  • fudan_abc
  • 2007年09月01日 13:30
  • 17466

Linux内核---57.sysfs的读写操作

Linux内核---57.sysfs的读写操作
  • wangcong02345
  • wangcong02345
  • 2016年07月09日 10:43
  • 354

Linux那些事儿之我是Sysfs(12)举例三:sysfs读入文件夹内容

上回我们说到,如何创建文件夹和文件。我们发现,在sysfs中,inode并不那么重要。这是因为我们所要读写的信息已经就在内存中,并且已经形成了层次结构。我们只需有dentry,就可以dentry->f...
  • xie0812
  • xie0812
  • 2016年05月17日 17:49
  • 345
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux那些事儿之我是Sysfs(12)举例三:sysfs读入文件夹内容
举报原因:
原因补充:

(最多只允许输入30个字)