MacOS开发 技术集锦

深入解析Mac OS X & iOS 操作系统 学习笔记

2016-11-11  本文已影响630人  CoderKo1o

文件系统和虚拟文件系统交换

内核的一个重要职责就是管理数据,这些数据既包括用户数据也包括系统数据。为了实现这个目的,数据按照文件和目录的方式组织,文件和目录保存在各种类型的文件系统上。
XNU的BSD层负责文件系统的实现,BSD 文件系统使用了一个名为虚拟文件系统交互(VFS)的框架。这个框架成为了UNIX 中内核和各种文件系统实现(本地文件系统和各种文件系统)之间的标准借接口。

磁盘设备和分区

OS X 和 iOS 遵循BSD 将硬盘当做设备节点的命名约定。每一个磁盘都可以以块设备的形式(/dev/disk#)或字符设备(裸设备)的形式(/dev/rdisk#)访问。通常情况下,磁盘和分区都是块设备。系统通过mount(2)挂载文件系统时使用的是块设备的表示方式。裸设备模式主要被一些底层程序使用,例如fsck(8)和pdisk(8),这些程序需要直接访问磁盘上的块。

分区方案

文件系统并不是独立存在的,而是存在在磁盘分区上。每一个磁盘都至少有一个分区,而每一个分区都可以单独格式化为文件系统。在某些情况下,可以允许一个文件系统跨越多个分区。分区方案(partitioning scheme)定义了磁盘的布局,逻辑地将磁盘分隔为一个或多个区域(每一个区域为一个分区),每个分区中包含的是连续的扇区。通常情况下,磁盘的头几个扇区保存了磁盘的分区表,分区表列出了磁盘中的区域(起始扇区和扇区数)以及每一个分区的文件系统类型。OS X 传统上支持3种分区方案:

通用文件系统的概念

尽管不同的文件系统会采用完全不同的方式管理磁盘上的文件,但是所有的文件系统基本上都提供了同样的原语。内核对文件的接口称为虚拟文件系统交换(Virtual FileSystem Switch, VFS),VFS 就是基于这些概念构建的。

文件

文件系统中最基本的概念就是文件。文件是在底层媒体(磁盘、CD-ROM或其他设备)上的一组或多组块。在理想情况下,文件一改是单独一组连续的块。然而在大部分情况下,文件会占用多个块的范围。这些范围成为extent。HFS+ 还定义了clump的概念,clump 表示当前一个文件被分配或扩张时提供的默认分配的块。
尽管会有碎片化,但是文件系统必须将文件表现为连续的、可自由寻址(随机访问)的区域。事实上,有一些文件系统就是完全虚拟的(例如Linux的/proc),还有一些是通过网络映射的(例如 NFS 和 AFS)。文件请求者只得到一个文件描述符(通过open(2)返回的整形fd,或是通过fopen(3)返回的FILE *指针),将文件描述符当成一个不透明的句柄。内核在提供文件请求服务时,需要将这个句柄转换为文件系统中的标识符。

扩展属性

扩展属性指的是用户(或系统)定义的属性,可以包含应用程序所需要的信息,在很多情况下实际包含了系统本身所需要的信息。Darwin 中通过扩展属性支持很多高级特性,例如透明的压缩和fork,还支持访问控制列表(Access Control List)

权限

并不是所有的文件都是平等的。有一些文件包含敏感信息,因此每一个严肃的文件系统(除了 FAT 系列的文件系统)都必须支持权限。UNIX 的文件系统(Mac 原生的HFS+文件系统也属于一种UNIX 文件系统)支持传统的用户/组/其他的读/写/执行的权限模型。从OS X 10.4 开始,VFS 开始支持更精细的权限:Access Control List(ASL,访问控制列表),OS X 允许通过chmod(1) 设置和修改ACL。通过ls(1) -e 可以显示访问控制列表。在ls(1) -l 的输出列表中,带有ACL的文件会带有一个加号(+)标记。VFS 通过扩展属性支持ACL,而ACL的实施是通过一个独立的机制KAUTH完成的。

时间戳

文件系统需要为其包含的文件记录时间戳。UNIX 要求维护三个时间戳:创建时间、修改时间和访问时间。touch(1)命令的-acm 选项就对应了这3个时间戳。ls(1) 命令的-u 参数能显示访问时间,-U 参数显示创建时间,如果不提供参数则显示修改时间。

快捷方式和连接

大部分UNIX用户都对连接(link)的概念很熟悉,其中既包括软连接(也称为符号连接)也包括硬链接。软连接是通过ln(1) -s 创建的,硬连接则是通过不带-s参数的ln(1)创建的。从VFS 角度看,软连接是一个不同的文件(即另一个inode,类型为 1,包含其指向的文件的文件名。而硬连接则是目录中的另一个条目,指向同一个底层的文件(从VFS角度看,是同一个inode)。通过另一种方式描述,可以说硬连接存在于目录层次,而软连接存在于文件层次。
硬连接和软连接一样,都提供了一种文件快捷方式的机制。但是和软连接的不同之处在于,硬连接可以防止误删文件,因为只有最后一个指向文件的连接被删除了,文件系统才会删除文件。下表是硬连接和软连接的比较:

| 软连接 | 硬连接
---|---|---
inode|指向不同inode的不同目录项(dentry)包含文件名|指向同一个inode的不同dentry
作用范围|跨越文件系统|同一个文件系统
目录|可连接|规定不可连接(除了 “.”和“..”之外)。实际中取决于具体实现
目标 rm/mv|软连接被破坏|硬连接依然存在
目标重新创建|软连接被修复|硬连接指向“旧”的文件
查找|find - L -samefile <target>|find -samefile <target>
find -inum <targetinodenum>

苹果生态圈中的文件系统

OS X 和 iOS 都支持各种各样的文件系统。实际上由于内核的模块化设计,内核可以支持任意种类的文件系统,只要求系统服从内核VFS标准即可。

苹果原生的文件系统
DOS/Windows 文件系统
CD/DVD 文件系统
基于网络的文件系统

网络文件系统的用途是将存储系统扩展到本地主机之外的远程主机,远程主机既可以在本地局域网中,也可以是通过Internet 连接的遥远主机。

伪文件系统

伪文件系统部署真正的文件系统。伪文件系统可以分为两类

挂载文件系统(仅限于 OS X)

OS X 支持文件系统的动态挂载和卸载,并且这种支持是通过两种机制实现的:

磁盘镜像文件

OS X 使用了磁盘镜像(disk image),磁盘镜像文件的后缀名为.dmg。这些文件上是一个文件中包含了整个文件系统,通常是HFS+文件系统。这个文件的格式为UDIF(Universal Disk Image Format,通用磁盘镜像格式)。双击DMG文件格式时,OS X 的Finder 可以自动挂载 DMG 文件(通过调用CoreServices 的 DiskImageMounter.app程序):hdiutil(1) 命令也可以挂载DMG文件。DMG文件的挂载是由DiskImages.framework框架负责完成的。这是一个私有框架。
BSD 层在vnode磁盘驱动程序中对磁盘镜像提供了原生的支持,通过用户态的/usr/libexec/vndevice命令可以访问这个驱动程序。通过这条命令可以将磁盘镜像挂载到某个BSD /dev/vn*设备。

虚拟文件系统交换

和大部分UN*X 一样, OS X 使用虚拟文件系统(Virtual File System,VFS)交换作为所有文件系统的抽象层。VFS 的基本思想是定义一套适用于所有文件系统的公共接口,而不管文件系统的具体实现是什么,这套文件系统简化为基础结构:文件系统条目、挂载条目以及vnode(抽象的inode)。任何已知的文件系统都可以遵循这套接口实现。有了这套接口,内核就可以像各种POSIX 文件 I/O 调用提供完全一致的接口,从而可以将多种文件系统无缝地整合进同一个文件树种。

文件系统条目

在内核中,通过vfs_fsentry 结构体数组维护文件系统。用过vfs_fsadd和vfs_fsremove 可以分别从内核添加和删除文件系统

挂载条目

挂载条目(mount entry)是一个结构体mount,向用户态只暴露了一个不透明的类型,表示一个已挂载的文件系统示例。挂载条目大致对应的是文件系统的超级块。超级块是一个描述符,其中保存了全局的文件系统属性。挂载条目还保存了文件系统的操作。文件系统可以注册,但是不一定被挂载。此外,同一个文件系统类型可以被挂载多次。

vnode 对象

vnode 对象建立在传统的UNIX inode之上。vnode 表示一个“虚拟的inode”,其中包含从磁盘获取文件或目录的必要信息。vnode 结构体中有一个重要的字段是 ubc_info 结构体:通过这个结构体可以在同一缓冲区缓存(unified buffer cache,UBC)中找到这个 vnode 的对象消息。UBC 是 BSD 保存缓存的 vnode 数据的机制,vnode 数据是从磁盘和设备文件获取的。ubc_info 将 vnode 和 Mach 的 memory_object_t连接在一起。每一个文件系统都定义了自己的内部节点表示方式,但是应该支持vnode 的基本表现形式,还应该支持一组定义在 vnode 上的操作:创建、读取、写入和删除。

FUSE:用户空间的文件系统

FUSE 的内核态组件非常简单:注册一个VFS(通过 vfs_fsadd),并且导出一组/dev/fuserXX字符设备。针对这个文件系统实例的操作都被内核扩展截获,然后序列化为一条消息发给用户态的文件系统处理。
FUSE在用户态的实现:在fuse_operations 结构体中填充自己的文件操作回调函数,然后通过fuse_main( ) 完成其他的工作。

进程的文件 I/O 操作

BSD proc_t 结构体中包含了一个字段 struct filedesc *p_fd,这个字段的结构体保存了进程打开的所有文件。filedesc结构体中关键的字段是fd_ofiles 和 fs_ofileflags。这两个字段表示的都是数组,用户态的整型文件描述符就是这些数组的索引(0:stdin;1:stdout;2:stderr)。第一个数组保存了对应描述符的文件“对象”,第二个数组保存了文件打开传入的标志位。fp_lookup 函数可以根据给定的文件描述符查找fileproc。

上一篇 下一篇

猜你喜欢

热点阅读