转载

协作翻译 | WSL 文件系统支持

本文是Windows上Linux子系统系列博文的第四篇。有关 背景资料,你可以读读 架构总览 , pico进程介绍 和 WSL系统调用 这些博客文章。

代表Sven Groot发布。

介绍

Windows上Linux子系统的一个关键目标是允许用户像在Linux系统上一样使用他们的文件,而又对Windows系统中的文件有充分的互操作性。不像一个虚拟机,你必须使用网络共享或其他解决方案来共享主机和其他操作系统的文件,WSL直接访问所有你的Windows磁盘,允许很容易的进行交互操作。

Windows文件系统与Linux文件系统有很大的不同,这篇文章将会介绍WSL如何在这两个世界间架起桥梁。

Linux上的文件系统

通过虚拟文件系统(VFS)对抽象文件系统操作,它即提供了接口供用户程序与文件系统交互(通过系统调用如打开、读取、修改文件权限,获取文件信息,等等),又提供了一个文件系统必须实现的接口。这使得多个文件系统可以共存,并提供相同的操作和语义,VFS提供所有这些文件系统的统一的命名空间视图给用户。

在这个命名空间里,文件系统挂载在不同的目录。例如,在一个典型的Linux系统硬盘可能安装在根目录,/,/ dev,/ proc, / sys, / mnt, / cdrom所有挂载的不同文件系统可能在不同的设备上。举例来说,Linux上使用的文件系统包括ext4,rfs,FAT以及其他。

VFS通过使用大量的数据结实现了文件系统操作的各种系统调用,比如索引节点,目录项和文件,以及相关文件系统必须实现的回调函数。

索引节点(Inode)

inode是VFS中使用核心数据结构。它代表一个文件系统对象如一个常规文件、目录、符号链接,等等。一个inode包括文件类型,大小,权限,最后修改时间和其他属性等信息。对于许多常见的Linux磁盘文件系统,如ext4,磁盘上用来表示文件元数据的数据结构直接对应于Linux内核使用的inode结构。

虽然一个索引节点代表一个文件,但它不代表一个文件名。一个文件可能有多个名称或硬链接,但只有一个inode。

文件系统提供了一个查找函数来回调VFS,用来检索特定文件的inode,它是基于父inode和孩子的名字。文件系统必须实现其他一些inode操作,如修改权限,获取文件信息,打开文件等等。

目录项

VFS使用目录项缓存来表示文件系统名称空间。目录项只存在于内存中,并包含一个指向该文件的inode。举个例子,如果你有一个像/home/user/foo这样的路径,那么就有一个目录项对应于home,user和foo,每个都有一个指针指向一个inode。目录项是快速查找时的缓存,但如果一个条目在缓存中没有,就用inode查找操作来从文件系统中检索索引节点,然后就可以创建一个新的目录项。

文件对象

当一个inode被打开,就创建了一个文件的的文件对象,它会记录该文件的很多信息,如跟踪文件偏移量、文件是只读,只写,还是两者兼而有之。文件系统必须提供的文件操作,如读read、写write、同步sync等。

文件描述符

应用程序通过文 件描述符引用到文件对象。它们在一个进程中都是唯一的 值,指向进程所打开的文件。 文件描述符可以指向其他提供文件接口的对象,在Linux中,提供文件接口的对象包括tty、套接字和管道。 多个文件描述符可以指向相同的文件对象,例如可使用dup系统调用获得同一个文件对象的文件描述符。

特殊的文件类型

除了常规的文件和目录,Linux支持许多额外的文件类型。 包括设备文件、fifo、套接字和符号链接。

其中有些文件会影响路径解析。 符号链接是一种特殊文件,指向一个不同的文件或目录,并通过VFS对符号链接指向的文件进行无缝地处理。 如果你打开路径/foo/bar/baz,并且bar是/zed的一个符号链接,那么你实际打开的就是/zed/baz。

类似地,可以使用一个目录作为另一个文件系统的挂载点。 在这种情况下,当一个路径包含这个目录,那么挂载点下面所有inode的操作实际都会在新的文件系统上。

特殊文件系统和伪文件系统

Linux使用许多并不从磁盘读取文件的文件系统。TmpFs作为临时内存文件系统使用,其内容将不会持久化。ProcFs和SysFs提供进程的内核信息、设备和驱动程序访问。这些文件系统没有相关的磁盘、网络或其他设备,而是由内核虚拟化出来的。

Windows上的文件系统

Windows将所有系统资源都泛化成对象。这些不仅包括文件,而且还包括线程,共享内存段,计时器,这里仅举几例。所有打开文件的请求最终都通过NT内核对象管理器,它通过I/O管理器将请求路由到正确的文件系统驱动程序。在Windows上文件系统驱动程序实现的接口更通用,并只需要更少的需求。例如,没有类似的公共的inode结构,也没有目录项;相反,文件系统驱动程序如ntfs.sys负责解析路径和打开文件对象。

Windows文件系统 虽然也可以挂载到其它文件系统的目录中,但 通常是挂载到诸如C:和D:这样的驱动器号上。这些驱动器号实际上是一种Win32的结构,对象管理器是不能直接对其进行处理的。对象管理器使用的命名空间和Linux文件系统的命名空间有点类似,它的根目录是/, 文件系统卷标 用路径为/设备名/硬盘卷标1这样的设备对象来表示。

当我们使用C:/foo/bar这样的路径打开某个文件时,Win32的CreateFile函数将其转换成一个NT路径,形式为“/Dos设备名/C:/foo/bar”,这里的“/Dos设备名/C:”通常是一个符号链接,例如,链接到“/设备名/硬盘卷标4”。因此,该文件真正的完整路径应当是“/设备名/硬盘卷标4/foo/bar”。由对象管理器确定路径中的每个组成部分,直到遇到了设备对象,这和Linux中的VFS很类似。这时候,对象管理器将请求提交给I/O管理器,I/O管理器创建一个包含剩余路径的I/O请求包(IRP),将该请求包发送至文件系统驱动器以确定设备名。

文件对象

当打开某个文件时,对象管理器会为该文件创建一个文件对象。对象管理器提供指向文件对象的句柄,而不是文件描述符。实际上,句柄可以指向任意的对象管理器对象,而不只是文件。

当你调用某个系统调用时,比如NtReadFile(通常使用Win32的ReadFile函数),I/O管理器会再次创建一个发送给文件系统驱动器的IRP(输入/输入请求包),以使文件对象可以执行此请求。

因为在NT中没有索引节点或者类似的东西,所以Windows中针对文件的绝大部分操作都需要一个文件对象。

Windows系统仅能支持两种文件类型:普通文件和目录。文件和目录都可以成为重新解析点,重解析点是具有固定的头部和任意数据块的特殊文件。头部包括一个用来标识重解析点类型的标签,并且必须通过文件系统过滤器进行处理,头部也可能包括内置的重解析点类型,也就是I/O管理器本身。

重解析点用来实现符号链接和挂载点。在这些情况下,标签表示重解析点是一个符号链接或挂载点,和重解析点相关联的数据中包括了链接目标或挂载点的卷标名。重解析点也可以具有其它的用途,比如作为Windows8系统中OneDrive使用的占位符文件。

大小写敏感

不像Linux,Windows文件系统默认情况下是不区分大小写的。实际上,Windows和NTFS是支持大小写敏感的,只是默认不启用而已。

WSL中的文件系统

Windows上的Linux子系统(WSL)必须将各种Linux文件系统操作转换成NT内核操作。 WSL必须提供一块控件来存放Linux系统文件,来支撑所有的功能,包括Linux权限,符号链接和其他特殊文件如FIFO;它还必须提供访问你系统中Windows卷的能力;它还必须提供一些特殊的文件系统比如ProcFs。

为了做到这些,WSL实现了一个VFS组件,它是仿照Linux上的 VFS。总架构如下所示。

协作翻译 | WSL 文件系统支持

当一个应用程序调用一个系统调用,它是被系统调用层处理,系统调用层定义了各种内核功能项如open、read、 chmod和stat等等。对于这些文件相关的系统调用,系统调用层几乎不做什么处理;它基本上就是把请求传递给VFS。

对于使用了路径的操作(比如open或者stat),VFS使用目录项缓存来解析路径。如果一个目录项不在缓存中,它调用文件系统插件中的某一个插件来生成这个目录项的inode。这些插件提供inode操作,比如查找,更改权限以及其他,很类似于Linux内核中对inode的操作。 当文件被打开时, VFS使用文件系统的inode打开操作来生成一个文件对象,并返回这个文件对象的文件描述符。对于文件描述符的系统调用(比如read, write或者 sync)直接调用文件系统定义的相应操作。这个系统有意的使用近似Linux行为,所以WSL可以支持相同的语义。

VFS定义了一些文件系统插件:VolFs和DrvFs用来表示磁盘上的文件,其余的包括内存中的文件系统TmpFs以及伪文件系统,比如ProcFs,SysFs和CgroupFs。

VolFs和DrvFs是用来将Linux文件系统满足Windows文件系统。他们展示了WSL是如何与你磁盘上的文件交互的,并且提供两种不同用途:VolFs被设计成提供所有Linux文件系统特性,DrvFs被设计为提供与Windows交互。

让我们更详细的来看看这些文件系统。

VolFs

WSL使用的主要的文件系统是VolFs。可以用它来存储Linux系统文件,以及Linux用户的home目录。因此,VolFs支持Linux虚拟文件系统(VFS)提供的绝大部分特性,其中包括Linux权限、符号链接、先入先出(FIFOs)、套接字(sockets)和设备文件。

VolFs用来挂载虚拟文件系统(VFS)的根目录,使用%LocalAppData%/lxss/rootfs作为备用存储器。另外,还有其它的几个VolFs挂载点,尤其是/root和/home,它们分别使用%LocalAppData%/lxss/root和%LocalAppData%/lxss/home挂载。分别进行挂载的原因是当卸载WSL时,默认情况下,home目录是不删除的,所以存储过的所有个人文件都会保留。

需要注意的是所有的这些挂载点都要使用Windows用户文件夹中的目录进行存储。每个Windows用户都拥有自己的WSL环境,因此也可以拥有Linux中的root权限,可以在不影响其它Windows用户的情况下安装程序。

索引节点和文件对象

因为 Windows 没有相关的 索引节点概念,VolFs 必须在索引节点上对 Windows 文件对象保持一个句柄。VFS 请求一个新的索引节点使用了 lookup 回调,VolFs 使用来自父索引节点和子节点名称来处理相关的打开和获取句柄。这些句柄的打开不需要任何的读/写文件,且只能用于元数据的请求。

当文件被打开,VolFs 创建一个 Linux 文件对象指向索引节点。它可以重复打开节点索引的文件句柄,并可以通过请求在文件对象上读/写访问和存储新的句柄。然后使用该句柄来满足文件操作,比如读和写。

模拟Linux特性

如上所述,Linux和Windows的文件系统有好几个方面的不同。VolFs必须对Windows不能直接支持的几个Linux特性提供支持。

Windows本身可以处理大小写敏感。正如前面提到的,Windows和NTFS实际上支持大小写敏感操作,所以,无论全局注册键如何控制,VolFs只需请求对象管理器将路径看做是大小写敏感的。

Linux的文件名还支持将全部字符视为合法字符。NT中却有更多的限制,有些字符根本不允许作为文件名,还有些字符可能具有特殊含义(例如“:”表示改变数据流)。为了支持所有Linux文件名,VolFs将文件名中的非法字符进行转义。

Linux中的断开链接(unlinking)和重命名(renaming)有一些不同的语义。具体的说,某个文件即使有打开着的文件描述符指向它,也可以断开链接。同样,某个文件即使打开着,也可以对其进行重命名的操作。在Windows中,如果要请求删除一个文件,那它最终的状态必须是关闭着的,此时文件名在文件系统中可见。为了支持Linux中的断开链接语义,请求删除前,VolFs会将断开链接的文件重命名至一个隐藏的临时文件夹中。

Linux的索引节点具有一些Windows中不存在的属性,包括拥有者和组、文件模式等。这些属性存储在与磁盘文件相关联的NTFS扩展属性中。扩展属性中存储的信息如下:

  • 模式(Mode):包括文件类型(普通文件、符号链接、FIFOs等)和该文件的权限位。

  • 拥有者(Owner):拥有该文件的Linux用户ID和组ID。

  • 设备ID(Device ID):设备文件的主设备号和次设备号。注意,WSL目前还不允许用户在VolFs中创建设备文件。

  • 文件时间(File times):Linux中的文件访问时间、修改时间和改变时间所采用的格式和粒度与Windows中不同,所以,这些时间也存储在EAs中。

另外,如果某个文件具有一些文件能力特性,那它会被存储在变异数据流中。注意,WSL目前还不允许用户更改文件的文件能力特性。

其余的索引节点属性,例如索引节点号和文件大小, 都源自于NTFS中保存的信息。

和Windows系统之间的互操作能力

上面提到了,VolFs文件以普通文件的方式存储在Windows系统的目录中,因此,不支持和Windows系统之间的互操作能力。如果从Windows系统中向这些目录添加一个新文件,因为缺少必要的EAs,所以VolFs不知道如何处理该文件,只能将其忽略掉。在WSL中,许多编辑器在保存一个已存在的文件时也会删除EAs,使得该文件再次成为不可用。

另外,因为VFS缓存目录项,当运行着WSL时,在Windows系统中对那些目录所做的任何改变都不会有准确的反应。

DrvFs

为了便于和Windows系统之间的互操作,WSL使用了DrvFs文件系统。WSL将具有可支持文件系统的固定驱动器自动挂载到/mnt目录中,例如/mnt/c、/mnt/d等。目前,仅能支持NTFS和ReFs卷标。

DrvFs的操作方式和VolFs类似。当创建索引节点和文件对象时,打开指向Windows文件的句柄。但是,和VolFs相比,DrvFs遵循Windows规则(有几个例外,下面会说明)。DrvFs使用Windows权限,只允许使用合法的NTFS文件名,不支持特殊的文件类型,比如FIFOs和sockets。

DrvFs 权限

Linux通常采用简单的权限模型,允许某个文件的所有者、所属组或其它的任何人拥有对该文件的读、写或执行权限。Windows却采用访问控制列表(ACLs),为每个单个文件和目录指定复杂的访问规则(Linux也的确能使用ACLs,只不过WSL目前还不支持)。

在DrvFs中,当打开一个文件时,使用基于用户令牌的Windows权限,令牌是由用户执行bash.exe产生的。所以,在WSL中要访问C:/Windows目录下的文件,在bash环境中使用“sudo”还是不行的,虽然你拥有了root权限,但并没有改变你的Windows用户令牌,还必须启动bash.exe以便进一步获得合适的权限。

为了给用户关于他针对某个文件所拥有的权限的提示,DrvFs检查用户有效的文件权限,并将其转换成“读/写/可执行”位,例如执行“ls -l”命令可以看到。但也并不都是一对一的映射关系。例如,Windows中对于在目录中创建文件和子目录需要不同的权限。如果用户拥有任意一种权限,DrvFs都视为对目录拥有写访问权限,但实际上有些操作可能还是会因拒绝访问而失败。

因为对文件的有效访问权限会因bash.exe是否启动是否提升了权限而不同,所以,DrvFs中显示的文件权限也会随着bash实例的权限提升与否而改变。

当计算对某个文件的有效访问权限时,在DrvFs中要考虑到只读属性。在Windows中对某个文件设置了只读属性表现在WSL中就是没有写的权限。使用Chmod可以设置文件的只读属性(通过移除所有的写权限,比如,使用命令“chmod a-w 某个文件”)或者清除只读属性(通过添加任意写权限,比如,使用命令"chmod u+w 某个文件")。这种方法和Linux中的CIFS文件系统很类似,CIFS用来访问Windows SMB共享。

大小写敏感

因为支持Windows的NTFS,DrvFs支持区分大小写文件。这意味着可以创建两个只文件名大小写不同的DrvFs。请注意,许多的Windows应用程序可能无法处理这种情况,并且可能无法打开一个或两个文件。

大小写敏感被禁用在卷根上,但其它地方可以用。因此,为了使用大小写敏感的文件。不要尝试创建/mnt/c,而是创建一个目录,在这个目录里可以创建文件。

符号链接

虽然NT支持符号链接,我们也不能依赖这种支持,因为WSL创建的符号链接有可能指向在Windows中没有任何意义的路径,比如/proc。另外,在NT中创建符号链接是需要管理员权限的。因此,必须找到其它的解决方案。

和VolFs不同,在DrvFs中,我们不能依赖EAs来标示某个文件是符号链接。取而代之的是,WSL采用一种全新的重解析点来表示符号链接。因此,这些链接只在WSL中有效,而不能被其它的Windows组件所识别,比如文件浏览器(File Explorer)或者cmd.exe。需要注意的是,既然ReFs对重解析点缺少支持,那么它也不支持WSL中的符号链接。然而,NTFS已经对WSL中的符号链接有了全面支持。

和Windows之间的互操作

和VolFs不同,DrvFs不会存储任何的额外信息。相反,所有的索引节点属性都是通过查询NT中使用的文件属性、有效权限以及其它的信息派生而来的。DrvFs还禁用了目录项缓存,以确保即使Windows进程对目录的内容进行了修改的情况下,它也总能提供正确的、最新的信息。因此,当使用DrvFs时,对Windows进程如何处理文件没有任何限制。

DrvFs还对文件使用了Windows删除语义,所以,如果某个文件存在任何打开着的文件描述符(或者Windows进程在处理着),那我们就不能取消对其的链接。

ProcFs和SysFs

正如在Linux中,这些特殊的文件系统不会显示磁盘上的文件,而是代表了内核中有关进程、线程和设备的信息。这些文件在运行时动态产生。有些情况下,这些文件的信息完全保存在lxcore.sys驱动中。在其它情况下,例如某个进程对CPU的使用,WSL需要查询NT内核以获取相关信息。然而,和Windows文件系统之间是没有任何交互的。

结论

通过使用VolFs,WSL为其内部的Linux文件系统模拟出完整的Linux特性,从而提供了对Windows文件的访问,并且通过使用DrvFs,提供了对Windows设备及文件的完全访问。在写作本文时,DrvFs已经实现了Linux文件系统的一些功能,比如大小写敏感和符号链接,同时还支持和Windows之间的互操作。

将来,我们会继续增强对Linux文件系统特性的支持,对于VolFs和DrvFs都是如此。在VolFs挂载的同时要进行必要的互操作时会遇到各种限制,我们的目标就是减少这种情况发生的次数。从GitHub和User Voice社区上,我们获得了大量反馈,这些都会促使我们改进,帮助我们以最重要的场景为目标。

原文  http://www.oschina.net/translate/wsl-file-system-support
正文到此结束
Loading...