文件系統(tǒng)和虛擬文件系統(tǒng)交換
內(nèi)核的一個重要職責(zé)就是管理數(shù)據(jù),這些數(shù)據(jù)既包括用戶數(shù)據(jù)也包括系統(tǒng)數(shù)據(jù)。為了實現(xiàn)這個目的,數(shù)據(jù)按照文件和目錄的方式組織,文件和目錄保存在各種類型的文件系統(tǒng)上。
XNU的BSD層負責(zé)文件系統(tǒng)的實現(xiàn),BSD 文件系統(tǒng)使用了一個名為虛擬文件系統(tǒng)交互(VFS)的框架。這個框架成為了UNIX 中內(nèi)核和各種文件系統(tǒng)實現(xiàn)(本地文件系統(tǒng)和各種文件系統(tǒng))之間的標(biāo)準(zhǔn)借接口。
磁盤設(shè)備和分區(qū)
OS X 和 iOS 遵循BSD 將硬盤當(dāng)做設(shè)備節(jié)點的命名約定。每一個磁盤都可以以塊設(shè)備的形式(/dev/disk#)或字符設(shè)備(裸設(shè)備)的形式(/dev/rdisk#)訪問。通常情況下,磁盤和分區(qū)都是塊設(shè)備。系統(tǒng)通過mount(2)掛載文件系統(tǒng)時使用的是塊設(shè)備的表示方式。裸設(shè)備模式主要被一些底層程序使用,例如fsck(8)和pdisk(8),這些程序需要直接訪問磁盤上的塊。
分區(qū)方案
文件系統(tǒng)并不是獨立存在的,而是存在在磁盤分區(qū)上。每一個磁盤都至少有一個分區(qū),而每一個分區(qū)都可以單獨格式化為文件系統(tǒng)。在某些情況下,可以允許一個文件系統(tǒng)跨越多個分區(qū)。分區(qū)方案(partitioning scheme)定義了磁盤的布局,邏輯地將磁盤分隔為一個或多個區(qū)域(每一個區(qū)域為一個分區(qū)),每個分區(qū)中包含的是連續(xù)的扇區(qū)。通常情況下,磁盤的頭幾個扇區(qū)保存了磁盤的分區(qū)表,分區(qū)表列出了磁盤中的區(qū)域(起始扇區(qū)和扇區(qū)數(shù))以及每一個分區(qū)的文件系統(tǒng)類型。OS X 傳統(tǒng)上支持3種分區(qū)方案:
- 主引導(dǎo)記錄(Master Boot Record,MBR)分區(qū):MBR 是PC XT 和 AT 年代遺留下來的產(chǎn)物,現(xiàn)在依然廣泛使用。這個分區(qū)方案依賴于 BIOS,局限性非常大,最多允許4個主分區(qū),而且是32位的(最多支持約40億個扇區(qū)),但是這個分區(qū)方案的優(yōu)點在于所有的操作系統(tǒng)都支持這個方案
- Apple Partition Map:這個蘋果獨有的自定義分區(qū)方案。最初流行于基于PPC的Mac,這個分區(qū)方案也是32位的,而且是蘋果私有的。現(xiàn)在這個方案基本上被下一個方案GPT替代了,但是在一些iPod 設(shè)備(例如Classic 和 Nano)上仍然使用
- GUID分區(qū)表(GUID Partition Table,GPT):這是一個64位的方案,可管理的磁盤大小超越了千兆兆字節(jié),解決了所有最大分區(qū)的限制。這一點非常重要:MBR 和 APT 都是32位的,因此最大可尋址 232 個扇區(qū)。標(biāo)準(zhǔn)扇區(qū)大小為512字節(jié),因此磁盤大小最大允許為2TB。而蘋果的默認分區(qū)方案現(xiàn)在轉(zhuǎn)移到64位架構(gòu)。GPT 也是EFI標(biāo)準(zhǔn)的一部分,因此在蘋果基于EFI的Intel硬件上可以工作得很好。
通用文件系統(tǒng)的概念
盡管不同的文件系統(tǒng)會采用完全不同的方式管理磁盤上的文件,但是所有的文件系統(tǒng)基本上都提供了同樣的原語。內(nèi)核對文件的接口稱為虛擬文件系統(tǒng)交換(Virtual FileSystem Switch, VFS),VFS 就是基于這些概念構(gòu)建的。
文件
文件系統(tǒng)中最基本的概念就是文件。文件是在底層媒體(磁盤、CD-ROM或其他設(shè)備)上的一組或多組塊。在理想情況下,文件一改是單獨一組連續(xù)的塊。然而在大部分情況下,文件會占用多個塊的范圍。這些范圍成為extent。HFS+ 還定義了clump的概念,clump 表示當(dāng)前一個文件被分配或擴張時提供的默認分配的塊。
盡管會有碎片化,但是文件系統(tǒng)必須將文件表現(xiàn)為連續(xù)的、可自由尋址(隨機訪問)的區(qū)域。事實上,有一些文件系統(tǒng)就是完全虛擬的(例如Linux的/proc),還有一些是通過網(wǎng)絡(luò)映射的(例如 NFS 和 AFS)。文件請求者只得到一個文件描述符(通過open(2)返回的整形fd,或是通過fopen(3)返回的FILE *指針),將文件描述符當(dāng)成一個不透明的句柄。內(nèi)核在提供文件請求服務(wù)時,需要將這個句柄轉(zhuǎn)換為文件系統(tǒng)中的標(biāo)識符。
擴展屬性
擴展屬性指的是用戶(或系統(tǒng))定義的屬性,可以包含應(yīng)用程序所需要的信息,在很多情況下實際包含了系統(tǒng)本身所需要的信息。Darwin 中通過擴展屬性支持很多高級特性,例如透明的壓縮和fork,還支持訪問控制列表(Access Control List)
權(quán)限
并不是所有的文件都是平等的。有一些文件包含敏感信息,因此每一個嚴(yán)肅的文件系統(tǒng)(除了 FAT 系列的文件系統(tǒng))都必須支持權(quán)限。UNIX 的文件系統(tǒng)(Mac 原生的HFS+文件系統(tǒng)也屬于一種UNIX 文件系統(tǒng))支持傳統(tǒng)的用戶/組/其他的讀/寫/執(zhí)行的權(quán)限模型。從OS X 10.4 開始,VFS 開始支持更精細的權(quán)限:Access Control List(ASL,訪問控制列表),OS X 允許通過chmod(1) 設(shè)置和修改ACL。通過ls(1) -e 可以顯示訪問控制列表。在ls(1) -l 的輸出列表中,帶有ACL的文件會帶有一個加號(+)標(biāo)記。VFS 通過擴展屬性支持ACL,而ACL的實施是通過一個獨立的機制KAUTH完成的。
時間戳
文件系統(tǒng)需要為其包含的文件記錄時間戳。UNIX 要求維護三個時間戳:創(chuàng)建時間、修改時間和訪問時間。touch(1)命令的-acm 選項就對應(yīng)了這3個時間戳。ls(1) 命令的-u 參數(shù)能顯示訪問時間,-U 參數(shù)顯示創(chuàng)建時間,如果不提供參數(shù)則顯示修改時間。
快捷方式和連接
大部分UNIX用戶都對連接(link)的概念很熟悉,其中既包括軟連接(也稱為符號連接)也包括硬鏈接。軟連接是通過ln(1) -s 創(chuàng)建的,硬連接則是通過不帶-s參數(shù)的ln(1)創(chuàng)建的。從VFS 角度看,軟連接是一個不同的文件(即另一個inode,類型為 1,包含其指向的文件的文件名。而硬連接則是目錄中的另一個條目,指向同一個底層的文件(從VFS角度看,是同一個inode)。通過另一種方式描述,可以說硬連接存在于目錄層次,而軟連接存在于文件層次。
硬連接和軟連接一樣,都提供了一種文件快捷方式的機制。但是和軟連接的不同之處在于,硬連接可以防止誤刪文件,因為只有最后一個指向文件的連接被刪除了,文件系統(tǒng)才會刪除文件。下表是硬連接和軟連接的比較:
| 軟連接 | 硬連接
---|---|---
inode|指向不同inode的不同目錄項(dentry)包含文件名|指向同一個inode的不同dentry
作用范圍|跨越文件系統(tǒng)|同一個文件系統(tǒng)
目錄|可連接|規(guī)定不可連接(除了 “.”和“..”之外)。實際中取決于具體實現(xiàn)
目標(biāo) rm/mv|軟連接被破壞|硬連接依然存在
目標(biāo)重新創(chuàng)建|軟連接被修復(fù)|硬連接指向“舊”的文件
查找|find - L -samefile <target>|find -samefile <target>
find -inum <targetinodenum>
蘋果生態(tài)圈中的文件系統(tǒng)
OS X 和 iOS 都支持各種各樣的文件系統(tǒng)。實際上由于內(nèi)核的模塊化設(shè)計,內(nèi)核可以支持任意種類的文件系統(tǒng),只要求系統(tǒng)服從內(nèi)核VFS標(biāo)準(zhǔn)即可。
蘋果原生的文件系統(tǒng)
- 層次文件系統(tǒng)(HFS):蘋果在Mac OS 早期時開發(fā)的原生文件系統(tǒng)結(jié)構(gòu)
- 層次文件系統(tǒng) Plus(HFS+):用來替代HFS。HFS+ 對 HFS 增加了很多擴展以克服HFS的各種局限性
DOS/Windows 文件系統(tǒng)
- 文件分配表(FAT):最簡單最原始的文件系統(tǒng),最流行的FAT-32仍然局限于2TB的卷
- NT 文件系統(tǒng)(NTFS):FAT 缺少的主要功能是權(quán)限和限額。權(quán)限系統(tǒng)的作用是支持文件的選擇性訪問控制。限額機制的作用是防止用戶創(chuàng)建過多文件導(dǎo)致共享文件系統(tǒng)的濫用,為了同時滿足這兩個 需求,NT 文件系統(tǒng)(NTFS)出現(xiàn)了。并且是現(xiàn)在Windows的原始文件系統(tǒng)
CD/DVD 文件系統(tǒng)
- CD 音頻文件系統(tǒng)(CDDAFS)
- CD-ROM 文件系統(tǒng)(CDFS/ISO-9660)
- 通用磁盤格式(UDF)
基于網(wǎng)絡(luò)的文件系統(tǒng)
網(wǎng)絡(luò)文件系統(tǒng)的用途是將存儲系統(tǒng)擴展到本地主機之外的遠程主機,遠程主機既可以在本地局域網(wǎng)中,也可以是通過Internet 連接的遙遠主機。
- 蘋果文件傳輸協(xié)議:Apple Filing Protocol,AFP是Mac OS 8 和 9 默認的網(wǎng)絡(luò)文件協(xié)議,當(dāng)時還稱為 AppleShare。這是一個應(yīng)用層協(xié)議,建立在蘋果私有的AppleTalk協(xié)議之上(后來蘋果投入了TCP/IP的懷抱)。目前AFP使用TCP端口427和528
- 網(wǎng)絡(luò)文件系統(tǒng)協(xié)議:網(wǎng)絡(luò)文件系統(tǒng)(Network File Systems,NFS)一個老牌的應(yīng)用層協(xié)議
- 服務(wù)器消息塊(SMB/CIFS/SMB2)協(xié)議
- 文件傳輸協(xié)議:FTP(對應(yīng)RFC 959)是最老的互聯(lián)網(wǎng)協(xié)議之一
- Web Distribute Authoring and Versioning(WebDAV):是一個推薦的HTTP擴展協(xié)議
偽文件系統(tǒng)
偽文件系統(tǒng)部署真正的文件系統(tǒng)。偽文件系統(tǒng)可以分為兩類
- 內(nèi)核數(shù)據(jù)結(jié)構(gòu)和設(shè)備的文件系統(tǒng)接口:Linux 的/proc 和 /sys 文件系統(tǒng),這兩個文件系統(tǒng)提供了大量診斷數(shù)據(jù)和內(nèi)核參數(shù)。UNIX 的 /dev 文件系統(tǒng),內(nèi)核通過/dev 文件系統(tǒng)暴露了各種設(shè)備的驅(qū)動程序
- 文件系統(tǒng)組件:這些根本不是文件系統(tǒng),但是提供了處理特殊文件類型或特殊掛載選項的機制。BSD(和XNU)的deadfs、specfs、FIFOfs和unionfs都屬于這一類
掛載文件系統(tǒng)(僅限于 OS X)
OS X 支持文件系統(tǒng)的動態(tài)掛載和卸載,并且這種支持是通過兩種機制實現(xiàn)的:
- automount:內(nèi)核的automount 組件是 autofs.kext 內(nèi)核擴展,autofs.text 在 VFS 中注冊了 autofs 文件系統(tǒng)。autofs.text 向用戶態(tài)暴露了/dev/autofs。為了automount 操作的成功執(zhí)行,用戶態(tài)有幾個輔助 automount 的守護程序:
- autofsd:由launchd 啟動,輔助監(jiān)聽網(wǎng)絡(luò)配置變化通知以及對automount 的調(diào)用
- autmount:查詢/etc/auto_master 文件,請求特定的掛載操作,automountd 執(zhí)行實際的掛載操作
- 磁盤仲裁:磁盤仲裁框架隱藏了內(nèi)核驅(qū)動層I/O Kit 發(fā)送消息的果餐。如果不適用磁盤仲裁框架,也可以直接從I/O Kit 注冊通知
磁盤鏡像文件
OS X 使用了磁盤鏡像(disk image),磁盤鏡像文件的后綴名為.dmg。這些文件上是一個文件中包含了整個文件系統(tǒng),通常是HFS+文件系統(tǒng)。這個文件的格式為UDIF(Universal Disk Image Format,通用磁盤鏡像格式)。雙擊DMG文件格式時,OS X 的Finder 可以自動掛載 DMG 文件(通過調(diào)用CoreServices 的 DiskImageMounter.app程序):hdiutil(1) 命令也可以掛載DMG文件。DMG文件的掛載是由DiskImages.framework框架負責(zé)完成的。這是一個私有框架。
BSD 層在vnode磁盤驅(qū)動程序中對磁盤鏡像提供了原生的支持,通過用戶態(tài)的/usr/libexec/vndevice命令可以訪問這個驅(qū)動程序。通過這條命令可以將磁盤鏡像掛載到某個BSD /dev/vn*設(shè)備。
虛擬文件系統(tǒng)交換
和大部分UN*X 一樣, OS X 使用虛擬文件系統(tǒng)(Virtual File System,VFS)交換作為所有文件系統(tǒng)的抽象層。VFS 的基本思想是定義一套適用于所有文件系統(tǒng)的公共接口,而不管文件系統(tǒng)的具體實現(xiàn)是什么,這套文件系統(tǒng)簡化為基礎(chǔ)結(jié)構(gòu):文件系統(tǒng)條目、掛載條目以及vnode(抽象的inode)。任何已知的文件系統(tǒng)都可以遵循這套接口實現(xiàn)。有了這套接口,內(nèi)核就可以像各種POSIX 文件 I/O 調(diào)用提供完全一致的接口,從而可以將多種文件系統(tǒng)無縫地整合進同一個文件樹種。
文件系統(tǒng)條目
在內(nèi)核中,通過vfs_fsentry 結(jié)構(gòu)體數(shù)組維護文件系統(tǒng)。用過vfs_fsadd和vfs_fsremove 可以分別從內(nèi)核添加和刪除文件系統(tǒng)
掛載條目
掛載條目(mount entry)是一個結(jié)構(gòu)體mount,向用戶態(tài)只暴露了一個不透明的類型,表示一個已掛載的文件系統(tǒng)示例。掛載條目大致對應(yīng)的是文件系統(tǒng)的超級塊。超級塊是一個描述符,其中保存了全局的文件系統(tǒng)屬性。掛載條目還保存了文件系統(tǒng)的操作。文件系統(tǒng)可以注冊,但是不一定被掛載。此外,同一個文件系統(tǒng)類型可以被掛載多次。
vnode 對象
vnode 對象建立在傳統(tǒng)的UNIX inode之上。vnode 表示一個“虛擬的inode”,其中包含從磁盤獲取文件或目錄的必要信息。vnode 結(jié)構(gòu)體中有一個重要的字段是 ubc_info 結(jié)構(gòu)體:通過這個結(jié)構(gòu)體可以在同一緩沖區(qū)緩存(unified buffer cache,UBC)中找到這個 vnode 的對象消息。UBC 是 BSD 保存緩存的 vnode 數(shù)據(jù)的機制,vnode 數(shù)據(jù)是從磁盤和設(shè)備文件獲取的。ubc_info 將 vnode 和 Mach 的 memory_object_t連接在一起。每一個文件系統(tǒng)都定義了自己的內(nèi)部節(jié)點表示方式,但是應(yīng)該支持vnode 的基本表現(xiàn)形式,還應(yīng)該支持一組定義在 vnode 上的操作:創(chuàng)建、讀取、寫入和刪除。
FUSE:用戶空間的文件系統(tǒng)
FUSE 的內(nèi)核態(tài)組件非常簡單:注冊一個VFS(通過 vfs_fsadd),并且導(dǎo)出一組/dev/fuserXX字符設(shè)備。針對這個文件系統(tǒng)實例的操作都被內(nèi)核擴展截獲,然后序列化為一條消息發(fā)給用戶態(tài)的文件系統(tǒng)處理。
FUSE在用戶態(tài)的實現(xiàn):在fuse_operations 結(jié)構(gòu)體中填充自己的文件操作回調(diào)函數(shù),然后通過fuse_main( ) 完成其他的工作。
進程的文件 I/O 操作
BSD proc_t 結(jié)構(gòu)體中包含了一個字段 struct filedesc *p_fd,這個字段的結(jié)構(gòu)體保存了進程打開的所有文件。filedesc結(jié)構(gòu)體中關(guān)鍵的字段是fd_ofiles 和 fs_ofileflags。這兩個字段表示的都是數(shù)組,用戶態(tài)的整型文件描述符就是這些數(shù)組的索引(0:stdin;1:stdout;2:stderr)。第一個數(shù)組保存了對應(yīng)描述符的文件“對象”,第二個數(shù)組保存了文件打開傳入的標(biāo)志位。fp_lookup 函數(shù)可以根據(jù)給定的文件描述符查找fileproc。