Linux ubi子系統原理分析

本文思惟導圖總綱:
思惟導圖總綱html

綜述

關於ubi子系統,早已有比較正式的介紹,也提供很是形象的介紹ubi子系統ppt
國內的前輩 alloysystem 不辭辛勞爲咱們提供了部分正式介紹的中文譯文,以及找不到原文的轉載譯文linux

感謝這些資料讓我迅速入門ubi,進而整理出這博文算法

此博文是對上文的總結以及中文譯文的補充ide

在閱讀本文以前,建議先學習PPT中文譯文函數

概念對比

UBI Vs. MTD

UBI層次

上圖很是形象地描述了從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 Vs. UBIFS

若是說UBI在MTD之上,在FS之下的中間層,用於抽象MTD屏蔽nand差別,那麼ubifs就是正兒八經的文件系統。
ubifs是基於UBI子系統的文件系統,實現文件系統該有的全部基本功能,例如文件的實現,例如日誌的實現。

這裏須要特別注意的是,ubifs跟jffs/yaffs相比,並不包含nand特性的管理,而是交由ubi來實現。

UBI Vs. Block Layer

Block Layer是適用於常見塊設備的通用塊層,其特有的概念有bio、request、電梯算法等,其典型的設備有磁盤、SSD、mmc等。
而ubi基於mtd,雖然能模擬塊設備,從本質上來說其並非塊設備。跟蹤UBIFS的IO操做,發現其IO操做並不通過通用塊設備層。

UBI Vs. FTL

FTL(Flash Translation Layer)是一個"黑盒子",其跟UBI很是像,都是對nand特性進行封裝。

按個人理解,UBI跟FTL的目標不一樣,致使其實現上會有差別。UBI屏蔽nand特性是爲了對接UBIFS,而FTL則是爲了對接Block Layer。例如MMC其實也是封裝起來的Nand,只不過在MMC內部實現了FTL,通過FTL的轉換就能以塊設備層的方法直接操做Nand,就能在mmc上格式化常見的塊文件系統,例如EXT、VFAT等。

UBI Volume Vs. UBI Device

在UBI中還有兩個概念,分別是UBI卷(UBI Volume)和UBI設備(UBI Device)。這兩個概念,咱們能夠這麼理解:

UBI設備 至關於 磁盤設備(sda,mmcblk0)
UBI卷 至關於 磁盤上對應分區(sda1,mmcblk0p1)

換句話說,UBI設備是在MTD設備上建立出來的設備,而UBI卷則是從UBI設備上劃分出來的分區, 從設備節點名(ubi0)和卷名(ubi0_3)能夠看出端倪。

上面的描述是爲了方便理解UBI卷和UBI設備,實際上UBI卷和分區的概念之間仍是有差異的。

LEB Vs. PEB

在UBI子系統中,還有LEB和PEB的概念:

LEB指Logical Erase Block,即邏輯擦除塊,簡稱邏輯塊,表示邏輯卷中的一個塊
PEB指Physical Erase Block,即物理擦除塊,簡稱物理塊,表示物理Nand中的一個塊

爲何要劃分邏輯塊和物理塊?從PPT中咱們能夠發現,物理塊和邏輯塊存在動態映射關係,且因爲UBI頭的存在,邏輯塊通常會比物理塊小2個頁。

UBI子系統扮演的角色及其做用

UBI子系統就是ubifs與mtd之間的中間層,其向下鏈接MTD設備,實現nand特性的管理邏輯,向上呈現無壞塊的卷。

因此UBI子系統的做用,主要包括兩點:

1. 屏蔽nand特性(壞塊管理、磨損平衡、位翻轉)
2. UBI卷的實現

UBI卷的邏輯擦除塊(LEB)與物理擦除塊(PEB)之間是動態映射的,詳細能夠看PPT

UBI相關的工具

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子系統須要往每一個物理塊的開頭寫入兩個關鍵數據,這兩個關鍵數據就叫作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卷表(UBI Volume Table)

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()

原文可參考連接

UBI管理開銷

什麼是管理開銷呢?爲了管理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

詳細參考原文連接

相關文章
相關標籤/搜索