中易网

虚拟文件系统 ?

答案:1  悬赏:0  
解决时间 2021-10-27 18:15
虚拟文件系统 ?
最佳答案
Richard Gooch 23-APR-1999翻译:difeijing 本文档中的惯例用法 ==================文档中的每一节标题的右边都有一个字符串""。每个小节都会有个""在右边。这些字符串是为了在文档中查询更容易而设的。 注意:本文档的最新更新可在下面找到: 它到底是什么? =============Virtual File System(或者被称为Virtual Filesystem Switch)是Linux内核中的一个软件层,用于给用户空间的程序提供文件系统接口。它也提供了内核中的一个抽象功能,允许不同的文件系统共存。 它的工作方式的概览 ==================在这一节里,在讲解细节问题之前,我会简单扼要的介绍一下VFS是如何工作的。首先,介绍一下当用户程序打开或者操作文件时发生了些什么,然后看看一个文件系统是如何被支持的。 打开一个文件 ------------VFS实现了open(2)系统调用。路径参数被VFS用来在目录入口缓存(dentry cache or "dcache")。这提供了一个将路径名转化为特定的dentry的一个快的查找机制。 一个单独的dentry通常包含一个指向i节点(inode)的指针。i节点存在于磁盘驱动器上,它可以是一个规则文件,目录,FIFO文件,等等。Dentry存在于RAM中,并且永远不会被存到磁盘上:它们仅仅为了提高系统性能而存在。i节点存在于磁盘上,当需要时被拷入内存中,之后对它的任何改变将被写回磁盘。存在于RAM中的i节点就是VFS的i节点,dentry所包含的指针指向的就是它。 dcache是你的整个文件空间的观察点。跟Linus不同,我们中的大多数人不可能有足够的RAM空间来放我们的文件空间的所有文件的目录入口缓存(dentry),所以我们的dcache会有缺少的项。为了将路径名转换为一个dentry,VFS不得不采取创建dentry的方式,并在创建dentry时将指针指向相应的i节点。这是通过对i节点的查找完成的。 为了查找一个文件的i节点(通常从磁盘上读),VFS需要调用该文件的父目录的lookup()方法,此方法是特定的文件系统所设置的。后面对此将会有更详尽的描述。 一旦VFS得到了所需要的dentry(同时也得到了相应的i节点),我们就能够对文件做想要的操作:打开文件,或者用stat(2)来看i节点中的数据。stat(2)的操作非常简单:在VFS得到dentry之后,它取得inode中的一些数据并将其中的一部分送回用户空间。打开一个文件需要其它的操作:分配一个struct file(定义于linux/fs.h,这是内核中的文件描述)结构。新分配的struct file结构被指向dentry的指针和对文件进行操作的函数集合所初始化,这些都是从i节点中得到的。通过这种方式,特定的文件系统实现才能起作用。 文件结构(struct file)被放在进程的文件描述符表中。 读,写和关闭文件(或者其它的VFS操作)是通过使用用户空间的文件描述符找到相应的文件结构(struct file),然后调用所需要的方法函数来实现的。 当文件处于打开状态时,系统保持相应的dentry为"open"状态(正在使用),这表示相应的i节点在被使用。 注册和安装一个文件系统 ----------------------如果你想在内核中支持一种新的文件系统的话,你所需要做的仅仅是调用函数register_filesystem().你向内核中传递一个描述文件系统实现的结构(struct filesystem), 此结构将被加入到内核的支持文件系统表中去。你可以运行下面的命令:% cat /proc/filesystems这样可以看到你的系统支持哪些文件系统。 当一个mount请求出现时,VFS将会为特定的文件系统调用相应的方法。安装点的dentry结构将会被改为指向新文件系统的根i节点。 现在是看看细节的时候了,nice to look! struct file_system_type =======================此结构描述了文件系统。在内核2.1.99中,此结构的定义如下:(注:在2.2的内核中,此结构也没有变化)struct file_system_type {const char *name;int fs_flags;struct super_block *(*read_super) (struct super_block *, void *, int);struct file_system_type * next;}; 其中各个域的意义:name:文件系统的类型名称,如"vfat","ext2",等等。fs_flags:变量标志,如FS_REQUIRES_DEV, FS_NO_DCACHE,等等.read_super:当此种文件系统的一个新的实例要被安装时,此方法会被调用。next:被内部的VFS实现所使用,你只需要将其初试化为NULL。 函数read_super具有以下的参数:struct super_block *sb:超级块结构。此结构的一部分被VFS初始化,余下的部分必须被函数read_super初始化。void * data:任意的安装选项,通常是ASCII的字符串。int silent:表示当出现错误时是否保持安静。(不报警?) read_super方法必须确定指定的块设备是否包含了一个所支持的文件系统。当成功时返回超级块结构的指针,错误时返回NULL。 read_super方法填充进超级块结构(struct super_block)的最有用的域是"s_op"域。这是一个指向struct super_operations的指针,此结构描述了文件系统实现的下一层细节。 struct super_operations =======================此结构描述了VFS对文件系统的超级块所能进行的操作。在内核2.1.99中,此结构的定义如下:(注:在2.2的内核中,此结构已经有了改变)struct super_operations {void (*read_inode) (struct inode *);void (*write_inode) (struct inode *);void (*put_inode) (struct inode *);void (*delete_inode) (struct inode *);int (*notify_change) (struct dentry *, struct iattr *);void (*put_super) (struct super_block *);void (*write_super) (struct super_block *);int (*statfs) (struct super_block *, struct statfs *, int);int (*remount_fs) (struct super_block *, int *, char *);void (*clear_inode) (struct inode *);}; 除非特别提出,所有的方法都在未加锁的情况下被调用,这意味着大多数方法都可以安全的被阻塞。所有的方法都仅仅在进程空间被调用(例如,在中断处理程序和底半部中不能调用它们) read_inode:从一个文件系统中读取一个特定的i节点时调用此方法。i节点中的域"i_ino"被VFS初始化为指向所读的i节点,其余的域被此方法所填充。 write_inode:当VFS需要向磁盘上的一个i节点写时调用。 put_inode:当VFS的i节点被从i节点缓冲池移走时被调用。此方法是可选的。 delete_inode:当VFS想删除一个i节点时调用次方法。 notify_change:当VFS的i节点的属性被改变时调用。若此域为NULL则VFS会调用rite_inode.此方法调用时需要锁住内核。put_super:当VFS要释放超级块时调用(umount一个文件系统).此方法调用时需要锁住内核。 write_super:当VFS超级块需要被写入磁盘时被调用。此方法为可选的。 statfs:当VFS需要得到文件系统的统计数据时调用。此方法调用时需要锁住内核。 remount_fs:当文件系统被重新安装时调用。此方法调用时需要锁住内核。 clear_inode:当VFS清除i节点时调用。可选项。 以上方法中,read_inode需要填充"i_op"域,此域为一个指向struct inode_operations结构的指针,它描述了能够对一个单独的i节点所能进行的操作。 struct inode_operations =======================此结构描述了VFS能够对文件系统的一个i节点所能进行的操作。在内核2.1.99中,此结构的定义如下:(注:在2.2的内核中,此结构已经有了少许改变)struct inode_operations {struct file_operations * default_file_ops;int (*create) (struct inode *,struct dentry *,int);int (*lookup) (struct inode *,struct dentry *);int (*link) (struct dentry *,struct inode *,struct dentry *);int (*unlink) (struct inode *,struct dentry *);int (*symlink) (struct inode *,struct dentry *,const char *);int (*mkdir) (struct inode *,struct dentry *,int);int (*rmdir) (struct inode *,struct dentry *);int (*mknod) (struct inode *,struct dentry *,int,int);int (*rename) (struct inode *, struct dentry *,struct inode *, struct dentry *);int (*readlink) (struct dentry *, char *,int);struct dentry * (*follow_link) (struct dentry *, struct dentry *);int (*readpage) (struct file *, struct page *);int (*writepage) (struct file *, struct page *);int (*bmap) (struct inode *,int);void (*truncate) (struct inode *);int (*permission) (struct inode *, int);int (*smap) (struct inode *,int);int (*updatepage) (struct file *, struct page *, const char *,unsigned long, unsigned int, int);int (*revalidate) (struct dentry *);}; default_file_ops:这是一个指向struct file_operations的指针,包含了对一个打开的文件所能进行的操作。 create:被open(2)和creat(2)所调用,仅仅在你要支持普通文件时才需要。参数中的dentry不应该包含有i节点的指针(即应该为一个negative dentry)。这里你可能需要对传入的dentry和i节点调用函数d_instantiate. lookup:当VFS要在一个父目录中查找一个i节点时调用。待查找的文件名在dentry中。此方法必须调用d_add函数把找到的i节点插入到dentry中,i节点的"i_count"域要加一。若指定的i节点不存在的话,一个NULL的i节点指针将被插入到dentry中去(这种情况的dentry被称为negative dentry)。Returning an error code from this routine must only be done on a real error, otherwise creating inodes with system calls like create(2), mknod(2), mkdir(2) and so on will fail.If you wish to overload the dentry methods then you should initialise the "d_dop" field in the dentry; this is a pointer to a struct "dentry_operations".This method is called with the directory semaphore held。 link:被link(2)所调用。仅在你需要支持hard link时才需要它。跟create方法相同的原因,你可能在此方法中也需要调用d_instantiate()函数来验证。 unlink:被unlink(2)所调用。仅在你要支持对i节点的删除时才需要它。 symlink:被symlink(2)调用。仅在需要支持符号链接时才需要它。通上面两处,你需要对传入的参数进行验证,要调用d_instantiate()函数。 mkdir:被mkdir(2)调用。仅在你要支持建立子目录时才需要它。同上,你需要调用d_instantiate()函数进行验证。 rmdir:被rmdir(2)所调用。仅在你要支持对子目录的删除时才需要它。 mknod:被mknod(2)所调用,用于建立一个设备i节点,或者FIFO,或socket.仅当你需要支持对这些类型的i节点的建立时才需要此方法。同上面几个,你可能也需要调用_instantiate来验证参数。 readlink:被readlink(2)调用。仅当你要支持对符号链接的读取才需要它。 follow_link:被VFS调用,用以从一个符号链接找到相应的i节点。仅当你需要支持符号链接时才需要此方法。 struct file_operations ======================结构file_operations包含了VFS对一个已打开文件的操作。在内核2.1.99中,此结构的定义如下:(注:在2.2的内核中,此结构已经有了少许改变)struct file_operations {loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char *, size_t, loff_t *);ssize_t (*write) (struct file *, const char *, size_t, loff_t *);int (*readdir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, struct dentry *);int (*fasync) (struct file *, int);int (*check_media_change) (kdev_t dev);int (*revalidate) (kdev_t dev);int (*lock) (struct file *, int, struct file_lock *);}; llseek:当VFS需要移动文件指针的位置时调用。 read:被read(2)所调用。 write:被write(2)所调用。 readdir:当VFS需要读取目录中的内容时被调用。 poll: called by the VFS when a process wants to check if there is activity on this file and (optionally) go to sleep until there is activity.(注:这里我怎么想都翻不好,所以就把原文放在这里了,poll就是相当于select的东西) ioctl:被ioctl(2)所调用。 mmap:被mmap(2)所调用。 open:当VFS要打开一个i节点时调用它。当VFS打开一个文件时,它建立一个新的struct file结构,并用i节点中的"default_file_ops"来初始化其中的f_op域,然后对新分配的文件结构调用open方法。你可以认为open方法实际上属于struct inode_operations。I think it's done the way it is because it makes filesystems simpler to implement.open方法是一个很好的初始化文件结构中的"private_data"域的的地方。 release:当没有对被打开文件的引用时调用此方法。 fsync:被fsync(2)所调用。 fasync:当用fcntl(2)激活一个文件的异步模式时此方法被调用。 这些文件操作是由i节点所在的特定文件系统所实现的。当打开一个设备节点时(字符或块设备特殊文件),大多数文件系统会调用VFS中的特定支持例程,由此来找到所需要的设备驱动信息; 这些支持例程用设备驱动程序的方法来代替文件系统的文件操作,然后继续对文件调用新的open方法。这就是为什么当你打开文件系统上的一个设备特殊文件时,最后被调用的却是设备驱动程序的open方法。另外,devfs(Device Filesystem)有一个从设备节点到设备驱动程序的更直接的方式(这是非的内核补丁) struct dentry_operations ========================This describes how a filesystem can overload the standard dentryoperations.Dentries和dcache是属于VFS和单个文件系统实现的,设备驱动与此无关。在内核2.1.99中,此结构的定义如下:(注:在2.2的内核中,此结构没有改变)struct dentry_operations {int (*d_revalidate)(struct dentry *);int (*d_hash) (struct dentry *, struct qstr *);int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);void (*d_delete)(struct dentry *);void (*d_release)(struct dentry *);void (*d_iput)(struct dentry *, struct inode *);}; d_revalidate:当VFS要使一个dentry重新生效时被调用。 d_hash:当VFS向哈希表中加入一个dentry时被调用。 d_compare:当指向一个dentry的最后的引用被去除时此方法被调用,因为这意味这没有人在使用此dentry;当然,此dentry仍然有效,并且仍然在dcache中。 d_release: 当一个dentry被清除时调用此方法。 d_iput:当一个dentry释放它的i节点时(在dentry被清除之前)此方法被调用。The default when this is NULL is that the VFS calls iput(). If you define this method, you must call iput() yourself. 每个dentry都有一个指向其父目录dentry的指针,一个子dentry的哈希列表。子dentry基本上就是目录中的文件。 dget:为一个已经存在的dentry打开一个新的句柄(这仅仅增加引用计数) dput:关闭一个dentry的句柄(减少引用计数).如果引用计数减少为0,d_delete方法将会被调用;并且,如果此dentry仍然在其父目录的哈希列表中的话,此dentry将被放置于一个未被使用的列表中。将dentry放置于未使用表中意味着当系统需要更多的RAM时,将会遍历未使用的dentry的列表,并回收其内存空间。假如当detry的引用计数为0时,它已经没有在父目录的哈希表中的话,在d_delete方法被调用之后系统就会回收起内存空间。来自:
我要举报
如以上问答内容为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
聊聊设计竞赛这件事儿
网络贷款平台靠得往的有?
倩碧黄油和DHCQ10哪个保湿强?拜托各位大神
帮帮忙,有谁知道哪回收旧游戏机?
源码电脑安防怎么去啊,我要去那办事
美甲店合作問題。
点球怎么踢贴地球
格兰仕电烤箱怎么样?格兰仕电烤箱好不好?格
汉喜绿姬 红瑶淘米水怎样鉴别真伪
锦州犀牛兄弟户外店地址在哪,我要去那里办事
浙江工商大学志愿者废旧电池处理问题!
哈士奇怎么养啊
人为什么打呼噜
巫溪溪源宾馆地址在什么地方,想过去办事
名将熊廷弼的简介有哪些呢?
推荐资讯
现代爱情电视剧有什么危害
艾灸可以减少脸部出油太多吗
有人知道西单大悦城五层手机是行货吗?(看着比
photoshop的绘图板画功能在哪里啊
氙气灯泡刚换上是不是发黄光还不亮?好的n
求艾曼纽·贝阿的《隐私欲望》 种子
伊布熊韩派儿童品牌衣柜地址在什么地方,想过
运城河津有没有运城河津的宝妈?
泰州天仁人力资源有限公司什么时候上市啊??
中国移动积分商城换的话费能干什么,能充Q币
腰部经常酸痛,小腿酸胀,而且有点变粗了,穿
金达物流(工业四路)地址在什么地方,想过去办
手机登qq时,显示手机磁盘不足,清理后重新登
刺客的套装怎么选啊?