天天看點

ubifs design

Flash memory在存儲之前需要擦除,是以flash mem檔案系統需要做異地更新。

Flash memory的擦除過程比較耗時,選擇異地更新會比較明智,往一個已經擦除好的block上寫

比拿到髒塊擦除後再寫要快得多。

要做異地更新,那自然有做擦除髒資料塊的機制,即垃圾收集機制。寫資料隻需要往擦除過的block寫,

GC則需要回收丢棄的block并擦除之。

檔案系統需要能夠辨別存儲在erase block上的資料,讓GC機制工作。FS是用過檔案名來找到所屬檔案的資料,

而GC則是通過data找到是否屬于某個檔案。

檔案的metadata和data儲存在一起,稱之為node,每一個node記錄了所屬檔案,以及什麼資料儲存在該node中

在這一點上,jffs2與ubifs相同,都是基于node設計。在讀取eraseblock的資料時可以直接決定是否搬運到其他EB上,亦或丢棄。

jffs2與ubifs最大的不同之處在于,ubifs把檔案index存儲在Flash上,而jffs2則把index建立在記憶體中。

這會導緻jffs2支援的尺寸有限制,mount時間與記憶體消耗都會随flash mem size正比增長。

存儲index到flash中非常麻煩,index也需要做異地更新,引用index的index也需要更新。解決這種依賴更新的辦法是使用Wandering tree。

ubifs的遊離樹是使用B+樹,樹的葉子節點儲存檔案資訊,其他節點為index nodes。

對葉子節點的更新,會引起父節點的更新,知道根節點,更新的inex nodes的數目顯然等于樹的高度。

樹的根節點需要存在固定的位置,即masternode中,會有兩個LEB(ubifs使用的邏輯擦除塊)LEB1/LEB2中各儲存一份。

使用兩個LEB儲存兩份master node是為了出現損壞時以便恢複。有兩種情況會導緻master node損壞,1,寫master node時斷電,

2,flash媒體本身出現損壞。第一種情況可以使用前一版本的master node來恢複,而第二種情況則無法判斷哪個是有效的master node。

第二種情況比較麻煩,需要readback資料來重建或找到問題所在。

UBIFS在建立的時候有6個areas是固定的,

UBI device上的第一個LEB是LEB0,儲存superblock node,儲存檔案系統基本不變的參數。

Master node存在LEB1,LEB2,

LOG area,

LEB properties tree aera

orphan area

main area

superblock與mater node前面都有提到了。

LOG是UBIFS日志的一部分,用來降低falsh index更新頻率。

更新檔案系統的葉子節點,需要地遞歸更新其父節點,可能會頻繁的做這樣的動作,以至效率低下。

UBIFS通過日志,僅僅寫葉子節點,并不立即更新flash上的index,當然記憶體中的index會立即更新,當日志系統認為日志滿了,進行送出。

送出過程包括寫入memory index以及相應的master node。

日志的資料總是比falsh的index相比更新,在mount的時候會replay日志中的index。

日志的size是在mkfs.ubifs确定,預設情況下,ubifs不使用fask unmount,在unmount前執行一次commit。

這會讓日志幾乎為空,下次mount會非常快。

commit過程本身不會從日志中移動葉子節點,而是修改日志本身,即修改日志的位置。

log中包含兩類節點,commit start node記錄一個commit一斤剛開始,reference nodes記錄組成journal的LEBs的序号。

這些LEBs叫做buds,日志包含log和buds,log的尺寸是固定的,可認為是一個circular buffer。

待續。。。