Gnome VFS
2010-03-31 13:30:24 阿炯

Gnome VFS is short for GNOME Virtual File System. It provides an abstraction layer for the reading, writing and execution of files. It was primarily used by the Nautilus file manager and other GNOME applications before GNOME 2.22.


Gnome VFS 是虚拟文件系统的简称,它为读、写和文件执行提供了一个抽象层。在 GNOME 2.22以前,GnomeVFS 主要被文件管理器(Nautilus)和其它的应用程序使用。GVFS是GNOME新一种虚拟文件系统,用来代替过时的Gnome VFS虚拟文件系统。GVFS算是Gnome 2.22中一个比较大的改动、一个主要的新特性。

A cause of confusion is the fact that the file system abstraction used by the Linux kernel is also called the virtual file system (VFS) layer. This is however at a lower level.

A replacement called GVFS is currently in development which also allows partitions to be mounted through FUSE.

As of April 2008, the GNOME project has declared GnomeVFS deprecated in favour of GVFS and GIO, requesting that developers not use it in new applications.

一个容易引起混淆的事实是Linux kernel用的文件抽象系统用的也是虚拟文件系统层。目前正在开发中的替代系统叫GVFS,它允许各分区通过FUSE进行安装。作为2008年4月的更新版, GNOME项目宣布 GnomeVFS将会被弃用而采用 GVFS 和GIO代替之,并要求开发者不要将其用于新的应用程序中。


GVFS 是一个带有诸如 SFTP, FTP, DAV, SMB, ObexFTP 等协议后台的用户空间虚拟文件系统。GVFS 是 GNOME-VFS 的替代品。GNOME-VFS 将不再被赞成使用,开发者也不应在新的应用程序中继续使用。

GVFS 包含两个部分:
* GIO,作为 GLib的一部分的新共享库,提供了 针对 GVFS 的 API。
* GVFS 本身,是一个包含多种文件系统和协议(如SFTP, FTP, DAV, SMB 和 ObexFTP)支持的后台软件包。

GVFS/GIO 致力于提供一个现代的,易用的 VFS 系统。它的目标是提供一些列 API 给开发者,以是他们不再使用原始的 POSIX IO 访问。它提供了一个更高级的以文件为中心的接口,而不仅仅是 POSIX IO 的复制品。除了文件的读写支持外,GIO 还提供了文件监视工具,异步 IO,和文件名完成功能。

GVFS 通过运行一个单独的主守护进程 (gvfsd) 来工作,它保证了对当前的 GVFS 挂载的跟踪。每一个挂在都有独立的守护进程。(一些挂载也会同时共享一个进程,但多数情况下不会这样。) 客户端通过一个联合 D-Bus 会话来与这些挂载通信(在会话总线上,但是使用点对点 D-Bus),同时用一个用户协议来进操作文件内容。通过进程进行后台传递大大简化了程序的依赖关系,使整个系统更加健壮。

GVFS 也提供了在 ~/.gvfs/ 提供了一个 FUSE 挂在点,这样可以使得 GVFS 挂载可以被传统的使用标准 POSIX IO 的应用程序使用。

不同于 GNOME-VFS,GVFS 中的连接是有状态的。这意味着用户仅仅需要输入一次密码,而不是每次成功的连接都需要一次次地重复输入。因为转为使用 GVFS,自动挂载和自动运行现在已经直接由 Nautilus 完成而不再使用 gnome-volume-manager。

为什么现在的发行版中同时包括 GNOME-VFS和GVFS?
因为目前很多程序使用的仍然是 GNOME-VFS。

网络访问方面,gvfs通过gvfs-fuse-daemon 把 gvfs 上的文件挂载到 ~/.gvfs目录下。可以查看gvfs的相关包,可以看出gvfs支持的各种vfs模块。有回收站的,FTP,SFTP,SMB等等,还有硬件监视的gvfs-hal-volume-monitor等。


Linux内核是如何抽象文件系统的


Unix的哲学之一就是一切皆文件,可以看出文件系统在操作系统层面是非常重要的,很多基本单元都是通过文件系统展开的,所以了解文件系统有利于分析整个操作系统的脉络。

在 Linux 当中文件系统有多种,比较常见的有 EXT、XFS,还有基于内存的 ramfs、tmpfs 、nfs,和基于用户态的 fuse,当然 fuse 应该不能完全的文件系统,只能算是一个能把文件系统实现放到用户态的模块,满足了内核文件系统的接口,他们都是文件系统的一种实现。这个 wiki 上列出了很多 Linux 的文件系统类型。

对于这些文件系统,Linux 做了一层抽象就是 VFS 虚拟文件系统,这个其实就是软件设计必然的过程,对于不同的实现规定统一的接口,也就是定义与实现分离,如果想要自己实现一个文件系统的话只要实现一个满足 VFS 层的文件系统就能加入到内核当中。所以其实内核的文件和我们普通理解的文件其实有点不一样,这里的文件更像是一个接口,只不过最初是从磁盘上的文件衍生过来的,最后抽象成了一种可以对接各种功能的接口。


VFS 有几个必不可少的元素,filesystem_type,super_block,dentry,inode,file,vfsmount,nameidata 等等。

首先是 filesystem_type 和 super_block,这两者的关系有点类似于软件中的 class 和 object 的关系。在内核当中有一个全局的file_systems链表串接了所有的文件系统类型的代表filesystem_type,对于文件系统的注册和删除就是在链表当中增加和删除对应的节点。而super_block就是一个文件系统的实例,本身也是通过全局链表串连起来的。filesystem_type本身非常简单,定义了获取和删除super_block的接口,和一些共同的相关信息。

对于super_block来说超级块定义了文件系统的具体信息和对应文件系统的接口,比如write_super,alloc_inode,sync_fs等,这些都是有具体的文件系统实现的。所有的inode都链接到了super_block。

对于文件系统来说挂载点是个很有意思的点,在内核当中挂载点用vfsmount表示,挂载点是文件系统之间的衔接部分,如果要添加一个新的文件系统势必要将文件系统挂载在某个目录下面使得文件系统生效,vfsmount就是这样一个接口。当文件系统挂载以后原目录将不可见。vfsmount的主要内容是vfsmount的拓扑关系以及指向的目录和super_block。所以从宏观的角度来说,整个文件系统的组织是如图这样的。


这是文件系统本身这个结构在操作系统里的组织结构,接下来分析文件系统满足 VFS 要包含哪些内容。

第一个要说的就是 dentry,dentry 表现的是文件在文件系统中的树状关系,dentry 也要实现相应的接口,包括 d_delete,d_release,d_compare等接口。dentry 代表的是目录结构中的一个文件,而文件其实就是没有子目录的文件。dentry 链接到了超级快和父 dentry 和子 dentry 以及对应的 inode。

接下来是 inode, inode 本身代表的一个文件,保存的信息很多,包括文件的大小,创建时间,文件的块大小等参数,以及文件的读写缓存等信息,还要定义对应的针对文件的函数接口,包括增删改查等等。没有文件名,因为它代表的是文件的原信息,具体的路径的表示依赖dentry。

dentry 和 inode 的关系是多对一的,即多个 dentry 可以指向同一个文件,这和 linux 当中的文件链接有关。

接下来就是 file,file 虽然叫 file 但是对应的却不像 inode 一样,它对应的是一个进程所打开的文件。例如两个不同的进程打开了磁盘上的同一个文件,那么他们对应的 inode 是相同的,这也是 inode 意义。但是不同进程之间的 file 不是同一个引用,file 本身的结构还是和文件操作有关的。

整个关系如图所示


对应的文件目录如下
.
├── a
│   └── ab
└── b
    ├── bc -> ../a/ab
    └── bd

图中展示了一个硬链接代表着 bc 和 ab 的 dentry 指向了同一个inode,硬链接是不同 dentry 指向同一个inode,这也是为什么硬链接不能夸文件系统,因为inode是属于特定文件系统的。图中其实inode是串联在super_block上的,super_block维护了文件系统中inodes,因为画上去太乱了所以省略了。

VFS 的整体结构就是这样,接下来简要地说几个具体内容:

所谓的打开文件描述符其实就是进程的 files 数组这个文件描述符表的下标,通过对应的 fd 就能找到 file 结构。例如 dentry,vfsmount 这样的结构都有一个 hashtable 来缓存搜索的内容,这样就能加开目录的遍历搜索。

inode 其实也有一个全局的 hashtable 用于快速查找,inode 本身能代表的东西很多,一切皆文件就体现在他身上,他既可以表示一个 socket,也可以表示一个管道,还可以表示块设备、字符设备,然后就是普通文件了。

以上讲的就是整个内核当中 VFS 层的抽象,并没有牵涉到具体的文件系统,在下一篇博客我将会实现一个简单的文件系统,不就具体的代码分析,来熟悉这里提到的这些概念。其实了解了概念以后,就会给人一种不过如此的感觉,真正值得玩味的是下层的实现,这也是我后面的博客将会介绍的内容。比如基于磁盘的文件系统更多的是要关注 I\O 层的东西。

其实内核的 I/O 路径是这样的:user space -> VFS -> FS -> I/O layer -> I/O scheduler(optional) -> block_driver -> block_device, 一个 I/O 经过了这些才真正到达了对应的存储上。一个用户态的系统调用先通过 VFS 找到对应的文件系统再向下传递 I/O,这是 I/O 的一般路径。所以说对于用户来说,一切都是操作文件了。


微软更改备受争议的 GVFS 项目名称风波

微软在2017年发布了一个名为 GVFS 的项目,这是一个 Git 虚拟文件系统,全称为 Git Virtual File System,允许 Git 处理 TB 规模的代码库,比如 270 GB 的 Windows 代码库。

该项目从发布之初就引起了争议,原因是 GNOME 项目的虚拟文件系统也叫 GVfs 。GNOME 的 GVfs 最早发布于 2006 年,之后的教程、文档、论坛用的都是这个名字。在微软的 GVFS 项目发布后,很快超过了 Gnome GVfs 项目的搜索排名,且由于二者都与虚拟文件系统有关,导致用户在查找信息时容易出现混淆。

当开发者发现该问题时,多次在微软 GVFS 的 GitHub 页面上发起了改名的请求,但微软均关闭了相关的 pull request ,并表示无意改名。这让部分开发者感到不满,认为微软过于傲慢,不关注 Linux 和开源社区。在传出微软收购 Github 的消息时,该行为也被媒体和用户重新拿出来,表达对微软接手 Github 的担忧,改名的请求也再次被提出。就在微软正式宣布收购 GitHub 的两天后,微软在 GVFS 项目中创建了一个新的 issue ,表示将重命名该项目并开始征集新的名称。