版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第7章嵌入式文件系統(tǒng)
7.1文件系統(tǒng)基本概念
7.2虛擬文件系統(tǒng)VFS
7.3基于Flash的文件系統(tǒng) 7.4基于RAM的文件系統(tǒng)
7.5Busybox
Linux的一個(gè)最重要特點(diǎn)就是可以支持許多不同的文件系統(tǒng)。這使Linux非常靈活,能夠與許多其他的操作系統(tǒng)共存。Linux支持的常見的文件系統(tǒng)有:JFS、ReiserFS、Ext、Ext2、Ext3、ISO9660、XFS、Minx、MSDOS、UMSDOS、VFAT、NTFS、HPFS、NFS、SMB、SysV、PROC等。隨著時(shí)間的推移,Linux支持的文件系統(tǒng)數(shù)還會(huì)增加。7.1文件系統(tǒng)基本概念
Linux是通過把系統(tǒng)支持的各種文件系統(tǒng)鏈接到一個(gè)單獨(dú)的樹形層次結(jié)構(gòu)中,來實(shí)現(xiàn)對多文件系統(tǒng)的支持。該樹形層次結(jié)構(gòu)把文件系統(tǒng)表示成一個(gè)整個(gè)的獨(dú)立實(shí)體。無論什么類型的文件系統(tǒng),都被裝配到某個(gè)目錄上,由被裝配的文件系統(tǒng)的文件覆蓋該目錄原有的內(nèi)容。該目錄被稱為裝配目錄或裝配點(diǎn)。在文件系統(tǒng)卸載時(shí),裝配目錄中原有的文件才會(huì)顯示出來。7.1.1嵌入式根文件系統(tǒng)
Linux下的根文件系統(tǒng)目錄結(jié)構(gòu)如下:
目錄習(xí)慣用法
bin 用戶命令所在目錄
dev 硬件設(shè)備文件及其他特殊文件
etc 系統(tǒng)配置文件,包括啟動(dòng)文件等
home多用戶主目錄
lib 鏈接庫文件目錄
mnt 裝配點(diǎn),用于裝配臨時(shí)文件系統(tǒng)或其他的文件
系統(tǒng)
opt 附加的軟件套件目錄
proc 虛擬文件系統(tǒng),用來顯示內(nèi)核及進(jìn)程信息
root root用戶主目錄
sbin 系統(tǒng)管理員命令目錄
tmp 臨時(shí)文件目錄
usr 用戶命令目錄
var 監(jiān)控程序和工具程序所存放的可變數(shù)據(jù)
對于用途單一的嵌入式系統(tǒng),上述的一些用于多用戶的目錄可以省略,例如/home、/opt、/root目錄等。而/bin、/dev、/etc、/lib、/proc、/sbin和/usr目錄,幾乎是每個(gè)系統(tǒng)必備的目錄,也是不可或缺的目錄。7.1.2嵌入式系統(tǒng)存儲(chǔ)設(shè)備及其管理機(jī)制分析
構(gòu)建適用于嵌入式系統(tǒng)的Linux文件系統(tǒng),必然會(huì)涉及到兩個(gè)關(guān)鍵問題,一是文件系統(tǒng)類型的選擇,關(guān)系到文件系統(tǒng)的讀/寫性能、大??;另一個(gè)是根文件系統(tǒng)內(nèi)容的選擇,關(guān)系到根文件系統(tǒng)所能提供的功能及文件大小。
1.閃存技術(shù)
目前在嵌入式系統(tǒng)應(yīng)用的Flash存儲(chǔ)器從結(jié)構(gòu)上大體可以分為AND、NAND、NOR和DiNOR等幾種。其中NOR和DiNOR的特點(diǎn)為相對電壓低、隨機(jī)讀取快、功耗低、穩(wěn)定性高,而NAND和AND的特點(diǎn)為容量大、回寫速度快、芯片面積小。NOR和NANDFlash的應(yīng)用最為廣泛,除了在嵌入式設(shè)備上得到廣泛的應(yīng)用外,在CompactFlash、SecureDigital、PCCards、MMC存儲(chǔ)卡以及USB閃盤存儲(chǔ)器市場都占用較大的份額。
NOR型閃存可以直接讀取芯片內(nèi)儲(chǔ)存的數(shù)據(jù),因而速度比較快,但是價(jià)格較高。NOR型芯片,地址線與數(shù)據(jù)線分開,所以NOR型芯片可以像SRAM一樣連在數(shù)據(jù)線上,對NOR芯片可以“字”為基本單位操作,因此傳輸效率很高,應(yīng)用程序可以直接在Flash內(nèi)運(yùn)行,不必再把代碼讀到系統(tǒng)RAM中運(yùn)行。NOR型閃存與SRAM的最大不同在于寫操作需要經(jīng)過擦除和寫入兩個(gè)過程。
NAND型閃存芯片共用地址線與數(shù)據(jù)線,內(nèi)部數(shù)據(jù)以塊為單位進(jìn)行存儲(chǔ),直接將NAND芯片做啟動(dòng)芯片比較難。NAND閃存是連續(xù)存儲(chǔ)介質(zhì),適合存放大文件。擦除NOR器件時(shí)是以64~128?KB的塊進(jìn)行的,執(zhí)行一個(gè)寫入/擦除操作的時(shí)間為5?s;擦除NAND器件是以8~32?KB的塊進(jìn)行的,執(zhí)行相同的操作最多只需要4?ms。NANDFlash的單元尺寸幾乎是NOR器件的一半,由于生產(chǎn)過程更為簡單,NAND結(jié)構(gòu)可以在給定的模具尺寸內(nèi)提供更高的容量,也就相應(yīng)地降低了價(jià)格。NORFlash占據(jù)了小容量閃存市場的大部分,而NANDFlash只是用在大容量產(chǎn)品當(dāng)中,這也說明NOR主要應(yīng)用在代碼存儲(chǔ)介質(zhì)中,NAND適合于數(shù)據(jù)存儲(chǔ)。在NAND閃存中每個(gè)塊的最大擦/寫次數(shù)是一百萬次,而NOR的擦/寫次數(shù)是十萬次。NAND存儲(chǔ)器除了具有10?:?1的塊擦除周期優(yōu)勢,典型的NAND塊尺寸是NOR器件的1/9,每個(gè)NAND存儲(chǔ)器塊在給定的時(shí)間內(nèi)的刪除次數(shù)要少一些。這兩種結(jié)構(gòu)性能上的異同(見表7-1)分析如下:
(1)?NOR的讀取速度比NAND稍快一些。
(2)?NAND的寫入速度比NOR快很多。
(3)?NAND的擦除速度遠(yuǎn)比NOR快。
(4)?NAND的擦除單元更小,相應(yīng)的擦除電路也更加簡單。
(5)?NAND閃存中每個(gè)塊的最大擦/寫次數(shù)是一百萬次,而NOR的擦/寫次數(shù)是十萬次。此外,NAND的實(shí)際應(yīng)用方式要比NOR復(fù)雜得多。NOR可以直接使用,并在上面直接運(yùn)行代碼。而NAND需要I/O接口,因此使用時(shí)需要驅(qū)動(dòng)程序。不過,當(dāng)今流行的操作系統(tǒng)對NANDFlash都提供驅(qū)動(dòng)支持,Linux內(nèi)核也對NANDFlash提供了很好的支持。由于以上Flash的特性,在嵌入式設(shè)備中,一般會(huì)把只讀屬性的映像文件,如啟動(dòng)引導(dǎo)程序Blob、內(nèi)核、文件系統(tǒng)文件存放在NORFlash中,而把一些讀/寫類的文件,如用戶應(yīng)用程序等存放在NANDFlash中。出于成本的考慮,很多廠家會(huì)選用低容量、昂貴的NORFlash存儲(chǔ)啟動(dòng)引導(dǎo)程序和內(nèi)核,而把文件系統(tǒng)存放在NANDFlash中。表7-1NOR閃存與NAND閃存的比較
NORFlashNANDFlash接口時(shí)序同SRAM,易使用地址/數(shù)據(jù)線復(fù)用,數(shù)據(jù)位較窄讀取速度較快讀取速度較慢擦除速度慢,以64~128?KB的塊為單位擦除速度快,以8~32?KB的塊為單位寫入速度慢(因?yàn)橐话阋炔脸?寫入速度快隨機(jī)存取速度較快,支持XIP(eXecuteInPlace,芯片內(nèi)執(zhí)行),適用于代碼存儲(chǔ)。在嵌入式系統(tǒng)中,常用于存放引導(dǎo)程序、根文件系統(tǒng)等順序讀取速度較快,隨機(jī)存取速度慢,適用于數(shù)據(jù)存儲(chǔ)(如大容量的多媒體應(yīng)用)。在嵌入式系統(tǒng)中,常用于存放用戶文件系統(tǒng)等單片容量較小,1~32?MB單片容量較大,8~128?MB,提高了單元密度最大擦/寫次數(shù)為十萬次
2.驅(qū)動(dòng)
所有嵌入式系統(tǒng)的啟動(dòng)都至少需要使用某種形式的永久性存儲(chǔ)設(shè)備,需要合適的驅(qū)動(dòng)程序,當(dāng)前在嵌入式Linux中有三種常用的塊驅(qū)動(dòng)程序可以選擇。
1)?Blkmem驅(qū)動(dòng)層
Blkmem驅(qū)動(dòng)是為mCLinux專門設(shè)計(jì)的,也是最早的一種塊驅(qū)動(dòng)程序,現(xiàn)在仍然有很多嵌入式Linux操作系統(tǒng)選用它作為塊驅(qū)動(dòng)程序,尤其是在mCLinux中。Blkmem相對來說是最簡單,而且只支持建立在NOR型Flash和RAM中的根文件系統(tǒng)。使用Blkmem驅(qū)動(dòng),建立Flash分區(qū)配置比較困難,這種驅(qū)動(dòng)程序?yàn)镕lash提供了一些基本擦除/寫入操作。
2)?RAMdisk驅(qū)動(dòng)層
RAMdisk驅(qū)動(dòng)層通常應(yīng)用在標(biāo)準(zhǔn)Linux中無盤工作站的啟動(dòng),對Flash存儲(chǔ)器并不提供任何的直接支持,RAMdisk
就是在開機(jī)時(shí),把一部分的內(nèi)存虛擬成塊設(shè)備,并且把之
前所準(zhǔn)備好的檔案系統(tǒng)映像解壓縮到該RAMdisk環(huán)境中。當(dāng)在Flash中放置壓縮的文件系統(tǒng)時(shí),可以將文件系統(tǒng)解壓到
RAM,使用RAMdisk驅(qū)動(dòng)層支持保持在RAM中的文件系統(tǒng)。
3)?MTD驅(qū)動(dòng)層
Linux內(nèi)核納入了MTD(MemoryTechnologyDevice)子系統(tǒng),從而提供了統(tǒng)一的接口,讓底層的MTD芯片驅(qū)動(dòng)程序無縫地與較高層接口組合在一起。
7.1.3嵌入式Linux中的MTD驅(qū)動(dòng)層
要在Flash存儲(chǔ)器中使用CramFS或YAFFS文件系統(tǒng),就離不開MTD驅(qū)動(dòng)程序?qū)拥闹С帧TD是Linux中的一個(gè)存儲(chǔ)設(shè)備通用接口層,雖然也可以建立在RAM上,但是專為基于Flash的設(shè)備而設(shè)計(jì)的。MTD包含特定Flash芯片的驅(qū)動(dòng)程序,并且越來越多的芯片驅(qū)動(dòng)正被添加進(jìn)來。用戶要使用MTD,首先要選擇適合的Flash芯片驅(qū)動(dòng)。Flash芯片驅(qū)動(dòng)向上層提供讀、寫、擦除等基本的Flash操作方法。MTD對這些操作進(jìn)行封裝后向用戶層提供MTDchar和MTDblock類型的設(shè)備。
MTDchar類型的設(shè)備包括/dev/mtd0、/dev/mtd1等,這些設(shè)備文件提供對Flash的原始字符訪問;MTDblock類型的設(shè)備包括/dev/mtdblock0、/dev/mtdblockl等,這些設(shè)備是將Flash模擬成塊設(shè)備,因此可以在這些模擬的塊設(shè)備上創(chuàng)建YAFFS或CramFS等格式的文件系統(tǒng)。
另外,MTD支持CFI(CommonFlashInterface)接口,利用CFI接口可以在一塊Flash存儲(chǔ)芯片上創(chuàng)建多個(gè)Flash分區(qū)。每一個(gè)分區(qū)作為一個(gè)MTDblock設(shè)備,可以把系統(tǒng)軟件和數(shù)據(jù)等分配到不同的分區(qū)上,同時(shí)可以在不同的分區(qū)上采用不同的文件系統(tǒng)格式。
1.LinuxMTD介紹
MTD內(nèi)存技術(shù)設(shè)備是用于訪問Memory設(shè)備(ROM、Flash)的Linux子系統(tǒng)。MTD的主要目的是為了使新的存貯設(shè)備的驅(qū)動(dòng)更加簡單,在硬件和上層之間提供了一個(gè)抽象的接口。MTD的所有源代碼在/drivers/mtd子目錄下。一般可將CFI接口的MTD設(shè)備分為四層(從設(shè)備節(jié)點(diǎn)直到底層硬件驅(qū)動(dòng)),這四層從上到下依次是:設(shè)備節(jié)點(diǎn)層(包括字符設(shè)備節(jié)點(diǎn)層和塊設(shè)備節(jié)點(diǎn)層)、MTD設(shè)備層(包括MTD塊設(shè)備層和MTD字符設(shè)備層)、MTD原始設(shè)備層和Flash硬件驅(qū)動(dòng)層,見圖7-1。圖7-1MTD設(shè)備層
1)?Flash硬件驅(qū)動(dòng)層
Flash硬件驅(qū)動(dòng)層負(fù)責(zé)在init時(shí)驅(qū)動(dòng)Flash硬件,LinuxMTD設(shè)備的NORFlash芯片驅(qū)動(dòng)遵循CFI接口標(biāo)準(zhǔn),其驅(qū)動(dòng)程序位于drivers/mtd/chips子目錄下。NANDFlash的驅(qū)動(dòng)程序則位于/drivers/mtd/nand子目錄下。
2)?MTD原始設(shè)備層
MTD原始設(shè)備層由兩部分組成,一部分是MTD原始設(shè)備的通用代碼,另一部分是各個(gè)特定的Flash數(shù)據(jù),例如分區(qū)。用于描述MTD原始設(shè)備的數(shù)據(jù)結(jié)構(gòu)是mtd_info,其中定義了關(guān)于MTD的數(shù)據(jù)和操作函數(shù)。mtd_table(mtdcore.c)是所有MTD原始設(shè)備的列表,mtd_part(mtd_part.c)是用于表示MTD原始設(shè)備分區(qū)的結(jié)構(gòu),其中包含了mtd_info。因?yàn)槊恳粋€(gè)分區(qū)都是被看成一個(gè)MTD原始設(shè)備加在mtd_table中的,所以mtd_part.mtd_info中的大部分?jǐn)?shù)據(jù)都從該分區(qū)的主分區(qū)mtd_part->master中獲得。
在drivers/mtd/maps/子目錄下存放的是特定的Flash數(shù)據(jù),每一個(gè)文件都描述了一塊開發(fā)板上的Flash。其中調(diào)用add_mtd_device()、del_mtd_device()建立/刪除mtd_info結(jié)構(gòu)并將其加入/刪除mtd_table(或者調(diào)用add_mtd_partition()、del_mtd_partition()(mtdpart.c)建立/刪除mtd_part結(jié)構(gòu)并將mtd_part.mtd_info加入/刪除mtd_table)。
3)?MTD設(shè)備層
基于MTD原始設(shè)備層,Linux系統(tǒng)可以定義MTD的塊設(shè)備(主設(shè)備號(hào)31)層和字符設(shè)備(設(shè)備號(hào)90)層。MTD字符設(shè)備的定義在mtdchar.c中實(shí)現(xiàn),通過注冊一系列fileoperation函數(shù)(lseek、open、close、read、write)完成。MTD塊設(shè)備則是定義了描述MTD塊設(shè)備的結(jié)構(gòu)mtdblk_dev,并聲明了名為mtdblks的指針數(shù)組,該數(shù)組中的每個(gè)mtdblk_dev和mtd_table中的mtd_info一一對應(yīng)。
4)?設(shè)備節(jié)點(diǎn)層
通過mknod在/dev子目錄下建立MTD字符設(shè)備節(jié)點(diǎn)(主設(shè)備號(hào)為90)層和MTD塊設(shè)備節(jié)點(diǎn)(主設(shè)備號(hào)為31)層,通過訪問此設(shè)備節(jié)點(diǎn)即可訪問MTD字符設(shè)備和塊設(shè)備。
5)?根文件系統(tǒng)層
在Bootloader中將JFFS(或JFFS2)的文件系統(tǒng)映像jffs.image(或jffs2.img)燒寫到Flash的某一個(gè)分區(qū)中,在/arch/arm/mach-your/arch.c文件的your_fixup函數(shù)中將該分區(qū)作為根文件系統(tǒng)掛載。
6)文件系統(tǒng)層
內(nèi)核啟動(dòng)后,通過掛載命令可以將Flash中的其余分區(qū)作為文件系統(tǒng)掛載到掛載點(diǎn)上。
設(shè)備層和原始設(shè)備層的函數(shù)調(diào)用關(guān)系如下:
一個(gè)MTD原始設(shè)備可以通過mtd_part分割成數(shù)個(gè)MTD原始設(shè)備,并注冊進(jìn)mtd_table,mtd_table中的每個(gè)MTD原始設(shè)備都可以被注冊成一個(gè)MTD設(shè)備,其中字符設(shè)備的主設(shè)備號(hào)為90,次設(shè)備號(hào)為0、2、4、6…(奇數(shù)次設(shè)備號(hào)為只讀設(shè)備),塊設(shè)備的主設(shè)備號(hào)為31,次設(shè)備號(hào)為0、1、2、3…?。代碼如下:mtd_notifier
mtd_notifier
字符設(shè)備
mtd_fops
塊設(shè)備
mtd_fops(mtdchar.c)
(mtdblock.c)
mtdblks設(shè)備層
register_mtd_user()
get_mtd_device()
unregister_mtd_user()
put_mtd_device()
erase_info
mtd_notifiers
mtd_table
mtd_info
mtd_part
(mtdcore.c)
(mtdpart.c)
YourFlash
(your-flash.c)
add_mtd_partitions()
del_mtd_partitions()
原始設(shè)備層
add_mtd_device()
del_mtd_device()
mtd_partition
NOR型Flash芯片驅(qū)動(dòng)與MTD原始設(shè)備
所有的NOR型Flash的驅(qū)動(dòng)(探測)程序在drivers/mtd/chips目錄下,一個(gè)MTD原始設(shè)備可以由一塊或者數(shù)塊相同的Flash芯片組成。假設(shè)由4塊devicetype為x8的Flash,每塊大小為8?MB,interleave為2,起始地址為0x01000000,地址相連,則構(gòu)成一個(gè)MTD原始設(shè)備(0x01000000~0x03000000),其中兩塊interleave構(gòu)成一個(gè)chip,其地址為0x01000000~0x02000000,另兩塊interleave構(gòu)成一個(gè)chip,其地址為0x02000000~0x03000000。所有組成一個(gè)MTD原始設(shè)備的Flash芯片必須是同類型的(無論是interleave還是地址相連),在描述MTD原始設(shè)備的數(shù)據(jù)結(jié)構(gòu)中也只是采用了同一個(gè)結(jié)構(gòu)來描述組成它的Flash芯片,例如:
0x03000000
0x02000000
0x01000000
每個(gè)MTD原始設(shè)備都有一個(gè)mtd_info結(jié)構(gòu),其中的priv指針指向一個(gè)map_info結(jié)構(gòu),map_info結(jié)構(gòu)中的fldrv_priv指向一個(gè)cfi_private結(jié)構(gòu),cfi_private結(jié)構(gòu)的cfiq指針指向一個(gè)cfi_ident結(jié)構(gòu),chips指針指向一個(gè)flchip結(jié)構(gòu)的數(shù)組。其中mtd_info、map_info和cfi_private結(jié)構(gòu)用于描述MTD原始設(shè)備;因?yàn)榻M成MTD原始設(shè)備的NORFlash相同,所以cfi_ident結(jié)構(gòu)用于描述Flash芯片的信息;而flchip結(jié)構(gòu)用于描述每個(gè)Flash芯片的專有信息(比如起始地址)。驅(qū)動(dòng)還用于對DiskOnChip產(chǎn)品進(jìn)行仿真和NAND閃存的管理,包括糾錯(cuò)、壞塊處理和損耗平衡。
2.Linux下的文件系統(tǒng)結(jié)構(gòu)
Linux啟動(dòng)時(shí),第一個(gè)必須掛載的是根文件系統(tǒng);若系統(tǒng)不能從指定設(shè)備上掛載根文件系統(tǒng),則系統(tǒng)會(huì)出錯(cuò)而退出啟動(dòng),之后可以自動(dòng)或手動(dòng)掛載其他的文件系統(tǒng)。因此,一個(gè)系統(tǒng)中可以同時(shí)存在不同的文件系統(tǒng)。
不同的文件系統(tǒng)類型有不同的特點(diǎn),因而根據(jù)存儲(chǔ)設(shè)備的硬件特性、系統(tǒng)需求等有不同的應(yīng)用場合。在嵌入式Linux應(yīng)用中,主要的存儲(chǔ)設(shè)備為RAM(DRAM,SDRAM)和ROM(常采用Flash存儲(chǔ)器),常用的基于存儲(chǔ)設(shè)備的文件系統(tǒng)類型包括:JFFS2、YAFFS、CramFS、ROMFS、RAMdisk、Ramfs/Tmpfs等。在Linux文件系統(tǒng)中,文件用i節(jié)點(diǎn)來表示,目錄只是包含有一組目錄條目列表的簡單文件,而設(shè)備可以通過特殊文件上的I/O請求被訪問。
1)節(jié)點(diǎn)(Inodes)
每個(gè)文件都是由被稱為i節(jié)點(diǎn)的一個(gè)結(jié)構(gòu)來表示的。每個(gè)i節(jié)點(diǎn)都含有對特定文件的描述:文件類型、訪問權(quán)限、屬主、時(shí)間戳、大小、指向數(shù)據(jù)塊的指針。分配給一個(gè)文件的數(shù)據(jù)塊的地址也存儲(chǔ)在該文件的i節(jié)點(diǎn)中。當(dāng)一個(gè)用戶在該文件上請求一個(gè)I/O操作時(shí),內(nèi)核代碼將當(dāng)前偏移量轉(zhuǎn)換成一個(gè)塊號(hào),并使用這個(gè)塊號(hào)作為塊地址表中的索引來讀/寫實(shí)際的物理塊。圖7-2表示了一個(gè)i節(jié)點(diǎn)的結(jié)構(gòu)。圖7-2i節(jié)點(diǎn)的結(jié)構(gòu)
2)目錄
目錄是一個(gè)分層的樹結(jié)構(gòu)。每個(gè)目錄可以包含文件和子目錄。目錄是作為一個(gè)特殊的文件實(shí)現(xiàn)的。實(shí)際上,目錄是一個(gè)含有目錄條目的文件,每個(gè)條目含有一個(gè)i節(jié)點(diǎn)號(hào)和一個(gè)文件名。當(dāng)進(jìn)程使用一個(gè)路徑名時(shí),內(nèi)核代碼就會(huì)在目錄中搜索以找到相應(yīng)的i節(jié)點(diǎn)號(hào),在文件名被轉(zhuǎn)換成了一個(gè)i節(jié)點(diǎn)以后,該i節(jié)點(diǎn)就被加載到內(nèi)存中并被隨后的請求所使用。圖7-3表示了一個(gè)目錄結(jié)構(gòu)。圖7-3目錄結(jié)構(gòu)
3)鏈接
Linux文件系統(tǒng)實(shí)現(xiàn)了鏈接(Links)的概念。幾個(gè)文件名可以與一個(gè)i節(jié)點(diǎn)相關(guān)聯(lián)。i節(jié)點(diǎn)含有一個(gè)字段,其中含有與文件的關(guān)聯(lián)數(shù)目。要增加一個(gè)鏈接只需簡單地建立一個(gè)目錄項(xiàng),該目錄項(xiàng)的i節(jié)點(diǎn)號(hào)指向該i節(jié)點(diǎn)并增加該i節(jié)點(diǎn)的鏈接數(shù)即可。但刪除一個(gè)鏈接時(shí),也即當(dāng)使用rm命令刪除一個(gè)文件名時(shí),內(nèi)核會(huì)遞減i節(jié)點(diǎn)的鏈接計(jì)數(shù)值,如果該計(jì)數(shù)值等于零的話,就會(huì)釋放該i節(jié)點(diǎn)。
這種類型的鏈接稱為硬鏈接(HardLink),并且只能在單獨(dú)的文件系統(tǒng)內(nèi)使用,也即不可能創(chuàng)建一個(gè)跨越文件系統(tǒng)的硬鏈接。而且,硬鏈接只能指向文件,為了防止目錄樹的循環(huán),不能創(chuàng)建目錄的硬鏈接。
在大多數(shù)Linux文件系統(tǒng)中還有另外一種鏈接,即符號(hào)鏈接(SymbolicLink)。符號(hào)鏈接僅是含有一個(gè)文件名的簡單文件。在從路徑名到i節(jié)點(diǎn)的轉(zhuǎn)換中,當(dāng)內(nèi)核遇到一個(gè)符號(hào)鏈接時(shí),就用該符號(hào)鏈接文件的內(nèi)容替換鏈接的文件名,也即用目標(biāo)文件的名稱來替換,并重新開始路徑名的翻譯工作。由于符號(hào)鏈接并沒有指向i節(jié)點(diǎn),因此就有可能創(chuàng)建一個(gè)跨越文件系統(tǒng)的符號(hào)鏈接。符號(hào)鏈接可以指向任何類型的文件,甚至是一個(gè)不存在的文件。由于沒有與硬鏈接相關(guān)的限制,因此符號(hào)鏈接非常有用。然而,符號(hào)鏈接會(huì)占用一部分磁盤空間,并且需要為它們分配i節(jié)點(diǎn)和數(shù)據(jù)塊。由于內(nèi)核在遇到一個(gè)符號(hào)鏈接時(shí)需要重新開始路徑名到i節(jié)點(diǎn)的轉(zhuǎn)換工作,因此會(huì)造成路徑名到i節(jié)點(diǎn)轉(zhuǎn)換的額外負(fù)擔(dān)。
4)設(shè)備特殊文件
在Linux類操作系統(tǒng)中,設(shè)備是可以通過特殊的文件進(jìn)行訪問的。設(shè)備特殊文件(DeviceSpecialFiles)不會(huì)占用文件系統(tǒng)上的任何空間,它只是設(shè)備驅(qū)動(dòng)程序的一個(gè)訪問點(diǎn)。
存在兩類設(shè)備特殊文件:字符設(shè)備特殊文件和塊設(shè)備特殊文件。前者允許以字符模式進(jìn)行I/O操作,而后者需要通過高速緩沖功能以塊模式寫數(shù)據(jù)的方式進(jìn)行操作。當(dāng)對設(shè)備特殊文件進(jìn)行I/O請求操作時(shí),就會(huì)傳遞到(虛擬的)設(shè)備驅(qū)動(dòng)程序中。對特殊文件的引用是通過主設(shè)備號(hào)和次設(shè)備號(hào)進(jìn)行的,主設(shè)備號(hào)確定了設(shè)備的類型,而次設(shè)備號(hào)指明了設(shè)備單元。
5)虛擬文件系統(tǒng)
Linux內(nèi)核有虛擬文件系統(tǒng)(VirtualFileSystem,VFS)層,用于系統(tǒng)調(diào)用操作文件。VFS層是一個(gè)間接層,用于處理涉及文件的系統(tǒng)調(diào)用,并調(diào)用物理文件系統(tǒng)代碼中的必要功能來進(jìn)行I/O操作。該間接機(jī)制常用于Unix類操作系統(tǒng)中,以利于集成和使用幾種類型的文件系統(tǒng)。
當(dāng)處理器發(fā)出基于文件的系統(tǒng)調(diào)用時(shí),內(nèi)核就會(huì)調(diào)用VFS函數(shù)處理與結(jié)構(gòu)無關(guān)的操作,并且把調(diào)用重新轉(zhuǎn)到與結(jié)構(gòu)相關(guān)的物理文件系統(tǒng)代碼中的函數(shù)。文件系統(tǒng)代碼使用高速緩沖功能來請求對設(shè)備進(jìn)行I/O操作。
6)VFS的結(jié)構(gòu)
VFS定義了每個(gè)文件系統(tǒng)必須實(shí)現(xiàn)的函數(shù)集。該接口由一組操作集組成,涉及三類對象:文件系統(tǒng)、i節(jié)點(diǎn)和打開文件。
VFS知道內(nèi)核所支持的文件系統(tǒng)的類型,使用在內(nèi)核配置時(shí)定義的表來獲取這些信息。該表中的每個(gè)條目均描述了一個(gè)文件系統(tǒng)類型:含有文件系統(tǒng)類型的名稱以及在加載操作時(shí)調(diào)用函數(shù)的指針。當(dāng)需要加載一個(gè)文件系統(tǒng)時(shí),就會(huì)調(diào)用相應(yīng)的加載函數(shù)。該函數(shù)負(fù)責(zé)從磁盤上讀取超級塊、初始化內(nèi)部變量,并且向VFS返回被加載文件系統(tǒng)的描述符。在文件系統(tǒng)已被加載以后,VFS函數(shù)就可以使用這個(gè)描述符來訪問物理文件系統(tǒng)的子程序。
VFS還使用了另外兩類描述符:i節(jié)點(diǎn)描述符和打開文件描述符。每個(gè)描述符含有與所使用文件相關(guān)的信息以及物理文件系統(tǒng)代碼提供的操作集。i節(jié)點(diǎn)描述符含有用于任何文件操作(例如create、unlink)的函數(shù)指針集,而文件描述符含有操作已被打開文件的函數(shù)的指針(例如read、write)。7.1.4常見的嵌入式文件系統(tǒng)
文件系統(tǒng)都會(huì)被燒錄在某一存儲(chǔ)設(shè)備上。嵌入式設(shè)備上很少使用大容量的IDE硬盤作為自己的存儲(chǔ)設(shè)備,嵌入式設(shè)備往往選用ROM、閃存等作為主要存儲(chǔ)設(shè)備。在嵌入式設(shè)備上選用哪種文件系統(tǒng)格式與閃存的特點(diǎn)是相關(guān)的。
Linux支持多種文件系統(tǒng),包括Ext2、Ext3、VFAT、NTFS、ISO9660、JFFS、JFFS、Romfs和NFS等,為了對各類文件系統(tǒng)進(jìn)行統(tǒng)一管理,Linux引入了虛擬文件系統(tǒng),為各類文件系統(tǒng)提供一個(gè)統(tǒng)一的操作界面和應(yīng)用編程接口。
Linux下的文件系統(tǒng)結(jié)構(gòu)如圖7-4所示。圖7-4Linux下的文件系統(tǒng)結(jié)構(gòu)
Linux啟動(dòng)時(shí),第一個(gè)必須掛載的是根文件系統(tǒng);若系統(tǒng)不能從指定設(shè)備上掛載根文件系統(tǒng),則系統(tǒng)會(huì)出錯(cuò)而退出啟動(dòng),之后可以自動(dòng)或手動(dòng)掛載其他的文件系統(tǒng)。因此,一個(gè)系統(tǒng)中可以同時(shí)存在不同的文件系統(tǒng)。
1.Ext2fs文件系統(tǒng)
Ext2fs是Linux事實(shí)上的標(biāo)準(zhǔn)文件系統(tǒng),已經(jīng)取代了擴(kuò)展文件系統(tǒng)(或Extfs)。Extfs支持的文件大小最大為2?GB,支持的最大文件名稱大小為255個(gè)字符,而且不支持索引節(jié)點(diǎn)(包括數(shù)據(jù)修改時(shí)間標(biāo)記)。Ext2fs的功能更強(qiáng),優(yōu)點(diǎn)包括:
(1)?Ext2fs支持達(dá)4TB的內(nèi)存。
(2)?Ext2fs文件名稱最長可以到1012個(gè)字符。
(3)當(dāng)創(chuàng)建文件系統(tǒng)時(shí),管理員可以選擇邏輯塊的大小(通常大小可選擇1024?B、2048?B和4096?B)。
(4)?Ext2fs實(shí)現(xiàn)了快速符號(hào)鏈接,不需要為此分配數(shù)據(jù)塊,并且將目標(biāo)名稱直接存儲(chǔ)在索引節(jié)點(diǎn)表中。這使Ext2fs的性能有所提高,特別是在速度上。
因?yàn)镋xt2fs文件系統(tǒng)的穩(wěn)定性、可靠性和健壯性,所以幾乎在所有基于Linux的系統(tǒng)(包括臺(tái)式機(jī)、服務(wù)器和工作站,甚至一些嵌入式設(shè)備)上都使用Ext2fs文件系統(tǒng)。然而,在嵌入式設(shè)備中使用Ext2fs時(shí)有一些缺點(diǎn),表現(xiàn)如下:
(1)?Ext2fs是為類IDE塊設(shè)備設(shè)計(jì)的,這些設(shè)備的邏輯塊大小是512?B、1?KB等的倍數(shù)。不適合扇區(qū)大小因設(shè)備不同而不同的閃存設(shè)備。
(2)??Ext2fs文件系統(tǒng)沒有提供對基于扇區(qū)的擦除/寫入操作的良好管理。在Ext2fs中,為了在一個(gè)扇區(qū)中擦除單個(gè)字節(jié),必須將整個(gè)扇區(qū)復(fù)制到RAM,擦除后再重新寫入。
(3)考慮到閃存設(shè)備具有有限的擦除壽命(大約能進(jìn)行100?000次擦除),在此之后就不能使用,所以這不是一個(gè)特別好的方法。
(4)在出現(xiàn)電源故障時(shí),Ext2fs不是防崩潰的。
(5)??Ext2fs文件系統(tǒng)不支持損耗平衡,因此縮短了扇區(qū)/閃存的壽命。(損耗平衡確保將地址范圍的不同區(qū)域輪流用于寫和/或擦除操作以延長閃存設(shè)備的壽命。)
(6)?Ext2fs沒有特別完美的扇區(qū)管理,這使設(shè)計(jì)塊驅(qū)動(dòng)程序十分困難。
由于這些原因,通常相對于Ext2fs,在嵌入式環(huán)境中使用MTD/JFFS2組合是更好的選擇。
2.基于Flash的文件系統(tǒng)
Flash(閃存)作為嵌入式系統(tǒng)的主要存儲(chǔ)媒介,有其自身的特性。Flash的寫入操作只能把對應(yīng)位置的1修改為0,而不能把0修改為1(擦除Flash就是把對應(yīng)存儲(chǔ)塊的內(nèi)容恢復(fù)為1),因此,一般情況下,向Flash寫入內(nèi)容時(shí),需要先擦除對應(yīng)的存儲(chǔ)區(qū)間,這種擦除是以塊(Block)為單位進(jìn)行的。
閃存主要有NOR和NAND兩種技術(shù)。Flash存儲(chǔ)器的擦/寫次數(shù)是有限的,NANDFlash還有特殊的硬件接口和讀/寫時(shí)序。因此,必須針對Flash的硬件特性設(shè)計(jì)符合應(yīng)用要求的文件系統(tǒng);傳統(tǒng)的文件系統(tǒng)(如Ext2等)用作Flash的文件系統(tǒng)時(shí)會(huì)有諸多弊端。在嵌入式Linux下,MTD(存儲(chǔ)技術(shù)設(shè)備)為底層硬件(閃存)和上層(文件系統(tǒng))之間提供統(tǒng)一的抽象接口,即Flash的文件系統(tǒng)都是基于MTD驅(qū)動(dòng)層的(參見圖7-4)。使用MTD驅(qū)動(dòng)程序的主要優(yōu)點(diǎn)在于,它是專門針對各種非易失性存儲(chǔ)器(以閃存為主)而設(shè)計(jì)的,因而對Flash有更好的支持、管理和基于扇區(qū)的擦除、讀/寫操作接口。
一塊Flash芯片可以被劃分為多個(gè)分區(qū),各分區(qū)可以采用不同的文件系統(tǒng);兩塊Flash芯片也可以合并為一個(gè)分區(qū)使用,采用同一文件系統(tǒng)。文件系統(tǒng)是針對于存儲(chǔ)器分區(qū)而言的,而非存儲(chǔ)芯片。
1)?JFFS2
瑞典的AxisCommunications開發(fā)了最初的JFFS,RedHat的DavidWoodhouse進(jìn)行了改進(jìn),推出了第二個(gè)版本JFFS2,用于微型嵌入式設(shè)備的原始閃存芯片的實(shí)際文件系統(tǒng)。JFFS2文件系統(tǒng)是日志結(jié)構(gòu)化的,這意味著是一長列節(jié)點(diǎn)。每個(gè)節(jié)點(diǎn)包含有關(guān)文件的信息,可能是文件的名稱,也可能是一些數(shù)據(jù)。相對于Ext2fs,JFFS2因?yàn)橛幸韵聝?yōu)點(diǎn)而在無盤嵌入式設(shè)備中得到更多應(yīng)用:
(1)??JFFS2在扇區(qū)級別上執(zhí)行閃存擦除/寫/讀操作要比Ext2文件系統(tǒng)好。
(2)??JFFS2提供了比Ext2fs更好的崩潰/掉電安全保護(hù)。當(dāng)需要更改少量數(shù)據(jù)時(shí),Ext2文件系統(tǒng)將整個(gè)扇區(qū)復(fù)制到內(nèi)存(DRAM)中,在內(nèi)存中合并新數(shù)據(jù),并寫回整個(gè)扇區(qū)。這意味著為了更改單個(gè)字,必須對整個(gè)扇區(qū)(64?KB)執(zhí)行讀/擦除/寫例程。這樣做的效率非常低。如果在DRAM中合并數(shù)據(jù)時(shí),發(fā)生了電源故障或其他事故,那么將丟失整個(gè)數(shù)據(jù),這是因?yàn)樵趯?shù)據(jù)讀入DRAM后就擦除了閃存扇區(qū)。JFFS2附加文件而不是重寫整個(gè)扇區(qū),而且具有崩潰/掉電安全保護(hù)這一功能。
這可能是最重要的一點(diǎn):JFFS2是專門為像閃存芯片的嵌入式設(shè)備創(chuàng)建的,所以整個(gè)設(shè)計(jì)提供了更好的閃存管理。當(dāng)文件系統(tǒng)已滿或接近滿時(shí),因?yàn)槔占瘑栴}JFFS2會(huì)大大放慢運(yùn)行速度。
2)?YAFFS(YetAnotherFlashFileSystem)
YAFFS/YAFFS2是專為嵌入式系統(tǒng)使用NAND型閃存而設(shè)計(jì)的日志型文件系統(tǒng)。與JFFS2相比,它減少了一些功能(例如不支持?jǐn)?shù)據(jù)壓縮),所以速度更快,掛載時(shí)間很短,對內(nèi)存的占用較小。另外,它還是跨平臺(tái)的文件系統(tǒng),除了Linux和eCos,還支持WindowsCE、pSOS和ThreadX等。
YAFFS/YAFFS自帶NAND芯片驅(qū)動(dòng),并且為嵌入式系統(tǒng)提供了直接訪問文件系統(tǒng)的API,用戶可以不使用Linux中的MTD與VFS,直接對文件系統(tǒng)進(jìn)行操作。當(dāng)然,YAFFS也可與MTD驅(qū)動(dòng)程序配合使用。
YAFFS與YAFFS2的主要區(qū)別在于,前者僅支持小頁(512?B)NAND閃存,后者則可支持大頁(2?KB)NAND閃存。同時(shí),YAFFS2在內(nèi)存空間占用、垃圾回收速度、讀/寫速度等方面均有大幅提升。
3)?CramFS(CompressedRAMFileSystem)
CramFS是Linux的創(chuàng)始人LinusTorvalds參與開發(fā)的一種基于MTD驅(qū)動(dòng)程序只讀的壓縮文件系統(tǒng)。
CramFS文件系統(tǒng)中,每一頁(4?KB)被單獨(dú)壓縮,可以隨機(jī)頁訪問,其壓縮比高達(dá)2?:?1,為嵌入式系統(tǒng)節(jié)省大量的Flash存儲(chǔ)空間,使系統(tǒng)可通過更低容量的Flash存儲(chǔ)相同的文件,從而降低了系統(tǒng)成本。
CramFS文件系統(tǒng)以壓縮方式存儲(chǔ),在運(yùn)行時(shí)解壓縮,所以不支持應(yīng)用程序以XIP(eXecuteInPlace,片內(nèi)運(yùn)行)方式運(yùn)行,所有的應(yīng)用程序要求被拷到RAM里去運(yùn)行,但這并不代表要比Ramfs需求的RAM空間大一點(diǎn),因?yàn)镃ramFS是采用分頁壓縮的方式存放文件,在讀取文件時(shí),不會(huì)馬上就耗用過多的內(nèi)存空間,只針對目前實(shí)際讀取的部分分配內(nèi)存,尚沒有讀取的部分不分配內(nèi)存空間,當(dāng)讀取的檔案不在內(nèi)存時(shí),CramFS文件系統(tǒng)自動(dòng)計(jì)算壓縮后的資料所存的位置,再即時(shí)解壓縮到RAM中。另外,CramFS的速度快,效率高,其只讀的特點(diǎn)有利于保護(hù)文件系統(tǒng)免受破壞,提高了系統(tǒng)的可靠性。
由于以上特性,CramFS在嵌入式系統(tǒng)中應(yīng)用廣泛。但是它的只讀屬性同時(shí)又是它的一大缺陷,使得用戶無法對其內(nèi)容進(jìn)行擴(kuò)充。
CramFS映像通常放在Flash中,但是也能放在別的文件系統(tǒng)里,使用loopback設(shè)備可以把它安裝到別的文件系統(tǒng)里。
4)?Romfs
傳統(tǒng)型的Romfs文件系統(tǒng)是一種簡單、緊湊、只讀的文件系統(tǒng),不支持動(dòng)態(tài)擦/寫保存,按順序存放數(shù)據(jù),因而支持應(yīng)用程序以XIP方式運(yùn)行,在系統(tǒng)運(yùn)行時(shí)可節(jié)省RAM空間。mCLinux系統(tǒng)通常采用Romfs文件系統(tǒng)。
其他文件系統(tǒng):FAT/FAT32也可用于實(shí)際嵌入式系統(tǒng)的擴(kuò)展存儲(chǔ)器(例如PDA、Smartphone、數(shù)碼相機(jī)等的SD卡),這主要是為了更好地與最流行的Windows桌面操作系統(tǒng)相兼容。
3.基于RAM的文件系統(tǒng)
1)?RAMdisk
RAMdisk是將一部分固定大小的內(nèi)存當(dāng)作分區(qū)來使用。它并非實(shí)際的文件系統(tǒng),而是一種將實(shí)際的文件系統(tǒng)裝入內(nèi)存的機(jī)制,并且可以作為根文件系統(tǒng)。將一些經(jīng)常被訪問而又不會(huì)更改的文件(如只讀的根文件系統(tǒng))通過RAMdisk放在內(nèi)存中,可以明顯地提高系統(tǒng)的性能。
在Linux的啟動(dòng)階段,Initrd提供了一套機(jī)制,可以將內(nèi)核映像和根文件系統(tǒng)一起載入內(nèi)存。
2)?Ramfs/Tmpfs
Ramfs是LinuxTorvalds開發(fā)的一種基于內(nèi)存的文件系統(tǒng),工作于虛擬文件系統(tǒng)(VFS)層,不能格式化,可以創(chuàng)建多個(gè),在創(chuàng)建時(shí)可以指定其最大能使用的內(nèi)存大小。(實(shí)際上,VFS本質(zhì)上可看做一種內(nèi)存文件系統(tǒng),它統(tǒng)一了文件在內(nèi)核中的表示方式,并對磁盤文件系統(tǒng)進(jìn)行緩沖。)
如果Linux已經(jīng)將Ramfs編譯進(jìn)內(nèi)核,就可以很容易地使用Ramfs。只要?jiǎng)?chuàng)建一個(gè)目錄,加載Ramfs到該目錄即可。
#mkdir-p/RAM1
#mount-tramfsnone/RAM1
缺省情況下,Ramfs被限制最多可使用內(nèi)存大小的一半,可以通過maxsize(以KB為單位)選項(xiàng)來改變。
#mkdir-p/RAM1
#mount-tramfsnone/RAM1-omaxsize=10000
以上即創(chuàng)建了一個(gè)限定了最大使用內(nèi)存大小為10?MB的RAMdisk。
Tmpfs是一個(gè)虛擬內(nèi)存文件系統(tǒng),它不同于傳統(tǒng)的用塊設(shè)備形式來實(shí)現(xiàn)的RAMdisk,也不同于針對物理內(nèi)存的Ramfs。Tmpfs可以使用物理內(nèi)存,也可以使用交換分區(qū)。在Linux內(nèi)核中,虛擬內(nèi)存資源由物理內(nèi)存(RAM)和交換分區(qū)組成,這些資源由內(nèi)核中的虛擬內(nèi)存子系統(tǒng)負(fù)責(zé)分配和管理。Tmpfs就是和虛擬內(nèi)存子系統(tǒng)“打交道”的,向虛擬內(nèi)存子系統(tǒng)請求頁存儲(chǔ)文件,同Linux的其他請求頁的部分一樣,不知道分配給自己的頁是在內(nèi)存中還是在交換分區(qū)中。Tmpfs同Ramfs一樣,其大小也不是固定的,而是隨著所需要的空間而動(dòng)態(tài)地增減。使用Tmpfs,首先在編譯內(nèi)核時(shí)需選擇“虛擬內(nèi)存文件系統(tǒng)支持(VirtualMemoryFileSystemSupport)”,然后才能加載Tmpfs文件系統(tǒng)。
#mkdir-p/mnt/tmpfs
#mounttmpfs/mnt/tmpfs-ttmpfs
為了防止Tmpfs使用過多的內(nèi)存資源而造成系統(tǒng)的性能下降或死機(jī),可以在加載時(shí)指定Tmpfs文件系統(tǒng)大小的最大限制。
#mounttmpfs/mnt/tmpfs-ttmpfs-osize=32m
以上創(chuàng)建的Tmpfs文件系統(tǒng)規(guī)定了其最大為32?MB。不管是使用Ramfs還是Tmpfs,必須指出的是,一旦系統(tǒng)重啟,它們中的內(nèi)容將會(huì)丟失。所以哪些內(nèi)容可以放在內(nèi)存文件系統(tǒng)中需根據(jù)系統(tǒng)的具體情況而定。
Ramfs/Tmpfs文件系統(tǒng)把所有的文件都放在RAM中,所以讀/寫操作發(fā)生在RAM中,可以用Ramfs/Tmpfs存儲(chǔ)一些臨時(shí)性或經(jīng)常要修改的數(shù)據(jù),例如/tmp和/var目錄,這樣既避免了對Flash存儲(chǔ)器的讀/寫損耗,也提高了數(shù)據(jù)讀/寫速度。
Ramfs/Tmpfs相對于傳統(tǒng)的RAMdisk的不同之處主要在于:不能格式化,文件系統(tǒng)大小可隨所含文件內(nèi)容大小變化。
Tmpfs的另一個(gè)缺點(diǎn)是當(dāng)系統(tǒng)重新引導(dǎo)時(shí)會(huì)丟失所有數(shù)據(jù)。
4.網(wǎng)絡(luò)文件系統(tǒng)
網(wǎng)絡(luò)文件系統(tǒng)(NetworkFileSystem,NFS)是由Sun公司開發(fā)并發(fā)展起來的一項(xiàng)在不同機(jī)器、不同操作系統(tǒng)之間通過網(wǎng)絡(luò)共享文件的技術(shù)。在嵌入式Linux系統(tǒng)的開發(fā)調(diào)試階段,可以利用該技術(shù)在主機(jī)上建立基于NFS的根文件系統(tǒng),掛載到嵌入式設(shè)備,從而可以很方便地修改根文件系統(tǒng)的內(nèi)容。
以上討論的都是基于存儲(chǔ)設(shè)備的文件系統(tǒng)(Memory-basedFileSystem),它們都可用作Linux的根文件系統(tǒng)。實(shí)際上,Linux還支持邏輯的或偽文件系統(tǒng)(LogicalorPseudoFileSystem),例如PROCFS(PROC文件系統(tǒng))用于獲取系統(tǒng)信息,而DEVFS(設(shè)備文件系統(tǒng))和SYSFS用于維護(hù)設(shè)備文件。
Linux引入了虛擬文件系統(tǒng)(VFS),為各類文件系統(tǒng)提供一個(gè)統(tǒng)一的操作界面和應(yīng)用編程接口。7.2虛擬文件系統(tǒng)
Linux的文件系統(tǒng)部分中,以下分析源代碼基于2.4.20內(nèi)核。Linux中的文件系統(tǒng)主要可分為三大塊:一是上層的文件系統(tǒng)的系統(tǒng)調(diào)用,二是虛擬文件系統(tǒng),三是掛載到VFS中的各實(shí)際文件系統(tǒng),例如Ext2、JFFS等。通過具體的代碼分析來解釋Linux內(nèi)核中VFS的內(nèi)在機(jī)制,在此過程中會(huì)涉及到上層文件系統(tǒng)調(diào)用和下層實(shí)際文件系統(tǒng)如何掛載的問題。本節(jié)內(nèi)容從一個(gè)較高的角度描述Linux下的VFS文件系統(tǒng)機(jī)制,所以在敘述中更側(cè)重于整個(gè)模塊的主脈絡(luò),而不拘泥于細(xì)節(jié)。相對來說,VFS部分的代碼比較繁瑣復(fù)雜,若要對Linux下的VFS整體運(yùn)作機(jī)制有個(gè)清楚的理解,建議學(xué)習(xí)本節(jié)前,先閱讀文件系統(tǒng)的源代碼,以便建立起Linux中文件系統(tǒng)最基本的概念,至少應(yīng)熟悉super、block、dentry、inode、vfsmount等數(shù)據(jù)結(jié)構(gòu)所表示的意義。
7.2.1VFS概述
VFS是一種軟件機(jī)制,稱為Linux的文件系統(tǒng)管理者似乎更確切些。與VFS相關(guān)的數(shù)據(jù)結(jié)構(gòu)只存在于物理內(nèi)存當(dāng)中,所以在每次系統(tǒng)初始化期間,Linux都首先要在內(nèi)存當(dāng)中構(gòu)造VFS的目錄樹(在Linux的源代碼里稱之為namespace),實(shí)際上便是在內(nèi)存中建立相應(yīng)的數(shù)據(jù)結(jié)構(gòu)。VFS目錄樹在Linux的文件系統(tǒng)模塊中是很重要的概念,不要將其與實(shí)際文件系統(tǒng)目錄樹相混淆。VFS中的各目錄其主要用途是用來提供實(shí)際文件系統(tǒng)的掛載點(diǎn),當(dāng)然在VFS中也會(huì)涉及到文件級的操作,此處不涉及這種情況。下文提到的目錄樹或目錄,如果不特別說明,均指VFS的目錄樹或目錄。圖7-5是一種可能的目錄樹在內(nèi)存中的映像。
圖7-5VFS目錄樹在內(nèi)存中的映像7.2.2文件系統(tǒng)的注冊
文件系統(tǒng)是指會(huì)被掛載到目錄樹中的各個(gè)實(shí)際文件系統(tǒng)。所謂實(shí)際文件系統(tǒng),即是指VFS中的實(shí)際操作最終要通過它們來完成,并不意味著一定要存在于某種特定的存儲(chǔ)設(shè)備上。比如在Linux下可注冊“rootfs”、“proc”、“ext2”、“sockfs”等十幾種文件系統(tǒng)。1.?dāng)?shù)據(jù)結(jié)構(gòu)
在Linux源代碼中,每種實(shí)際的文件系統(tǒng)用以下的數(shù)據(jù)結(jié)構(gòu)表示:
structfile_system_type{
constchar*name;
int
fs_flags;
structsuper_block*(*read_super)(structsuper_block*,void*,int);
structmodule*owner;
structfile_system_type*next;
structlist_headfs_supers;};
注冊過程實(shí)際上是將表示各實(shí)際文件系統(tǒng)的structfile_system_type數(shù)據(jù)結(jié)構(gòu)實(shí)例化,然后形成一個(gè)鏈表,內(nèi)核中用file_systems的全局變量來指向該鏈表的表頭。
2.注冊rootfs文件系統(tǒng)
在眾多的實(shí)際文件系統(tǒng)中,之所以單獨(dú)介紹rootfs文件系統(tǒng)的注冊過程,是因?yàn)樵撐募到y(tǒng)與VFS的關(guān)系密切,rootfs文件系統(tǒng)是VFS存在的基礎(chǔ)。一般文件系統(tǒng)的注冊都是通過module_init宏以及do_initcalls()函數(shù)完成的(可參考module_init宏的聲明及arch\i386\vmlinux.lds文件來理解這一過程),但是rootfs的注冊是通過init_rootfs()這一初始化函數(shù)來完成的,這意味著rootfs的注冊過程是Linux內(nèi)核初始化階段不可分割的一部分。init_rootfs()通過調(diào)用register_filesystem(&rootfs_fs_type)函數(shù)完成rootfs文件系統(tǒng)注冊,其中rootfs_fs_type定義如下:
structfile_system_typerootfs_fs_type={\name:“rootfs”,\
read_super:ramfs_read_super,\
fs_flags:FS_NOMOUNT|FS_LITTER,\
owner:THIS_MODULE,\
}
注冊之后的file_systems鏈表結(jié)構(gòu)如圖7-6所示。圖7-6file_systems鏈表結(jié)構(gòu)
7.2.3VFS目錄樹的建立
本節(jié)闡述Linux在初始化階段如何建立根節(jié)點(diǎn),即“/”目錄,其中包括掛載rootfs文件系統(tǒng)到根目錄“/”的具體過程。構(gòu)造根目錄的代碼在init_mount_tree()函數(shù)(fs\namespace.c)中。
首先,init_mount_tree()函數(shù)調(diào)用do_kern_mount("rootfs",0,"rootfs",NULL)來掛載已經(jīng)注冊的rootfs文件系統(tǒng)。根據(jù)前面的說法,應(yīng)該先有掛載目錄,然后在其上掛載相應(yīng)的文件系統(tǒng),然而此時(shí)VFS并沒有建立其根目錄。這是因?yàn)檫@里調(diào)用的do_kern_mount()函數(shù)內(nèi)部自然會(huì)創(chuàng)建關(guān)鍵的根目錄(在Linux中,目錄對應(yīng)的數(shù)據(jù)結(jié)構(gòu)是structdentry)。在這種情況下,do_kern_mount()做的工作主要如下:
(1)調(diào)用alloc_vfsmnt()函數(shù)在內(nèi)存里申請一塊該類型的內(nèi)存空間(structvfsmount*mnt),并初始化其部分成員變量。
(2)調(diào)用get_sb_nodev()函數(shù)在內(nèi)存中分配一個(gè)超級塊結(jié)構(gòu)(structsuper_block)sb,并初始化其部分成員變量,將成員s_instances插入到rootfs文件系統(tǒng)類型結(jié)構(gòu)中fs_supers指向的雙向鏈表中。
(3)通過rootfs文件系統(tǒng)中的read_super函數(shù)指針調(diào)用ramfs_read_super()函數(shù)。當(dāng)初注冊rootfs文件系統(tǒng)時(shí),其成員read_super指針指向了ramfs_read_super()函數(shù),參見圖7-7。圖7-7分配各種數(shù)據(jù)結(jié)構(gòu)和rootfs文件系統(tǒng)的關(guān)系
(4)ramfs_read_super()函數(shù)調(diào)用ramfs_get_inode()在內(nèi)存中分配了一個(gè)inode結(jié)構(gòu)(StructInode),并初始化其部分成員變量,其中比較重要的有i_op、i_fop和i_sb:
inode->i_op=&ramfs_dir_inode_operations;
inode->i_fop=&dcache_dir_ops;
inode->i_sb=sb;
這使得將來通過文件系統(tǒng)調(diào)用對VFS發(fā)起的文件操作等指令將被rootfs文件系統(tǒng)中相應(yīng)的函數(shù)接口所接管。
(5)?ramfs_read_super()函數(shù)在分配和初始化了inode結(jié)構(gòu)之后,調(diào)用d_alloc_root()函數(shù)為VFS的目錄樹建立起關(guān)鍵的根目錄(structdentry)dentry,并將dentry中的d_sb指針指向sb,d_inode指針指向inode。
(6)將mnt中的mnt_sb指針指向sb,mnt_root和mnt_mountpoint指針指向dentry,而mnt_parent指針則指向自身。
因此,當(dāng)do_kern_mount()函數(shù)返回時(shí),以上分配得到的各數(shù)據(jù)結(jié)構(gòu)和rootfs文件系統(tǒng)的關(guān)系如圖7-7所示。圖中mnt、sb、inode、dentry結(jié)構(gòu)塊下方的數(shù)字表示它們在內(nèi)存里被分配的先后順序。限于篇幅的原因,各結(jié)構(gòu)中只給出了部分成員變量,可以對照源代碼根據(jù)圖中所示加以理解。
最后,init_mount_tree()函數(shù)會(huì)為系統(tǒng)最開始的進(jìn)程(即init_task進(jìn)程)準(zhǔn)備它的進(jìn)程數(shù)據(jù)塊中的namespace域,主要目的是將do_kern_mount()函數(shù)中建立的mnt和dentry信息記錄在init_task進(jìn)程的進(jìn)程數(shù)據(jù)塊中,所有以后從init_task進(jìn)程fork出來的進(jìn)程也都先天地繼承了這一信息,在后面用sys_mkdir在VFS中創(chuàng)建目錄的過程中,為進(jìn)程建立namespace的主要代碼如下:namespace=kmalloc(sizeof(*namespace),GFP_KERNEL);
list_add(&mnt->mnt_list,&namespace->list);//mntisreturnedbydo_kern_mount()
namespace->root=mnt;
init_space=namespace;
for_each_task(p){
get_namespace(namespace);
p->namespace=namespace;
}
set_fs_pwd(current->fs,namespace->root,namespace->root->mnt_root);
set_fs_root(current->fs,namespace->root,namespace->root->mnt_root);
該段代碼的最后兩行便是將do_kern_mount()函數(shù)中建立的mnt和dentry信息記錄在當(dāng)前進(jìn)程的fs結(jié)構(gòu)中。
對以上數(shù)據(jù)結(jié)構(gòu)來歷的描述,最終是要在內(nèi)存中建立VFS目錄樹。更確切地說,init_mount_tree()函數(shù)為VFS建立了根目錄“/”,而一旦有了根目錄,就可以通過系統(tǒng)調(diào)用sys_mkdir建立新的節(jié)點(diǎn),所以系統(tǒng)設(shè)計(jì)者又將rootfs文件系統(tǒng)掛載到了根目錄上。關(guān)于rootfs文件系統(tǒng),如果參考一下圖7-6中的file_system_type結(jié)構(gòu),會(huì)發(fā)現(xiàn)一個(gè)成員函數(shù)指針read_super指向的是ramfs_read_super,單從這個(gè)函數(shù)名稱中的Ramfs,這個(gè)文件所涉及的文件操作都是針對內(nèi)存中的數(shù)據(jù)對象。從另一個(gè)角度而言,VFS本身就是內(nèi)存中的一個(gè)數(shù)據(jù)對象,在其上的操作僅限于內(nèi)存。在接下來的章節(jié)中,將通過具體的例子討論如何利用rootfs所提供的函數(shù)為VFS增加一個(gè)新的目錄節(jié)點(diǎn)。
VFS中各目錄的主要用途是為以后掛載文件系統(tǒng)提供掛載點(diǎn),所以真正的文件操作還是通過掛載后的文件系統(tǒng)提供的功能接口來進(jìn)行。7.2.4VFS下目錄的建立
為了更好地理解VFS,下文通過實(shí)例描述Linux如何在VFS的根目錄下建立新的目錄“/dev”。
要在VFS中建立新的目錄,首先對該目錄進(jìn)行搜索,搜索的目的是找到將要建立的目錄其父目錄的相關(guān)信息。比如要建立目錄/home/ricard,那么首先必須沿目錄路徑進(jìn)行逐層搜索。本例先從根目錄找起,然后在根目錄下找到home目錄,然后再往下,便是要新建的目錄名ricard,那么前面提到的要先對目錄搜索,在該例中便是要找到ricard這個(gè)新目錄的父目錄,也就是home目錄所對應(yīng)的信息。當(dāng)然,如果搜索的過程中發(fā)現(xiàn)錯(cuò)誤,比如要建立目錄的父目錄并不存在,或者當(dāng)前進(jìn)程并無相應(yīng)的權(quán)限等等,這種情況下系統(tǒng)必然會(huì)調(diào)用相關(guān)的過程進(jìn)行處理。
Linux下用系統(tǒng)調(diào)用sys_mkdir在VFS目錄樹中增加新節(jié)點(diǎn)。同時(shí),為了配合路徑搜索,引入了下面一個(gè)數(shù)據(jù)結(jié)構(gòu):
structnameidata{
structdentry*dentry;
structvfsmount*mnt;
structqstrlast;
unsignedintflags;
intlast_type;
};這個(gè)數(shù)據(jù)結(jié)構(gòu)在路徑搜索的過程中用來記錄相關(guān)信息,起著類似“路標(biāo)”的作用。其中前兩項(xiàng)中的dentry記錄的是要建立目錄的父目錄信息,mnt成員接下來會(huì)予以解釋。后三項(xiàng)記錄的是所查找路徑的最后一個(gè)節(jié)點(diǎn)(即待建目錄或文件)信息?,F(xiàn)在為建立目錄“/dev”而調(diào)用sys_mkdir("/dev",0700),其中參數(shù)0700不需關(guān)注,只是限定將要建立目錄的某種模式。sys_mkdir函數(shù)首先調(diào)用path_lookup("/dev",LOOKUP_PARENT,&nd)對路徑查找,其中nd為structnameidatand聲明的變量。在接下來的敘述中,因?yàn)楹瘮?shù)調(diào)用關(guān)系較繁瑣,為了突出過程主線,將不再嚴(yán)格按照函數(shù)的調(diào)用關(guān)系來描述。
path_lookup發(fā)現(xiàn)“/dev”是以“/”開頭,所以從當(dāng)前進(jìn)程的根目錄開始往下查找,具體代碼如下:
nd->mnt=mntget(current->fs->rootmnt);
nd->dentry=dget(current->fs->root);
在init_mount_tree()函數(shù)的后半段曾經(jīng)將新建立的VFS根目錄相關(guān)信息記錄在了init_task進(jìn)程的進(jìn)程數(shù)據(jù)塊中,于是nd->mnt便指向了圖7-7中的mnt變量,nd->dentry便指向了圖7-7中的dentry變量。然后調(diào)用函數(shù)path_walk接著查找,運(yùn)行一次最后通過變量nd返回的信息是=“dev”,nd.last.len=3,nd.last_type=LAST_NORM,至于nd中mnt和dentry成員,此時(shí)還是前面設(shè)置的值,并無變化。這樣運(yùn)行一次,只是用nd記錄了相關(guān)信息,實(shí)際的目錄建立工作并沒有真正展開,但是前面所做的工作卻為接下來建立新節(jié)點(diǎn)收集了必要的信息。
到此為止,真正建立新目錄節(jié)點(diǎn)的工作即將展開,由函數(shù)lookup_create來完成,調(diào)用這個(gè)函數(shù)時(shí)會(huì)傳入兩個(gè)參數(shù):lookup_create(&nd,1)。其中參數(shù)nd便是前面提到的變量,參數(shù)1表明要建立一個(gè)新目錄。建立新目錄節(jié)點(diǎn)的過程如下:新分配了一個(gè)structdentry結(jié)構(gòu)的內(nèi)存空間,用于記錄dev目錄所對應(yīng)的信息,該dentry結(jié)構(gòu)將會(huì)掛接到其父目錄中,也就是圖7-7中“/”目錄對應(yīng)的dentry結(jié)構(gòu)中,由鏈表實(shí)現(xiàn)這一關(guān)系。接下來再分配一個(gè)structinode結(jié)構(gòu)。inode中的i_sb和dentry中的d_sb分別
都指向圖7-7中的sb,在同一文件系統(tǒng)下建立新的目錄時(shí)并不需要重新分配超級塊結(jié)構(gòu),因?yàn)樗鼈兌紝儆谕晃募到y(tǒng),所以一個(gè)文件系統(tǒng)只對應(yīng)一個(gè)超級塊。當(dāng)調(diào)用sys_mkdir成功地在VFS的目錄樹中新建立一個(gè)目錄“/dev”之后,在圖7-7的基礎(chǔ)上,新的數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系如圖7-8所示。圖7-8中兩個(gè)矩形塊new_inode和new_dentry便是在sys_mkdir()函數(shù)中新分配的內(nèi)存結(jié)構(gòu),至于圖中的mnt、sb、dentry、inode等結(jié)構(gòu),仍為圖7-7中相應(yīng)的數(shù)據(jù)結(jié)構(gòu),其相互之間的鏈接關(guān)系不變(圖中為避免過多的鏈接曲線,忽略了一些鏈接關(guān)系,如mnt和sb、dentry之間的鏈接,可在圖7-7的基礎(chǔ)上參看圖7-8)。圖7-8在VFS樹中新建一目錄“dev”既然rootfs文件系統(tǒng)被掛載到了VFS樹上,rootfs在sys_mkdir的過程中必然會(huì)參與進(jìn)來,在整個(gè)過程中,rootfs文件系統(tǒng)中的ramfs_mkdir、ramfs_lookup等函數(shù)都曾被調(diào)用過。7.2.5在VFS樹中掛載文件系統(tǒng)
在本節(jié)中,將描述在VFS的目錄樹中向其中某個(gè)目錄(安裝點(diǎn)(MountPoint))上掛載(Mount)一個(gè)文件系統(tǒng)的過程。
將某一設(shè)備(dev_name)上某一文件系統(tǒng)(file_system_type)安裝到VFS目錄樹上的某一安裝點(diǎn)(dir_name)。要解決的問題是:將對VFS目錄樹中某一目錄的操作轉(zhuǎn)化為具體安裝到其上的實(shí)際文件系統(tǒng)的對應(yīng)操作。比如說,如果將hda2上的根文件系統(tǒng)(假設(shè)文件系統(tǒng)類型為Ext2)安裝到了前一節(jié)中新建立的“/dev”目錄上(此時(shí),“/dev”目錄就成為了安裝點(diǎn)),那么安裝成功之后應(yīng)達(dá)到這樣的目的,即對VFS文件系統(tǒng)的“/dev”目錄執(zhí)行l(wèi)s指令,該條指令應(yīng)能列出hda2上Ext2文件系統(tǒng)的根目錄下所有的目錄和文件。這里的關(guān)鍵是如何將對VFS樹中“/dev”的目錄操作指令轉(zhuǎn)化為安裝在其上的Ext2這一實(shí)際文件系統(tǒng)中的相應(yīng)指令。對目錄或文件的操作將最終由目錄或文件所對應(yīng)的inode結(jié)構(gòu)中的i_op和i_fop所指向的函數(shù)表中對應(yīng)的函數(shù)來執(zhí)行。
通過將對“/dev”目錄所對應(yīng)的inode中i_op和i_fop的調(diào)用轉(zhuǎn)換到hda2上根文件系統(tǒng)ext2中根目錄所對應(yīng)的inode中i_op和i_fop的操作。
初始過程由sys_mount()系統(tǒng)調(diào)用函數(shù)發(fā)起,該函數(shù)原型聲明如下:
asmlinkagelongsys_mount(char*dev_name,char*dir_name,char*type,
unsignedlongflags,void*data);
其中,參數(shù)char*type為標(biāo)識(shí)將要安裝的文件系統(tǒng)類型字符串,對于Ext2文件系統(tǒng)而言,就是“ext2”。參數(shù)flags為安裝時(shí)的模式標(biāo)識(shí)數(shù),和接下來的data參數(shù)一樣。為了更好地理解這一過程,下面列舉一個(gè)具體實(shí)例,將來自主硬盤第2分區(qū)(hda2)上的Ext2文件系統(tǒng)安裝到前面創(chuàng)建的“/dev”目錄中,那么對于sys_mount()函數(shù)的調(diào)用具體為
sys_mount(“hda2”,“/dev”,“ext2”,…);
該函數(shù)在將這些來自用戶內(nèi)存空間(UserSpace)的參數(shù)拷貝到內(nèi)核空間后,便調(diào)用do_mount()函數(shù)開始真正的文件系統(tǒng)安裝。
do_mount()函數(shù)首先調(diào)用path_lookup()函數(shù)得到安裝點(diǎn)的相關(guān)信息,如同創(chuàng)建目錄過程所述,該安裝點(diǎn)的信息最終記錄在structnameidata類型的變量中,為敘述方便,記該變量為nd。在本例中,當(dāng)path_lookup()函數(shù)返回時(shí),nd中記錄的信息如下:nd.entry=new_entry;nd.mnt=mnt;?,變量如圖7-7和圖7-8中所示。
然后,do_mount()函數(shù)根據(jù)調(diào)用參數(shù)flags決定調(diào)用以下四個(gè)函數(shù)之一:do_remount()、do_loopback()、do_move_mount()、do_add_mount()。在當(dāng)前的例子中,系統(tǒng)會(huì)調(diào)用do_add_mount()函數(shù)來向VFS樹中的安裝點(diǎn)“/dev”安裝一個(gè)實(shí)際的文件系統(tǒng)。在do_add_mount()中,主要完成了兩件重要事情:一是獲得一個(gè)新的安裝區(qū)域塊,二是將該新的安裝區(qū)域塊加入安裝系統(tǒng)鏈表。分別調(diào)用do_kern_mount()函數(shù)和graft_tree()函數(shù)完成。
do_kern_mount()函數(shù)建立新的安裝區(qū)域塊,具體內(nèi)容在前面VFS目錄樹的建立中已經(jīng)敘述。
graft_tree()函數(shù)將do_kern_mount()函數(shù)返回的structvfsmount類型的變量加入到安裝系統(tǒng)鏈表中,同時(shí)graft_tree()將新分配的structvfsmount類型的變量加入到一個(gè)hash表中。當(dāng)do_kern_mount()函數(shù)返回時(shí),在圖7-8的基礎(chǔ)上,新的數(shù)據(jù)結(jié)構(gòu)間的關(guān)系將如圖7-9所示。其中,圓圈區(qū)域里面的數(shù)據(jù)結(jié)構(gòu)便是安裝區(qū)域塊的內(nèi)容,其中可以稱e2_mnt為安裝區(qū)域塊的指針,始于e2.mnt的三條箭頭曲線即構(gòu)成了安裝系統(tǒng)鏈表。圖7-9安裝ext2類型根文件系統(tǒng)到“/dev”目錄上在把這些函數(shù)調(diào)用后形成的數(shù)據(jù)結(jié)構(gòu)關(guān)系理清之后,再回到本節(jié)開始提到的問題,即將ext2文件系統(tǒng)安裝到了“/dev”上之后,對該目錄上的操作如何轉(zhuǎn)化為對ext2文件系統(tǒng)相應(yīng)的操作。從圖7-9上可看到,對sys_mount()函數(shù)的調(diào)用并沒有直接改變“/dev”目錄所對應(yīng)的inode(即圖中的new_inode變量)結(jié)構(gòu)中的i_op和i_fop指針,而且“/dev”所對應(yīng)的dentry(即圖中的new_dentry變量)結(jié)構(gòu)仍然在VFS的目錄樹中,并沒有被隱藏。相應(yīng)地,來自hda2上的ext2文件系統(tǒng)的根目錄所對應(yīng)的e2_entry也不是將VFS目錄樹中的new_dentry取而代之,那么這之間的轉(zhuǎn)化如何實(shí)現(xiàn)?請注意下面的這段代碼:
while(d_mountpoint(dentry)&&__follow_down(&nd->mnt,&dentry));
這段代碼在link_path_walk()函數(shù)中被調(diào)用,link_path_
walk()最終又會(huì)被path_lookup()函數(shù)調(diào)用,如果閱讀過Linux關(guān)于文件系統(tǒng)部分的代碼,就可以了解path_lookup()函數(shù)在整個(gè)Linux繁瑣的文件系統(tǒng)代碼中屬于一個(gè)重要的基礎(chǔ)性的函數(shù)。這個(gè)函數(shù)用于解析文件路徑名,這里的文件路徑名和在應(yīng)用程序中所涉及到的概念相同,比如在Linux的應(yīng)用程序中打開或讀取一個(gè)文件/home/windfly.cs時(shí),這里的/home/windfly.cs就是文件路徑名,path_lookup()函數(shù)的責(zé)任就是對文件路徑名進(jìn)行搜索,直到找到目標(biāo)文件所屬目錄對應(yīng)的dentry或者將目標(biāo)直接作為一個(gè)目錄,只要記住path_lookup()會(huì)返回一個(gè)目標(biāo)目錄即可。上面的代碼在總體中不很顯著,以至于初次閱讀文件系統(tǒng)的代碼時(shí)會(huì)忽略掉,但是前文所提到從VFS的操作到實(shí)際文件系統(tǒng)操作的轉(zhuǎn)化卻由它完成,對VFS中實(shí)現(xiàn)的文件系統(tǒng)的安裝十分重要。仔細(xì)剖析該段代碼:d_mountpoint
(dentry)的作用很簡單,只是返回dentry中d_mounted成員變量的值。這里的dentry仍然是在VFS目錄樹上。如果VFS目錄樹上某個(gè)目錄被安裝過一次,那么該值為1。對VFS中的目錄可進(jìn)行多次安裝,后面會(huì)有例子說明。
/dev”所對應(yīng)的new_dentry中d_mounted=1,所以while循環(huán)中第一個(gè)條件滿足。在_follow_down(&nd->mnt,&dentry)代碼中,nd中的dentry成員就是圖7-9所示的new_dentry,nd中的mnt成員就是圖7-9所示的mnt,所以可以_follow_down
(&nd->mnt,&dentry)改寫成_follow_down(&mnt,?&new_
dentry)。接下來將_follow_down()函數(shù)的代碼改寫(只是去除掉一些不太相關(guān)的代碼,并且為了便于說明,在部分代碼行前加上了序號(hào))如下:staticinlineint__follow_down(structvfsmount**mnt,structdentry**dentry)
{
structvfsmount*mounted;
[1]mounted=lookup_mnt(*mnt,*dentry);
if(mounted){
[2]*mnt=mounted;
[3]*dentry=mounted->mnt_root;
return1;
}
return0;
}代碼行[1]中的lookup_mnt()函數(shù)用于查找VFS目錄樹下某一目錄最近一次被掛載時(shí)的安裝區(qū)域塊的指針,在本例中最終會(huì)返回圖7-9中的e2_mnt。查找的原理如下:當(dāng)在安裝ext2文件系統(tǒng)到“/dev”時(shí),在后期會(huì)調(diào)用graft_tree()函數(shù),在這個(gè)函數(shù)里會(huì)把圖7-9中的安裝區(qū)域塊指針e2_mnt掛到hash表(Linux2.4.20源代碼中稱之為mount_hashtable)中的某一項(xiàng),而該項(xiàng)的鍵值由被安裝點(diǎn)所對應(yīng)的dentry(本例中new_dentry)
和
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024標(biāo)準(zhǔn)技術(shù)服務(wù)采購協(xié)議:精準(zhǔn)定制版B版
- 2024年項(xiàng)目居間服務(wù)協(xié)議標(biāo)準(zhǔn)格式一
- 2024潤滑油行業(yè)展會(huì)贊助與推廣合作合同3篇
- 四川省宜賓市中考語文試卷五套【附參考答案】
- 專用場地租賃合作分成合同全文預(yù)覽一
- 16《人的呼吸》說課稿-2024-2025學(xué)年三年級上冊科學(xué)蘇教版
- 2024年石粉購銷合同協(xié)議規(guī)定規(guī)定樣本
- 2025年度網(wǎng)絡(luò)安全隱秘操作風(fēng)險(xiǎn)評估與監(jiān)管服務(wù)協(xié)議3篇
- 2024鄭州二手房買賣合同的文本
- 福建省南平市衛(wèi)閩中學(xué)2021年高二地理月考試卷含解析
- 專項(xiàng)債券培訓(xùn)課件
- 2025年1月普通高等學(xué)校招生全國統(tǒng)一考試適應(yīng)性測試(八省聯(lián)考)語文試題
- CNAS-CL01-G001:2024檢測和校準(zhǔn)實(shí)驗(yàn)室能力認(rèn)可準(zhǔn)則的應(yīng)用要求
- 校園重點(diǎn)防火部位消防安全管理規(guī)定(3篇)
- 臨時(shí)施工圍擋安全應(yīng)急預(yù)案
- ICP-網(wǎng)絡(luò)與信息安全保障措施-1.信息安全管理組織機(jī)構(gòu)設(shè)置及工作職責(zé)
- 育肥牛購銷合同范例
- 2024城市河湖底泥污染狀況調(diào)查評價(jià)技術(shù)導(dǎo)則
- MT-T 1199-2023 煤礦用防爆柴油機(jī)無軌膠輪運(yùn)輸車輛通用安全技術(shù)條件
- 《無成人陪伴兒童乘機(jī)申請書》樣本
- 超星爾雅學(xué)習(xí)通【西方文論原典導(dǎo)讀(吉林大學(xué))】章節(jié)測試附答案
評論
0/150
提交評論