Source https://www.cnblogs.com/wahaha02/p/4814698.html
問題領域
flash存放裝置存在如下特點:
·
存在壞塊
·
使用壽命較短
·
存儲介質不穩定
·
讀寫速度慢
·
不支援隨機訪問(nand)
·
只能通過擦除將0改成1
·
最小讀寫單位為page or sub-page
·
便宜
針對flash設備的特點,flash檔案系統的核心功能需求和品質需求需包括如下這幾個方面:
·
讀寫
·
性能
·
可靠性
·
持久性
針對這些需求,可分析得出flash檔案系統需要滿足如下屬性要求:
·
資料保護
·
壞塊管理
·
垃圾回收
·
磨損均衡
·
分區管理
·
文件管理
·
性能優化
在ubifs檔案系統中,這7條屬性中的資料保護、壞塊管理、垃圾回收、磨損均衡、分區管理等需求由ubi子系統實現,也是此次分析的重點。
架構模型
ubi是ubifs的一個子系統,其位於MTD之上,ubifs之下,如圖所示。
ubi子系統內部又細分多個模組(如下),每個模組後面逐個展開介紹。
其設計架構如下:
為了管理架構棧中的各個子系統,ubi在使用者態匯出多個控制介面,以便於對模型進行控制管理。
/dev/mtd0:
mtd物件,對mtd設備操作的實體
/dev/ubi_ctrl:
ubi控制物件,用於ubi與mtd的映射與解映射(attach and detach)
/dev/ubi0:
ubi 抽象層物件,對ubi操作的實體
/dev/ubi0_0:
ubi volume物件,對ubi volume操作的實體
UBI資料模型
資料是建模和設計的核心,UBI有2個頂層資料物件:ubi_attach_info和ubi_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_hdr、ubi_vid_hdr、ubi_vtbl_record、OOB的資料結構定義、存儲位置和資料示例如下:
ubi_ec_hdr,存放在每個PEB(1MB)的page 0,每個page(8K)一段OOB(0x1C0);
ubi_vid_hdr,對於已分配到volume中的PEB,vid hdr存放在PEB page 1(8K) or
page 0 sub-page 1(2K);
ubi_vtbl_record,作為UBI_LAYOUT_VOLUME_ID的資料,LEB0,LEB1相互備份,從PEB的page 2 開始存放。
每個PEB塊有個OOB區,OOB前面幾個位元組是壞塊標記(橙色標示),尾部一段位元組為ECC資料(綠色標示),如果中間有多餘位元組,則閒置不用(黃色標示)。各段的大小依賴於頁格式、ecc位數、各flash廠商定義的壞塊標記形式而定。
UBI attaching子系統
attaching子系統的核心任務就是創建並初始化ubi設備,其核心資料是ubi_attch_info物件,對照上一節的資料模型,這個過程包括創建ubi_ainf_volume物件;掃描所有PEB的ec header和vid header,讀取OOB區壞塊標記,統計壞塊個數,初始化ai->bad_peb_count;如果attaching時PEB的ec header為無效值,此時會有平均的ec值初始化其ec header;如果發現2個PEB具有相同的lnum,選用seqnum大的PEB,seqnum小的PEB放入 ai->erase鏈表。
校驗每個塊的ec header、vid header和data,並對其錯誤類型進行分類,對可糾正的錯誤,放入ai->erase表,對於無法糾正的錯誤,放入ai->corr或ai->alien表;對於沒有錯誤的塊,放入ai->free表。具體分類規則請參照下表。
錯誤類型:
·
UBI_IO_FF: 全0xFF;
·
UBI_IO_FF_BITFLIPS:
全0xFF,但是有可糾正的ECC錯誤;
·
UBI_IO_BAD_HDR: EC或VID頭損壞(如magic number錯誤或者CRC錯誤)
·
UBI_IO_BAD_HDR_EBADMSG:
由不可糾正的ECC錯誤導致的EC或VID頭損壞
·
UBI_IO_BITFLIPS: 有可糾正的ECC錯誤;
PEB分類:
·
free:正常塊;
·
erase:擦除塊,需要進行擦除;
·
corr:損壞塊,不再參與磨損均衡;
·
alien:異常塊,不再參與磨損均衡;
·
scrub:擦洗塊,資料搬移到正常快上,並對其進行擦除,確認沒有問題;
·
torture:拷問塊,資料搬移到正常快上,並對其反復多次讀寫擦除,確認沒有問題;
UBI EBA子系統
EBA子系統主要提供如下功能:
·
LEB/PEB的映射表管理:上層只看到LEB,不再關心塊的讀寫錯誤處理、替換等細節;
·
LEB的sequence counter管理:seq counter主要是為了標記順序,解決LEB/PEB的映射衝突;
·
LEB訪問介面封裝:如read, write, copy,
check, unmap, atomic change等;
·
LEB訪問保護:每一個LEB的併發訪問都由讀寫信號量鎖rwsem進行保護;
EBA提供了2種寫方式:ubi_eba_write_leb和ubi_eba_atomic_leb_change。ubi_eba_write_leb用於對塊的write,ubi_eba_atomic_leb_change用於對塊的modify或者append。ubi_eba_write_leb寫後會做讀校驗,如果有-EIO錯誤,將老PEB上的資料移動到新的PEB上,並將新資料也寫到新的PEB中,對老PEB進行torture。ubi_eba_atomic_leb_change為了避免破壞已有資料,採用異地更新的方式來實現原子寫,並加一個ubi->alc_mutex來進行序列化保護,其具體流程如下:
1.
讀取leb資料(ubifs內完成)
2.
檢查寫資料長度是否為0,為0時,unmap leb
3.
分配初始化vid_hdr
4.
分配新的peb(ubi_wl_get_peb)
5.
新peb中寫入vid_hdr
6.
新peb中寫入老leb資料+新增資料
7.
回收老的peb(ubi_wl_put_peb)
8.
更新leb map(vol->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 PEB。PEB的回收通過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