中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Linux文件系統(tǒng)—源代碼導(dǎo)讀
文件系統(tǒng)

    眾所周知,文件系統(tǒng)是Unix系統(tǒng)最基本的資源。最初的Unix系統(tǒng)一般都只支持一種單一類型的文件系統(tǒng),在這種情況下,文件系統(tǒng)的結(jié)構(gòu)深入到整個系統(tǒng)內(nèi)核中。而現(xiàn)在的系統(tǒng)大多都在系統(tǒng)內(nèi)核和文件系統(tǒng)之間提供一個標準的接口,這樣不同文件結(jié)構(gòu)之間的數(shù)據(jù)可以十分方便地交換。Linux也在系統(tǒng)內(nèi)核和文件系統(tǒng)之間提供了一種叫做VFS(virtual file system)的標準接口。
    這樣,文件系統(tǒng)的代碼就分成了兩部分:上層用于處理系統(tǒng)內(nèi)核的各種表格和數(shù)據(jù)結(jié)構(gòu);而下層用來實現(xiàn)文件系統(tǒng)本身的函數(shù),并通過VFS來調(diào)用。這些函數(shù)主要包括:
    * 管理緩沖區(qū)(buffer. c)。
    * 響應(yīng)系統(tǒng)調(diào)用fcntl() 和ioctl()(fcntl.c and ioctl.c)。
    * 將管道和文件輸入/輸出映射到索引節(jié)點和緩沖區(qū)(fifo.c, pipe.c)。
    * 鎖定和不鎖定文件和記錄(locks.c)。
    * 映射名字到索引節(jié)點(namei.c, open.c)。
    * 實現(xiàn)select( )函數(shù)(select . c)。
    * 提供各種信息(stat.c)。
    * 掛接和卸載文件系統(tǒng)(super.c)。
    * 調(diào)用可執(zhí)行代碼和轉(zhuǎn)存核心(exec.c)。
    * 裝入各種二進制格式(bin_fmt*.c)。
    VFS接口則由一系列相對高級的操作組成,這些操作由和文件系統(tǒng)無關(guān)的代碼調(diào)用,并且由不同的文件系統(tǒng)執(zhí)行。其中最主要的結(jié)構(gòu)有 inode_operations 和file_operations。file_system_type是系統(tǒng)內(nèi)核中指向真正文件系統(tǒng)的結(jié)構(gòu)。每掛接一次文件系統(tǒng),都將使用 file_system_type組成的數(shù)組。file_system_type組成的數(shù)組嵌入到了fs/filesystems.c中。相關(guān)文件系統(tǒng)的 read_super函數(shù)負責填充super_block結(jié)構(gòu)。
 
--------------------------------------------------------------------------------
 

源碼導(dǎo)讀
*Linux 如何維護它支持的文件系統(tǒng)中的文件
*描述了虛擬文件系統(tǒng)( Virtual File System VFS )
*解釋了 Linux 核心中真實的文件系統(tǒng)如何被支持
    Linux 的一個最重要的特點之一使它可以支持許多不同的文件系統(tǒng)。這讓它非常靈活,可以和許多其他操作系統(tǒng)共存。在寫作本章的時候, Linux 可一直支持15 種文件系統(tǒng): ext 、 ext2 、 xia 、 minix 、 umsdos 、 msdos 、vfat 、 proc 、 smb 、 ncp 、 iso9660 、 sysv 、 hpfs 、 affs 和 ufs ,而且不容置疑,隨著時間流逝,會加入更多的文件系統(tǒng)。
    在 Linux 中,象 Unix 一樣,系統(tǒng)可以使用的不同的文件系統(tǒng)不是通過設(shè)備標識符(例如驅(qū)動器編號或設(shè)備名稱)訪問,而是連接成一個單一的樹型的結(jié)構(gòu),用一個統(tǒng)一的單個實體表示文件系統(tǒng)。 Linux 在文件系統(tǒng)安裝的時候把它加到這個單一的文件系統(tǒng)樹上。所有的文件系統(tǒng),不管什么類型,都安裝在一個目錄,安裝的文件系統(tǒng)的文件掩蓋了這個目錄原來存在的內(nèi)容。這個目錄叫做安裝目錄或安裝點。當這個文件系統(tǒng)卸載的時候,安裝目錄自己的文件又可以顯現(xiàn)出來。
    當磁盤初始化的時候(比如用 fdisk ),利用一個分區(qū)結(jié)構(gòu)把物理磁盤劃分成一組邏輯分區(qū)。每一個分區(qū)可以放一個文件系統(tǒng),例如一個 EXT2 文件系統(tǒng)。文件系統(tǒng)在物理設(shè)備的塊上通過目錄、軟鏈接等把文件組織成邏輯的樹型結(jié)構(gòu)。可以包括文件系統(tǒng)的設(shè)備是塊設(shè)備。系統(tǒng)中的第一個 IDE 磁盤驅(qū)動器的第一個分區(qū),IDE 磁盤分區(qū) /dev/hda1 ,是一個塊設(shè)備。 Linux 文件系統(tǒng)把這些塊設(shè)備看成簡單的線性的塊的組合,不知道也不去關(guān)心底層的物理磁盤的尺寸。把對設(shè)備的特定的塊的讀的請求映射到對于設(shè)備有意義的術(shù)語:這個塊保存在硬盤上的磁道、扇區(qū)和柱面,這是每一個塊設(shè)備驅(qū)動程序的任務(wù)。一個文件系統(tǒng)不管它保存在什么設(shè)備上,都應(yīng)該用同樣的方式工作,有同樣的觀感。另外,使用 Linux 的文件系統(tǒng)
,是否這些不同的文件系統(tǒng)在不同的硬件控制器的控制下的不同的物理介質(zhì)上都是無關(guān)緊要的(至少對于系統(tǒng)用戶是這樣)。文件系統(tǒng)甚至可能不在本地系統(tǒng)上,它可能是通過網(wǎng)絡(luò)連接遠程安裝的。考慮以下的例子,一個 Linux 系統(tǒng)的根文件系統(tǒng)在一個 SCSI 磁盤上。
A E boot etc lib opt tmp usr
C F cdrom fd proc root var sbin
D bin dev home mnt lost+found
    不管是操作這些文件的用戶還是程序都不需要知道 /C 實際上是在系統(tǒng)的第一個 IDE 磁盤上的一個安裝的 VFAT 文件系統(tǒng)。本例中(實際是我家中的 Linux 系統(tǒng)), /E 是次 IDE 控制器上的 master IDE 磁盤。第一個 IDE 控制器是 PCI控制器,而第二個是 ISA 控制器,也控制著 IDE CDROM ,這些也都無關(guān)緊要。我可以用一個 modem 和 PPP 網(wǎng)絡(luò)協(xié)議撥號到我工作的網(wǎng)絡(luò),這時,我可以遠程安裝
我的 Alpha AXP Linux 系統(tǒng)的文件系統(tǒng)到 /mnt/remote 。
    文件系統(tǒng)中的文件包含了數(shù)據(jù)的集合:包含本章源的文件是一個 ASCII 文件,叫做 filesystems.tex 。一個文件系統(tǒng)不僅保存它包括的文件的數(shù)據(jù),也保存文件系統(tǒng)的結(jié)構(gòu)。它保存了 Linux 用戶和進程看到的所有的信息,例如文件、目錄、軟鏈接、文件保護信息等等。另外,它必須安全地保存這些信息,操作系統(tǒng)的基本的一致性依賴于它的文件系統(tǒng)。沒有人可以使用一個隨機丟失數(shù)據(jù)和文件的操作系統(tǒng)(不知道是否有,雖然我曾經(jīng)被擁有的律師比 Linux 開發(fā)者還多的操作系統(tǒng)傷害過)。
    Minix 是 Linux 的第一個文件系統(tǒng),有相當?shù)木窒?,性能比較差。它的文件名不能長于 14 個字符(這仍然比 8.3 文件名要好),最大的文集大小是 64M 字節(jié)。第一眼看去, 64M 字節(jié)好像足夠大,但是設(shè)置中等的數(shù)據(jù)庫需要更大的文件大小。第一個專為 Linux 設(shè)計的文件系統(tǒng),擴展文件系統(tǒng)或 EXT ( Extend File System ),在 1992 年 4 月引入,解決了許多問題,但是仍然感到性能低。所以, 1993 年,增加了擴展文件系統(tǒng)第二版,或 EXT2 。這種文件系統(tǒng)在本章稍后詳細描述。
    當 EXT 文件系統(tǒng)增加到 Linux 的時候進行了一個重要的開發(fā)。真實的文件系統(tǒng)通過一個接口層從操作系統(tǒng)和系統(tǒng)服務(wù)中分離出來,這個接口叫做虛擬文件系統(tǒng)或 VFS 。 VFS 允許 Linux 支持許多(通常是不同的)文件系統(tǒng),每一個都向VFS 表現(xiàn)一個通用的軟件接口。 Linux 文件系統(tǒng)的所有細節(jié)都通過軟件進行轉(zhuǎn)換,所以所有的文件系統(tǒng)對于 Linux 核心的其余部分和系統(tǒng)中運行的程序顯得一樣。 Linux 的虛擬文件系統(tǒng)層允許你同時透明地安裝許多不同的文件系統(tǒng)。
    Linux 虛擬文件系統(tǒng)的實現(xiàn)使得對于它的文件的訪問盡可能的快速和有效。它也必須保證文件和文件數(shù)據(jù)正確地存放。這兩個要求相互可能不平等。 Linux VFS 在安裝和使用每一個文件系統(tǒng)的時候都在內(nèi)存中高速緩存信息。在文件和目錄創(chuàng)建、寫和刪除的時候這些高速緩存的數(shù)據(jù)被改動,必須非常小心才能正確地更新文件系統(tǒng)。如果你能看到運行的核心中的文件系統(tǒng)的數(shù)據(jù)結(jié)構(gòu),你就能夠看到文件系統(tǒng)讀寫數(shù)據(jù)塊,描述正在訪問的文件和目錄的數(shù)據(jù)結(jié)構(gòu)會被創(chuàng)建和破壞,同時設(shè)備驅(qū)動程序會不停地運轉(zhuǎn),獲取和保存數(shù)據(jù)。這些高速緩存中最重要的是 BufferCache ,在文件系統(tǒng)訪問它們底層的塊設(shè)備的時候結(jié)合進來。當塊被訪問的時候它們被放到 Buffer Cache ,根據(jù)它們的狀態(tài)放在不同的隊列中。 Buffer Cache 不僅緩存數(shù)據(jù)緩沖區(qū),它也幫助管理塊設(shè)備驅(qū)動程序的異步接口。
The Second Extended File System (EXT2)
    EXT2 被發(fā)明( Remy Card )作為 Linux 一個可擴展和強大的文件系統(tǒng)。它至少在 Linux 社區(qū)中是最成功的文件系統(tǒng),是所有當前的 Linux 發(fā)布版的基礎(chǔ)。 EXT2 文件系統(tǒng),象所有多數(shù)文件系統(tǒng)一樣,建立在文件的數(shù)據(jù)存放在數(shù)據(jù)塊中的前提下。這些數(shù)據(jù)塊都是相同長度,雖然不同的 EXT2 文件系統(tǒng)的塊長度可以不同,但是對于一個特定的 EXT2 文件系統(tǒng),它的塊長度在創(chuàng)建的時候就確定了(使用
mke2fs )。每一個文件的長度都按照塊取整。如果塊大小是 1024 字節(jié),一個1025 字節(jié)的文件會占用兩個 1024 字節(jié)的塊。不幸的是這一意味著平均你每一個文件浪費半個塊。通常計算中你會用磁盤利用來交換 CPU 對于內(nèi)存的使用,這種情況下, Linux 象大多數(shù)操作系統(tǒng)一樣,為了較少 CPU 的負載,使用相對低效率的磁盤利用率來交換。不是文件系統(tǒng)中所有的塊都包含數(shù)據(jù),一些塊必須用于放置描述文件系統(tǒng)結(jié)構(gòu)的信息。 EXT2 用一個 inode 數(shù)據(jù)結(jié)構(gòu)描述系統(tǒng)中的每一個文件,定義了系統(tǒng)的拓撲結(jié)構(gòu)。一個 inode 描述了一個文件中的數(shù)據(jù)占用了哪些塊以及文件的訪問權(quán)限、文件的修改時間和文件的類型。 EXT2 文件系統(tǒng)中的每一個文件都用一個 inode 描述,而每一個 inode 都用一個獨一無二的數(shù)字標識。文件
系統(tǒng)的 inode 都放在一起,在 inode 表中。 EXT2 的目錄是簡單的特殊文件(它們也使用 inode 描述),包括它們目錄條目的 inode 的指針。
    只要提到文件系統(tǒng),塊設(shè)備都可以看作一系列能夠讀寫的塊。文件系統(tǒng)不需要關(guān)心自身要放在物理介質(zhì)的哪一個塊上,這是設(shè)備驅(qū)動程序的工作。當一個文件系統(tǒng)需要從包括它的塊設(shè)備上讀取信息或數(shù)據(jù)的時候,它請求對它支撐的設(shè)備驅(qū)動程序讀取整數(shù)數(shù)目的塊。 EXT2 文件系統(tǒng)把它占用的邏輯分區(qū)劃分成塊組( Block Group )。每一個組除了當作信息和數(shù)據(jù)塊來存放真實的文件和目錄之外,還復(fù)制對于文件系統(tǒng)一致性至關(guān)重要的信息。這種復(fù)制的信息對于發(fā)生災(zāi)難,文件系統(tǒng)需要恢復(fù)的時候是必要的。下面對于每一個塊組的內(nèi)容進行了詳細的描述。
The EXT2 Inode ( EXT2 I 節(jié)點)
    在 EXT2 文件系統(tǒng)中, I 節(jié)點是建設(shè)的基石:文件系統(tǒng)中的每一個文件和目錄都用一個且只用一個 inode 描述。每一個塊組的 EXT2 的 inode 都放在 inode 表中,還有一個BITMap,讓系統(tǒng)跟蹤分配和未分配的 I 節(jié)點。顯示了一個 EXT2 inode 的格式,在其他信息中,它包括一些域:
參見 include/linux/ext2_fs_i.h
    mode 包括兩組信息:這個 inode 描述了什么和用戶對于它的權(quán)限。對于EXT2 ,一個 inode 可以描述一個文件、目錄、符號鏈接、塊設(shè)備、字符設(shè)備或FIFO 。
    Owner Information 這個文件或目錄的數(shù)據(jù)的用戶和組標識符。這允許文件系統(tǒng)正確地進行文件訪問權(quán)限控制
    Size 文件的大小(字節(jié))
    Timestamps 這個 inode 創(chuàng)建的時間和它上次被修改的時間。
    Datablocks 指向這個 inode 描述的數(shù)據(jù)的塊的指針。最初的 12 個是指向這個 inode 描述的數(shù)據(jù)的物理塊,最后的 3 個指針包括更多級的間接的數(shù)據(jù)塊。例如,兩級的間接塊指針指向一個指向數(shù)據(jù)塊的塊指針的塊指針。的這意味著小于或等于 12 數(shù)據(jù)塊大小的文件比更大的文件的訪問更快。
    你應(yīng)該注意 EXT2 inode 可以描述特殊設(shè)備文件。這些不是真正的文件,程序可以用于訪問設(shè)備。 /dev 下所有的設(shè)備文件都是為了允許程序訪問 Linux 的設(shè)備。例如 mount 程序用它希望安裝的設(shè)備文件作為參數(shù)。
The EXT2 Superblock ( EXT2 超級塊)
    超級塊包括這個文件系統(tǒng)基本大小和形狀的描述。它里面的信息允許文件系統(tǒng)管理程序用于維護文件系統(tǒng)。通常文件系統(tǒng)安裝時只有塊組 0 中的超級塊被讀取,但是每一個塊組中都包含一個復(fù)制的拷貝,用于系統(tǒng)崩潰的時候。除了其他一些信息,它包括:
參見 include/linux/ext2_fs_sb.h
Magic Number 允許安裝軟件檢查這是否是一個 EXT2 文件系統(tǒng)的超級塊。對于當前版本的 EXT2 是 0xEF53 。
    Revision Level major 和 minor 修訂級別允許安裝代碼確定這個文件系統(tǒng)是否支持只有在這種文件系統(tǒng)特定修訂下才有的特性。這也是特性兼容域,幫助安裝代碼確定哪些新的特征可以安全地使用在這個文件系統(tǒng)上。
Mount Count and Maximum Mount Count 這些一起允許系統(tǒng)確定這個文件系統(tǒng)是否需要完全檢查。每一次文件系統(tǒng)安裝的時候 mount count 增加,當它等于maximum mount count 的時候,會顯示告警信息“ maximal mount count reached , running e2fsck is recommended ”。
Block Group Number 存放這個超級塊拷貝的塊組編號。
Block Size 這個文件系統(tǒng)的塊的字節(jié)大小,例如 1024 字節(jié)。
Blocks per Group 組中的塊數(shù)目。象塊大小一樣,這是文件系統(tǒng)創(chuàng)建的時候確定的。
Free Blocks 文件系統(tǒng)中空閑塊的數(shù)目
Free Inodes 文件系統(tǒng)中空閑的 inode
First Inode 這是系統(tǒng)中第一個 inode 的編號。一個 EXT2 根文件系統(tǒng)中的第一個 inode 是‘ / ’目錄的目錄條目

The EXT2 Group Descriptor ( EXT2 組描述符)
每一個塊組都有一個數(shù)據(jù)結(jié)構(gòu)描述。象超級塊,所有得虧組的組描述符在每一塊組都進行復(fù)制。每一個組描述符包括以下信息:
參見 include/linux/ext2_fs.h ext2_group_desc
Blocks Bitmap 這個塊組的塊分配位圖的塊編號,用在塊的分配和回收過程中
Inode Bitmap 這個塊組的 inode 位圖的塊編號。用在 inode 的分配和回收過程中。
Inode Table 這個塊組的 inode table 的起始塊的塊編號。每一個 EXT2 inode數(shù)據(jù)結(jié)構(gòu)表示的 inode 在下面描述
Free blocks count , Free Inodes count , Used directory count
    組描述符依次排列,它們一起組成了組描述符表( group descriptor
table )。每一個塊組包括塊組描述符表和它的超級塊的完整拷貝。只有第一個拷貝(在塊組 0 )實際被 EXT2 文件系統(tǒng)使用。其他拷貝,象超級塊的其他拷貝一樣,只有在主拷貝損壞的時候才使用。
EXT2 Directories ( EXT2 目錄)
    在 EXT2 文件系統(tǒng)中,目錄是特殊文件,用來創(chuàng)建和存放對于文件系統(tǒng)中的文件的訪問路徑。圖 9.3 顯示了內(nèi)存中一個目錄條目的布局。一個目錄文件,是一個目錄條目的列表,每一個目錄條目包括以下信息:
參見 include/linux/ext2_fs.h ext2_dir_entry
這個目錄條目的 inode 。這是個放在塊組的 inode 表中的 inode 數(shù)組的索引。
Name length 這個目錄條目的字節(jié)長度
Name 這個目錄條目的名字
每一個目錄中的前兩個條目總是標準的“ . ”和“ .. ” , 分別表示“本目錄”和“父目錄”。
9.1.5 Finding a File in a EXT2 File System (在一個 EXT2 文件系統(tǒng)中查找一個文件)
    Linux 的文件名和所有的 Unix 文件名的格式一樣。它是一系列目錄名,用“ / ”分隔,以文件名結(jié)尾。一個文件名稱的例子是 /home/rusling/.cshrc ,其中 /home 和 /rusling 是目錄名,文件名是 .cshrc 。象其它 Unix 系統(tǒng)一樣, Linux 不關(guān)心文件名本身的格式:它可以任意長度,由可打印字符組成。為了在EXT2 文件系統(tǒng)中找到代表這個文件的 inode ,系統(tǒng)必須逐個解析目錄中的文件
名直到得到這個文件。
    我們需要的第一個 inode 是這個文件系統(tǒng)的根的 inode 。我們通過文件系統(tǒng)的超級塊找到它的編號。為了讀取一個 EXT2 inode 我們必須在適當?shù)膲K組中的inode 表中查找。舉例,如果根的 inode 編號是 42 ,那么我們需要塊組 0 中的 inode 表中的第 42 個 inode 。 Root inode 是一個 EXT2 目錄,換句話說root inode 的模式描述它是一個目錄,它的數(shù)據(jù)塊包括 EXT2 目錄條目。
    Home 是這些目錄條目之一,這個目錄條目給了我們描述 /home 目錄的 inode 編號。我們必須讀取這個目錄(首先讀取它的 inode ,然后讀取從這個 inode描述的數(shù)據(jù)塊讀取目錄條目),查找 rusling 條目,給出描述 /home/rusling 目錄的 inode 編號。最后,我們讀取描述 /home/rusling 目錄的 inode 指向的目錄條目,找到 .cshrc 文件的 inode 編號,這樣,我們得到了包括文件里信息的
數(shù)據(jù)塊。
Changing the size of a File in an EXT2 File System (在 EXT2 文件系統(tǒng)中改變一個文件的大?。?/div>
    文件系統(tǒng)的一個常見問題是它趨于更多碎片。包含文件數(shù)據(jù)的塊分布在整個文件系統(tǒng),數(shù)據(jù)塊越分散,對于文件數(shù)據(jù)塊的順序訪問越?jīng)]有效率。 EXT2 文件系統(tǒng)試圖克服這種情況,它分配給一個文件的新塊物理上和它的當前數(shù)據(jù)塊接近或者至少和它的當前數(shù)據(jù)塊在一個塊組里面。只有這個失敗了它才分配其它塊組中的數(shù)據(jù)塊。
    無論何時一個進程試圖象一個文件寫入數(shù)據(jù), Linux 文件系統(tǒng)檢查數(shù)據(jù)是否會超出文件最后分配塊的結(jié)尾。如果是,它必須為這個文件分配一個新的數(shù)據(jù)塊。直到這個分配完成,該進程無法運行,它必須等待文件系統(tǒng)分配新的數(shù)據(jù)塊并把剩下的數(shù)據(jù)寫入,然后才能繼續(xù)。 EXT2 塊分配例程所要做的第一個事情是鎖定這個文件系統(tǒng)的 EXT2 超級塊。分配和釋放塊需要改變超級塊中的域, Linux 文件系統(tǒng)不能允許多于一個進程同一時間都進行改變。如果另一個進程需要分配更多的數(shù)據(jù)塊,它必須等待,直到這個進程完成。等待超級塊的進程被掛起,不能運行,直到超級塊的控制權(quán)被它的當前用戶釋放。對于超級塊的訪問的授權(quán)基于一個先來先服務(wù)的基礎(chǔ)( first come first serve ),一旦一個進程擁有了超級塊的控制,它一直維持控制權(quán)到它完成。鎖定超級塊之后,進程檢查文件系統(tǒng)是否有足夠的空閑塊。如果沒有足夠的空閑塊,分配更多的嘗試會失敗,進程交出這個文件系統(tǒng)超級塊的控制權(quán)。
    如果文件系統(tǒng)中有足夠的空閑塊,進程會試圖分配一塊。如果這個 EXT2 文件系統(tǒng)已經(jīng)建立了預(yù)分配的數(shù)據(jù)塊,我們就可以取用。預(yù)分配的塊實際上并不存在,它們只是分配塊的位圖中的保留塊。 VFS inode 用兩個 EXT2 特有的域表示我們試圖分配新數(shù)據(jù)塊的文件: prealloc_block and prealloc_count ,分別是預(yù)分配塊中第一塊的編號和預(yù)分配塊的數(shù)目。如果沒有預(yù)分配塊或者預(yù)分配被禁止,EXT2 文件系統(tǒng)必須分配一個新的數(shù)據(jù)塊。 EXT2 文件系統(tǒng)首先查看文件最后一個數(shù)據(jù)塊之后數(shù)據(jù)塊是否空閑。邏輯上,這是可分配的效率最高的塊,因為可以讓順序訪問更快。如果這個塊不是空閑,繼續(xù)查找,在隨后的 64 塊中找理想的數(shù)據(jù)塊。這個塊,雖然不是最理想,但是至少和文件的其它數(shù)據(jù)塊相當接近,在一個塊組中。
參見 fs/ext2/balloc.c ext2_new_block()
    如果這些塊都沒有空閑的,進程開始順序查看所有其它塊組直到它找到空閑的塊。塊分配代碼在這些塊組中查找 8 個空閑數(shù)據(jù)塊的簇。如果無法一次找到 8 個,它會降低要求。如果希望進行塊預(yù)分配,并允許,它會相應(yīng)地更新prealloc_block 和 prealloc_count 。
    不管在哪里找到了空閑的數(shù)據(jù)塊,塊分配代碼會更新塊組的塊位圖,并從buffer cache 中分配一個數(shù)據(jù)緩沖區(qū)。這個數(shù)據(jù)緩沖區(qū)使用支撐文件系統(tǒng)的設(shè)備標識符和分配塊的塊編號來唯一標識。緩沖區(qū)中的數(shù)據(jù)被置為 0 ,緩沖區(qū)標記為“ dirty ”表示它的內(nèi)容還沒有寫到物理磁盤上。最后,超級塊本身也標記位“ dirty ”,顯示它進行了改動,然后它的鎖被釋放。如果有進程在等待超級塊,那么隊列中第一個進程就允許運行,得到超級塊的排它控制權(quán),進行它的文件操作。進程的數(shù)據(jù)寫到新的數(shù)據(jù)塊,如果數(shù)據(jù)塊填滿,整個過程重復(fù)進行,再分配其它數(shù)據(jù)塊
The Virtual File System (虛擬文件系統(tǒng) VFS )
    Linux 核心的虛擬文件系統(tǒng)和它的真實的文件系統(tǒng)之間的關(guān)系。虛擬文件系統(tǒng)必須管理任何時間安裝的所有的不同的文件系統(tǒng)。為此它管理描述整個文件系統(tǒng)(虛擬)和各個真實的、安裝的文件系統(tǒng)的數(shù)據(jù)結(jié)構(gòu)。
    相當混亂的是, VFS 也使用術(shù)語超級塊和 inode 來描述系統(tǒng)的文件,和EXT2 文件系統(tǒng)使用的超級塊和 inode 的方式非常相似。象 EXT2 的 inode ,VFS 的 inode 描述系統(tǒng)中的文件和目錄:虛擬文件系統(tǒng)的內(nèi)容和拓撲結(jié)構(gòu)。從現(xiàn)在開始,為了避免混淆,我會用 VFS inode 和 VFS 超級塊以便同 EXT2 的 inode和超級塊區(qū)分開來。
參見 fs/*
    當每一個文件系統(tǒng)初始化的時候,它自身向 VFS 登記。這發(fā)生在系統(tǒng)啟動操作系統(tǒng)初始化自身的時候。真實的文件系統(tǒng)自身建立在內(nèi)核中或者是作為可加載的模塊。文件系統(tǒng)模塊在系統(tǒng)需要的時候加載,所以,如果 VFAT 文件系統(tǒng)用核心模塊的方式實現(xiàn),那么它只有在一個 VFAT 文件系統(tǒng)安裝的時候才加載。當一個塊設(shè)備文件系統(tǒng)安裝的時候,(包括 root 文件系統(tǒng)), VFS 必須讀取它的超級塊。
每一個文件系統(tǒng)類型的超級塊的讀取例程必須找出這個文件系統(tǒng)的拓撲結(jié)構(gòu),并把這些信息映射到一個 VFS 超級塊的數(shù)據(jù)結(jié)構(gòu)上。 VFS 保存系統(tǒng)中安裝的文件系統(tǒng)的列表和它們的 VFS 超級塊列表。每一個 VFS 超級塊包括了文件系統(tǒng)的信息和完成特定功能的例程的指針。例如,表示一個安裝的 EXT2 文件系統(tǒng)的超級塊包括一個 EXT2 相關(guān)的 inode 的讀取例程的指針。這個 EXT2 inode 讀取例程,象所有
的和文件系統(tǒng)相關(guān)的 inode 讀取例程一樣,填充 VFS inode 的域。每一個 VFS超級塊包括文件系統(tǒng)中的一個 VFS inode 的指針。對于 root 文件系統(tǒng),這是表示“ / ”目錄的 inode 。這種信息映射對于 EXT2 文件系統(tǒng)相當高效,但是對于其他文件系統(tǒng)相對效率較低。

    當系統(tǒng)的進程訪問目錄和文件的時候,調(diào)用系統(tǒng)例程,游歷系統(tǒng)中的 VFSinode 。例如再一個目錄中輸入 ls 或者 cat 一個文件,讓 VFS 查找代表這個文件系統(tǒng)的 VFS inode 。映為系統(tǒng)中的每一個文件和目錄都用一個 VFS inode 代表,所以一些 inode 會被重復(fù)訪問。這些 inode 保存在 inode cache ,這讓對它們的訪問更快。如果一個 inode 不在 inode cache 中,那么必須調(diào)用一個和文件系統(tǒng)相關(guān)的例程來讀取適當?shù)?inode 。讀取這個 inode 的動作讓它被放到了inode cache ,以后對這個 inode 的訪問會讓它保留在 cache 中。較少使用的VFS inode 會從這個高速緩存中刪除。
參見 fs/inode.c
    所有的 Linux 文件系統(tǒng)使用一個共同的 buffer cache 來緩存底層的設(shè)備的數(shù)據(jù)緩沖區(qū),這樣可以加速對于存放文件系統(tǒng)的物理設(shè)備的訪問,從而加快對文件系統(tǒng)的訪問。這個 buffer cache 獨立于文件系統(tǒng),集成在 Linux 核心分配、讀和寫數(shù)據(jù)緩沖區(qū)的機制中。讓 Linux 文件系統(tǒng)獨立于底層的介質(zhì)和支撐的設(shè)備驅(qū)動程序有特殊的好處。所有的塊結(jié)構(gòu)的設(shè)備向 Linux 核心登記,并表現(xiàn)為一個統(tǒng)一的,以塊為基礎(chǔ)的,通常是異步的接口。甚至相對復(fù)雜的塊設(shè)備比如 SCSI 設(shè)備也是這樣。當真實的文件系統(tǒng)從底層的物理磁盤讀取數(shù)據(jù)的,引起塊設(shè)備驅(qū)動程序從它們控制的設(shè)備上讀取物理塊。在這個塊設(shè)備接口中集成了 buffer cache 。當文件系統(tǒng)讀取了塊的時候,它們被存放到了所有的文件系統(tǒng)和 Linux 核心共享的
全局的 buffer cache 中。其中的 buffer (緩沖區(qū))用它們的塊編號和被讀取設(shè)備的一個唯一的標識符來標記。所以,如果相同的數(shù)據(jù)經(jīng)常需要,它會從buffer cache 中讀取,而不是從磁盤讀?。〞ㄙM更多時間)。一些設(shè)備支持超前讀( read ahead ),數(shù)據(jù)塊會預(yù)先讀取,以備以后可能的讀取。
參見 fs/buffer.c
    VFS 也保存了一個目錄查找的緩存,所以一個常用的目錄的 inode 可以快速找到。作為一個試驗,試著對于你最近沒有列表的目錄列表。第一次你列表的時候,你會注意到短暫的停頓,當時第二次你列表的時候,結(jié)果會立即出來。目錄緩存本身不存儲目錄里的 inode ,這是 inode cache 負責的,目錄緩存只是存儲目錄項目全稱和它們的 inode 編號。
參見 fs/dcache.c
The VFS Superblock ( VFS 超級塊)
每一個安裝的文件系統(tǒng)都用 VFS 超級塊表示。除了其它信息, VFS 超級塊包括:

參見 include/linux/fs.h
Device 這是包含文件系統(tǒng)的塊設(shè)備的設(shè)備標識符。例如, /dev/hda1 ,系統(tǒng)中的第一個 IDE 磁盤,設(shè)備標識符是 0x301
Inode pointers 其中的 mounted inode 指針指向該文件系統(tǒng)的第一個 inode 。
Covered inode 指針指向文件系統(tǒng)安裝到的目錄的 inode 。對于 root 文件系統(tǒng),它的 VFS 超級塊中沒有 covered 指針。
Blocksize 文件系統(tǒng)塊的字節(jié)大小,例如 1024 字節(jié)。
Superblock operations 指向一組本文件系統(tǒng)超級塊例程的指針。除了其他類型之外, VFS 使用這些例程讀寫 inode 和超級塊
File System type 指向這個安裝的文件系統(tǒng)的 file_system_type 數(shù)據(jù)結(jié)構(gòu)的一個指針
File System Specific 指向這個文件系統(tǒng)需要的信息的一個指針

The VFS Inode
象 EXT2 文件系統(tǒng), VFS 中每一個文件、目錄等等都用一個且只用一個 VFS inode 代表。每一個 VFS inode 中的信息使用文件系統(tǒng)相關(guān)的例程從底層的文件系統(tǒng)中獲取。 VFS inode 只在核心的內(nèi)存中存在,只要對系統(tǒng)有用,就一直保存在 VFS inode cache 中。除了其它信息, VFS inode 包括一些域:
參見 include/linux/fs.h
device 存放這個文件(或這個 VFS inode 代表的其它實體)的設(shè)備的設(shè)備標識符。
Inode nunber 這個 inode 的編號,在這個文件系統(tǒng)中唯一。 Device 和 inode number 的組合在整個虛擬文件系統(tǒng)中是唯一的。
Mode 象 EXT2 一樣,這個域描述這個 VFS inode 代表的東西和對它的訪問權(quán)限。
User ids 屬主標識符
Times 創(chuàng)建、修改和寫的時間
Block size 這個文件的塊的字節(jié)大小,例如 1024 字節(jié)
Inode operations 指向一組例程地址的指針。這些例程和文件系統(tǒng)相關(guān),執(zhí)行對于這個 inode 的操作,例如 truncate 這個 inode 代表的文件
Count 系統(tǒng)組件當前使用這個 VFS inode 的數(shù)目。 Count 0 意味著這個 inode是空閑,可以廢棄或者重用。
Lock 這個域用于鎖定這個 VFS inode 。例如當從文件系統(tǒng)讀取它的時候
Dirty 顯示這個 VFS inode 是否被寫過,如果這樣,底層的文件系統(tǒng)需要更新。

File system specific information
Registering the File Systems (登記文件系統(tǒng))

    當你建立 Linux 核心的時候,你會被提問是否需要每一個支持的文件系統(tǒng)。當核心建立的時候,文件系統(tǒng)初始化代碼包括對于所有內(nèi)建的文件系統(tǒng)的初始化例程的調(diào)用。 Linux 文件系統(tǒng)也可以建立成為模塊,這種情況下,它們可以在需要的時候加載或者手工使用 insmod 加載。當家在一個文件系統(tǒng)模塊的時候,它自身向核心登記,當卸載的時候,它就注銷。每一個文件系統(tǒng)的初始化例程都向虛擬文件系統(tǒng)注冊自身,并用一個 file_system_type 數(shù)據(jù)結(jié)構(gòu)代表,這里面包括文件系統(tǒng)的名稱和一個指向它的 VFS 超級塊的讀取例程的指針。file_system_type 數(shù)據(jù)結(jié)構(gòu)被放到了由 file_systems 指針指向的一個列表中。每一個 file_system_type 數(shù)據(jù)結(jié)構(gòu)包括以下信息:
參見 fs/filesystems.c sys_setup()
參見 include/linux/fs.h file_system_type
Superblock read routine 在這個文件系統(tǒng)的一個實例安裝的時候,由 VFS 調(diào)用這個例程
File Systme name 文件系統(tǒng)的名稱,例如 ext2
Device needed 是否這個文件系統(tǒng)需要一個設(shè)備支持?并非所有的文件系統(tǒng)需要一個設(shè)備來存放。例如 /proc 文件系統(tǒng),不需要一個塊設(shè)備
你可以檢查 /proc/filesystems 來查看登記了哪些文件系統(tǒng),例如:
ext2
nodev proc
iso9660
Mounting a File System (安裝一個文件系統(tǒng))
    當超級用戶試圖安裝一個文件系統(tǒng)的時候, Linux 核心必須首先驗證系統(tǒng)調(diào)用中傳遞的參數(shù)。雖然 mount 可以執(zhí)行一些基本的檢查,但是它不知道這個核心建立是可以支持的文件系統(tǒng)或者提議的安裝點是否存在??紤]以下的 mount 命令:
$ mount –t iso9660 –o ro /dev/cdrom /mnt/cdrom
    這個 mount 命令會傳遞給核心三部分信息:文件系統(tǒng)的名稱、包括這個文件系統(tǒng)的物理塊設(shè)備和這個新的文件系統(tǒng)要安裝在現(xiàn)存的文件系統(tǒng)拓撲結(jié)構(gòu)中的哪一個地方。
    虛擬文件系統(tǒng)要做的第一件事情是找到這個文件系統(tǒng)。它首先查看file_systems 指向的列表中的每一個 file_system_type 數(shù)據(jù)結(jié)構(gòu),查看所有已知的文件系統(tǒng)。如果它找到了一個匹配的名稱,它就直到這個核心支持這個文件系統(tǒng)類型,并得到了文件系統(tǒng)相關(guān)例程的地址,去讀取這個文件系統(tǒng)的超級塊。如果它不能找到一個匹配的文件系統(tǒng)名稱,如果核心內(nèi)建了可以支持核心模塊按需加載,就可以繼續(xù)。這種情況下,在繼續(xù)之前,核心會請求核心守護進程加載適當?shù)奈募到y(tǒng)模塊。
參見 fs/super.c do_mount()
參見 fs/super.c get_fs_type()

    第二步,如果 mount 傳遞的物理設(shè)備還沒有安裝,必須找到即將成為新的文件系統(tǒng)的安裝點的目錄的 VFS inode 。這個 VFS inode 可能在 inode cache 或者必須從支撐這個安裝點的文件系統(tǒng)的塊設(shè)備上讀取。一旦找到了這個 inode ,就檢查它是否是一個目錄,而且沒有其他文件系統(tǒng)安裝在那里。同一個目錄不能用作多于一個文件系統(tǒng)的安裝點。
    這時,這個 VFS 安裝代碼必須分配以一個 VFS 超級塊并傳遞安裝信息給這個文件系統(tǒng)的超級塊讀取例程。系統(tǒng)所有的 VFS 超級塊都保存在 super_block 數(shù)據(jù)結(jié)構(gòu)組成的 super_blocks 向量表中,必須為這次安裝分配一個結(jié)構(gòu)。超級塊讀取例程必須根據(jù)它從物理設(shè)備讀取得信息填充 VFS 超級塊的域。對于 EXT2 文件系統(tǒng)而言,這種信息的映射或者轉(zhuǎn)換相當容易,它只需要讀取 EXT2 的超級塊并填到 VFS 超級塊。對于其他文件系統(tǒng),例如 MS DOS 文件系統(tǒng),并不是這么簡單的任務(wù)。不管是什么文件系統(tǒng),填充 VFS 超級塊意味著必須從支持它的塊設(shè)備讀取描述該文件系統(tǒng)的信息。如果塊設(shè)備不能讀取或者它不包含這種類型的文件系統(tǒng),mount 命令會失敗。
    每一個安裝的文件系統(tǒng)用一個 vfsmount 數(shù)據(jù)結(jié)構(gòu)描述。它們在 vfsmntlist 指向的一個列表中排隊。另一個指針, vfsmnttail 指向列表中最后一個條目,而 mru_vfsmnt 指針指向最近使用的文件系統(tǒng)。每一個 vfsmount 結(jié)構(gòu)包括存放這個文件系統(tǒng)的塊設(shè)備的設(shè)備編號,文件系統(tǒng)安裝的目錄和一個指向這個文件系統(tǒng)安裝時所分配的 VFS 超級塊的指針。 VFS 超級塊指向這一類型的文件系統(tǒng)的file_system_type 數(shù)據(jù)結(jié)構(gòu)和這個文件系統(tǒng)的 root inode 。這個 inode在這個文件系統(tǒng)加載過程中一直駐留在 VFS inode cache 中。
參見 fs/super.c add_vfsmnt()
Finding a File in the Virtual File System (在虛擬文件系統(tǒng)中查找一個文件)
    為了找到一個文件在虛擬文件系統(tǒng)中的 VFS inode , VFS 必須依次名稱,一次一個目錄,找到中間的每一個的目錄的 VFS inode 。每一個目錄查找都要調(diào)用和文件系統(tǒng)相關(guān)的查找例程(地址放在代表父目錄的 VFS inode 中)。因為在文件系統(tǒng)的 VFS 超級塊中總是有文件系統(tǒng)的 root inode ,并在超級塊中用指針指示,所以整個過程可以繼續(xù)。每一次查找真實文件系統(tǒng)中的 inode 的時候,都要檢查這個目錄的目錄緩存。如果目錄緩存中沒有這個條目,真實文件系統(tǒng)要么從底層的文件系統(tǒng)要么從 inode cache 中獲得 VFS inode 。
Unmounting a File System (卸載一個文件系統(tǒng))
    我的工作手冊通常把裝配描述成為拆卸的反過程,但是對于卸載文件系統(tǒng)有些不同。如果系統(tǒng)有東西在使用文件系統(tǒng)的一個文件,那么這個文件系統(tǒng)就不能被卸載。例如,如果一個進程在使用 /mnt/cdrom 目錄或它的子目錄,你就不能卸載/mnt/cdrom 。如果有東西在使用要卸載的文件系統(tǒng),那么它的 VFS inode 會在VFS inode cache 中。卸載代碼檢查整個 inode 列表,查找屬于這個文件系統(tǒng)所占用的設(shè)備的 inode 。如果這個安裝的文件系統(tǒng)的 VFS 超級塊是 dirty ,就是它被修改過了,那么它必須被寫回到磁盤上的文件系統(tǒng)。一旦它寫了磁盤,這個VFS 超級塊占用的內(nèi)存就被返回到核心的空閑內(nèi)存池中。最后,這個安裝的vmsmount 數(shù)據(jù)結(jié)構(gòu)也從 vfsmntlist 中刪除并釋放。
參見 fs/super.c do_umount()
參見 fs/super.c remove_vfsmnt()
The VFS Inode Cache
當游歷安裝的文件系統(tǒng)的時候,它們的 VFS inode 不斷地被讀取,有時是寫入。虛擬文件系統(tǒng)維護一個 inode cache ,用于加速對于所有安裝的文件系統(tǒng)的訪問。每一次從 inode cache 讀出一個 VFS inode ,系統(tǒng)就可以省去對于物理設(shè)備的訪問。
參見 fs/inode.c
    VFS inode cache 用散列表( hash table )的方式實現(xiàn),條目是指針,指向既有同樣 hash value 的 VFS inode 列表。一個 inode 的 hash value 從它的inode 編號和包括這個文件系統(tǒng)的底層的物理設(shè)備的設(shè)備編號中計算出來。不論何時虛擬文件系統(tǒng)需要訪問一個 inode ,它首先查看 VFS inode cache 。為了在inode hash table 中查找一個 inode ,系統(tǒng)首先計算它的 hash value ,然后用它作為 inode hash table 的索引。這樣得到了具有相同 hash value 的 inode的列表的指針。然后它一次讀取所有的 inode 直到它找到和它要找的 inode 具有相同的 inode 編號和相同的設(shè)備標識符的 inode 為止。
    如果可以在 cache 中找到這個 inode ,它的 count 就增加,表示它有了另一個用戶,文件系統(tǒng)的訪問繼續(xù)進行。否則必須找到一個空閑的 VFS inode 讓文件系統(tǒng)把 inode 讀入到內(nèi)存。如何得到一個空閑的 inode , VFS 有一系列選擇。如果系統(tǒng)可以分配更多的 VFS inode ,它就這樣做:它分配核心頁并把它們分成新的、空閑的 inode ,放到 inode 列表中。系統(tǒng)中所有的 VFS inode 除了在 inode hash table 中之外也在一個由 first_inode 指向的列表。如果系統(tǒng)已經(jīng)擁有了它允許有的所有的 inode ,它必須找到一個可以重用的 inode 。好的候選是哪些使用量( count )是 0 的 inode :這表示系統(tǒng)當前沒有使用它們。真正重要的 VFS inode ,例如文件系統(tǒng)的 root inode ,已經(jīng)有了一個大于 0 的使用量,所以永遠不會選做重用。一旦定位到一個重用的候選,它就被清除。這個 VFS
inode 可能是臟的,這時系統(tǒng)必須等待它被解鎖然后才能繼續(xù)。在重用之前這個 VFS inode 的候選必須被清除。
    雖然找到了一個新的 VFS inode ,還必須調(diào)用一個和文件系統(tǒng)相關(guān)的例程,用從底層的真正的文件系統(tǒng)中毒取得信息填充這個 inode 。當它填充的時候,這個新的 VFS inode 的使用量為 1 ,并被鎖定,所以在它填入了有效的信息之前除了它沒有其它進程可以訪問。
    為了得到它實際需要的 VFS inode ,文件系統(tǒng)可能需要訪問其它一些inode 。這發(fā)生在你讀取一個目錄的時候:只有最終目錄的 inode 是需要的,但是中間目錄的 inode 也必須讀取。當 VFS inode cache 使用過程并填滿時,較少使用的 inode 會被廢棄,較多使用的 inode 會保留在高速緩存中。

The Directory Cache (目錄緩存)
    為了加速對于常用目錄的訪問, VFS 維護了目錄條目的一個高速緩存。當真正的文件系統(tǒng)查找目錄的時候,這些目錄的細節(jié)就被增加到了目錄緩存中。下一次查找同一個目錄的時候,例如列表或打開里邊的文件,就可以在目錄緩存中找到。只有短的目錄條目(最多 15 字符)被緩存,不過這是合理的,因為較短的目錄名稱是最常用的。例如:當 X 服務(wù)器啟動的時候, /usr/X11R6/bin 非常頻繁地被訪問。
參見 fs/dcache.c
    目錄緩存中包含一個 hash table ,每一個條目都指向一個具有相同的hash value 的目錄緩存條目的列表。 Hash 函數(shù)使用存放這個文件系統(tǒng)的設(shè)備的設(shè)備編號和目錄的名稱來計算在 hash table 中的偏移量或索引。它允許快速找到緩存的目錄條目。如果一個緩存在查找的時候花費時間太長,或根本找不到,這樣的緩存是沒有用的。
    為了保持這些 cache 有效和最新, VFS 保存了一個最近最少使用( LRU )目錄緩存條目的列表。當一個目錄條目第一次被放到了緩存,就是當它第一次被查找的時候,它被加到了第一級 LRU 列表的最后。對于充滿的 cache ,這會移去LRU 列表前面存在的條目。當這個目錄條目再一次被訪問的時候,它被移到了第二個 LRU cache 列表的最后。同樣,這一次它移去了第二級 LRU cache 列表前面的二級緩存目錄條目。這樣從一級和二級 LRU 列表中移去目錄條目是沒有問題的。這些條目之所以在列表的前面只是因為它們最近沒有被訪問。如果被訪問,它們會在列表的最后。在二級 LRU 緩存列表中的條目比在一級 LRU 緩存列表中的條目更加安全。因為這些條目不僅被查找而且曾經(jīng)重復(fù)引用。

The Buffer Cache

    當使用安裝的文件系統(tǒng)的時候,它們會對塊設(shè)備產(chǎn)生大量的讀寫數(shù)據(jù)塊的請求所有的塊數(shù)據(jù)讀寫的請求都通過標準的核心例程調(diào)用,以 buffer_head 數(shù)據(jù)結(jié)構(gòu)的形式傳遞給設(shè)備驅(qū)動程序。這些數(shù)據(jù)結(jié)構(gòu)給出了設(shè)備驅(qū)動程序需要的所有信息:設(shè)備標識符唯一標識了設(shè)備,塊編號告訴了驅(qū)動程序讀去哪一塊。所有的塊設(shè)備被看成同樣大小的塊的線性組合。為了加速對于物理塊設(shè)備的訪問, Linux 維護了一個塊緩區(qū)的緩存。系統(tǒng)中所有的塊緩沖區(qū)動保存在這個 buffer cache ,甚至包括那些新的、未使用的緩沖區(qū)。這個緩存區(qū)被所有的物理塊設(shè)備共享:任何時候緩存區(qū)中都有許多塊緩沖區(qū),可以屬于任何一個系統(tǒng)塊設(shè)備,通常具有不同的狀態(tài)。如果在 buffer cache 中有有效的數(shù)據(jù),這就可以節(jié)省系統(tǒng)對于物理設(shè)備的訪
問。任何用于從 / 向塊設(shè)備讀取 / 寫入數(shù)據(jù)的塊緩沖區(qū)都進入這個 buffercache 。隨著時間的推移,它可能從這個緩存區(qū)中刪除,為其它更需要的緩沖區(qū)讓出空間,或者如果它經(jīng)常被訪問,就可能一直留在緩存區(qū)中。
    這個緩存區(qū)中的塊緩沖區(qū)用這個緩沖區(qū)所屬的設(shè)備標識符和塊編號唯一標識。這個 buffer cache 由兩個功能部分組成。第一部分是空閑的塊緩沖區(qū)列表。每一個同樣大小的緩沖區(qū)(系統(tǒng)可以支持的)一個列表。系統(tǒng)的空閑的塊緩沖區(qū)當?shù)谝淮蝿?chuàng)建或者被廢棄的時候就在這些列表中排隊。當前支持的緩沖區(qū)大小是 512 、 1024 、 2048 、 4096 和 8192 字節(jié)。第二個功能部分是緩存區(qū)( cache )本身。這是一個 hash table ,是一個指針的向量表,用于鏈接具有相同 hashindex 的 buffer 。 Hash index 從數(shù)據(jù)塊所屬的設(shè)備標識符和塊編號產(chǎn)生出來。圖 9.7 顯示了這個 hash table 和一些條目。塊緩沖區(qū)要么在空閑列表之一,要么在 buffer cache 中。當它們在 buffer cache 的時候,它們也在 LRU 列表中排隊。每一個緩沖區(qū)類型一個 LRU 列表,系統(tǒng)使用這些類型在一種類型的緩沖區(qū)上執(zhí)行操作。例如,把有新數(shù)據(jù)的緩沖區(qū)寫到磁盤上。緩沖區(qū)的類型反映了它的狀態(tài), Linux 當前支持以下類型:
clean 未使用,新的緩沖區(qū)( buffer )
locked 鎖定的緩沖區(qū),等待被寫入
dirty 臟的緩沖區(qū)。包含新的有效的數(shù)據(jù),將被寫到磁盤,但是直到現(xiàn)在還沒有調(diào)度到寫
shared 共享的緩沖區(qū)
unshared 曾經(jīng)共享的緩沖區(qū),但是現(xiàn)在沒有共享
    不論何時文件系統(tǒng)需要從它的底層的物理設(shè)備讀取一個緩沖區(qū)的時候,它都試圖從 buffer cache 中得到一個塊。如果它不能從 buffer cache 中得到一個緩沖區(qū),它就從適當大小的空閑列表中取出一個干凈的緩沖區(qū),這個新的緩沖區(qū)會進入到 buffer cache 中。如果它需要的緩沖區(qū)已經(jīng)在 buffer cache 中,那么它可能是也可能不是最新。如果它不是最新,或者它是一個新的塊緩沖區(qū),文件系統(tǒng)必須請求設(shè)備驅(qū)動程序從磁盤上讀取適當?shù)臄?shù)據(jù)塊。
    象所有的高速緩存一樣, buffer cache 必須被維護,這樣它才能有效地運行,并在使用 buffer cache 的塊設(shè)備之間公平地分配緩存條目。 Linux 使用核心守護進程 bdflush 在這個緩存區(qū)上執(zhí)行大量的整理工作,不過另一些是在使用緩存區(qū)的過程中自動進行的。
9.3.1 The bdflush Kernel Daemon (核心守護進程 bdflsuh )
    核心守護進程 bdflush 是一個簡單的核心守護進程,對于有許多臟的緩沖區(qū)(包含必須同時寫到磁盤的數(shù)據(jù)的緩沖區(qū))的系統(tǒng)提供了動態(tài)的響應(yīng)。它在系統(tǒng)啟動的時候作為一個核心線程啟動,相當容易混淆,它叫自己位“ kflushd ”,而這是你用 ps 顯示系統(tǒng)中的進程的時候你會看得的名字。這個進程大多數(shù)時間在睡眠,等待系統(tǒng)中臟的緩沖區(qū)的數(shù)目增加直到太巨大。當緩沖區(qū)分配和釋放的時候,就檢查系統(tǒng)中臟的緩沖區(qū)的數(shù)目,然后喚醒 bdflush 。缺省的閾值是 60% ,但是如果系統(tǒng)非常需要緩沖區(qū), dflush 也會被喚醒。這個值可以用 updage 命令檢查和設(shè)置:
#update –d
bdflush version 1.4
0: 60 Max fraction of LRU list to examine for dirty blocks
1: 500 Max number of dirty blocks to write each time bdflush activated
2: 64 Num of clean buffers to be loaded onto free list by
refill_freelist
3: 256 Dirty block threshold for activating bdflush in refill_freelist
4: 15 Percentage of cache to scan for free clusters
5: 3000 Time for data buffers to age before flushing
6: 500 Time for non-data (dir, bitmap, etc) buffers to age before
flushing
7: 1884 Time buffer cache load average constant
8: 2 LAV ratio (used to determine threshold for buffer fratricide).
    不管什么時候?qū)懭肓藬?shù)據(jù),成為了臟的緩沖區(qū),所有的臟的緩沖區(qū)都鏈接在BUF_DIRTY LRU 列表中, bdflush 會嘗試把合理數(shù)目的緩沖區(qū)寫到它們的磁盤中。這個數(shù)目也可以用 update 命令檢查和設(shè)置,缺省是 500 (見上例)。
The update Process ( update 進程)
update 命令不僅僅是一個命令,它也是一個守護進程。當以超級用戶身份(系統(tǒng)初始化)運行的時候,它會定期把所有舊的臟緩沖區(qū)寫到磁盤上。它通過調(diào)用系統(tǒng)服務(wù)例程執(zhí)行這些任務(wù),或多或少和 bdflush 的任務(wù)相同。當生成了一個臟緩沖區(qū)的時候,都標記上它應(yīng)該被寫到它自己的磁盤上的系統(tǒng)時間。每一次 update 運行的時候,它都查看系統(tǒng)中所有的臟的緩沖區(qū),查找具有過期的寫時間的緩沖區(qū)。每一個過期的緩沖區(qū)都被寫到磁盤上。
參見 fs/buffer.c sys_bdflush()
The /proc File System
    /proc 文件系統(tǒng)真實地體現(xiàn)了 Linux 虛擬文件系統(tǒng)的能力。它實際上并不存在(這也是 Linux 另外一個技巧), /proc 和它的子目錄以及其中的文件都不存在。但是為什么你可以 cat /proc/devices ? /proc 文件系統(tǒng),象一個真正的文件系統(tǒng)一樣,也向虛擬文件系統(tǒng)登記自己,但是當它的文件和目錄被打開, VFS執(zhí)行調(diào)用請求它的 inode 的時候, /proc 文件系統(tǒng)才利用核心中的信息創(chuàng)建這些文件和目錄。例如,核心的 /proc/devices 文件是從核心描述它的設(shè)備的數(shù)據(jù)結(jié)構(gòu)中產(chǎn)生出來的。
/proc 文件系統(tǒng)代表了一個用戶可讀的窗口,進入核心的內(nèi)部工作空間。一些Linux 子系統(tǒng),例如第 12 章描述的 Linux 核心模塊,都在 /proc 文件系統(tǒng)中創(chuàng)建條目。
Device Special Files
    Linux ,象所有版本的 Unix 一樣,把它的硬件設(shè)備表示成為特殊文件。例如, /dev/null 是空設(shè)備。設(shè)備文件不在文件系統(tǒng)中占用任何數(shù)據(jù)空間,它只是設(shè)備驅(qū)動程序的一個訪問點。 EXT2 文件系統(tǒng)和 Linux 的 VFS 都把設(shè)備文件作為特殊類型的 inode 。有兩種類型的設(shè)備文件:字符和塊特殊文件。在核心內(nèi)部本身,設(shè)備驅(qū)動程序都實現(xiàn)文件的基本操作:你可以打開、關(guān)閉等等。字符設(shè)備允許字符模式的 I/O 操作,而塊設(shè)備要求所有的 I/O 通過 buffer cache 。當對于一個設(shè)備文件執(zhí)行一個 I/O 請求的時候,它被轉(zhuǎn)到系統(tǒng)中適當?shù)脑O(shè)備驅(qū)動程序。通常這不是一個真正的設(shè)備驅(qū)動程序,而是一個用于子系統(tǒng)的偽設(shè)備驅(qū)動程序(pseudo-device driver )例如 SCSI 設(shè)備驅(qū)動程序?qū)?。設(shè)備文件用主設(shè)備編號(
標識設(shè)備類型)和次類型來引用(用于標識單元,或者主類型的實例)。例如,對于系統(tǒng)中的第一個 IDE 控制器上的 IDE 磁盤,主設(shè)備編號是 3 , IDE 磁盤的第一個分區(qū)的次設(shè)備編號應(yīng)該是 1 ,所以, ls –l /dev/hda1 輸出
$ brw-rw---- 1 root disk 3, 1 Nov 24 15:09 /dev/hda1
參見 /include/linux/major.h 中所有 Linux 的主設(shè)備編號
    在核心中,每一個設(shè)備用一個 kdev_t 數(shù)據(jù)類型唯一描述。這個類型有兩個字節(jié)長,第一個包括設(shè)備的次設(shè)備編號,第二個包括主設(shè)備編號。上面的 IDE 設(shè)備在核心中保存為 0x0301 。代表一個塊或者字符設(shè)備的 EXT2 inode 把設(shè)備的主和次設(shè)備號放在它的第一個直接塊指針那里。當它被 VFS 讀取的時候,代表它的VFS inode 數(shù)據(jù)結(jié)構(gòu)的 I_rdev 域被設(shè)成正確的設(shè)備標識符。
參見 include/linux/kdev_t.h
本文來自:我愛研發(fā)網(wǎng)(52RD.com) - R&D大本營
詳細出處:http://www.52rd.com/Blog/Archive_Thread.asp?SID=21133
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
生活服務(wù)
熱點新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服