博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

[OS][FS]Linux VFS

Posted on 2010-06-11 09:52  xuczhang  阅读(943)  评论(0编辑  收藏  举报

本文将描述Linux内核中的VFS(Virtual File System)。对于VFS这个概念其实非常容易理解,无非是一个抽象的统一接口:它定义了所有文件系统都支持的基本的和概念上的接口和数据结构,这样就在用户上层看来,无论对何种文件系统都拥有统一的接口,和操作方式。其实,对VFS的理解停留在这个层面上对于掌握其思想已经够用了,剩下要讨论的也就是它的实现和一些和进程和文件系统的外延部分了。

目前总有一些困惑就是对于一个问题或者概念的抽象层次的把握,比如对于一个软件工程师,他需要对计算机有所了解,不过不可能做到样样深入,比如内存,我们需要知道它是用来存储临时数据的,性能介于寄存器和磁盘之间,我们不需要知道它是如何设计的,经过多少工艺制作而成的。所以有的时候,你对一个问题的抽象层次决定着你对问题的把握。因为不可能完全把问题从最底层剖析,我们只能在我们所熟知的层面或者说是我们所需要的层面去剖析问题。

话题有些扯远了,不过我想表达的是,如果只是想知道VFS是什么东西的话,第一段的几句话我认为已经够用了。那么继续深入的意义究竟何在呢?或者说目的究竟何在呢?我认为有这么几点吧:

1. 文件系统的内存表示

文件系统一方面定义了如何在磁盘上组织用户的数据信息,那如何高效的读写管理文件就是内核要考虑的事情了。VFS就是linux用来管理文件系统的方式(当然不仅仅是vfs,还牵涉到I/O等等方面)。

2. VFS设计

VFS是一个比较成功的例子,它为所有的文件系统提供统一的接口,这个思想和设计可以被借鉴到其他地方。另外VFS用到的面向对象的概念,所以这又是一个c语言实现的面向对象范例。

3. 算法

对dcache中用到LRU. slab存储dentry

 

好了,有了目标,那接下来就是各取所需了。

文件系统的内存表示

这个标题有点起大了,更贴切的应该说是vfs中的一些数据结构。

首先来说一下Linux中用到的和文件系统相关的传统抽象概念:文件,目录项,i-node,mount point

这里我想从i-node说起,因为i-node本身的概念使得文件和目录项并不是我们通常说想象的那样了。i-node是*nux文件系统中用来表示文件和目录的数据结构。也就是说通过i-node我们可以知道文件的所有信息。具体的描述可以参考另一篇文章:Ext3 File system Disk Layout

那么如果i-node已经代表文件和目录,那么这里的文件和目录项又是什么意思呢?

文件对象

我们先说文件对象,这里的文件对象是指打开的文件在内存中的表示。该对象由open()系统调用创建,由close()系统调用销毁。也就是说一个文件系统中的文件可能存在多个对应的文件对象。它其实是用在进程的角度的,多个进程可以同时打开同一个文件,不过打开的文件会有自己特有的状态信息,比如文件的偏移量。所有在内存中需要有这个对象记录这些信息。

这个对象是以struct file **fd;形式存储的,如下图所示,一个fd指向一个File Object。

 

image

当然File Object又应该指向其对应的i-node,虽然事实上File Object并没有存inode的指针,而是存着dentry的指针(dentry指向i-node)。这里就引出了下一个概念:目录项(dentry)

目录项与目录项缓存

我们既然有了i-node来表示目录,那为什么还需要dentry呢?原因是VFS经常需要执行目录相关的操作,比如路径名查找等。路径名查找需要不断的解析路径,为了方便起见,就引入了dentry这个概念。目录项没有对应的磁盘数据结构,VFS根据字符串形式的路径名现场创建它。

dentry就是目录的内存表示,比如/tmp/test这个路径,内核为根目录"/”创建一个目录项对象,为tmp创建一个第二级目录项对象,为test创建第三级目录项对象。这里要说明的是/tmp/test和/home/test中test目录项有什么不同,虽然名字同是test,不过很显然它们指的是不同的文件,所以它们的i-node不同。另外,在dentry中会记录其父目录的目录项对象d_parent。当然,如果/home/test是链接到/tmp/test文件上,它们就会有相同的i-node,不过它们的父目录的目录项不同,一个是tmp,而另一个是home。可见,对目录项的hash就应该是针对当前文件名和父目录的目录项对象。

现在我们来说一下目录项高速缓存:

1. 所有未使用的目录项对象都存放在一个LRU的双向链表中,既然是LRU,那当目录项高速缓存空间减少的时候会从LRU的尾部删除。这个链表头存放在dentry_unsued变量中,链表由每个dentry的d_lru变量链接。

2. 在使用的目录项对象是被相应的i-node节点的i_dentry变量所指向,i_dentry同样是一个list头指针,这里用list的原因是每个i-node节点可能与若干硬连接关联。而目录项对象的d_alias变量存放这个链接表的相邻元素。当在使用的目录项对象被删除时就会被移动到上面所说的未使用目录项的LRU中。

3. 散列表dentry_hashtable是一个链表的数组,其作用是用来快速定位dentry的,其hash函数是由目录项的parent指针和文件名决定的。

这里顺便提一下,dentry对象是存储在kernel的slab分配器高速缓存中的,是在Dcahce.c中的dentry_cache。slab高速缓存是内存对象管理的一种算法,这个已经超出了本文的范围。

Mount Point

//TODO:

 

路径名查找

//TODO:

image