免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2500 | 回复: 0
打印 上一主题 下一主题

创建Linux虚拟文件系统(续) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-05-26 00:34 |只看该作者 |倒序浏览
一个更简单的方法
上面的例子包含了大段的模板代码。这些代码对于很多应用程序来说都是必须的,但是对于很多其他的,有捷径可走。如果在编译的时候你就知道需要创建哪些文件,并且你没有必要创建子目录,请继续看更简单的方式。
在这部分,我们将讨论lwnfs模块的另一版本,它省掉了约1/3的代码量。它实现了一个不包含子目录,只包含四个计数器的简单序列(array)。再说一遍,如果你有兴趣,
源码
就在这里。
上面,我们看到了一个叫做lfs_fill_super()的函数,它负责初始化文件系统的超级块,创建根目录和导出文件。在这个更简单的版本里面,函数整体将变成如下:
    static int lfs_fill_super(struct super_block *sb, void *data, int silent)
    {
            return simple_fill_super(sb, LFS_MAGIC, OurFiles);
    }
simple_fill_super()是libfs中的一个函数,它几乎做了我们需要的所有工作。它的原型是:
int simple_fill_super(struct super_block *sb, int magic,
                          struct tree_descr *files);
参数super_block结构体可以直接传入,并且magic和我们上面见过的幻数(magic number)相同。参数files描述了我们应该在这个文件系统中创建哪些文件;相关结构定义如下:
    struct tree_descr {
            char *name;
            struct file_operations *ops;
            int mode;
    };
到目前为止,那些参数应该相当清楚了;每个结构体给出将要创建的文件的文件名,与这个文件相关的操作函数集,和这个文件的保护位。但是,我们仍有必要看看tree_descr这个结构体是如何创建的:
  • 那些被初始化为NULL的入口项(更确切地说是name为NULL)将被简单地忽略掉。不要试图用一个NULL的入口项结束,除非你想解码OOps消息。
  • 相反,这个列表(list)是以一个name项为空字符串的入口项结束的。

  • 些入口项直接和最终被赋给目标文件的inode号是一致的。这些信息可以用来在文件的操作代码中获知当前打开的是哪个文件。但是,这也隐含了这个列表的第
    一项不可用,因为文件系统的根目录将占用0号inode。因此,当你创建tree_descr列表的时候,第一项必须为NULL。

明白了以上知识之后,我们将用下面的方式为那四个“counter”文件创建列表:
    static struct tree_descr OurFiles[] = {
            { NULL, NULL, 0 },                  /* Skipped */
            { .name = "counter0",                /* Inode 1 */
              .ops = &lfs_file_ops,
              .mode = S_IWUSR|S_IRUGO },
            { .name = "counter1",                /* Inode 2 */
              .ops = &lfs_file_ops,
              .mode = S_IWUSR|S_IRUGO },
            { .name = "counter2",                /* Inode 3 */
              .ops = &lfs_file_ops,
              .mode = S_IWUSR|S_IRUGO },
            { .name = "counter3",                /* Inode 4 */
              .ops = &lfs_file_ops,
              .mode = S_IWUSR|S_IRUGO },
            { "", NULL, 0 }                 /* Terminates the list */
    };

旦simple_fill_super()返回,大功告成,文件系统也可用了。省下的唯一一个细节也许就是你的open()方法;如果你有多个文件共享同
一个file_operations结构体,你将需要指出当前操作的是哪个。这里的关键就在于inode号,也就是i_ino成员。修改过的
lfs_open()通过以下方式找到正确的计数器:
    static int lfs_open(struct inode *inode, struct file *filp)
    {
            if (inode->i_ino > NCOUNTERS)
                    return -ENODEV;  /* Should never happen.  */
            filp->private_data = counters + inode->i_ino - 1;
            return 0;
    }
函数read()和write()用成员private_data_field,因此我们没有必要修改上个版本的实现。
结论
这里仅作为libfs示例,实际上libfs的代码被广泛应用于实现驱动特定的虚拟文件系统。如想深入学习,请参考2.5内核源码的如下几个地方:
  • drivers/hotplug/pci_hotplug_core.c
  • drivers/usb/core/inode.c
  • drivers/oprofile/oprofilefs.c
  • fs/ramfs/inode.c
  • fs/nfsd/nfsctl.c (simple_fill_super() 示例)
...和其他一些地方--grep是你的好朋友!
请记住,2.6的驱动模型代码使得用自己的虚拟文件系统导出信息变得容易;就很多应用而言,它将成为把信息导到用户空间的较好方法。
驱动移植系列
有很多关于驱动模型和sysfs的文章。但是,在只有一个定制的文件系统才能奏效的情况下,libfs使得这项工作变得(相对)简单。
译者注:
以前有人问我哪里能获得有关Linux变化和发展的介绍性文章,我无言以对。现在,总算知道了些有较好技术文章的网站,比如说lwn,linuxjournal和IBM的developer works。
这篇文章最开始写于2003年11月11号(似乎是光棍节),可我现在才注意到,真是感觉有些落伍啊!不敢独享,遂翻译出来与诸君共同把玩!
本想用一年时间熟悉Linux内核的开发,知其然,可随着时间的推进,发现其实知其然和知其所以然是相辅相成的,窃喜!
BTW: 翻译东西还真的很不简单啊,不要笑我哦!
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/97267/showart_1944695.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP