參考資料:
衷心感謝網友的分享:
UBI系統原理分析
http://blog.chinaunix.net/uid-28236237-id-4164656.html
Ubifs檔案系統和mkfs.ubifs以及ubinize工具的用法
https://blog.csdn.net/wjjontheway/article/details/8977871
Linux ubi子系統原理分析
https://www.cnblogs.com/gmpy/p/10874475.html
一、UBI檔案系統的概念:
1、UBI檔案系統:無排序區塊鏡像檔案系統(Unsorted Block Image File System, UBIFS)是用于固態存盤設備上,并與LogFS相互競爭,作為JFFS2的后繼檔案系統之一,
2、UBIFS涉及三個子系統
1)MTD子系統:flash驅動直接操作設備,而MTD在flash驅動之上,向上呈現統一的操作介面,所以MTD子系統的使命是:屏蔽不同flash的操作差異,向上提供統一的操作介面;對應drivers/mtd;
2)UBI子系統:UBI子系統是基于MTD子系統的,在MTD上實作nand特性的管理邏輯,向上屏蔽nand的特性;對應drivers/mtd/ubi;
3)UBIFS檔案系統:是基于UBI子系統的檔案系統,實作檔案系統的所有基本功能,例如檔案的實作,日志的實作;對應fs/ubifs;
4)ubi檔案系統的結構:

3、nand flash的特性:
1)操作最小單元為頁(Page)/塊(Block):nand flash不同于nor flash,nor可以以位元組為單位操作flash,但是nand的最小讀寫單元是頁,擦除最小單元是塊,
2)擦除壽命限制:nand flash的物理性質決定了其每個塊都有擦除壽命的限制,因此驅動必須做到磨損平衡,
3)位翻轉(bit-filps):nand物理性質使其可能會在使用、保存程序中出現位翻轉現象,所以要不在nand flash的內部,要不在nand flash控制器都會存在ecc校正模塊,在位翻轉后校正,然而ecc并不是萬能的,其校正能力有限,所以驅動必須在位翻轉數量進一步變多之前把資料搬移到其它快,ecc都已經校正了,為什么還要搬移?因為ecc校正是從flash讀到記憶體中的資料,而不是flash本身存盤的資料,此時flash中的資料依然是錯的,如果不搬移,隨著翻轉的位數量積累,ecc就校驗不了,此時就相當于永久丟失正確資料,
4)存在壞塊(Bad Block)
制作工藝和nand本身的物理性質導致在出廠和正常使用程序中都會產生壞塊,
4、UBI與Block Layer
Block Layer是適用于常見塊設備的通用塊層,其本質上來講并不是塊設備,UBIFS的IO操作并不通過通用塊設備,
5、UBI與FTL
FTL(Flash Translation Layer)是一個"黑盒子",其跟UBI非常像,都是對nand特性進行封裝,
UBI子系統屏蔽nand特性是為了對接UBIFS,而FTL則是為了對接Block Layer,
6、UBI Volume 與 UBI Device
在UBI中有兩個概念:UBI卷與UBI設備
UBI設備相當于磁盤設備(sda、mmcblk0);
UBI卷相當于磁盤上對應磁區(sda1,mmcblk0p1);
UBI設備是在MTD設備上創建出來的設備,而UBI卷則是從UBI設備上劃分出來的磁區;
7、LEB與PEB
LEB:Logical Erase Block,即邏輯擦除塊,簡稱邏輯塊,表示邏輯卷中的一個塊;
PEB:Physical Erase Block,即物理擦除塊,簡稱物理塊,表示nand中的一個塊;
8、UBI子系統的作用:
UBI子系統就是UBIFS與MTD子系統的中間層,其向下連接MTD設備,實作nand特性管理,向上呈現無壞塊的卷;
所以UBI子系統的作用主要包括兩點:
1)屏蔽nand特性(壞塊管理、磨損平衡、位翻轉);
2)UBI卷實作;
9、UBI頭部:
UBI子系統需要往每個物理塊開頭寫入兩個關鍵資料,這兩個關鍵資料組成了UBI頭部;
這兩個關鍵資料分別是此物理塊擦除次數和次物理塊的邏輯卷標記頭,也分別稱為EC頭(Erase Count)和VID頭(Volume IDentifier),
EC頭和VID頭,都是64Bytes,分別記錄于物理塊的第一頁和第二頁;
1)為什么要有兩個頭:
nand每個block都有擦除壽命限制,因此需要記錄擦除次數,以實作磨損平衡,因此需要EC頭;為了實作卷,必須記錄物理塊與邏輯塊之間的映射關系,因此需要VID頭;
2)為什么不合并成一個頭?
兩者寫入時機不同,導致兩個頭必須分開寫入,EC頭在每次擦除后,必須馬上寫入以避免丟失,而VID頭只有在卷映射后才會寫入,
3)不管是EC頭還是VID頭都是64Bytes,為什么要用倆個Page?
使用兩個Page是對nand來說的,因為nand的最小讀寫單元是Page;對于NOR FLASH,最小讀寫單元使Byte,因此對于Nor可以只使用64Bytes.
4)在記錄擦除次數時掉電等,導致丟失實際擦除次數怎么辦?
取所有物理塊擦除次數的平均數;
10、UBI卷表(UBI Volume Table):
UBI子系統有個對用戶隱藏的特殊卷,叫層卷(layout volume),用來記錄卷表,我們可以把卷表等價于磁區表,記錄各個卷的資訊,
卷表大小為兩個邏輯擦除塊,每個邏輯擦除塊記錄一份卷表,即UBI子系統為了保證卷表的可靠性,用了兩個邏輯卷記錄兩份卷表資訊;
由于層卷的大小是固定的,導致能保存的卷資訊受限,所以最大支持的卷數量是隨著邏輯塊的大小改變的,但最多不超過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;
卷資訊是被CRC232保護的,
11、動態卷和靜態卷
1)vol_type記錄了卷的型別,在創建卷時指定,可選動態卷和靜態卷,
2)動態卷:是可讀可寫的,資料的完整性由檔案系統保證;
3)靜態卷:靜態卷是只讀的,是UBI子系統試用CRC232來校驗保護整個卷的資料;
12、flags是否自動分配大小標識
在首次運行時自動resize卷,讓卷大小覆寫所有未使用的邏輯塊,
例如Flash大小是128M,在燒錄的鏡像中分配的所有卷加起來只用了100M,如果有卷被表示為autoresize,那么在首次運行時,那個卷會自動擴大,把剩余的28M囊括在內,
注意:只允許一個卷設定autoresize標志;
13、壞塊標記:
1)有兩個場景可能會識別壞塊,分別是在寫失敗和擦除失敗,擦除失敗且回傳EIO,則直接標記壞塊,
2)寫失敗壞塊判斷邏輯:
a. 擦除嫌疑壞塊
b. 讀取擦除后的值,判斷是否都是0xFF(擦除后理應全為0xFF)
c. 寫入特定資料
d. 讀取并校驗寫入的資料
e. 以不同的資料模式重復步驟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管理開銷 = UBI特性開銷 + UBI頭開銷
其中:
壞塊預留 = MAX(出廠壞塊數量,壞塊管理預留數量)
特性開銷 = (壞塊預留 + 1磨損平衡開銷 + 2卷表開銷 + 1原子操作開銷)* 物理塊大小(物理塊位元組數,假設一個物理塊是128KB)
UBI頭開銷 = 2 * 頁大小 * (含壞塊的總塊數 - 壞塊預留 - 1個磨損平衡開銷 - 1個原子操作開銷 - 2個層卷開銷)
UBI管理總開銷 = (壞塊預留 + 4)* 物理塊大小 + 2 * 頁大小 * (含壞塊的總塊數 - 壞塊預留 - 4)
例子:
總大小:128M(1Gbit)
頁大小:2K bytes
塊大小:128K
塊數量:1024
假設是完全無壞塊的片子,其管理開銷為:
UBI管理開銷 = (20 + 4) * 128K + 2 * 2K * (1024 - 20 - 4) = 7072K ≈ 7M
三、UBI檔案系統的使用
1、UBI用戶空間工具:
工具 作用
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設備的資訊
2、制作ubi鏡像檔案范例
1)mkfs.ubifs的用法
Usage: mkfs.ubifs [OPTIONS] target
Make a UBIFS file system image from an existing directory tree
Examples:
Build file system from directory /opt/img, writting the result in the ubifs.img file
mkfs.ubifs -m 512 -e 128KiB -c 100 -r /opt/img ubifs.img
The same, but writting directly to an UBI volume
mkfs.ubifs -r /opt/img /dev/ubi0_0
Creating an empty UBIFS filesystem on an UBI volume
mkfs.ubifs /dev/ubi0_0
Options:
-r, -d, --root=DIR build file system from directory DIR
-m, --min-io-size=SIZE minimum I/O unit size,最小輸入輸出大小
-e, --leb-size=SIZE logical erase block size邏輯可擦出塊大小
-c, --max-leb-cnt=COUNT maximum logical erase block count最大邏輯可擦出塊數目
-o, --output=FILE output to FILE輸出檔案名
-j, --jrn-size=SIZE journal size
-R, --reserved=SIZE how much space should be reserved for the super-user
-x, --compr=TYPE compression type - "lzo", "favor_lzo", "zlib" or
"none" (default: "lzo")
-X, --favor-percent may only be used with favor LZO compression and defines
how many percent better zlib should compress to make
mkfs.ubifs use zlib instead of LZO (default 20%)
-f, --fanout=NUM fanout NUM (default: 8)
-F, --space-fixup file-system free space has to be fixed up on first moun
(requires kernel version 3.0 or greater)
-k, --keyhash=TYPE key hash type - "r5" or "test" (default: "r5")
-p, --orph-lebs=COUNT count of erase blocks for orphans (default: 1)
-D, --devtable=FILE use device table FILE
-U, --squash-uids squash owners making all files owned by root
-l, --log-lebs=COUNT count of erase blocks for the log (used only for debugging)
-v, --verbose verbose operation
-V, --version display version information
-g, --debug=LEVEL display debug information (0 - none, 1 - statistics, 2 - files, 3 - more details)
-h, --help display this help text
例:
mkfs.ubifs -x lzo -m 2KiB -e 124KiB -c 720 -o system_ubifs.img -d $path_to_system
-x壓縮格式為lzo
-m最小輸入輸出大小為2KiB(2048bytes),一般為頁大小
-e邏輯可擦除塊大小為124KiB=(每塊的頁數-2)*頁大小=(64-2)*2KiB=124KiB
-c最多邏輯可擦除塊數目為720(720*128KiB=90MiB),這個可根據ubi volume來設定,實際上是設定此卷的最大容量,
通過此命令制作的出的UBIFS檔案系統鏡像可在u-boot下使用ubi write命令燒寫到NAND FLASH上,
========================================================================================
2)ubinize的用法
Usage: ubinize [-o filename] [-p <bytes>] [-m <bytes>] [-s <bytes>] [-O <num>] [-e
<num>][-x <num>] [-Q <num>] [-v] [-h] [-V] [--output=<filename>]
[--peb-size=<bytes>] [--min-io-size=<bytes>] [--sub-page-size=<bytes>]
[--vid-hdr-offset=<num>] [--erase-counter=<num>] [--ubi-ver=<num>]
[--image-seq=<num>] [--verbose] [--help] [--version] ini-file
Example: ubinize -o ubi.img -p 16KiB -m 512 -s 256 cfg.ini - create UBI image
'ubi.img' as described by configuration file 'cfg.ini'
-o, --output=<file name> output file name
-p, --peb-size=<bytes> size of the physical eraseblock of the flash
this UBI image is created for in bytes,
kilobytes (KiB), or megabytes (MiB)
(mandatory parameter)物理可擦出塊大小
-m, --min-io-size=<bytes> minimum input/output unit size of the flash
in bytes
-s, --sub-page-size=<bytes> minimum input/output unit used for UBI
headers, e.g. sub-page size in case of NAND
flash (equivalent to the minimum input/output
unit size by default)子頁大小
-O, --vid-hdr-offset=<num> offset if the VID header from start of the
physical eraseblock (default is the next
minimum I/O unit or sub-page after the EC
header)VID頭部偏移量,默認是512
-e, --erase-counter=<num> the erase counter value to put to EC headers (default is 0)
-x, --ubi-ver=<num> UBI version number to put to EC headers (default is 1)
-Q, --image-seq=<num> 32-bit UBI image sequence number to use
(by default a random number is picked)
-v, --verbose be verbose
-h, --help print help message
-V, --version print program version
例:
ubinize –o ubi.img -m 2KiB -p 128KiB -s 2048 $system_cfg_file –v
-m最小輸入輸出大小為2KiB(2048bytes),一般為頁大小
-p物理可擦出塊大小為128KiB=每塊的頁數*頁大小=64*2KiB=128KiB
-s用于UBI頭部資訊的最小輸入輸出單元,一般與最小輸入輸出單元(-m引數)大小一樣,
此命令生成的ubi.img可直接使用NAND FLASH的燒寫命令燒寫到FLASH上(帶有UBI檔案系統鏡像卷標),
3)ubinize需要指定一個組態檔$system_cfg_file,內容如下:
[rootfs-volume]
mode=ubi
image=system_ubifs.img
vol_id=0
vol_size=90MiB
vol_type=dynamic
vol_name=system
======================================================================
組態檔說明
INI-file format.
The input configuration ini-file describes all the volumes which have to
be included to the output UBI image. Each volume is described in its own
section which may be named arbitrarily. The section consists on
"key=value" pairs, for example:
[jffs2-volume]
mode=ubi
image=../jffs2.img mkfs.ubi生成的源鏡像
vol_id=1 卷序號
vol_size=30MiB 卷大小
vol_type=dynamic 動態卷
vol_name=jffs2_volume 卷名
vol_flags=autoresize
vol_alignment=1
This example configuration file tells the utility to create an UBI image with one volume with ID 1, volume size 30MiB, the volume is dynamic, has name "jffs2_volume", "autoresize" volume flag, and alignment 1. The "image=../jffs2.img" line tells the utility to take the contents of the volume from the "../jffs2.img" file. The size of the image file has to be less or equivalent to the volume size (30MiB). The "mode=ubi" line is mandatory and just tells that the section describes an UBI volume - other section modes may be added in the future.
Notes:
* size in vol_size might be specified kilobytes (KiB), megabytes (MiB), gigabytes (GiB) or bytes (no modifier);
* if "vol_size" key is absent, the volume size is assumed to be equivalent to the size of the image file (defined by "image" key);
* if the "image" is absent, the volume is assumed to be empty;
* volume alignment must not be greater than the logical eraseblock size;
* one ini file may contain arbitrary number of sections, the utility will put all the volumes which are described by these section to the output UBI image file.
3、寫入鏡像
將ubi.img鏡像寫入到nand flash上
1)使用open(),write()等系統呼叫函式將鏡像寫入到/dev/xxx_ubi卷上;
2)或者使用ubiupdatevol更新卷,更新鏡像中的卷;
例如,把/dev/ubi1_x的內容同步到/dev/ubi0_x
dd if=/dev/ubi1_x of=xxx.ubi
ubiupdatevol /dev/ubi0_x xxx.ubi
3)手動寫入:按照設備啟動程序中加載ubi卷這一節中的1)~ 4)步驟操作;
4、設備啟動程序中加載ubi卷
1)格式化mtd設備然后寫入鏡像(如果是手動寫入ubi卷需要加這一步操作):
擦除:flash_eraseall /dev/mtd2或ubiformat /dev/mtd2
寫入:nandwrite -p /dev/mtd2 xxx.ubi
2)鏈接MTD設備到UBI并且創建相應的UBI設備:
ubiattach -m mtd2 -d 2
3)從UBI設備上創建UBI卷:
ubimkvol /dev/ubi0 -N user1 -s 100MiB
在UBI設備/dev/ubi0上創建UBI卷ubix_x,第一個卷為ubix_0,user1為ubi卷名,ubix_0與ubix:user1是等價的,
4)mount將ubi卷掛載到檔案系統中某個目錄下,可以通過操作這個目錄下的檔案來實作ubi讀寫:
mount -t ubifs ubi0_0 /mnt/ubi或mount -t ubifs ubi0:user1 /mnt/ubi
將ubi0_0卷以ubi檔案系統的格式掛載到/mnt/ubi目錄下,-t指定掛載的檔案系統格式,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/35841.html
標籤:其他
