2019年1月22日 星期二

Find duplicate lines in a file and count how many time each line was duplicated?

https://stackoverflow.com/questions/6712437/find-duplicate-lines-in-a-file-and-count-how-many-time-each-line-was-duplicated

Assuming there is one number per line:
sort  | uniq -c
You can use the more verbose --count flag too with the GNU version, e.g., on Linux:
sort  | uniq --count

NAND FLASH以及相關ECC校驗方法

Source https://hk.saowen.com/a/40df7145abfef183a8ba6ee8551e66514b1e2188d7c48e58d18a11e90cc81d70

Flash名稱的由來,Flash的擦除操作是以block塊為單位的,與此相對應的是其他很多存儲設備,是以bit位為最小讀取/寫入的單位,Flash是一次性地擦除整個塊:在發送一個擦除命令後,一次性地將一個block,常見的塊的大小是128KB/256KB,全部擦除為1,也就是裏面的內容全部都是0xFF了,由於是一下子就擦除了,相對來説,擦除用的時間很短,可以用一閃而過來形容,所以,叫做Flash Memory。所以一般將Flash翻譯為 (快速)閃存。

 

NAND Flash 在嵌入式系統中有着廣泛的應用,負載平均和壞塊管理是與之相關的兩個核心議題。Uboot 和 Linux 系統對 NAND 的操作都封裝了對這兩個問題的處理方法。 本文首先講述Nandflash基礎知識,然後介紹現有的幾類壞塊管理(BBM)方法,通過分析典型嵌入式系統的 NAND 存儲表,指出了輕量級管理方法的優勢所在,分析了當前廣泛使用的輕量級管理方法,指出其缺陷所在並詳細説明了改進方法。
基礎知識 
Flash的硬件實現機制
Flash的內部存儲是MOSFET,裏面有個懸浮門(Floating Gate),是真正存儲數據的單元。
在Flash之前,紫外線可擦除(uv-erasable)的EPROM,就已經採用了Floating Gate存儲數據這一技術了。
典型的Flash內存物理結構
數據在Flash內存單元中是以電荷(electrical charge) 形式存儲的。存儲電荷的多少,取決於圖中的外部門(external gate)所被施加的電壓,其控制了是向存儲單元中衝入電荷還是使其釋放電荷。而數據的表示,以所存儲的電荷的電壓是否超過一個特定的閾值Vth來表示,因此,Flash的存儲單元的默認值,不是0(其他常見的存儲設備,比如硬盤燈,默認值為0),而是1,而如果將電荷釋放掉,電壓降低到一定程度,表述數字0。

NandFlash的簡介 
Nand flash成本相對低,説白了就是便宜,缺點是使用中數據讀寫容易出錯,所以一般都需要有對應的軟件或者硬件的數據校驗算法,統稱為ECC。但優點是,相對來説容量比較大,現在常見的Nand Flash都是1GB,2GB,更大的8GB的都有了,相對來説,價格便宜,因此適合用來存儲大量的數據。其在嵌入式系統中的作用,相當於PC上的硬盤,用於存儲大量數據。
SLC和MLC 
Nand Flash按照內部存儲數據單元的電壓的不同層次,也就是單個內存單元中,是存儲1位數據,還是多位數據,可以分為SLC和MLC。那麼軟件如何識別系統上使用過的SLC還是MLC呢?
Nand Flash設計中,有個命令叫做Read ID,讀取ID,讀取好幾個字節,一般最少是4個,新的芯片,支持5個甚至更多,從這些字節中,可以解析出很多相關的信息,比如此Nand Flash內部是幾個芯片(chip)所組成的,每個chip包含了幾片(Plane),每一片中的頁大小,塊大小,等等。在這些信息中,其中有一個,就是識別此flash是SLC還是MLC。 
 oob / Redundant Area / Spare Area
每一個頁,對應還有一塊區域,叫做空閒區域(spare area)/宂餘區域(redundant area),而Linux系統中,一般叫做OOB(Out Of Band),這個區域,是最初基於Nand Flash的硬件特性:數據在讀寫時候相對容易錯誤,所以為了保證數據的正確性,必須要有對應的檢測和糾錯機制,此機制被叫做EDC(Error Detection Code)/ECC(Error Code Correction, 或者 Error Checking and Correcting),所以設計了多餘的區域,用於放置數據的校驗值。
Oob的讀寫操作,一般是隨着頁的操作一起完成的,即讀寫頁的時候,對應地就讀寫了oob。
關於oob具體用途,總結起來有:
  1. 標記是否是壞快
  2. 存儲ECC數據
  3. 存儲一些和文檔系統相關的數據。如jffs2就會用到這些空間存儲一些特定信息,而yaffs2文檔系統,會在oob中,存放很多和自己文檔系統相關的信息。

Bad Block Management壞塊管理
Nand Flash由於其物理特性,只有有限的擦寫次數,超過那個次數,基本上就是壞了。在使用過程中,有些Nand Flash的block會出現被用壞了,當發現了,要及時將此block標註為壞塊,不再使用。於此相關的管理工作,屬於Nand Flash的壞塊管理的一部分工作。
Wear-Leveling負載平衡
Nand Flash的block管理,還包括負載平衡。
正是由於Nand Flash的block,都是有一定壽命限制的,所以如果你每次都往同一個block擦除然後寫入數據,那麼那個block就很容易被用壞了,所以我們要去管理一下,將這麼多次的對同一個block的操作,平均分佈到其他一些block上面,使得在block的使用上,相對較平均,這樣相對來説,可以更能充分利用Nand Flash。
 ECC錯誤校驗碼
Nand Flash物理特性上使得其數據讀寫過程中會發生一定機率的錯誤,所以要有個對應的錯誤檢測和糾正的機制,於是才有此ECC,用於數據錯誤的檢測與糾正。Nand Flash的ECC,常見的算法有海明碼和BCH,這類算法的實現,可以是軟件也可以是硬件。不同系統,根據自己的需求,採用對應的軟件或者是硬件。
相對來説,硬件實現這類ECC算法,肯定要比軟件速度要快,但是多加了對應的硬件部分,所以成本相對要高些。如果系統對於性能要求不是很高,那麼可以採用軟件實現這類ECC算法,但是由於增加了數據讀取和寫入前後要做的數據錯誤檢測和糾錯,所以性能相對要降低一些,即Nand Flash的讀取和寫入速度相對會有所影響。
其中,Linux中的軟件實現ECC算法,即NAND_ECC_SOFT模式,就是用的對應的海明碼。
而對於目前常見的MLC的Nand Flash來説,由於容量比較大,動輒2GB,4GB,8GB等,常用BCH算法。BCH算法,相對來説,算法比較複雜。
筆者由於水平有限,目前仍未完全搞懂BCH算法的原理。
BCH算法,通常是由對應的Nand Flash的Controller中,包含對應的硬件BCH ECC模塊,實現了BCH算法,而作為軟件方面,需要在讀取數據後,寫入數據之前,分別操作對應BCH相關的寄存器,設置成BCH模式,然後讀取對應的BCH狀態寄存器,得知是否有錯誤,和生成的BCH校驗碼,用於寫入。
其具體代碼是如何操作這些寄存器的,由於是和具體的硬件,具體的nand flash的controller不同而不同,無法用同一的代碼。如果你是nand flash驅動開發者,自然會得到對應的起nand flash的controller部分的datasheet,按照手冊説明,去操作即可。
不過,額外説明一下的是,關於BCH算法,往往是要從專門的做軟件算法的廠家購買的,但是Micron之前在網上放出一個免費版本的BCH算法。
位反轉
Nand Flash的位反轉現象,主要是由以下一些原因/效應所導致:
  1. 漂移效應(Drifting Effects)
    漂移效應指的是,Nand Flash中cell的電壓值,慢慢地變了,變的和原始值不一樣了。
  2. 編程干擾所產生的錯誤(Program-Disturb Errors)
    此現象有時候也叫做,過度編程效應(over-program effect)。
    對於某個頁面的編程操作,即寫操作,引起非相關的其他的頁面的某個位跳變了。
  3. 讀操作干擾產生的錯誤(Read-Disturb Errors)
    此效應是,對一個頁進行數據讀取操作,卻使得對應的某個位的數據,產生了永久性的變化,即Nand Flash上的該位的值變了。

對應位反轉的類型,Nand Flash位反轉的類型和解決辦法,有兩種:

  1. 一種是nand flash物理上的數據存儲的單元上的數據,是正確的,只是在讀取此數據出來的數據中的某位,發生變化,出現了位反轉,即讀取出來的數據中,某位錯了,本來是0變成1,或者本來是1變成0了。此處可以成為軟件上位反轉。此數據位的錯誤,當然可以通過一定的校驗算法檢測並糾正。
  2. 另外一種,就是nand flash中的物理存儲單元中,對應的某個位,物理上發生了變化,原來是1的,變成了0,或原來是0的,變成了1,發生了物理上的位的數據變化。此處可以成為硬件上的位反轉。此錯誤,由於是物理上發生的,雖然讀取出來的數據的錯誤,可以通過軟件或硬件去檢測並糾正過來,但是物理上真正發生的位的變化,則沒辦法改變了。不過個人理解,好像也是可以通過擦除Erase整個數據塊Block的方式去擦除此錯誤,不過在之後的Nand Flash的使用過程中,估計此位還是很可能繼續發生同樣的硬件的位反轉的錯誤。
以上兩種類型的位反轉,其實對於從Nand Flash讀取出來的數據來説,解決其中的錯誤的位的方法,都是一樣的,即通過一定的校驗算法,常稱為ECC,去檢測出來,或檢測並糾正錯誤。
如果只是單獨檢測錯誤,那麼如果發現數據有誤,那麼再重新讀取一次即可。
實際中更多的做法是,ECC校驗發現有錯誤,會有對應的算法去找出哪位錯誤並且糾正過來。
其中對錯誤的檢測和糾正,具體的實現方式,有軟件算法,也有硬件實現,即硬件Nand Flash的控制器controller本身包含對應的硬件模塊以實現數據的校驗和糾錯的。

Nand Flash的一些typical特性

  1. 頁擦除時間是200us,有些慢的有800us
  2. 塊擦除時間是1.5ms
  3. 頁數據讀取到數據寄存器的時間一般是20us
  4. 串行訪問(Serial access)讀取一個數據的時間是25ns,而一些舊的Nand Flash是30ns,甚至是50ns
  5. 輸入輸出端口是地址和數據以及命令一起multiplex複用的
  6. Nand Flash的編程/擦除的壽命:即,最多允許10萬次的編程/擦除,達到和接近於之前常見的Nor Flash,幾乎是同樣的使用壽命了。
  7. 封裝形式:48引腳的TSOP1封裝 或 52引腳的ULGA封裝

Nand Flash控制器與Nand Flash芯片

我們寫驅動,是寫Nand Flash 控制器的驅動,而不是Nand Flash 芯片的驅動,因為獨立的Nand Flash芯片,一般來説,是很少直接拿來用的,多數都是硬件上有對應的硬件的Nand Flash的控制器,去操作和控制Nand Flash,包括提供時鐘信號,提供硬件ECC校驗等等功能,我們所寫的驅動軟件,是去操作Nand Flash的控制器
然後由控制器去操作Nand Flash芯片,實現我們所要的功能。
由於Nand Flash讀取和編程操作來説,一般最小單位是頁,所以Nand Flash在硬件設計時候,就考慮到這一特性,對於每一片(Plane),都有一個對應的區域專門用於存放,將要寫入到物理存儲單元中去的或者剛從存儲單元中讀取出來的,一頁的數據,這個數據緩存區,本質上就是一個緩存buffer,但是隻是此處datasheet裏面把其叫做頁寄存器page register而已,實際將其理解為頁緩存,更貼切原意。
而正是因為有些人不瞭解此內部結構,才容易產生之前遇到的某人的誤解,以為內存裏面的數據,通過Nand Flash的FIFO,寫入到Nand Flash裏面去,就以為立刻實現了實際數據寫入到物理存儲單元中了,而實際上只是寫到了這個頁緩存中,只有當你再發送了對應的編程第二階段的確認命令,即0x10,之後,實際的編程動作才開始,才開始把頁緩存中的數據,一點點寫到物理存儲單元中去。

壞塊的標記

具體標記的地方是,對於現在常見的頁大小為2K的Nand Flash,是塊中第一個頁的oob起始位置的第1個字節(舊的小頁面,pagesize是512B甚至256B的Nand Flash,壞塊標記是第6個字節),如果不是0xFF,就説明是壞塊。相對應的是,所有正常的塊,好的塊,裏面所有數據都是0xFF的。
對於壞塊的標記,本質上,也只是對應的flash上的某些字節的數據是非0xFF而已,所以,只要是數據,就是可以讀取和寫入的。也就意味着,可以寫入其他值,也就把這個壞塊標記信息破壞了。對於出廠時的壞塊,一般是不建議將標記好的信息擦除掉的。
uboot中有個命令是
nand scrub
就可以將塊中所有的內容都擦除了,包括壞塊標記,不論是出廠時的,還是後來使用過程中出現而新標記的。
nand erase
只擦除好的塊,對於已經標記壞塊的塊,不要輕易擦除掉,否則就很難區分哪些是出廠時就壞的,哪些是後來使用過程中用壞的了。

Uboot 的輕量級壞塊管理方法

NAND 壞塊管理都是基於壞塊表(BBT)的,通過這張表來標識系統中的所有壞塊。所以,不同的管理方法之間的差異可以通過以下幾個問題來找到答案。
  • 如何初始化和讀取壞塊表?
  • 產生新的壞塊時,如何標記並更新壞塊表?
  • 如何保存壞塊表?是否有保存時斷電保護機制?
  • 對 NAND 寫入數據時,如果當前塊是壞塊,如何找到可替換的好塊?
Uboot 是目前使用最為廣泛的 bootloader,它提供了兩種輕量級壞塊管理方法,可稱之為基本型和改進型。通過下表,我們可以看到兩者的差異。
雖然 uboot 的改進型壞塊管理方法的做了一些改進,但它仍然有三個主要的缺點。
  1. 出現壞塊,則將數據順序寫入下一個好塊。如果 NAND 中存放了多個軟件模塊,則每個模塊都需要預留一個較大的空間作為備用的好塊,這會浪費較多的 NAND 空間。通常,每個模塊預留的備用好塊數為 NAND 芯片所允許的最大壞塊數,該值因不同的芯片而有所不同,典型值為 20 或 80。假設 NAND 是大頁類型,總共有 N 個模塊,則總共需要預留的空間大小為 N*80*128KB。
  2. 讀取 BBT 時僅檢查簽名,沒有對 BBT 的數據做校驗。
  3. 沒有掉電保護機制。如果在保存 BBT 時斷電,BBT 將丟失。
針對現有管理方法的缺陷,本文提出了一種更加安全高效的管理方法,將從以下三個方面闡述其實現原理。

共用好塊池機制

首先,使用一個統一的備用好塊池,為所有存放在 NAND 中的模塊提供可替換的好塊。這樣,就不需要在每個模塊後面放置一個保留區,提高了 NAND 的空間利用率。
共用好塊池示意圖
共用好塊池示意圖
為了實現共用好塊池,需要創建一個從壞塊到好塊的映射,所以,除了 BBT 之外,還需定義一個替換表(SBT)。這樣一來,當讀第 i 個塊的數據時,如果發現 BBT 中記錄該塊為壞塊,就去 SBT 中查詢其替換塊;如果寫第 i 個塊出錯,需要在 BBT 中標記該塊為壞塊,同時從好塊池中獲取一個新的好塊,假設其序號為 j,然後將此好塊的序號 j 寫入 SBT 中的第 i 個字節,而且 SBT 的第 j 個字節寫序號 i。SBT 中的這種雙向映射可確保數據的可靠性。此外,好塊池中的塊也有可能成為壞塊,如果掃描時發現是壞塊,則將 SBT 中的對應位置標記為 0x00,如果是在寫的過程中出錯,則除了在 SBT 對應位置標記 0x00 之外,還要更新雙向映射數據。
 BBT/SBT 映射示意圖

安全的 BBT/SBT 數據校驗機制

傳統方法僅檢查 BBT 所在塊的簽名,將讀到的前幾個字節和一個特徵字符串進行比較,如果一致,就認為當前塊的數據為 BBT,然後讀取接下來的 BBT 數據,但並不對 BBT 的數據做校驗。如果 BBT 保存在 NAND 中,數據的有效性是可以得到驗證的,因為 NAND 控制器或驅動一般都會對數據做 ECC 校驗。但是,大多數控制器使用的 ECC 算法也僅僅能糾正一個 bit、發現 2 兩個 bit 的錯誤。如果 BBT 保存在其他的沒有 ECC 校驗機制的存儲體中,比如 NOR Flash,沒有對 BBT 的數據進行校驗顯然是不安全的。
為了更加可靠和靈活地驗證 BBT/SBT 數據,定義下面這個結構體來描述 BBM 信息。
BBM 頭信息
typedef struct {
UINT8     acSignature[4];/* BBM 簽名 */
UINT32    ulBBToffset;/* BBT 偏移 */
UINT32    ulSBToffset;/* SBT 偏移 */
UINT16    usBlockNum;/* BBM 管理的 block 數目 */    
UINT16    usSBTstart;/* SBT 所在位置的起始 block 序號 */
UINT16    usSBtop;/* SBT top block */
UINT16    usSBnum;/* SBT number */
UINT32    ulBBTcrc;/* BBT 數據 CRC 校驗碼 */
UINT32    ulSBTcrc;/* SBT 數據 CRC 校驗碼 */
UINT32    ulHeadcrc;/* BBM 頭信息 CRC 校驗碼 */
} BBM_HEAD
BBT/SBT 的保存形式
BBT/SBT 的保存形式
使用三重 CRC 校驗機制,無論 BBT 保存在哪種存儲體中,都可以更加嚴格地驗證數據的有效性。

安全的掉電保存機制

傳統的方法僅保存一份 BBT 數據,如果在寫 BBT 時系統掉電,則 BBT 丟失,系統將可能無法正常啟動或工作。為安全起見,本文所述方法將同時保留三個備份,如果在寫某個備份時掉電,則還有兩個完好的備份。最壞的情況是,如果在寫第一個備份時掉電,則當前最新的一個壞塊信息丟失。
讀取壞塊表時,順序讀取三個備份,如果發現三個備份的數據不一致,用記錄的壞塊數最多的備份為當前的有效備份,同時立刻更新另外兩備份。

總結

本文介紹了NandFlash基礎知識和幾類 NAND 壞塊管理方法,指出了 uboot 的輕量級管理方法的缺陷,提出了一種改進的方法,提高了 NAND 的利用率及壞塊管理的安全性,可對嵌入式開發起到有很好的借鑑作用。

ECC定義

ECC校驗是一種內存糾錯原理,它是比較先進的內存錯誤檢查和更正的手段。ECC內存即糾錯內存,簡單的説,其具有發現錯誤,糾正錯誤的功能,一般多應用在高檔台式電腦/服務器及圖形工作站上,這將使整個電腦系統在工作時更趨於安全穩定。

技術原理

內存是一種電子器件,在其工作過程中難免會出現錯誤,而對於穩定性要求高的用户來説,內存錯誤可能會引起致命性的問題。內存錯誤根據其原因還可分為硬錯誤和軟錯誤。硬件錯誤是由於硬件的損害或缺陷造成的,因此數據總是不正確,此類錯誤是無法糾正的;軟錯誤是隨機出現的,例如在內存附近突然出現電子干擾等因素都可能造成內存軟錯誤的發生。
為了能檢測和糾正內存軟錯誤,在ECC技術出現之前,首先出現的是內存“奇偶校驗(Parity)”。內存中最小的單位是比特,也稱為“位(bit)”,位有隻有兩種狀態分別以1和0來標示,每8個連續的比特叫做一個字節(byte)。不帶奇偶校驗的內存每個字節只有8位,如果其某一位存儲了錯誤的值,就會導致其存儲的相應數據發生變化,進而導致應用進程發生錯誤。而奇偶校驗就是在每一字節(8位)之外又增加了一位作為錯誤檢測位。在某字節中存儲數據之後,在其8個位上存儲的數據是固定的,因為位只能有兩種狀態1或0,假設存儲的數據用位標示為1、1、1、0、0、1、0、1,那麼把每個位相加(1+1+1+0+0+1+0+1=5),結果是奇數。對於偶校驗,校驗位就定義為1,反之則為0;對於奇校驗,則相反。當CPU讀取存儲的數據時,它會再次把前8位中存儲的數據相加,計算結果是否與校驗位相一致。從而一定程度上能檢測出內存錯誤,奇偶校驗只能檢測出錯誤而無法對其進行修正,同時雖然雙位同時發生錯誤的概率相當低,奇偶校驗卻無法檢測出雙位錯誤。
通過上面的分析我們知道Parity內存是通過在原來數據位的基礎上增加一個數據位來檢查當前8位數據的正確性,但隨着數據位的增加Parity用來檢驗的數據位也成倍增加,就是説當數據位為16位時它需要增加2位用於檢查,當數據位為32位時則需增加4位,依此類推。特別是當數據量非常大時,數據出錯的機率也就越大,對於只能糾正簡單錯誤的奇偶檢驗的方法就顯得力不從心了,正是基於這樣一種情況,一種新的內存技術應允而生了,這就是ECC(錯誤檢查和糾正),這種技術也是在原來的數據位上外加校驗位來實現的。不同的是兩者增加的方法不一樣,這也就導致了兩者的主要功能不太一樣。它與Parity不同的是如果數據位是8位,則需要增加5位來進行ECC錯誤檢查和糾正,數據位每增加一倍,ECC只增加一位檢驗位,也就是説當數據位為16位時ECC位為6位,32位時ECC位為7位,數據位為64位時ECC位為8位,依此類推,數據位每增加一倍,ECC位只增加一位。總之,在內存中ECC能夠容許錯誤,並可以將錯誤更正,使系統得以持續正常的操作,不致因錯誤而中斷,且ECC具有自動更正的能力,可以將Parity無法檢查出來的錯誤位查出並將錯誤修正。

示例

ECC(Error Checking and Correcting,錯誤檢查和糾正)內存,它同樣也是在數據位上額外的位存儲一個用數據加密的代碼。當數據被寫入內存,相應的ECC代碼與此同時也被保存下來。當重新讀回剛才存儲的數據時,保存下來的ECC代碼就會和讀數據時產生的ECC代碼做比較。如果兩個代碼不相同,他們則會被解碼,以確定數據中的哪一位是不正確的。然後這一錯誤位會被拋棄,內存控制器則會釋放出正確的數據。被糾正的數據很少會被放回內存。假如相同的錯誤數據再次被讀出,則糾正過程再次被執行。重寫數據會增加處理過程的開銷,這樣則會導致系統性能的明顯降低。如果是隨機事件而非內存的缺點產生的錯誤,則這一內存地址的錯誤數據會被再次寫入的其他數據所取代。

相關推薦:

2019年1月14日 星期一

Linux UBI子系統設計初探


Source https://www.cnblogs.com/wahaha02/p/4814698.html

問題領域
flash存放裝置存在如下特點:
·         存在壞塊
·         使用壽命較短
·         存儲介質不穩定
·         讀寫速度慢
·         不支援隨機訪問(nand
·         只能通過擦除將0改成1
·         最小讀寫單位為page or sub-page
·         便宜
針對flash設備的特點,flash檔案系統的核心功能需求和品質需求需包括如下這幾個方面:
·         讀寫
·         性能
·         可靠性
·         持久性
針對這些需求,可分析得出flash檔案系統需要滿足如下屬性要求:
·         資料保護
·         壞塊管理
·         垃圾回收
·         磨損均衡
·         分區管理
·         文件管理
·         性能優化
ubifs檔案系統中,這7條屬性中的資料保護、壞塊管理、垃圾回收、磨損均衡、分區管理等需求由ubi子系統實現,也是此次分析的重點。

架構模型
ubiubifs的一個子系統,其位於MTD之上,ubifs之下,如圖所示。

ubi子系統內部又細分多個模組(如下),每個模組後面逐個展開介紹。

其設計架構如下:

為了管理架構棧中的各個子系統,ubi在使用者態匯出多個控制介面,以便於對模型進行控制管理。
/dev/mtd0
  mtd物件,對mtd設備操作的實體
/dev/ubi_ctrl
  ubi控制物件,用於ubimtd的映射與解映射(attach and detach)
/dev/ubi0
  ubi 抽象層物件,對ubi操作的實體
/dev/ubi0_0
  ubi volume物件,對ubi volume操作的實體
UBI資料模型
 資料是建模和設計的核心,UBI2個頂層資料物件:ubi_attach_infoubi_volume_desc。其資料關係模型如下:


UBI資料持久化設計
因為磨損均衡、邏輯塊管理、分卷管理等需要,ubi自身支援這些功能的中繼資料需要持久化存儲,如:塊擦除次數、LEB/PEB映射、volume/LEB映射、分卷表、fastmap等資料,具體的資料結構有:
OOB
ubi_ec_hdr - UBI erase counter header
ubi_vid_hdr - on-flash UBI volume identifier header
ubi_vtbl_record - a record in the volume table.
ubi_fm_sb - UBI fastmap super block
ubi_fm_hdr - header of the fastmap data set
ubi_fm_scan_pool - Fastmap pool PEBs to be scanned while attaching
ubi_fm_ec - stores the erase counter of a PEB
ubi_fm_volhdr - Fastmap volume header
ubi_fm_eba - denotes an association beween a PEB and LEB
其中ubi_ec_hdrubi_vid_hdrubi_vtbl_recordOOB的資料結構定義、存儲位置和資料示例如下:
ubi_ec_hdr,存放在每個PEB1MB)page 0,每個page8K)一段OOB0x1C0)
ubi_vid_hdr,對於已分配到volume中的PEBvid hdr存放在PEB page 1(8K) or page 0 sub-page 1(2K)
ubi_vtbl_record,作為UBI_LAYOUT_VOLUME_ID的資料,LEB0LEB1相互備份,從PEBpage 2 開始存放。

每個PEB塊有個OOB區,OOB前面幾個位元組是壞塊標記(橙色標示),尾部一段位元組為ECC資料(綠色標示),如果中間有多餘位元組,則閒置不用(黃色標示)。各段的大小依賴於頁格式、ecc位數、各flash廠商定義的壞塊標記形式而定。

UBI attaching子系統
attaching子系統的核心任務就是創建並初始化ubi設備,其核心資料是ubi_attch_info物件,對照上一節的資料模型,這個過程包括創建ubi_ainf_volume物件;掃描所有PEBec headervid header,讀取OOB區壞塊標記,統計壞塊個數,初始化ai->bad_peb_count;如果attachingPEBec header為無效值,此時會有平均的ec值初始化其ec header;如果發現2PEB具有相同的lnum,選用seqnum大的PEBseqnum小的PEB放入 ai->erase鏈表。
校驗每個塊的ec headervid headerdata,並對其錯誤類型進行分類,對可糾正的錯誤,放入ai->erase表,對於無法糾正的錯誤,放入ai->corrai->alien表;對於沒有錯誤的塊,放入ai->free表。具體分類規則請參照下表。
錯誤類型:
·         UBI_IO_FF: 0xFF
·         UBI_IO_FF_BITFLIPS: 0xFF,但是有可糾正的ECC錯誤;
·         UBI_IO_BAD_HDR: ECVID頭損壞(magic number錯誤或者CRC錯誤)
·         UBI_IO_BAD_HDR_EBADMSG: 由不可糾正的ECC錯誤導致的ECVID頭損壞
·         UBI_IO_BITFLIPS: 有可糾正的ECC錯誤;
PEB分類:
·         free:正常塊;
·         erase:擦除塊,需要進行擦除;
·         corr:損壞塊,不再參與磨損均衡;
·         alien:異常塊,不再參與磨損均衡;
·         scrub:擦洗塊,資料搬移到正常快上,並對其進行擦除,確認沒有問題;
·         torture:拷問塊,資料搬移到正常快上,並對其反復多次讀寫擦除,確認沒有問題;

UBI EBA子系統
 EBA子系統主要提供如下功能:
·         LEB/PEB的映射表管理:上層只看到LEB,不再關心塊的讀寫錯誤處理、替換等細節;
·         LEBsequence counter管理:seq counter主要是為了標記順序,解決LEB/PEB的映射衝突;
·         LEB訪問介面封裝:如read, write, copy, check, unmap, atomic change等;
·         LEB訪問保護:每一個LEB的併發訪問都由讀寫信號量鎖rwsem進行保護;
EBA提供了2種寫方式:ubi_eba_write_lebubi_eba_atomic_leb_changeubi_eba_write_leb用於對塊的writeubi_eba_atomic_leb_change用於對塊的modify或者appendubi_eba_write_leb寫後會做讀校驗,如果有-EIO錯誤,將老PEB上的資料移動到新的PEB上,並將新資料也寫到新的PEB中,對老PEB進行tortureubi_eba_atomic_leb_change為了避免破壞已有資料,採用異地更新的方式來實現原子寫,並加一個ubi->alc_mutex來進行序列化保護,其具體流程如下:
1.     讀取leb資料(ubifs內完成)
2.     檢查寫資料長度是否為0,為0時,unmap leb
3.     分配初始化vid_hdr
4.     分配新的pebubi_wl_get_peb
5.     peb中寫入vid_hdr
6.     peb中寫入老leb資料+新增資料
7.     回收老的pebubi_wl_put_peb
8.     更新leb mapvol->eba_tbl

UBI wear-leveling子系統
磨損均衡是UBI的核心功能之一,負責管理PEB的分配、回收、擦除、scrub、磨損均衡等。其中scrub、擦除, 磨損均衡功能由UBI後臺執行緒進行非同步調度管理。
UBI磨損均衡基於PEB的擦除次數實現,採用靜態磨損均衡策略。對於靜態磨損均衡,建立在如下假設上:擦除次數(ec)少的PEB比擦除次數多的PEB穩定,將ec大的PEB資料交換到ec小的PEB上,達到磨損均衡的目的。
PEB的分配、回收、擦除、scrub都會觸發磨損均衡檢查。為了避免頻繁磨損均衡,進一步加重磨損情況,磨損均衡的觸發頻率通過UBI_WL_THRESHOLD控制,UBI_WL_THRESHOLD值不宜太小。但這種策略也存在一些問題,為了避免極端情況下對某些特定塊反復擦除,通過磨損均衡_FREE_MAX_DIFF (2*UBI_WL_THRESHOLD)來控制挑選最壞的free PEB範圍。
根據attaching時的PEB分類,磨損均衡模組初始化時,啟動對erase塊的擦除,對torture塊的拷問,構建磨損均衡塊紅黑樹,scrub紅黑樹等。PEB的分配通過ubi_wl_get_peb介面實現,分配具有平均擦除次數的free PEBPEB的回收通過ubi_wl_put_peb介面實現,回收後調度erase_worker擦除。

UBI IO子系統
IO子系統主要為上層模組提供統一的讀寫介面,這主要包含:
PEB讀寫介面的統一封裝,包括mtd read/write 封裝;參數檢查;讀寫檢查(read io check, write verify check, 通過ubi->dbg.chk_io控制,默認沒有使能。
ubi ec/vid hdr的讀寫介面的統一封裝,包括有效性驗證;支援非對齊存儲;支持vid存於sub-page

UBI fastmap子系統
縮短ubi初始化(attach)時間,使attach時間複雜度是個常數,不隨PEB個數成線性增長。(Experimental feature,產品中暫未使能,未研究)

參考資料
Linux kernel 3.14-rc6 source code
http://en.wikipedia.org/wiki/Wear_leveling
www.linux-mtd.infradead.org