Steve Kleiman 在 1986 年撰寫了《Vnodes: An Architecture for Multiple File System Types in Sun UNIX[3]》一文。這篇論文幅較短,大部分內(nèi)容是數(shù)據(jù)結(jié)構(gòu)的列舉,以及 C 語言結(jié)構(gòu)之間相互指向的圖表。
Steve Kleiman是分布式文件系統(tǒng)領(lǐng)域的專家,在 Sun Microsystem 工作了多年,曾參與開發(fā) Sun Network File System(NFS)等項目,為分布式文件系統(tǒng)領(lǐng)域做出了重要貢獻。
Kleiman 希望在 Unix 中能夠擁有多個文件系統(tǒng),并希望這些文件系統(tǒng)能夠共享接口和內(nèi)存。具體而言,他希望設(shè)計一個能夠提供以下功能的架構(gòu):
一個可以支持多個實現(xiàn)的通用接口;支持 BSD FFS,以及兩個遠程文件系統(tǒng) NFS 和 RFS,還有特定的非 Unix 文件系統(tǒng),如 MS-DOS;接口定義的操作需要是原子性的。
并且,能夠在不影響性能的情況下動態(tài)地處理內(nèi)存和數(shù)據(jù)結(jié)構(gòu),支持重入(reentrant) 和多核,并且具有一定面向?qū)ο筮M行編程的特性。
重入(reentrant) 是指程序或子程序在尚未完成上一次調(diào)用之前,可以再次被調(diào)用且不會出錯或發(fā)生沖突。
兩個抽象概念
Steven 研究了文件系統(tǒng)的各種操作,決定將他們抽象為兩個概念:
??vfs,虛擬文件系統(tǒng),代表文件系統(tǒng)
??vnode,虛擬 inode,代表文件
vfs,虛擬文件系統(tǒng),它提供統(tǒng)一的接口,使操作系統(tǒng)可以以一致的方式訪問不同的文件系統(tǒng),無論是本地文件系統(tǒng)還是網(wǎng)絡(luò)文件系統(tǒng)。
vnode,虛擬 inode, 表示一個文件,每個文件都有一個相關(guān)聯(lián)的索引節(jié)點,其中包含了文件的元數(shù)據(jù)(如文件權(quán)限、所有者、大小等)以及指向文件數(shù)據(jù)存儲位置的指針。
采用了 C++風格(實際使用 C 語言),每一個類型會匹配一個虛函數(shù)表,通過虛函數(shù)表,系統(tǒng)在運行時根據(jù)對象的實際類型來調(diào)用適當?shù)奶摵瘮?shù),實現(xiàn)動態(tài)綁定:
??對于 vfs 類型,其虛函數(shù)表 struct vfsops,包含了一系列的函數(shù)指針,用來執(zhí)行諸如 mount、unmount、sync 和 vget 等操作。在論文的后面,會解釋這些函數(shù)的原型和功能;
??對于 vnode 類型也是類似的,其虛函數(shù)表 struct vnodeops,包含 open、rdwr 和 close 等函數(shù),還有create、unlink 和 rename 等函數(shù)。一些函數(shù)是針對特定的文件類型的,比如 readlink、mkdir、readdir 和 rmdir。
通過 vfs 對象來進行跟蹤實際的掛載,其虛函數(shù)表 struct vfsops 指向適用于該特定子樹的文件系統(tǒng)操作。
類似地,vnode 實例用來進行跟蹤打開的文件。它包含?struct *vnodeops?指針,作為 vfs 的一部分,有指針?struct *vfs?指向文件系統(tǒng)實例。
vfs 和 vnode 這兩個結(jié)構(gòu)體都需要一些用于存儲特定實現(xiàn)數(shù)據(jù)的字段(如“子類私有字段”)。他們都以?caddr_t ...data?指針結(jié)尾。這些私有數(shù)據(jù)并不是 vfs 和 vnode 的一部分,而是位于其他位置,并通過指針進行引用。
Vnodes 實操

在論文中,有一整頁的內(nèi)容專門用于展示各種相互指向的結(jié)構(gòu)。乍一看可能會感到困惑,但一旦追蹤下來,就會發(fā)現(xiàn)它非常直觀和優(yōu)雅。
Kleiman 詳細解釋了如何使用 lookuppn() 函數(shù)來解釋事物的工作原理,該函數(shù)替代了傳統(tǒng) Unix 中的 namei() 函數(shù)。類似于 namei() ,這個函數(shù)接受一個路徑,并返回表示該路徑所代表的 vnode 的 struct vnode 指針。
路徑遍歷始于根 vnode 或當前進程的當前目錄 vnode,具體取決于路徑的第一個字符是否為 /。
然后,這個函數(shù)會依次取出路徑的每一個子項,并調(diào)用當前 vnode 的 lookup 函數(shù),它接受一個路徑子項和一個假設(shè)是目錄的當前 vnode,并返回代表那個子項的 vnode。
當一個目錄是個掛載點,它的 vfsmountedhere 會被設(shè)置為一個指向 struct vfs 的指針。lookuppn 函數(shù)會跟隨這個指針,并調(diào)用 vfs 的根函數(shù),以獲取該文件系統(tǒng)的根 vnode,替換當前正在處理的 vnode。
反過來也是可能的:當解析父目錄(".. ")時,如果當前 vnode 的 "flags" 字段中設(shè)置了根標志,我們會跟隨 vfsmountedhere 指針從當前 vnode 到 vfs。然后,我們可以使用該 vfs 中的 vnodecovered 字段來獲取上層文件系統(tǒng)的 vnode。
無論如何,在成功完成后,會返回一個 struct vnode 指針,即所使用的路徑。
新增的系統(tǒng)調(diào)用
為了使系統(tǒng)高效地運行,需要添加一些新的系統(tǒng)調(diào)用來完善接口。
在 Unix 的歷史中,我們看到引入了 statsfs 和 fstatsfs ,通過這兩個函數(shù)可以獲得與用戶空間中的文件系統(tǒng)進行交互的接口。getdirentries 函數(shù)可以讓用戶一次性獲取多個目錄條目(取決于提供的緩沖區(qū)大?。?,這大大加快了遠程文件系統(tǒng)的目錄讀取速度。
在 Linux 系統(tǒng)中
通過查看 Linux 內(nèi)核源代碼,我們可以找到 Kleiman 設(shè)計的總體結(jié)構(gòu),盡管 Linux 內(nèi)核的復(fù)雜性和豐富性掩蓋了其中大部分內(nèi)容。Linux 內(nèi)核擁有豐富的文件系統(tǒng)類型,并且還添加了許多在 40 年前的 BSD 中不存在的功能。因此,我們可以找到更多的數(shù)據(jù)結(jié)構(gòu)和系統(tǒng)調(diào)用,它們被用于實現(xiàn)命名空間、配額、屬性、只讀模式、目錄名稱緩存等功能。
文件
如果你仔細觀察,原始的結(jié)構(gòu)仍然可以找到:Linux 內(nèi)存中的文件相關(guān)結(jié)構(gòu)分為兩部分,一個是已打開的文件,它是一個帶有當前位置的 inode;另一個是 inode,它代表整個文件。
我們可以在此處找到文件對象[4],struct file 的實例。在文件的所有其他內(nèi)容中,最值得注意的是一個字段?loff_t f_pos,它表示文件當前位置距離文件起始位置的偏移量(以字節(jié)為單位)。
文件的類[5]是通過一個虛函數(shù)表來定義。我們可以找到一個指針?struct file_operations *f_op?。它展示了文件可以執(zhí)行的所有操作,其中最常見的是打開(open)、關(guān)閉(close)、定位(lseek)、讀?。╮ead)和寫入(write)。
文件還包含指向 inode 的指針,即?struct inode *f_inode。
索引節(jié)點
對于不需要偏移量的文件操作,它們是針對整個文件進行的,定義為?struct inode *。
查看此處[6]的定義。我們可以看到這里還有其他的定義,40 年前的 BSD 中沒有類似的定義,比如 ACL(訪問控制列表)和屬性(attributes)。
我們發(fā)現(xiàn)?inode 的類[7]通過虛函數(shù)表來定義,即?struct inode_operations *i_op。同樣的,這其中很多函數(shù)涉及新特性,比如 ACL(訪問控制列表)和擴展屬性,但我們也會找到我們期望的功能,比如鏈接(link)、刪除(unlink)、重命名(rename)等。
Inode 還包含一個指向文件系統(tǒng)的指針,即?struct super_block *i_sb。
超級塊
掛載點用?struct super_block?來表示,在此處查看其定義。同樣地,它有?struct super_operations *s_op?定義的各個操作,在此處[8]查看其定義。
支持的文件系統(tǒng)不再有限,可以通過內(nèi)核模塊動態(tài)地添加新的文件系統(tǒng),通過數(shù)據(jù)結(jié)構(gòu)?struct file_system_type?來表示,它只有一個用于創(chuàng)建 superblock 的工廠函數(shù) mount。
小結(jié)
Unix 發(fā)生了變化。它的運行時變得更加復(fù)雜,增加了許多新的功能,并增加了系統(tǒng)調(diào)用。系統(tǒng)變得更有結(jié)構(gòu)。
但是,由 Steve Kleiman 和 Bill Joy(BSD 操作系統(tǒng)的共同創(chuàng)始人之一) 構(gòu)思的原始設(shè)計和數(shù)據(jù)結(jié)構(gòu)仍然存在,在當前的 Linux 系統(tǒng)中仍然可以找到,雖然已經(jīng)過去了 40 年。
電子發(fā)燒友App












































評論