本文思惟導圖總綱:
html
關於ubi子系統,早已有比較正式的介紹,也提供很是形象的介紹ubi子系統ppt
國內的前輩 alloysystem 不辭辛勞爲咱們提供了部分正式介紹的中文譯文,以及找不到原文的轉載譯文linux
感謝這些資料讓我迅速入門ubi,進而整理出這博文算法
此博文是對上文的總結以及中文譯文的補充ide
上圖很是形象地描述了從Flash到UBIFS的各個層次。從上圖咱們發現,MTD子系統在實際的Flash驅動之上 ,而UBI子系統則在MTD子系統之上。工具
要對比UBI和MTD的概念,咱們不妨問本身一個問題,UBI和MTD兩個不一樣的層次的"使命"分別是什麼?學習
Flash驅動直接操做設備,而MTD在Flash驅動之上,向上呈現統一的操做接口。因此MTD的"使命"是 屏蔽不一樣Flash的操做差別,向上提供統一的操做接口 。ui
UBI基於MTD,那麼UBI的目的是什麼呢? 在MTD上實現nand特性的管理邏輯,向上屏蔽nand的特性 。.net
nand有什麼特性呢?
(下文描述的 Nand驅動,是廣義上的操做Nand的集合,包括fs/ubi/mtd的層次,而非純粹的nand驅動)unix
1. 操做最小單元爲頁(Page)/塊(Block) Nand不一樣於Nor,Nor能夠以字節爲單位操做Flash,但Nand的讀寫最小單元是頁,擦除最小單元是塊。 對常見的1Gbit的spinand而言,其頁大小2KBytes,塊大小是128K,表示一個塊有64個頁。 2. 擦除壽命限制 Nand的物理性質決定了其每一個塊都有擦除壽命的限制,SLC約10W次,MLC約5000次,TLC約1000次。 所以,Nand驅動必需要作到磨損平衡。 所謂磨損平衡,就是儘量均衡使用每個塊,既不讓一個塊太大壓力,也不讓一個塊太過空閒。 3. 位翻轉(bit-flips) Nand的物理性質使其可能會在使用、保存過程當中出現位翻轉的現象。 例如,原始數據爲0xFFFC,在存儲過程當中Flash的數據卻變成了0xFFFF。 因此要不在nand內部,要不在nand控制器都會存在ecc校訂模塊,在位翻轉後校訂。 然而,ecc並非萬能的,其校訂能力有限,因此驅動必須在位翻轉數量進一步變多以前把數據搬移到其餘塊。 萌新可能會有疑問,ecc都已經校訂了爲何還要搬移?由於ecc校訂的是從Flash中讀到內存中的數據, 而不是Flash自己存儲的數據,換句話說,此時Flash中的數據依然是錯的,若是不搬移,隨着翻轉的位數量積累, ecc就校訂不了了,此時就至關於永久丟失正確數據了。 4. 存在壞塊(Bad Block) 製做工藝和Nand自己的物理性質,致使在出廠和正常使用過程當中都會產生壞塊。 所謂壞塊,就是說這個塊已經損壞,不能再用於存儲數據,所以Nand驅動須要能自動跳過壞塊。
關於SLC/MLC/TLC的比較,可參考這篇博客
若是說UBI在MTD之上,在FS之下的中間層,用於抽象MTD屏蔽nand差別,那麼ubifs就是正兒八經的文件系統。
ubifs是基於UBI子系統的文件系統,實現文件系統該有的全部基本功能,例如文件的實現,例如日誌的實現。
這裏須要特別注意的是,ubifs跟jffs/yaffs相比,並不包含nand特性的管理,而是交由ubi來實現。
Block Layer是適用於常見塊設備的通用塊層,其特有的概念有bio、request、電梯算法等,其典型的設備有磁盤、SSD、mmc等。
而ubi基於mtd,雖然能模擬塊設備,從本質上來說其並非塊設備。跟蹤UBIFS的IO操做,發現其IO操做並不通過通用塊設備層。
FTL(Flash Translation Layer)是一個"黑盒子",其跟UBI很是像,都是對nand特性進行封裝。
按個人理解,UBI跟FTL的目標不一樣,致使其實現上會有差別。UBI屏蔽nand特性是爲了對接UBIFS,而FTL則是爲了對接Block Layer。例如MMC其實也是封裝起來的Nand,只不過在MMC內部實現了FTL,通過FTL的轉換就能以塊設備層的方法直接操做Nand,就能在mmc上格式化常見的塊文件系統,例如EXT、VFAT等。
在UBI中還有兩個概念,分別是UBI卷(UBI Volume)和UBI設備(UBI Device)。這兩個概念,咱們能夠這麼理解:
UBI設備 至關於 磁盤設備(sda,mmcblk0) UBI卷 至關於 磁盤上對應分區(sda1,mmcblk0p1)
換句話說,UBI設備是在MTD設備上建立出來的設備,而UBI卷則是從UBI設備上劃分出來的分區, 從設備節點名(ubi0)和卷名(ubi0_3)能夠看出端倪。
上面的描述是爲了方便理解UBI卷和UBI設備,實際上UBI卷和分區的概念之間仍是有差異的。
在UBI子系統中,還有LEB和PEB的概念:
LEB指Logical Erase Block,即邏輯擦除塊,簡稱邏輯塊,表示邏輯卷中的一個塊 PEB指Physical Erase Block,即物理擦除塊,簡稱物理塊,表示物理Nand中的一個塊
爲何要劃分邏輯塊和物理塊?從PPT中咱們能夠發現,物理塊和邏輯塊存在動態映射關係,且因爲UBI頭的存在,邏輯塊通常會比物理塊小2個頁。
UBI子系統就是ubifs與mtd之間的中間層,其向下鏈接MTD設備,實現nand特性的管理邏輯,向上呈現無壞塊的卷。
因此UBI子系統的做用,主要包括兩點:
1. 屏蔽nand特性(壞塊管理、磨損平衡、位翻轉) 2. UBI卷的實現
UBI卷的邏輯擦除塊(LEB)與物理擦除塊(PEB)之間是動態映射的,詳細能夠看PPT
ubi的工具集成在包mtd-utils中,分別有如下工具及其做用
工具 | 做用 |
---|---|
ubinfo | 提供ubi設備和卷的信息 |
ubiattach | 連接MTD設備到UBI而且建立相應的UBI設備 |
ubidetach | ubiattach相反的操做,將MTD設備從UBI設備上去連接 |
ubimkvol | 從UBI設備上建立UBI卷 |
ubirmvol | 從UBI設備上刪除UBI卷 |
ubiblock | 管理UBI捲上的block |
ubiupdatevol | 更新卷,例如OTA直接更新某個分區鏡像 |
ubicrc32 | 使用與ubi相同的基數計算文件的crc32 |
ubinize | 製做UBI鏡像 |
ubiformat | 格式化空的Flash設備,擦除Flash,保存擦除計數,寫入UBI鏡像到Flash |
mtdinfo | 報告從系統中找到的UBI設備的信息 |
UBI子系統須要往每一個物理塊的開頭寫入兩個關鍵數據,這兩個關鍵數據就叫作UBI的頭部。
這兩個數據分別是 此物理塊擦除次數頭 和 此物理塊的邏輯卷標記頭,也分別稱爲 EC頭(Erase Count) 和 VID頭(Volume IDentifier)。
不論是EC頭仍是VID頭,都是64Bytes,分別記錄與Nand塊的第一個頁和第二個頁。
以Q&A的形式介紹UBI頭:
Q:爲何要這兩個頭? A:前文有說道,nand每一個block有擦除壽命限制,所以須要記錄擦除次數,以實現磨損平衡,所以須要EC頭。此外,爲了實現卷,必須記錄卷的邏輯塊與物理塊之間的映射關係,所以須要VID頭。 Q:爲何不合併成1個頭? A:二者寫入的時機不一致,致使兩個頭必須分開寫入。EC頭在每次擦除後,必須立刻寫入以免丟失,而VID頭只有在映射卷後纔會寫入。 Q:不論是EC頭仍是VID頭都是64B,爲何要用2個Page? A:使用2個Page是對Nand來講的。前文有說過,Nor的讀寫最小單元是Byte,而Nand的讀寫最小單元是Page,所以對Nor能夠只使用64Bytes,對Nand則必須使用2個Page,就是說,即便只有64Bytes有效數據,也須要用無效數據填充滿1個Page一次性寫入。 Q:在記錄擦除次數時掉電等,致使丟失實際擦除次數怎麼辦? A:取全部物理塊的擦除次數的平均數
關於UBI頭部的詳細介紹,可參考連接
UBI子系統有個對用戶隱藏的特殊卷,叫層卷(layout volume),用來記錄卷表。咱們能夠把卷表等價於分區表,記錄各個卷的信息。卷表大小爲2個邏輯擦除塊,每一個邏輯擦除塊記錄一份卷表,換句話說,UBI子系統爲了保證卷表的可靠性,用2個邏輯記錄2分卷標信息。
因爲層卷的大小是固定的(2個邏輯塊),致使能保存的卷信息受限,因此最大支持的卷數量是隨着邏輯塊的大小改變而改變的,但最多不超過128個。
卷表中每一個卷都保存了什麼信息?
struct ubi_vtbl_record { __be32 reserved_pebs; //物理塊數量 __be32 alignment; //卷對齊 __be32 data_pad; __u8 vol_type; //靜態卷or動態卷標識 __u8 upd_marker; //更新標識 __be16 name_len; //卷名長度 __u8 name[UBI_VOL_NAME_MAX+1]; //卷名 __u8 flags; //經常使用語自動重分配大小標記 __u8 padding[23]; //保留區域 __be32 crc; //卷信息的CRC32校驗值 } __packed;
由這個結構體咱們能夠發現,卷信息是被CRC32保護着的。比較有意思的有兩個成員:vol_type 和 flags
vol_type成員標記了卷的類型,在建立卷時指定,可選動態卷和靜態卷。那麼什麼是動態卷?什麼又是靜態卷?
動態卷和靜態卷是兩種卷的類型,靜態卷標記此卷只讀,因而UBI子系統使用CRC32來校驗保護整個卷的數據,動態卷是可讀寫的卷,數據的完整性由文件系統來保證。
關於靜態卷和動態卷的介紹,可參考連接
flags成員經常使用於標識是否自動重分配大小。怎麼樣自動充分配大小呢?在首次運行時自動resize卷,讓卷大小覆蓋全部未使用的邏輯塊。
例如Flash大小是128M,在燒錄的鏡像中分配的全部卷加起來只用了100M,若是有卷被表示爲autoresize
,那麼在首次運行時,那個卷會自動擴大,把剩餘的28M囊括在內。
這個功能挺實用的,例如某個方案規劃中,除去rootfs、內核等必要空間外,把剩餘全部空間儘量分配給用戶數據分區。
在開發過程當中加了個應用,致使rootfs卷鬚要更大的空間,進而須要壓縮user_data卷的空間。
若是user_data空間是autoresize的,那麼user_data卷的空間就會自動壓縮。
再例如舊方案用的是128M的nand,後面升級爲256M,即便使用相同的固件,也不用擔憂多出來的128M浪費掉了,
由於user_data卷自動擴大囊括多出來的128M。
須要注意的是,只容許1個卷設置autoresize標誌
關於更新標識更多的介紹,參考連接
咱們知道Nand的物理性質,致使在使用久以後會產生壞塊,那麼UBI是如何判斷好塊是否變成了壞塊的呢?
有兩個場景可能會標識壞塊,分別是寫失敗和擦除失敗。擦除失敗且返回是EIO,則直接標記壞塊。比較有意思的是寫失敗的判斷邏輯。
UBI子系統有後臺進程對疑似的壞塊進行"嚴刑拷打"(torturing),有5個步驟:
1. 擦除嫌疑壞塊 2. 讀取擦除後的值,判斷是否都是0xFF(擦除後理應全爲0xFF) 3. 寫入特定數據 4. 讀取並校驗寫入的數據 5. 以不一樣的數據模式重複步驟1-4
若是"嚴刑拷打"出問題,則標記壞塊,詳細的實現邏輯可參考函數torture_peb()
原文可參考連接
什麼是管理開銷呢?爲了管理Nand的空間,實現磨損平衡、壞塊管理等等功能,必須佔用一部分空間來存儲關鍵數據,就好像文件系統的元數據。管理佔用的空間是不會呈現給用戶空間使用的,這空間即爲管理的開銷。
對Nand來講,UBI管理開銷主要包含5個部分:
1. 層卷(卷表) : 佔用兩個物理塊 2. 磨損平衡:佔用一個物理塊 3. 邏輯塊修改原子操做:佔用一個物理塊 4. 壞塊管理:默認每1024個塊則預留20個塊(內核參數可配:CONFIG_MTD_UBI_BEB_LIMIT) 5. UBI頭:(物理塊總數*2)個頁
壞塊管理預留的塊數量,也能夠理解爲最大能容納多少個壞塊;再考慮壞塊的存在,管理開銷計算公式爲:
UBI管理總開銷 = 特性開銷 + UBI頭開銷 其中: 壞塊預留 = MAX(壞塊數量,壞塊管理預留數量) 特性開銷 = (壞塊預留 + 1個磨損平衡開銷 + 1個原子操做開銷 + 2個層捲開銷) * 物理塊大小 UBI頭開銷 = 2 * 頁大小 * (含壞塊的總塊數 - 壞塊預留 - 1個磨損平衡開銷 + 1個原子操做開銷 + 2個層捲開銷) 也就是說: UBI管理總開銷 = (壞塊預留 + 4) * 物理塊大小 + 2 * 頁大小 * (含壞塊的總塊數 - 壞塊預留 - 4)
以128M的江波龍的FS35ND01G-S1F1 SPI Nand爲例,其規格爲:
總大小:128M(1Gbit) 頁大小:2K bytes 塊大小:128K 塊數量:1024
假設是徹底無壞塊的片子,其管理開銷爲:
UBI管理開銷 = (20 + 4) * 128K + 2 * 2K * (1024 - 20 - 4) = 7072K ≈ 7M
詳細參考原文連接