正在加载
请稍等

菜单

红楼飞雪 梦

15526773247

文章

Home android 嵌入式开发 管道文件系统pipefs
Home android 嵌入式开发 管道文件系统pipefs

管道文件系统pipefs

android 嵌入式开发, linux开发学习 by

pipefs是一种简单的、虚拟的文件系统类型,因为它没有对应的物理设备,因此其安装时不需要块设备,大部分文件系统是以模块的形成来实现的。该文件系统相关的代码在fs/pipe.c中:

static DECLARE_FSTYPE(pipe_fs_type, "pipefs", pipefs_read_super,
                      FS_NOMOUNT|FS_SINGLE);
static int __init init_pipe_fs(void)
{
    int err = register_filesystem(&pipe_fs_type);
    if (!err)
    {
        pipe_mnt = kern_mount(&pipe_fs_type);
        err = PTR_ERR(pipe_mnt);
        if (IS_ERR(pipe_mnt))
            unregister_filesystem(&pipe_fs_type);
        else
            err = 0;
    }
    return err;
}
static void __exit exit_pipe_fs(void)
{
    unregister_filesystem(&pipe_fs_type);
    mntput(pipe_mnt);
}
module_init(init_pipe_fs)
module_exit(exit_pipe_fs)

pipefs文件系统是作为一个模块来安装的,其中module_init()是模块的初始化函数,module_exit()是模块的卸载函数

从 DECLARE_FSTYPE()宏定义可以看出,pipefs文件系统的FS_NOMOUNT和FS_SINGLE标志位为1,这就意味着该文件系统不 能从用户空间进行安装,并且在整个系统范围内只有一个超级块。FS_SINGLE标志也意味着在通过register_filesystem()成功地注 册了该文件系统后,应该通过kern_mount()来安装。

register_filesystem()函数把pipe_fs_type 链接到file_systems链表,因此,你可以通过读/proc/filesystems找到“pipefs”入口点,在那里,“nodev”标志表 示没有设置FS_REQUIRES_DEV标志,即该文件系统没有对应的物理设备。

kern_mount()类似于do_mount(),用来安装pipefs文件系统。当安装出现错误时,则调用unregister_filesystem()把pipe_fs_type从file_systems链表中拆除。

现在,pipefs文件系统已被注册,并成为内核中的一个模块,从此我们就可以使用它了。Pipefs文件系统的入口点就是pipe()系统调用,其内核 实现函数为sys_pipe(),而真正的工作是调用do_pipe()函数来完成的,其代码在/fs/pipe.c中,我们并同时给出了对代码的注释。

int do_pipe(int *fd)
{
    struct qstr this;
    char name[32];
    struct dentry *dentry;
    struct inode * inode;
    struct file *f1, *f2;   /*进程对每个已打开文件的操作是通过file结构进行的。一个管道实际上就是一个存在于内存的文件,对这个文件的操作要通过两个已打开的文件进行,f1、f2分别代表该管道的两端。*/
    int error;
    int i,j;
    error = -ENFILE;
    f1 = get_empty_filp();         /*管道两端各分配一个file 结构*/
    if (!f1)
        goto no_files;
    f2 = get_empty_filp();
    if (!f2)
        goto close_f1;
    inode = get_pipe_inode();  /*每个文件都有一个inode结构。由于管道文件在管道创建之前并不存在,因此,在创建管道时临时创建一个inode结构。*/
    if (!inode)
        goto close_f12;
    error = get_unused_fd();
    /* 分配打开文件号*/
    if (error < 0)
        goto close_f12_inode;
    i = error;
    error = get_unused_fd();
    if (error < 0)
        goto close_f12_inode_i;
    j = error;
    error = -ENOMEM;
    sprintf(name, "[%lu]", inode->i_ino);
    this.name = name;
    this.len = strlen(name);
    this.hash = inode->i_ino; /* will go */
    dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this);  /* File结构中有个指针f_dentry指向所打开文件的目录项dentry结构,而dentry 中有个指针指向相应的inode结构。所以,调用d_alloc()分配一个目录项是为了把file结构与inode结构联系起来。*/
         if (!dentry)
                 goto close_f12_inode_i_j;
        dentry->d_op = &pipefs_dentry_operations;
         d_add(dentry, inode);  /*使已分配的inode 结构与已分配的目录项结构挂勾*/
        f1->f_vfsmnt = f2->f_vfsmnt = mntget(mntget(pipe_mnt));   /* pipe_mnt就是在init_pipe_fs()中所获得的指向vfsmount结构的指针,因为这个结构多了两个使用者,因此调用两次mntget   ()使其引用计数加2 */
        f1->f_dentry = f2->f_dentry = dget(dentry); /*让两个已打开文件中的f_dentry指针都指向这个目录项,并使目录项的引用计数加1*/
                       /* read file */
    f1->f_pos = f2->f_pos = 0;
    f1->f_flags = O_RDONLY;
    f1->f_op = &read_pipe_fops;
    f1->f_mode = 1;
    f1->f_version = 0;
    /* write file */
    f2->f_flags = O_WRONLY;
    f2->f_op = &write_pipe_fops;
    f2->f_mode = 2;
    f2->f_version = 0;
    fd_install(i, f1);                              /*将已打开文件结构与分配得的打开文件号相关联(打开文件号只在一个进程的范围类有效)。*/
    fd_install(j, f2);
    fd[0] = i;
    /*使得fd[0]为管道读出端的打开文件号*/
    fd[1] = j;
    /*使得fd[1]为管道写出端的打开文件号*/
    return 0;
    /*以下为释放各种资源*/
close_f12_inode_i_j:
    put_unused_fd(j);
close_f12_inode_i:
    put_unused_fd(i);
close_f12_inode:
    free_page((unsigned long) PIPE_BASE(*inode));
    kfree(inode->i_pipe);
    inode->i_pipe = NULL;
    iput(inode);
close_f12:
    put_filp(f2);
close_f1:
    put_filp(f1);
no_files:
    return error;
}

下面对管道的单向性再做进一步的说明。从代码看出,把f1一端设置成“只读(O_RDONLY)”,另一端则设置成“只写(O_WRONLY)”。同时, 两端的文件操作也分别设置成read_pipe_fops和write_pipe_fops,其定义于pipe.c中:

struct file_operations read_pipe_fops =
{
llseek:
    pipe_lseek,
read:
    pipe_read,
write:
    bad_pipe_w,
poll:
    pipe_poll,
ioctl:
    pipe_ioctl,
open:
    pipe_read_open,
release:
    pipe_read_release,
};
 
struct file_operations write_pipe_fops =
{
llseek:
    pipe_lseek,
read:
    bad_pipe_r,
write:
    pipe_write,
poll:
    pipe_poll,
ioctl:
    pipe_ioctl,
open:
    pipe_write_open,
release:
    pipe_write_release,
};

在read_pipe_fops()中的写操 作函数为bad_pipe_w(),而在write_pipe_fops()中的读操作函数为bad_pipe_r(),这两个函数分别返回一个出错代 码。尽管代表着管道两端的两个已打开文件一个只能读,一个只能写。但是,另一方面,这两个逻辑上已打开的文件指向同一个inode,即用作管道的缓冲区, 显然,这个缓冲区既支持读也支持写。这进一步说明了file 、inode及dentry之间的不同和联系。

 

 

26 2015-11

 

我要 分享

 

 

本文 作者

 

相关 文章