JFFS2 文件系統(tǒng)及新特性介紹
JFFS2 是一個(gè)開放源碼的項(xiàng)目(www.infradead.org)。 它是在閃存上使用非常廣泛的讀/寫文件系統(tǒng),在嵌入式系統(tǒng)中被普遍的應(yīng)用。這篇文章首先分析了在閃存上使用 JFFS2 的必要性,然后詳細(xì)的闡述了 JFFS2 實(shí)現(xiàn)的內(nèi)部機(jī)制,包括日志結(jié)構(gòu)的文件系統(tǒng),關(guān)鍵的數(shù)據(jù)結(jié)構(gòu),掛載過程和垃圾收集機(jī)制。同時(shí)也指出了 JFFS2 的局限性,并介紹了最新的針對(duì) JFFS2 的不足進(jìn)行改進(jìn)的補(bǔ)丁程序。最后對(duì) JFFS3 的設(shè)計(jì)思想和現(xiàn)在的開發(fā)狀況給予了簡單的介紹。
1. 為什么需要 JFFS2
本文引用地址:http://m.butianyuan.cn/article/257970.htm這一小節(jié)首先介紹了閃存相對(duì)于磁盤介質(zhì)的特別之處,然后分析了將磁盤文件系統(tǒng)運(yùn)行在閃存上的不足,同時(shí)也給出了我們使用 JFFS2 的理由。
1.1 閃存(Flash Memory) 的特性和限制
這里所介紹的閃存的特性和限制都是從上層的文件系統(tǒng)的角度來看的,而不會(huì)涉及到具體的物理特性??偟膩碚f,有兩種類型的 flash memory: NOR flash 和 NAND flash. 先介紹一下這兩種閃存所具有的共同特性。
A) 閃存的最小尋址單位是字節(jié)(byte),而不是磁盤上的扇區(qū)(sector)。這意味著我們可以從一塊閃存的任意偏移(offset)讀數(shù)據(jù),但并不表明對(duì)閃存寫操作也是以字節(jié)為單位進(jìn)行的。我們會(huì)在下面的闡述中找到答案。
B) 當(dāng)一塊閃存處在干凈的狀態(tài)時(shí)(被擦寫過,但是還沒有寫操作發(fā)生),在這塊flash上的每一位(bit)都是邏輯1。
C) 閃存上的每一位(bit)可以被寫操作置成邏輯0。 可是把邏輯 0 置成邏輯 1 卻不能按位(bit)來操作,而只能按擦寫塊(erase block)為單位進(jìn)行擦寫操作。擦寫塊的大小從 4K 到128K 不等。從上層來看,擦寫所完成的功能就是把擦寫塊內(nèi)的每一位都重設(shè)置(reset)成邏輯 1。
D) 閃存的使用壽命是有限的。具體來說,閃存的使用壽命是由擦寫塊的最大可擦寫次數(shù)來決定的。超過了最大可擦寫次數(shù),這個(gè)擦寫塊就成為壞塊(bad block)了。因此為了避免某個(gè)擦寫塊被過度擦寫,以至于它先于其他的擦寫塊達(dá)到最大可擦寫次數(shù),我們應(yīng)該在盡量小的影響性能的前提下,使擦寫操作均勻的分布在每個(gè)擦寫塊上。這個(gè)過程叫做磨損平衡(wear leveling)。
NOR flash 與 NAND flash 的不同之處:
A) NOR flash 讀/寫操作的基本單位是字節(jié);而 NAND flash 又把擦寫塊分成頁(page), 頁是寫操作的基本單位,一般一個(gè)頁的大小是 512 或 2K 個(gè)字節(jié)。對(duì)于一個(gè)頁的重復(fù)寫操作次數(shù)是有限制的,不同廠商生產(chǎn)的 NAND flash 有不同的限制,有些是一次,有些是四次,六次或十次。
B) 按照現(xiàn)在的技術(shù)水平,一般來說NOR flash擦寫塊的最大可擦寫次數(shù)在十萬次左右,NAND flash擦寫塊的最大可擦寫次數(shù)在百萬次左右。
1.2 閃存轉(zhuǎn)換層
將磁盤文件系統(tǒng)(ext2, FAT)運(yùn)行在閃存上的很自然的方法就是在文件系統(tǒng)和閃存之間提供一個(gè)閃存轉(zhuǎn)換層(Flash Translation Layer), 它的功能就是將底層的閃存模擬成一個(gè)具有 512字節(jié)扇區(qū)大小的標(biāo)準(zhǔn)塊設(shè)備(block device)。對(duì)于文件系統(tǒng)來說,就像工作在一個(gè)普通的塊設(shè)備上一樣,沒有任何的差別。
圖一
一個(gè)閃存轉(zhuǎn)換層的最簡單的實(shí)現(xiàn)就是將模擬的塊設(shè)備一對(duì)一的映射到閃存上。舉例來說,當(dāng)上層的文件系統(tǒng)要寫一個(gè)塊設(shè)備的扇區(qū)時(shí),閃存轉(zhuǎn)換層要做下面的操作來完成這個(gè)寫請(qǐng)求:
1 將這個(gè)扇區(qū)所在擦寫塊地?cái)?shù)據(jù)讀到內(nèi)存中,放在緩存(buffer)中
2 將緩存中與這個(gè)扇區(qū)對(duì)應(yīng)的內(nèi)容用新的內(nèi)容替換掉
3 對(duì)該擦寫塊執(zhí)行擦寫操作
4 將緩沖中的數(shù)據(jù)寫回該擦寫塊
這種實(shí)現(xiàn)方式的缺點(diǎn)是很明顯的:
1 效率低,對(duì)一個(gè)扇區(qū)的更新要重寫整個(gè)擦寫塊上的數(shù)據(jù),造成數(shù)據(jù)帶寬很大的浪費(fèi)。
2 沒有提供磨損平衡,那些被頻繁更新的數(shù)據(jù)所在擦寫塊將首先變成壞塊。
3 非常不安全,很容易引起數(shù)據(jù)的丟失。如果在上面的第三步和第四步之間發(fā)生了突然掉電(power loss),那么整個(gè)擦寫塊中的數(shù)據(jù)就全部丟失了。這在突然掉電經(jīng)常發(fā)生的嵌入式系統(tǒng)中是不能接受的。
MTD 中的內(nèi)核模塊 mtdblock 就是基于這種機(jī)制實(shí)現(xiàn)的,同時(shí)還作了一些優(yōu)化。只有當(dāng)文件系統(tǒng)的寫請(qǐng)求超過了一個(gè)擦寫塊的邊界的時(shí)候,它才會(huì)執(zhí)行對(duì)閃存的擦寫,寫回操作。
因此,為了解決上面這種實(shí)現(xiàn)方式的問題,閃存轉(zhuǎn)換層需要做更多的事情。閃存轉(zhuǎn)換層不能只實(shí)現(xiàn)這種一對(duì)一的映射,而需要將模擬塊設(shè)備的扇區(qū)存儲(chǔ)在閃存的不同位置,并且維持扇區(qū)到閃存的映射關(guān)系。更進(jìn)一步,閃存轉(zhuǎn)換層還必須能理解上層文件系統(tǒng)的語義,否則閃存轉(zhuǎn)換層沒辦法做垃圾回收(Garbage Collection)。這樣實(shí)現(xiàn)最大的問題就是效率不高,具體來說,閃存轉(zhuǎn)換層為了能理解上層文件系統(tǒng)的語義,必須對(duì)文件系統(tǒng)的每個(gè)寫請(qǐng)求進(jìn)行解析,這勢必帶來寫操作性能的下降。另外要求文件系統(tǒng)下面的一層去理解文件系統(tǒng)的語義,很顯然這不是最好的解決方式。我們還有很好的解決問題的方法,就是實(shí)現(xiàn)一個(gè)特別針對(duì)閃存的文件系統(tǒng)。而 JFFS2 就是一個(gè)這樣的文件系統(tǒng)。
2. JFFS2
有 JFFS2 就要有 JFFS v1,沒錯(cuò),JFFS v1 最初是由瑞典的 Axis Communications AB 公司開發(fā)的,使用在他們的嵌入式設(shè)備中,并且在 1999 年末基于 GNU GPL 發(fā)布出來。最初的發(fā)布版本基于 Linux 內(nèi)核 2.0,后來 RedHat 將它移植到 Linux 內(nèi)核 2.2,做了大量的測試和 bug fix 的工作使它穩(wěn)定下來,并且對(duì)簽約客戶提供商業(yè)支持。但是在使用的過程中,JFFS v1 設(shè)計(jì)中的局限被不斷的暴露出來。于是在 2001 年初的時(shí)候,RedHat 決定實(shí)現(xiàn)一個(gè)新的閃存文件系統(tǒng),這就是現(xiàn)在的 JFFS2。下面將詳細(xì)介紹 JFFS2 設(shè)計(jì)中主要的思想,關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)和垃圾收集機(jī)制。這將為我們實(shí)現(xiàn)一個(gè)閃存上的文件系統(tǒng)提供很好的啟示。首先,JFFS2 是一個(gè)日志結(jié)構(gòu)(log-structured)的文件系統(tǒng),包含數(shù)據(jù)和原數(shù)據(jù)(meta-data)的節(jié)點(diǎn)在閃存上順序的存儲(chǔ)。JFFS2 之所以選擇日志結(jié)構(gòu)的存儲(chǔ)方式,是因?yàn)閷?duì)閃存的更新應(yīng)該是 out-of-place 的更新方式,而不是對(duì)磁盤的 in-place 的更新方式。在閃存上 in-place 更新方式的問題我們已經(jīng)在閃存轉(zhuǎn)換層一節(jié)描述過了。
2.1 節(jié)點(diǎn)頭部定義和兼容性
JFFS2 將文件系統(tǒng)的數(shù)據(jù)和原數(shù)據(jù)以節(jié)點(diǎn)的形式存儲(chǔ)在閃存上,具體來說節(jié)點(diǎn)頭部的定義如下:
圖二
幻數(shù)屏蔽位:0x1985 用來標(biāo)識(shí) JFFS2 文件系統(tǒng)。
節(jié)點(diǎn)類型:JFFS2 自身定義了三種節(jié)點(diǎn)類型,但是考慮到文件系統(tǒng)可擴(kuò)展性和兼容性,JFFS2從 ext2 借鑒了經(jīng)驗(yàn),節(jié)點(diǎn)類型的最高兩位被用來定義節(jié)點(diǎn)的兼容屬性,具體來說有下面幾種兼容屬性:
JFFS2_FEATURE_INCOMPAT:當(dāng) JFFS2 發(fā)現(xiàn)了一個(gè)不能識(shí)別的節(jié)點(diǎn)類型,并且它的兼容屬性是 JFFS2_FEATURE_INCOMPAT,那么 JFFS2 必須拒絕掛載(mount)文件系統(tǒng)。
JFFS2_FEATURE_ROCOMPAT:當(dāng) JFFS2 發(fā)現(xiàn)了一個(gè)不能識(shí)別的節(jié)點(diǎn)類型,并且它的兼容屬性是 JFFS2_FEATURE_ROCOMPAT,那么 JFFS2 必須以只讀的方式掛載文件系統(tǒng)。
JFFS2_FEATURE_RWCOMPAT_DELETE:當(dāng) JFFS2 發(fā)現(xiàn)了一個(gè)不能識(shí)別的節(jié)點(diǎn)類型,并且它的兼容屬性是 JFFS2_FEATURE_RWCOMPAT_DELETE,那么在垃圾回收的時(shí)候,這個(gè)節(jié)點(diǎn)可以被刪除。
JFFS2_FEATURE_RWCOMPAT_COPY:當(dāng) JFFS2 發(fā)現(xiàn)了一個(gè)不能識(shí)別的節(jié)點(diǎn)類型,并且它的兼容屬性是 JFFS2_FEATURE_RWCOMPAT_COPY,那么在垃圾回收的時(shí)候,這個(gè)節(jié)點(diǎn)要被拷貝到新的位置。
節(jié)點(diǎn)總長度:包括節(jié)點(diǎn)頭和數(shù)據(jù)的長度。
節(jié)點(diǎn)頭部 CRC 校驗(yàn):包含節(jié)點(diǎn)頭部的校驗(yàn)碼,為文件系統(tǒng)的可靠性提供了支持。
2.2 節(jié)點(diǎn)類型
JFFS2 定義了三種節(jié)點(diǎn)類型:
JFFS2_NODETYPE_INODE: INODE 節(jié)點(diǎn)包含了i-節(jié)點(diǎn)的原數(shù)據(jù)(i節(jié)點(diǎn)號(hào),文件的組 ID, 屬主 id, 訪問時(shí)間,偏移,長度等),文件數(shù)據(jù)被附在 INODE 節(jié)點(diǎn)之后。除此之外,每個(gè) INODE 節(jié)點(diǎn)還有一個(gè)版本號(hào),它被用來維護(hù)屬于一個(gè)i-節(jié)點(diǎn)的所有 INODE 節(jié)點(diǎn)的全序關(guān)系。下面舉例來說明這個(gè)全序關(guān)系在 JFFS2 的使用:
圖三
因此,當(dāng)文件系統(tǒng)從閃存上讀節(jié)點(diǎn)信息后,會(huì)生成下面的映射信息:
圖四
根據(jù)這個(gè)映射信息表,文件系統(tǒng)就知道到相應(yīng)的 INODE 節(jié)點(diǎn)去讀取相應(yīng)的文件內(nèi)容。最后要說明的是,JFFS2 支持文件數(shù)據(jù)的壓縮存儲(chǔ),因此在 INODE 節(jié)點(diǎn)中還包含了所使用的壓縮算法,在讀取數(shù)據(jù)的時(shí)候選擇相應(yīng)的壓縮算法來解壓縮。
JFFS2_NODETYPE_DIRENT:DIRENT 節(jié)點(diǎn)就是把文件名與 i 節(jié)點(diǎn)對(duì)應(yīng)起來。在 DIRENT節(jié)點(diǎn)中也有一個(gè)版本號(hào),這個(gè)版本號(hào)的作用主要是用來刪除一個(gè) dentry。具體來說,當(dāng)我們要從一個(gè)目錄中刪除一個(gè) dentry 時(shí),我們要寫一個(gè) DIRENT 節(jié)點(diǎn),節(jié)點(diǎn)中的文件名與被刪除的 dentry 中的文件名相同,i 節(jié)點(diǎn)號(hào)置為 0,同時(shí)設(shè)置一個(gè)更高的版本號(hào)。
JFFS2_NODETYPE_CLEANMARKER:當(dāng)一個(gè)擦寫塊被擦寫完畢后,CLEANMARKER 節(jié)點(diǎn)會(huì)被寫在 NOR flash 的開頭,或 NAND flash 的 OOB(Out-Of-Band) 區(qū)域來表明這是一個(gè)干凈,可寫的擦寫塊。在 JFFS v1 中,如果掃描到開頭的 1K 都是 0xFF 就認(rèn)為這個(gè)擦寫塊是干凈的。但是在實(shí)際的測試中發(fā)現(xiàn),如果在擦寫的過程中突然掉電,擦寫塊上也可能會(huì)有大塊連續(xù) 0xFF,但是這并不表明這個(gè)擦寫塊是干凈的。于是我們需要 CLEANMARKER 節(jié)點(diǎn)來確切的標(biāo)識(shí)一個(gè)干凈的擦寫塊。
2.3 JFFS2節(jié)點(diǎn),擦寫塊在內(nèi)存中的表示和操作
JFFS2 維護(hù)了幾個(gè)鏈表來管理擦寫塊,根據(jù)擦寫塊上的內(nèi)容,一個(gè)擦寫塊會(huì)在不同的鏈表上。具體來說,當(dāng)一個(gè)擦寫塊上都是合法(valid)的節(jié)點(diǎn)時(shí),它會(huì)在 clean_list 上;當(dāng)一個(gè)擦寫塊包含至少一個(gè)過時(shí)(obsolete)的節(jié)點(diǎn)時(shí),它會(huì)在 dirty_list 上;當(dāng)一個(gè)擦寫塊被擦寫完畢,并被寫入 CLEANMARKER 節(jié)點(diǎn)后,它會(huì)在 free_list 上。
通常情況下,JFFS2 順序的在擦寫塊上寫入不同的節(jié)點(diǎn),直到一個(gè)擦寫塊被寫滿。此時(shí) JFFS2 從 free_list 上取下一個(gè)擦寫塊,繼續(xù)從擦寫塊的開頭開始寫入節(jié)點(diǎn)。當(dāng) free_list 上擦寫塊的數(shù)量逐漸減少到一個(gè)預(yù)先設(shè)定的閥值的時(shí)候,垃圾回收就被觸發(fā)了,為文件系統(tǒng)清理出更多的可用擦寫塊。為了減少對(duì)內(nèi)存的占用,JFFS2 并沒有把 i 節(jié)點(diǎn)所有的信息都保留在內(nèi)存中,而只是把那些在請(qǐng)求到來時(shí)不能很快獲得的信息保留在內(nèi)存中。具體來說,對(duì)于在閃存上的每個(gè) i 節(jié)點(diǎn),在內(nèi)存里都有一個(gè) struct jffs2_inode_cache 與之對(duì)應(yīng),這個(gè)結(jié)構(gòu)里保存了 i 節(jié)點(diǎn)號(hào),指向 i 節(jié)點(diǎn)的連接數(shù),以及一個(gè)指向?qū)儆谶@個(gè) i 節(jié)點(diǎn)的物理節(jié)點(diǎn)鏈表的指針。所有的 struct jffs2_inode_cache 存儲(chǔ)在一個(gè)哈希表中。閃存上的每個(gè)節(jié)點(diǎn)在內(nèi)存中由一個(gè) struct jffs2_raw_node_ref 表示,這個(gè)結(jié)構(gòu)里保存了此節(jié)點(diǎn)的物理偏移,總長度,以及兩個(gè)指向 struct jffs2_raw_node_ref 的指針。一個(gè)指針指向此節(jié)點(diǎn)在物理擦寫塊上的下一個(gè)節(jié)點(diǎn),另一個(gè)指針指向?qū)儆谕粋€(gè) i-節(jié)點(diǎn)的物理節(jié)點(diǎn)鏈表的下一個(gè)節(jié)點(diǎn)。
圖五
在閃存上的節(jié)點(diǎn)的起始偏移都是 4 字節(jié)對(duì)齊的,所以 struct jffs2_inode_cache 中flash_offset 的最低兩位沒有被用到。JFFS2 正好利用最低位作為此節(jié)點(diǎn)是否過時(shí)的標(biāo)記。
下面舉一例來說明 JFFS2 是如何使用這些數(shù)據(jù)結(jié)構(gòu)的。VFS 調(diào)用 iget() 來得到一個(gè) i 節(jié)點(diǎn)的信息,當(dāng)這個(gè) i 節(jié)點(diǎn)不在緩存中的時(shí)候,VFS 就會(huì)調(diào)用 JFFS2 的 read_inode() 回調(diào)函數(shù)來得到 i 節(jié)點(diǎn)信息。傳給 read_inode() 的參數(shù)是 i 節(jié)點(diǎn)號(hào),JFFS2 用這個(gè) i 節(jié)點(diǎn)號(hào)從哈希表中查找相應(yīng)的 struct jffs2_inode_cache,然后利用屬于這個(gè) i 節(jié)點(diǎn)的節(jié)點(diǎn)鏈表從閃存上讀入節(jié)點(diǎn)信息,建立類似于表三的映射信息。
2.4 JFFS2 掛載過程
JFFS2 的掛載過程分為四個(gè)階段:
1) JFFS2 掃描閃存介質(zhì),檢查每個(gè)節(jié)點(diǎn) CRC 校驗(yàn)碼的合法性,同時(shí)分配了 struct jffs2_inode_cache 和 struct jffs2_raw_node_ref
2) 掃描每個(gè) i 節(jié)點(diǎn)的物理節(jié)點(diǎn)鏈表,標(biāo)識(shí)出過時(shí)的物理節(jié)點(diǎn);對(duì)每一個(gè)合法的 dentry 節(jié)點(diǎn),將相應(yīng)的 jffs2_inode_cache 中的 nlink 加一。
3 找出 nlink 為 0 的 jffs2_inode_cache,釋放相應(yīng)的節(jié)點(diǎn)。
4 釋放在掃描過程中使用的臨時(shí)信息。
2.5 JFFS2 垃圾回收機(jī)制
當(dāng) free_list 上的擦寫塊數(shù)太少了,垃圾回收就會(huì)被觸發(fā)。垃圾回收主要的任務(wù)就是回收那些已經(jīng)過時(shí)的節(jié)點(diǎn),但是除此之外它還要考慮磨損平衡的問題。因?yàn)槿绻晃兜膹?dirty_list上選取擦寫塊進(jìn)行垃圾回收,那么 dirty_list 上的擦寫塊將先于 clean_list 上的擦寫塊被磨損壞。JFFS2 的處理方式是以 99% 的概率從 dirty_list,1% 的概率從 clean_list 上取一個(gè)擦寫塊下來。由此可以看出 JFFS2 的設(shè)計(jì)思想是偏向于性能,同時(shí)兼顧磨損平衡。對(duì)這個(gè)塊上每一個(gè)沒有過時(shí)的節(jié)點(diǎn)執(zhí)行相同的操作:
1 找出這個(gè)節(jié)點(diǎn)所屬的 i 節(jié)點(diǎn)號(hào)(見圖五)。
2 調(diào)用 iget(),建立這個(gè) i 節(jié)點(diǎn)的文件映射表。
3 找出這個(gè)節(jié)點(diǎn)上沒有過時(shí)的數(shù)據(jù)內(nèi)容,并且如果合法的數(shù)據(jù)太少,JFFS2 還會(huì)合并相鄰的節(jié)點(diǎn)。
4 將數(shù)據(jù)讀入倒緩存里,然后將它拷貝到新的擦寫塊上。
5 將回收的節(jié)點(diǎn)置為過時(shí)。
當(dāng)擦寫塊上所有的節(jié)點(diǎn)都被置為過時(shí),就可以擦寫這個(gè)擦寫塊,回收使用它。
3. JFFS2 的不足之處
3.1 掛載時(shí)間過長
JFFS2 的掛載過程需要對(duì)閃存從頭到尾的掃描,這個(gè)過程是很慢的,我們?cè)跍y試中發(fā)現(xiàn),掛載一個(gè) 16M 的閃存有時(shí)需要半分鐘以上的時(shí)間。
3.2 磨損平衡的隨意性(random nature)
JFFS2 對(duì)磨損平衡是用概率的方法來解決的,這很難保證磨損平衡的確定性。在某些情況下,可能造成對(duì)擦寫塊不必要的擦寫操作;在某些情況下,又會(huì)引起對(duì)磨損平衡調(diào)整的不及時(shí)。
3.3 很差的擴(kuò)展性
JFFS2 中有兩個(gè)地方的處理是 O(N) 的,這使得它的擴(kuò)展性很差。
首先,掛載時(shí)間同閃存的大小,閃存上節(jié)點(diǎn)數(shù)目成正比。
其次,雖然 JFFS2 盡可能的減少內(nèi)存的占用,但通過上面對(duì) JFFS2 的介紹我們可以知道實(shí)際上它對(duì)內(nèi)存的占用量是同 i 節(jié)點(diǎn)數(shù)和閃存上的節(jié)點(diǎn)數(shù)成正比的。
因此在實(shí)際應(yīng)用中,JFFS2 最大能用在 128M 的閃存上。
4. JFFS2 的新特性
最近加入到 JFFS2 中的兩個(gè)補(bǔ)丁程序分別解決了上面提到的掛載時(shí)間過長和磨損平衡隨意性的問題。
4.1 磨損塊小結(jié)補(bǔ)丁程序(erase block summary patch)
這個(gè)補(bǔ)丁程序最基本的思想就是用空間來換時(shí)間。具體來說,就是將每個(gè)擦寫塊每個(gè)節(jié)點(diǎn)的原數(shù)據(jù)信息寫在這個(gè)擦寫塊的最后,當(dāng) JFFS2 掛載的時(shí)候,對(duì)每個(gè)擦寫塊只需要讀一次來讀取這個(gè)小結(jié)節(jié)點(diǎn),因此大大減少了掛載時(shí)間。使用了磨損塊小結(jié)補(bǔ)丁程序,一個(gè)擦寫塊的結(jié)構(gòu)就像下面這樣:
圖六
根據(jù)我們的測試,使用磨損塊小結(jié)補(bǔ)丁程序,掛載一個(gè) 12M 的閃存需要 2~3 秒,掛載一個(gè) 16M 的閃存需要 3~4 秒。
4.2 改進(jìn)的磨損平衡補(bǔ)丁程序
這個(gè)補(bǔ)丁程序的基本思想是,記錄每個(gè)擦寫塊的擦寫次數(shù),當(dāng)閃存上各個(gè)擦寫塊的擦寫次數(shù)的差距超過某個(gè)預(yù)定的閥值,開始進(jìn)行磨損平衡的調(diào)整。調(diào)整的策略是,在垃圾回收時(shí)將擦寫次數(shù)小的擦寫塊上的數(shù)據(jù)遷移到擦寫次數(shù)大的擦寫塊上。這樣一來我們提高了磨損平衡的確定性,我們可以知道什么時(shí)候開始磨損平衡的調(diào)整,也可以知道選取哪些擦寫塊進(jìn)行磨損平衡的調(diào)整。
4.3 擦寫塊頭部補(bǔ)丁程序
在寫改進(jìn)的磨損平衡補(bǔ)丁程序的過程之中,我們需要記錄每個(gè)擦寫塊的擦寫次數(shù),這個(gè)信息需要記錄在各自的擦寫塊上。可是我們發(fā)現(xiàn) JFFS2 中缺少一種靈活的對(duì)每個(gè)擦寫塊的信息進(jìn)行擴(kuò)展的機(jī)制。于是我們?yōu)槊總€(gè)擦寫塊引入了擦寫塊頭部(header),這個(gè)頭部負(fù)責(zé)紀(jì)錄每個(gè)擦寫塊的信息(比如說擦寫次數(shù)),并且它提供了靈活的擴(kuò)展機(jī)制,將來如果有新的信息需要記錄,可以很容易的加入到頭部之中。
5. JFFS3 簡介
雖然不斷有新的補(bǔ)丁程序來提高 JFFS2 的性能,但是不可擴(kuò)展性是它最大的問題,但是這是它自身設(shè)計(jì)的先天缺陷,是沒有辦法靠后天來彌補(bǔ)的。因此我們需要一個(gè)全新的文件系統(tǒng),而 JFFS3 就是這樣的一個(gè)文件系統(tǒng),JFFS3 的設(shè)計(jì)目標(biāo)是支持大容量閃存(>1TB)的文件系統(tǒng)。JFFS3 與 JFFS2 在設(shè)計(jì)上根本的區(qū)別在于,JFFS3 將索引信息存放在閃存上,而 JFFS2將索引信息保存在內(nèi)存中。比如說,由給定的文件內(nèi)的偏移定位到存儲(chǔ)介質(zhì)上的物理偏移地址所需的信息,查找某個(gè)目錄下所有的目錄項(xiàng)所需的信息都是索引信息的一種。 JFFS3 現(xiàn)在還處于設(shè)計(jì)階段,文件系統(tǒng)的基本結(jié)構(gòu)借鑒了 Reiser4 的設(shè)計(jì)思想,整個(gè)文件系統(tǒng)就是一個(gè) B+ 樹。JFFS3 的發(fā)起者正工作于垃圾回收機(jī)制的設(shè)計(jì),這是 JFFS3 中最復(fù)雜,也是最富有挑戰(zhàn)性的部分。JFFS3 的設(shè)計(jì)文檔可以在http://www.linux-mtd.infradead.org/doc/jffs3.html 得到,有興趣的讀者可以積極參與到 JFFS3 的設(shè)計(jì)中,發(fā)表自己的見解,參與討論。
致謝
在這里要特別感謝David Woodhouse, Artem B. Bityutskiy,Joern 和 Thomas Gleixner,在參與到JFFS2的開發(fā)過程中,這幾位主要的項(xiàng)目維護(hù)者(maintainer)不斷地給我?guī)椭?,耐心的回答我的問題,在與他們的討論過程中碰撞出很多智慧的火花和富有啟發(fā)性的思想,尤其是他們對(duì)我的補(bǔ)丁程序提出的”尖刻”的問題,讓我不斷的努力思考(thinking hard),不斷的完善它們。我想這種開放,無私,客觀的精神正是開源社區(qū)的精髓所在,吸引著越來越多的開發(fā)者參與進(jìn)來,并使開源社區(qū)不斷的壯大。
評(píng)論