UBIFS介紹 raw flash和MMC flash的區別【轉】

轉自:https://blog.csdn.net/deggfg/article/details/82587548

origin: http://sh.516878.com/2013/1101/25699.html

在瞭解UBIFS之前一定要注意UBIFS和任何傳統的文件系統是不一樣的:UBIFS不是運行在block device之上的(比如hard disk, MMC/SD卡,USB flash驅動等等)。UBIFS是運行於raw flash之上。請在開始UBIFS之旅前確保理解raw flash和MMC flash的區別。

  Overview

  UBIFS是nokia工程師在the university of Szeged大學幫助下開發的新的flash file system。UBIFS可以認爲是JFFS2文件系統的下一代產品。

  JFFS2運行在MTD設備之上,而UBIFS則只能工作於UBI volume之上。也可以說,UBIFS涉及三個子系統:

  1. MTD 子系統, 提供對flash芯片的訪問接口, MTD子系統提供了MTD device的概念,比如/dev/mtdx,MTD可以認爲是raw flash

  2. UBI subsystem,爲flash device提供了wear-leveling和 volume management功能; UBI工作在MTD設備之上,提供了UBI volume;UBI是MTD設備的高層次表示,對上層屏蔽了一些直接使用MTD設備需要處理的問題,比如wearing-leveling以及壞塊管理。

  3. UBIFS文件系統,工作於UBI之上

  以下是UBIFS的一些特點:

  可擴展性:UBIFS對flash 尺寸有着很好的擴展性; 也就是說mount時間,內存消耗以及I/O速度都不依賴於flash 尺寸(對於內存消耗的描述並不完全準確,但是依賴性非常的低); UBIFS可以很好的運行在GB級的 flashe設備; 當然UBI本身還是有擴展性的問題,無論如何 UBI/UBIFS都比JFFS2的可擴展性好,如果UBI成爲瓶頸,可以改進UBI而不需改變UBIFS本身。

  快速mount:不像JFFS2,UBIFS在mount階段不需要掃描整個文件系統,UBIFS mount的時間只是毫秒級,時間不依賴與flash的尺寸;然而UBI的初始化時間是依賴flash的尺寸的,因此必須把這個時間考慮在內。

  write-back 支持:回寫或者叫延遲寫更準確些吧,同JFFS2的write-through(立即寫入內存)相比可以顯著的提高文件系統的吞吐量

  異常unmount適應度:UBIFS是一個日誌文件系統可以容忍突然掉電以及unclean重啓; UBIFS 通過replay 日誌來恢復unclean unmount,在這種情況下replay會消耗一些時間,因此mount時間會稍微增加,但是replay過程並不會掃描整個flash介質,所以 UBIFS的異常mount時間大概在幾分之一秒。

  快速I/O - 即使我們disable write-back(可以在unmount時使用-o sync mount選項), UBIFS的性能仍然接近JFFS2; 記住,JFFS2的同步I/O是非常驚人的,因爲JFFS2不需要在flash上維護indexing data結構, 所以就沒有因此而帶來的負擔;而UBIFS恰恰是有index數據的,UBIFS之所以夠快是因爲UBIFS提交日誌的方式:不是把數據從一個地方移動到另外一個位置,而只是把數據的地址加到文件系統的index,然後選擇不同的eraseblock作爲新的日誌塊,此外還有multi-headed日誌方式等技巧。

  on-the_flight compression - 存儲在flash介質上的數據是壓縮的;同時也可以靈活的針對單個文件來打開關閉壓縮。例如,可能需要針對某個特定的文件打開壓縮;或者可能缺省方式下支持壓縮,但是對多媒體文件則關閉壓縮。

  可恢復性 - UBIFS可以從index破壞後恢復; UBIFS中的每一片信息都用一個header來描述,因此可以通過掃描整個flash介質來重構文件系統,這點和JFFS2非常類似。想像一下,如果你擦除了FAT文件系統的FAT表,對於FAT 文件系統是致命的錯誤,但是如果擦除UBIFS的index,你仍然可以重構文件系統,當然這需要使用一個用戶空間程序來做恢復

  完整性 - UBIFS通過把checksum寫到flash 介質上來保證數據的完整性,UBIFS不會無視損壞的文件數據或meta-data;缺省的情況,UBIFS僅僅檢查meta-data的CRC,但是你可以通過mount選項,強制進行data CRC的檢查。

  Scalabity

  UBIFS文件系統的所有數據結構都是使用tree,UBIFS對flash尺寸大小在算法上是可擴展的。然而UBI複雜度隨着flash size線性增長,因此UBI加UBIFS整體上是線性增大的。但是UBIFS的作者認爲可以創建一個新的UBI2,克服當前UBI的線性增長。當前的 UBI實現適和2~16GiB大小的raw flashes,具體大小依賴於I/O速度和系統需求。

  注意:儘管UBI是線性增長的,但是它的可擴展性依然好過JFFS2,因爲JFFS2最初是爲32MiB Nor flashes設計的。JFFS2的擴展性問題是文件系統級的,而UBI/UBIFS的擴展性問題則是raw flash級的,下表是兩個文件系統擴展性的對比

  Scalability

  issurJffS2UBIFS

  Mount time Linearly depends on the flash sizeTrue. 依賴是線性的,因爲JFFS2在mount時要掃描整個flash 介質空間UBIFS mount時間不依賴flash的尺寸。但是UBI需要掃描flash介質儘管掃描時間要比JFFS2快。所以整體上說, UBI/UBIFS是線性依賴的

  內存消耗是否線性依賴flash尺寸True. 依賴是線性的UBIFS 內存消耗的確依賴flash尺寸,因爲LPT shrinker還沒有實現。但是實現LPT shrinker移除依賴性是容易的。當前沒有移除的原因是由於內存消耗很小沒必要實現它。 UBI內存消耗是線性依賴flash尺寸,因此整體上說UBI/UBIFS線性依賴

  Mount時間是否依賴文件系統內容True. 存儲在文件系統內的數據越多,mount時間就越久,因爲JFFS2需要做更多的掃邁工作。False. mount時間不依賴文件系統內容,在最壞的情況下,UBIFS不得不掃描日誌來replay,而日誌是固定大小,並且可配置的

  mount是需要檢查真個文件系統True. 當JFFS2 mount到NAND flash上時 不得不檢查整個文件系統。檢查包括讀取每個inode的所有nodes 檢查他們的CRC checksums,這將消耗大量CPU,在mount完JFFS2後,可以通過運行top來觀察CPU佔用率,這也降低了整個系統啓動時間。因爲 JFFS2沒有存儲space 管理信息,因此也需要掃描整個flash介質來獲取這個信息。False. UBIFS不需要掃描整個文件系統,因爲UBIFS空間管理信息在LPT(Logical erase block Properties Tree)中

  內存消耗是否線性依賴文件系統尺寸True. JFFS2爲flash上的每一個node 保存了一片數據結構。所以存儲在文件系統的數據越多,那麼JFFS2所佔用的內存越多。False. UBIFS消耗的內存不依賴存儲在flash介質上的數據多少

  文件訪問時間線性依賴文件的大小Ture. JFFS2在打開一個文件時,不得不爲文件節點在內存保存一棵fragment tree. 這棵樹保存着文件的偏移所對應的nodes, fragment tree沒有保存在內存中,因此在打開文件時不得不讀取這個文件對應的節點來創建這棵fragment tree。這就意味着,文件越大,打開的時間越長。False. UBIFS存儲所有的index B-tree信息在flash 介質。當要讀取文件系統的一片數據,在B-tree查找到對應的flash 地址。當查找B-tree時會把B-tree節點緩存到TNC cache中,cache是可以回收的,這就是說當系統kernel需要更多內存時,可以回收cache

  文件系統性能依賴I/O歷史True. 因爲JFFS2是完全同步的,數據一到達立刻就向flash寫入。向一個文件寫入很少的字節,JFFS2立即寫入包含了這幾個字節的node,如果頻繁的隨機寫入,文件系統就會變得碎片化。JFFS2會合並這些碎塊爲4KiB的塊,這涉及到重新壓縮和重寫數據。這個 去碎片化隨機發生在垃圾收集過程,因爲JFFS2的磨損平衡算法是隨機選擇eraseblock。所以如果有很多的小寫入,JFFS2會在某一刻變得非常的慢,系統性能下降使得系統行爲變得不可預測False. UBIFS一直寫入4KiB的塊。數據到達後並不是立刻寫入flash,而是推遲以合併後來的寫入,當足夠的數據要求寫入時,纔回寫到flash上,回寫通常是background方式

  Write-back support

  UBIFS支持write-back, 意味着文件的改變並不是立刻提交到flash media上,而是cache這些修改,直到達到寫入的條件。這減少了I/O的數目因此改善I/O性能和系統性能。回寫本身也是文件系統的標準技術,由於數據沒有立刻寫入flash, 回寫帶來了數據丟失的風險。

  相反, JFFS2不支持write-back, JFFS2文件系統的所有變化都是立刻同步到flash介質上。事實上,JFFS2有一個很小的buffer大小是NAND page size(如果是 NAND flash)。這個buffer保存這最後要寫的數據,一旦buffer寫滿立刻就會執行flush。因此JFFS2非常類似於同步文件系統。

  write-back支持,需要應用程序注意及時同步重要的文件。否則掉電會導致這些文件的損壞和消失,掉電對於嵌入式系統而言是很常見的。

  然而一些應用空間程序並沒有考慮write-back這種情況。當這些應用運行在JFFS2上工作良好儘管這些應用是buggy的,一旦運行在 UBIFS上,bugs就很容易重現了。在把JFFS2換作UBIFS後,確保檢查你的應用是否正確處理掉電功能。下列是檢查列表以及一些建議:

  1. 如果你想切換到同步模式,在mount文件系統是使用 -o 同步選項。然而,要注意文件系統將會下降。此外,要記住UBIFS mount爲同步模式仍然不如JFFS2提供更多的保證

  2. 一定要時刻記住運行fsync在你修改重要數據後;當然,沒有必要sync臨時的文件;要先考慮文件數據的重要性,不要執行沒必要的fsync,因爲fsync操作會降低性能

  3. 如果你想更精確些,那麼就使用fdatasync,僅僅修改的數據被flushed,而inode meta-data變化不會被flush(比如mtime或者permissions)。

  4. 你也可以在open()調用時使用O_SYNC標誌;這使得這個文件所修改的data(不包括meta-data)都會在write()操作返回前寫入 media;通常來說,最好使用fsync(),因爲O_SYNC使得每個寫都是同步的,而fsync允許多個累積的寫。

  5. 還可以使一定數目inodes爲同步模式,通過設置inode的sync標誌; 在shell中執行chattr +S;在C程序中,則可以使用FS_IOC_SETFLAGS ioctl命令;注意,mkfs.ubifs工具會檢查原始的FS樹,如果文件在原始文件樹是同步的,那麼在UBIFS image也會是同步的。

  要強調的是,上面的方法對於任何文件系統都是可行的,包括JFFS2。

  fsync()可能包括目錄 - 它同步目錄inode的meta-data。 “sync” flag也可以用在目錄上,使得目錄inode變成同步的。但是"sync" flag是可繼承的,意味這這個目錄下的所有新節點都有這個標誌。 這個目錄的新文件和新子目錄也就變成同步的, 子目錄的child也是如此。這個功能對於創建一個整個目錄樹都同步的目錄是很有用的。

  fdatasync()調用對 UBIFS的目錄是不起作用的,因爲UBIFS對目錄項的操作都是同步的,當然不是所有文件系統都如此。類似的, "dirsync" inode 標誌對UBIFS沒有作用

  以上提到的功能都是作用於文件描述符,而不是文件stream(FILE *)。同步一個stream,你應該通過libc的fileno()取得文件描述符, 首先使用fflush()來flush stream ,然後調用fsync或者fdatasync. 你也可以使用其他的同步方法,但是記得在同步文件前要先flush stream. fflush() 和sync(),fsync,fdatasync與前者的區別,在於前者僅僅同步libc-level的buffer,而後者則是同步kernel- level buffers。

  Write-back knobs in Linux

  Linux有幾個內核參數可以用來調整write-back,可查看/proc/sys/vm. 這些參數是global, 所以會影響所有的文件系統。 參考Documentation/sysctl/vm.txt獲取更多的信息。

  1. dirty_writeback_centisecs: linux週期性write-back線程寫出dirty數據的週期,這個機制可以確保所有的髒數據在某個時間點都可以寫入介質。

  2. dirty_expire_centisecs: dirty數據的過期週期,這是數據爲dirty的最大時間。過了這個時間,dirty數據會被週期性write-back線程寫回介質。換句話說,週期性write-back線程每dirty- writeback-centisecs 時間喚醒,然後同步那些dirty_expire_centisecs時間之前就已經dirty的數據。

  3. dity_background_ratio: dirty數據與全部內存的最大百分比。當髒數據變多的時候,週期性的write-back線程開始同步數據使得髒數據比例變小。這個過程包括那些non-expired的數據。這個可以認爲是系統dirty數據的soft limit。

  4. dirty_ratio: dirty數據與全部內存的最大百分比,超過這個顯示,writes同步數據先於增加dirty數據。這個是系統diry 數據的hard limit。

  UBIFS write-buffer

  UBIFS是一個異步文件系統,和其他文件系統一樣,UBIFS也利用了page cache。page cache是一個通用的linux內存管理機制,page cache可以非常大以cache更多的數據。當你寫一個文件時,首先寫到page cache中,置爲dirty,然後write操作返回(同步的文件是例外)。以後數據會通過write-back機制寫回。

  write-buffer是UBIFS特定的buffer, 它位於page cache和flash介質之間。這意味着write-buffer 只是寫到write-buffer上 而不是flash介質。

  write-buffer 是用來優化UBIFS在NAND flashes上的速度。 NAND flashes包含NAND pages,頁是NAND flash的最小讀寫單位,通常爲512 2KiB或者4KiB。

  write-buffer尺寸等於NAND page size. 他的目的是積累samll writes爲一個滿的或者部分滿的page。考慮下面的例子,假定在半秒內寫了4x512bytes nodes,page size是2kiB的情況下。如果沒有write-buffer,那麼分開的寫會使用4個page,浪費6KiB的空間,而write-buffer 可以僅寫一次,並且沒有空間浪費。這意味着,write-buffer避免生成過多的dirty space,UBIFS的垃圾收集所做的工作就越少。

  當然上面的例子是一個理想狀態,即便write-buffer也可能浪費空間,比如使用同步I/O或者數據抵達的時間間隔較大。因爲write-buffer也有個過期時間,每3-5秒即便write-buffer不滿,也會寫出。這是爲了數據完整性的原因。

  當然,如果UBIFS寫大量的數據,那麼就不使用write-buffer。僅僅數據的最後一部分由於小於NAND page尺寸需要等待填滿page的數據,直到write-buffer的定時器到時。

  write-buffer實現上有一點複雜,UBIFS中使用了一些write-buffer,每個journal head都有一個。當然這並不改變write-buffer的基本機制。

  關於同步有幾點需要注意的:

  1. sycn()會同步所有的write-buffers

  2. fsync(fd)也會同步 fd相關的所有write-buffers

  3. 用O_SYNC打開文件,會忽略write-buffers, 所以I/O會直接寫入介質

  4. 如果文件系統mount時使用了-o sync選項,那麼write-buffers也會被忽略

  在數據同步時要考慮write-buffer的timer時間,在synchronization timout "dirty_expire_centisecs"加上額外的3-5秒,當然由於write-buffer很小,所以delay的數據很少

  UBIFS in synchronous mode vs JFFS2

  mount UBIFS文件系統使用-o sync標誌,所有文件系統的操作都變成了同步模式,意味着在file-system操作返回前,所有的數據都寫入了flash介質

  例如,如果你使用write()寫10MB數據到文件f.data,並且UBIFS是同步模式。在write操作返回前所有的10M文件數據以及 meta-data(file size, date changes)也寫入了flash介質。此時即便掉電,這個文件的數據也會包含所有的10MB數據。

  在打開文件時,使用O_SYNC標誌也有同樣的效果。

  在突然掉電的情況下,UBIFS並不能像JFFS2那樣提供較多的保證。

  在JFFS2中,所有的meta-data存儲在data node headers中。數據節點包含4KiB的壓縮數據。這意味meta-data信息在flash有多個版本,每次JFFS2寫一個data node到flash介質上時,都會更新文件的inode size。當JFFS2mount時,會掃描flash介質,發現最後的data node,同時獲取inode的size

  在實際使用中,JFFS2會順序的寫這10M數據,從頭到尾。如果中間發生掉電,那麼就丟失掉結尾的數據。比如寫10M的數據到JFFS2中,寫了5M,此時掉電發生,那麼可以得到一個5MB的文件,而丟掉了未寫入的5MB。

  對於UBIFS來說有一點點複雜,數據被存儲在data nodes中,而meta-data被存儲在分離的inode nodes中。meta-data在每個數據節點中沒有像JFFS2一樣有duplicated的版本。UBIFS從來不會寫on-flash inode size外的數據節點。如果不得不寫data node, 並且data node是在on-flash inode size之外(in-memory inodes已經更新爲up-to-data尺寸,但是髒的還沒更新到flash上),那麼UBIFS首先要把inode寫入介質,然後才能開始寫數據,此時掉電就可能會產生holes文件,看下面的例子

  1. 用戶創建一個空文件f.dat. 文件是同步的,或者UBIFS文件系統被mount爲同步模式。user調用write()函數來寫一個10MB buffer.

  2. kernel首先拷貝所有的10MB數據到page cache。inode size 被修改爲10MB並且inode被mark爲dirty。沒有任何數據和meta-data寫入flash media,此時如果發生掉電,那麼user看到的是一個空文件f.data。

  3. UBIFS看到I/O是同步的,那麼首先開始同步inode,首先寫inode node 到flash media中,此時如果發生掉電,那麼user會看到一個10MiB大小的空文件。

  4. UBIFS開始寫數據,如果掉電發生在這一點上,那麼user看到一個10Mib大小的文件,在文件後部是有個hole。

  注意,即便I/O不是同步的,UBIFS在開始寫數據 meta-data到flash media前就返回。write-back將在某個時刻開始寫flash media, 如果在write-back過程發生掉電,那麼同樣會產生hole

  因此,UBIFS並不能像JFFS2那樣,很完美的保留掉電前寫下的數據以及文件尺寸,主流文件系統比如ext3也沒有提供JFFS2類似的功能。

  雖然,有時人們用UBIFS替代JFFS2,人們希望UBIFS能夠像JFFS2一樣行事,這是可行的,需要hack一下UBIFS代碼。之所以UBIFS還沒有這樣實現,是因爲這個需求並沒有那麼強烈。或者自己實現它或者說服UBIFS作者實現這個功能。

  Synchronization exceptions for buggy applications

  UBIFS作爲一個異步的文件系統,application應該在需要的時候同步他們的文件。這同樣適用於大部分linux 文件系統

  然而,一些應用忽略了這一點,沒能夠正確的同步文件。

  Compression

  UBIFS支持快速的壓縮,UBIFS在把數據寫入flash media之前壓縮數據,在讀出來時解壓數據,這個compress/decompress過程對與用戶來說是完全透明的。UBIFS僅僅壓縮文件數據。目錄,設備節點等是不壓縮的。Meta-data和indexing信息也不壓縮的

  當前UBIFS支持LZO和zlib壓縮器。ZLib提供了更好的壓縮率,但是LZO在壓縮和解壓時的速度更快。LZO是UBIFS和mkfs.ubifs的缺省壓縮處理器。當然你可以在mkfs.ubifs命令選項中使用-x來disable UBIFS壓縮。

  UBIFS把數據分割爲4KiB的塊然後對每一個chunks進行單獨壓縮。這不是最優的,因爲大塊的數據壓縮效果更好,即便如此仍然提供了客觀的 flash空間效益。比如,一個真實的root file system鏡像利用LZO壓縮器可以減小40%空間,而用zlib壓縮器則減少50%空間。這意味如果你可以把一個300MB的文件系統放到 256MiB的UBI volume中,而且荏苒有100MiB的空閒空間。然而這可能隨着文件系統存放的內容不同而不同,比如,如果你的文件系統保存的都是mp3文件,UBIFS無法有效的壓縮他們,因爲mp3文件本身就是被壓縮的。

  在UBIFS中是可以針對每個文件節點來disable/enable壓縮功能的,方法是設置或者清除inode節點的compression標誌。注意,這個壓縮標誌對於目錄是可繼承的,也就是說這個目錄下的文件和子文件在創建時,他們的compression標誌是繼承自父目錄

  還要注意的是JFFS2 LZO壓縮和UBIFS的zlib壓縮有輕微不同。UBIFS使用crypto-API縮小方法,而JFFS2直接使用zlib庫。導致UBIFS和 JFFS2使用不同的zlib壓縮選項。名義上,JFFS2使用縮小level3,window bits15,而UBIFS使用level6 windows bit -11(負號使得zlib避免放一個header到數據流中)。經驗顯示JFFS2壓縮率稍微小一些,解壓速度慢一些,但是壓縮速度要快一些。

  Checksumming

  UBIFS寫入到介質的每一片數據都有一個CRC32 checksum。UBIFS使用CRC來保護data和meta-data。每次讀meta-data時,CRC校驗碼都會被驗證。CRC-32校驗是非常強大的,幾乎所有的數據損壞都可以檢查到。UBI也是如此,驗證每一片meta-data。

  data CRC在缺省情況下是不驗證的,這能改善文件系統的讀速度,當然UBIFS可以在mount時用chk_data-crc,來切換爲data驗證。這會減少UBIFS的讀速度,但是提供了更好的數據完成性保護。使用這個選項,UBIFS讀取的每一片信息都會被驗證,任何數據損壞也都會被檢查到。

  注意,當前UBIFS不能disableCRC-32的寫計算,因爲UBIFS在recovery過程依賴於它。當從一個unclean reboot恢復,replay日誌時,UBIFS需要檢測broken和寫了一半的UBIFS nodes然後拋棄他們,在這裏UBIFS依賴於CRC-32 checksum

  換句話說,如果你使用UBIFS時disable掉CRC-32,但是你仍然爲每一片數據生成了CRC-32 checksum, 你可以隨時激活讀校驗

  注意:在2.6.39之前default UBIFS行爲是相反的, UBIFS缺省支持CRC-32, 使用no_chk_data_crc來disable它

  Read-ahead

  read-ahead是一個文件系統的優化技術,每次讀取的數據比用戶請求的數據多一些。這個主意是基於文件的訪問一般都是從開始向後順序進行的,所以文件系統試着把將來可能用到的數據提前讀出了。

  LINUX VFS本身會做這個read-ahead而不需要file system的支持。這對於傳統的塊設備文件系統工作良好,但是UBIFS不會得益於此。UBIFS工作於UBI API之上,而UBI工作與MTD API之上,MTD API是同步地, MTD API是非常簡單的,沒有任何request queue。這意味這VFS 阻塞住 UBIFS readers, 讓他們等待read-ahead過程。block-device API是異步的 readers不需要等待read-ahead.

  VFS read-ahead是爲hard drives設計的。但是raw flash設備和hard drive是非常不同的, raw flash設備不需要耗時的尋道時間,所以適合hard disk的技術並不適合flash設備

  也就是說,VFS的read-ahead僅僅會使得UBIFS變慢,所以UBIFS 會disable 掉VFS的read-ahead。但是UBIFS有他自己內部的read-ahead,我們稱之爲bulk-read。你可以在mount時增加 “bulk_read”選項來使能bulk-read功能.

  有些flash可能一次讀出全部數據要比分多次讀出數據要快。例如,OneNAND可以做read-while-load如果它讀取超過一個 NAND page。所以UBIFS可以通過一次讀取較大的data chunks來獲取性能上的提升,這就是bulk-read 要做的

  如果UBIFS注意到一個文件正在被順序的讀取,UBIFS看到接下來的數據就存放在相同的eraseblock中,則UBIFS開始read ahead數據,通過使用大的read request。UBIFS把這些提前讀取的數據放到文件的cache中,所以用戶的進一步讀取可以直接從cache中獲得。

  很明顯,bulk-read 在某些情況下,可能會減慢UBIFS,所以要小心。此外注意在高度碎片化的文件系統上,bulk-read並不適合。儘管UBIFS不會主動碎片文件系統,但是也不會de-fragment文件系統。比如數序的寫一個文件,那麼不會有變得碎片化。但是如果你同時寫多個文件,他們就可能變得碎片化(這也依賴於write-back怎麼樣提交更新),UBIFS不會自動de-frament他們。當然,可以實現一個background的 defragmenter. 我們也可以使用per-inode的日誌頭來避免在一個LEB上混合屬於不同的inode的數據節點。所以仍然有改善的餘地。

  Space for superuser

  UBIFS問超級用戶保留了一些空間,這意味着當文件系統對於普通用戶爲滿時,仍然有一點保留空間給 super-user。其他文件系統比如ext2也有類似的特點,mkfs.ubifs有一個-R選項可以用來標識保留空間的尺寸。

  缺省情況下僅僅root可以使用保留空間,但是可以擴展特權用戶的列表。UBIFS可以記錄幾個user和group IDs在超級塊中,允許他們利用保留空間。儘管當前的mkfs.ubifs工具沒有相應的命令行選項,但是很容易實現這個功能。

  注意,UBIFS在mount文件系統時會輸出保留空間的數目。

  Extended attributes

  UBIFS支持擴展屬性: user, truested and security name-spaces. ACL支持還沒實現。

  注意,當前mkfs.ubifs忽略擴展屬性,沒有把他們寫入target文件系統image

  Mount options

  下面是UBIFS-specifi特定的mount選項

  1. chk_data-crc

  2. no_chk_data-crc

  3. bulk_read

  4. no_bulk_read

  此外UBIFS支持標準的sync mount 選項,可以用來disable UBIFS write-back和write-buffer,使得寫過程完全同步。

  注意UBIFS不支持atime,所有atime mount選項不起任何作用。

  Flash space accounting issues

  傳統的文件系統,比如ext2可以很容易的計算出空閒空間。計算是非常精確的,用戶對此已經習以爲常。然後,UBIFS則完全不同了,UBIFS無法彙報它還有多少空閒空間可用。只能彙報最少的可用空間數,這個數目通常會少於實際的數目,有時差錯甚至很大。例如,UBIFS彙報沒有空閒空間,但是仍然可以寫入很多的數據。

  之所以UBIFS彙報的空閒空間的數目少於實際擁有的,是基於以下幾個理由,我們逐一討論。

  Effect of compression

  第一因素是UBIFS的快速壓縮。用戶一般認爲文件系統彙報了N bytes空閒空間,那麼就意味着可以寫入N bytes的文件數據。因爲壓縮的存在,這種想法就不成立了。根據數據壓縮程度的不同,UBIFS可以寫入的數據可能數倍於彙報的空閒空間

  當UBIFS計算空閒空間時,他並不知道即將寫入的數據的特性,因此無法考慮壓縮,所以就假定爲最壞的情況,數據沒有壓縮。

  雖然這看起來問題不大。但是綜合考慮壓縮和write-back,壓縮就變成了估算空閒空間的大問題。換句話說,UBIFS無法知道cached dirty數據的壓縮,想知道結果的唯一辦法就是執行壓縮

  Effect of write-back

  假定在page cache中有X bytes的髒數據,他們將在某個時間被刷如flash media。UBIFS當前需要X+O bytes空間來寫這些數據,O是文件系統開支(比如數據的index,以及每個data node需要一個header)

  問題是UBIFS無法精確的計算出X和O,它使用悲觀的最壞情況的計算,所以當cached data被刷入flash, 所需的flash空間可能原少於需要的X+O,例如看下面的情況

  $ df Filesystem 1K-blocks Used Available Use% Mounted on ubi0:ubifs 49568 49568 0 100% /mnt/ubifs $ sync $ df Filesystem 1K-blocks Used Available Use% Mounted on ubi0:ubifs 49568 39164 7428 85% /mnt/ubifs

  第一次df彙報zero空閒空間,但是sync後彙報了15%的空閒空間。這是因爲有很多cached的dirty data, UBIFS爲他們保留了所有的空閒空間,但是在flash media過程中,僅使用了部分flash space。

  下面是UBIFS爲什麼保留這個多空閒空間的理由

  1. 還是關於compression。數據以uncompressed形式存儲在cache中,UBIFS並不能預估這些數據的壓縮,所以它假定數據完全不能壓縮。然而,現實生活數據是很容易壓縮的,除非.tgz或者.mp3文件。這就導致了對X的過分估計。

  2. 歸咎於設計,UBIFS nodes不會跨越earseblock的邊界,所以在每個eraseblock的末尾處都會有一些小的浪費空間。這個浪費的flash空間依賴於數據寫入和更改的順序。傳統的UBIFS會悲觀的估計這個浪費空間爲最大值,這也導致了對O的過份估計。

  因此UBIFS在同步後可以更精確的估計空閒空間值

  Wastage

  像上面提到的,UBIFS不會跨越LEB邊界。考慮下面數字:

  1. UBIFS node最大尺寸是4256字節

  2. UBIFS node最小尺寸是56 字節

  3. 依賴於名字長度,目錄項節點佔據56~304字節

  4. LEB尺寸:典型的NAND flash 128KiB的物理擦除塊 2048字節的NAND page,LEB的尺寸是126KiB(或者124KiB如果NAND chip不支持sub-pages)

  因此,如果大部分flash上的節點是非壓縮的data nodes, UBIFS將會浪費126KiB LEB的最後1344bytes。但是現實生活中的數據通常是壓縮的,所以node尺寸可能發生變化,因此在刪除塊末尾的wasted space範圍爲0~4255。

  UBIFS把一些小的節點,比如目錄項節點放到LEBs末尾來減少wasted space,但是不理想,UBIFS仍然在LEB的末尾浪費掉大塊的空間。

  當彙報空閒空間時,UBIFS不知道哪種數據,以何種順序寫入flash media。因此,它評估每個LEB的wastage爲最大可能值4255。這個計算對大多數現實世界都是太悲觀了,真實的wastage要遠少於 4255。然而,UBIFS彙報給用戶空間程序的是絕對最小值。

  以上意味着LEB越大,UBIFS對空閒空間的預測越準確,比如128KiB擦除塊要好於16KiB的參數塊

  Dirty space

  Dirty space是曾經別UBIFS nodes使用過的空間,但是由於改變或者removed導致這個空間變得無效。例如,如果文件的內容被re-write,那麼相應的數據node被無效,新的數據data寫入flash media。無效的節點包含dirty space,還有其他的機制會導致dirty space出現。

  UBIFS無法直接重用dirty space。因爲相應的flash areas沒有包含所有的0xff bytes。在dirty space可以重用前,UBIFS不得不垃圾收集相應的LEBs。垃圾收集回收dirty space的方法和JFFS2是相同的。請參考JFFS2 design document

  粗略的講,UBIFS垃圾收集選取一個LEB,這個LEB包含一些dirty space,然後把這個LEB上的有效UBIFS節點移到GC reserverd LEB上。這將消耗GC reserved LEB的一些空閒空間,GC選取另外一個需要收集的LEB,然後把有效數據移到這個GC reserved LEB,持續這個過程直到LEB變滿。GC選取另外一個 reserved LEB,繼續這個過程。

  UBIFS有一個概念叫最小I/O 單位, 描述可以寫入flash數據的最小數目。一般情況下UBIFS工作在large-page NAND flash上,最小I/O單位是2KiB

  事實上,UBIFS GC雖然嘗試不浪費任何空間,但是有時並不能如願。UBIFS不一定能夠回收那些dirty空間小於I/O unit的dirty space

  當UBIFS向users彙報空閒空間時,對待dirty space爲可用空間,因爲GC可能會回收這部分空間爲空閒空間,但如上面分析的,UBIFS無法回收所有的dirty space爲空閒空間,更壞的情況是UBIFS無法確切知道它可以回收多少dirty space。再一次UBIFS使用最悲觀的計算。

  因此dirty space越少,UBIFS彙報的free space越準確。在實際應用中,這意味着一個滿的文件系統要比一個空的文件系統更難預測空閒空間,因爲滿的文件系統有太多的dirty space。

  注意,解決這個問題,UBIFS可以在statfs()中運行GC, GC將把dirty space變爲free space, 因此預測空閒空間就變得更精確。然而,這將導致statfs變得非常的慢,因此調用statfs的應用的行爲將不可預測。此外也可以使用JFFS2使用的 background GC。

  Precise index size is not known

  大概你已經知道,UBIFS在flash media上維護文件系統的index。index佔據flash的一部分空間。UBIFS journal保存着FS data。journal中的FS data沒有index, 這意味着on-flash index沒有指向他們。 journal FS data的index是建立在RAM中的,當文件系統被mount時, UBIFS要掃描整個journal區,然後在RAM中重建index。journal某種程度像是UBIFS中的一個JFFS2文件系統。

  journal data在提交時會變成indexed。在UBIFS提交時,更新on-flash index,使得index指向journal data。然後UBIFS挑選其他的LEBs作爲新的journal, 所以journal在提交後會改變位置。這就是UBIFS的journal特點,日誌區不是固定的。

  UBIFS精確的記錄着index size。也就是,UBIFS一直很清楚當前on-flash index佔據了多少空間。然而,UBIFS無法精確的預測在提交後on-flash index要增加或減少多少。再一次的,UBIFS考慮最壞的情況。

  當然在提交後UBIFS再次知道index的確切尺寸。sync()不僅僅flush左右的髒數據,而且也會提交journal。這意味者同步過的文件系統對空閒空間的預測更準確。

  事實上,UBIFS本可以精確的預計index size而無須commit操作,但是UBIFS作者並沒有實現它,因爲實現很困難,而index size的影響又很小。

  Documentation

  如果文件系統對你來說是一個完全嶄新的領域,那麼推薦你首先從JFFS2開始,因爲UBIFS的很多想法來源於UBIFS。參看JFFS2 design文檔

  JFFS3 design 文檔,你可以發現很多JFFS2問題的描述,以及很多UBIFS的基本想法。記住,這個文檔比較老有些內容過時了。現在我們不再使用JFFS3這個名字,JFFS3已經改名爲UBIFS。在寫這個文檔時UBI並不存在,當時假定JFFS3直接運行在MTD設備上。當然JFFS2 overview, JFFS3 Requirements和Introduction to JFFS3章節大部分仍然是正確的並且對UBIFS的想法給了準確的介紹,比如wandering tree和journal。請注意,superblock的描述對UBIFS是不正確的,UBIFS是基於UBI不需要這個技巧。當然,superblock的位置注意可以用於UBI2 layer

  這個文檔以及UBIFS FAQ保存着關於UBIFS的大量信息。然而你也需要研究UBI,因爲UBIFS是依賴於UBI層提供的服務。參考UBI document和UBI FAQ

  UBIFS white-paper 對於新手來說非常的難,所以我們推薦你首先從JFFS3設計文檔開始。UBIFS white-paper包含UBIFS設計的總體圖,並且描述了UBIFS的內部。white-paper沒有包含本文檔和UBIFS FAQ的一些細節

  最後是UBIFS source code. 代碼中包含了大量註釋,所以我們推薦你在這裏找到你需要的細節。最後歡迎你到UBIFS mailing list提問

  Raw flash vs. FTL devices

  FTL 全稱 "Flash Translation Layer", 是一個軟件層用來在flash hardware上模擬一個block device。在早期 FTL運行在host computer上,今天FTL通常都是fireware, 運行在存儲設備內建的控制器上。例如,如果你查看一個USB flash盤,那麼你可以看到一個NAND chip和一個micro-controller, 這個控制器運行FTL firmware. 一些USB flash deivces甚至有強大的ARM處理器。類似的,MMC, eMMC, SD, SSD和其他的FTL devices有一個內建的處理器來運行firmware。

  所有的FTL設別都提供了一個block I/O訪問接口。雖然這些接口有不同的規範定義的,比如MMC, eMMC, SD, USB mass storage, ATA。但是他們都提供了對塊設備的訪問。基於塊設備的訪問意味着整個設備可以看作是一個線性blocks的排列。每一個塊都可讀可寫。

  儘管大部分常用的flash hardware有FTL, 但是仍讓存在一些裸flash沒有FTL。比如各種手持設備和嵌入式系統。裸flash設備和block設備是非常不同的。他們的工作模式不同,裸flash和block設備相比,有更多的限制和問題需要軟件考慮這些問題。使用FTL層,這些限制和問題都可以被FTL屏蔽。

  UBIFS文件系統被設計用來使用raw flash,假定是raw flash設備模型,他無法工作在block device之上。換句話說,它認爲設備有很多eraseblocks,可以寫入,讀出,或者擦除。UBIFS負責考慮以out-of-place方式寫數據,做垃圾收集等等。UBIFS利用UBI來實現磨損平衡和壞塊管理,正常的block drive都不需要處理這些事情。

  人們經常會問:問什麼有人需要使用raw flash而不是使用eMMC或者類似的塊設備?這個問題回答起來有點複雜,以下是UBIFS開發者的幾點想法。請記住這個觀點的時間(作者無法保證這些觀點隨着時間的改變而變得不正確),用戶也要根據自己系統的實際情況來考慮這幾點。

  1. 裸NAND 芯片更簡單更便宜,然而,隨着業界推動FTL設備,情況似乎在發生變化。事實上FTL設備遠比raw flash設備複雜,因爲FTL不得不內建額外的控制器。但是因爲業界生產了大量的FTL,FTL的價格在下降。

  2. 如果你使用一個FTLs設備,並且打算在上面跑FAT file system。那麼你應該選擇FTL device(eMMC, MMC, SD等等),確保FTL設備可以正確的執行wear-leveling

  3. 當你想使用FTL設備作爲系統存儲,比如rootfs,並且想使用更可靠的文件系統比如ext3。在這種情況下,要考慮各種系統需求比如對突然掉電的容忍度?下面的情況大部分是關於系統存儲情形的

  4. FTL devices是一個黑盒。FTL算法是vendor的祕密,但是你知道NAND flash有磨損平衡,壞塊管理,read-disturb等問題。如果這些問題對你很重要,特別是當使用MLC NAND flash(壽命僅爲1000 erase)。因爲FTL算法是封閉的,所有很難確保是否FTL device正確的處理了這些問題。

  5. 如果你開始考慮FTL是怎麼實現的,你可能意識到他必須實現GC。flash hardware需要寫是out-of-place的。但是FTL在通然斷電的情況下工作如何呢,如果通然斷電發生在垃圾收集的過程中呢? FTL device是否保證斷電前的數據不失蹤,不損壞呢?

  6. 掉電tolerance可以被測試,但是磨損平衡和read-disturb很難被測試,因爲需要很多時間來測試他們。

  7. 我們聽說過一些flash USB設備很快的磨損了。比如flash彙報I/O錯誤在經過幾周的密集使用後。這意味着USB device沒有做好wear-leveling,當然這並是說所有的USB device都不好用,而是說你要注意這一點。

  8. 我們聽說一些MMC, eMMC和SD cards在寫的過程掉電導致數據丟失和損壞,甚至在很久以前就存在的數據發生了丟失和損壞。這表示他們的FTL沒有正確處理。再次強調,並不是所有的MMCs/eMMCs SDs有同樣的問題

  9. 回顧歷史,許多FTL設備使用FAT文件系統存儲圖片和video。FAT文件系統不穩定,導致了FTL設備可能也不穩定。當然丟失幾幅圖片並不是什麼大事,但是確保system libraies不要因爲掉電而損壞。

  10. 好的FTL必定是一個複雜的軟件,特別是當FTL去處理MLC NAND。在firmware中實現他們很困難,運行他們需要強大的控制器。我們懷疑一些廠商使用了各種技巧和妥協來使得他們的設備足夠好和便宜。例如,衆多周知有些廠商針對FAT優化他們FTL,但是如果你在他們上面使用ext3,那麼你就可能會碰到很多不可預知的問題,設備可能會出乎意料的變化,當然,對於封閉的FTL你沒有辦法驗證

  11. SSD驅動和eMMC MMC/SD是非常不同的。他們很昂貴,而且使用強大的CPU來運行復雜的軟件,因此他們可能工作的很好

  12. FTL設備變得越來越便宜,同時也越來越好,儘管我們很難界定一個設備是好還是壞。通常來說使用FTL沒什麼不對,因爲你相信它,也測試過它,或者僅僅你的需求很適合用FTL

  13. 使用raw flash的好處是,你知道你正在做什麼,UBI/UBIFS處理NAND flash的所有事情,包括bad erase-blocks和wear-leveling。它保證掉電處理。同時它是開放的,你可以驗證,測試,修改它。沒有隱藏它能做什麼不能做什麼。另一方面,使用FTL你沒有辦法看到內部正在發生的事,FTL廠商可能騙你說他們的FTL設備有多好。當你發現一個bug時,開發商也不一定很快的給予反饋。

  14. 理論上,UBIFS可以更好的工作因爲他比FTL知道更多的信息,例如,UBIFS知道刪除的文件,而FTL不知道,所以FTL可能爲已經刪除的文件保留 sectors。然而,一些FTL設備可能支持"discard"請求,所以能處理來自文件系統的提示。無論如何,UBIFS在裸的NAND可以更好的工作。當然,FTL設備可以包括多個NAND chips,這就有了並行的可能來提高I/O速率

  15. 很明顯,FTL的優點是你可以在它上面使用老的可信的軟件。但是注意,有時這並不完全正確。UBIFS作者曾經測試過一個知名的eMMC,在掉電時產生了嚴重的問題。此外,這個eMMC不能和ext3很好的配合,因爲當這個FTL掉電時,會出現sectors不可用,讀操作會返回ECC錯誤。對於ext3 來說read errors是致命的,因爲文件系統沒有考慮這種情況。fsck.ext3工具也沒法修理彙報read errors的文件系統。

  所以很難有一個標準答案。在你的系統需求和決定中考慮正反因素。無論如何,raw flashed在嵌入式世界中廣泛使用,這也是爲什麼開發UBIFS的原因。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章