ubi子系统FAQ

ubi子系统FAQ

前言

概述

本文档主要介绍Linux UBI子系统常见FAQ等。

修订记录

日期作者版本修改说明
2023.10.10枫潇潇V1.0.0初始版本
2024.01.22枫潇潇V1.0.1增加ubi使用只读块设备
2024.01.23枫潇潇V1.0.2增加ubifs做rootfs
2024.01.24枫潇潇V1.0.3增加fastmap使用

ubi attach流程及作用

ubi如何attach mtd设备?

启动参数法

参数格式:

Parameter format: mtd=<name|num|path>[,<vid_hdr_offs>[,max_beb_per1024[,ubi_num]]]

在cmdline中加入ubi参数,示例如下:

ubi.mtd=rootfs ubi.mtd=firmware,0,20,1 ubi.mtd=/dev/mtdX,0,20,2 ubi.block=0,rootfs root=/dev/ubiblock0_0 rootfstype=squashfs 

cmdline中mtd分区参数,示例如下:

mtdparts=spi0.1:512k(boot)ro,512k(misc),512k(pstore),512k(factory),1536k(rp),4608k(system)ro,4608k(recovery)ro,5632k(rootfs),40m(firmware),-(data)

参数含义解析:

ubi.mtd=firmware,0,20,1

firmware:mtd分区名,也可以是8,或者是/dev/mtd8

0:vid_hdr_offs

20:每1024块中保留块的数量,当前ubi保留块的数量为:20*nand_size_in_blocks/1024

1:ubi设备号

模块参数法
modprobe ubi mtd=rootfs mtd=firmware,0,20,1
或者:
modprobe ubi mtd=7 mtd=8,0,20,1
mtd-utils工具法
ubiattach -h
ubiattach version 2.0.1 - a tool to attach MTD device to UBI.

Usage: ubiattach [<UBI control device node file name>]
        [-m <MTD device number>] [-d <UBI device number>] [-p <path to device>]
        [--mtdn=<MTD device number>] [--devn=<UBI device number>]
        [--dev-path=<path to device>]
        [--max-beb-per1024=<maximum bad block number per 1024 blocks>]
UBI control device defaults to /dev/ubi_ctrl if not supplied.
Example 1: ubiattach -p /dev/mtd0 - attach /dev/mtd0 to UBI
Example 2: ubiattach -m 0 - attach MTD device 0 (mtd0) to UBI
Example 3: ubiattach -m 0 -d 3 - attach MTD device 0 (mtd0) to UBI
           and create UBI device number 3 (ubi3)
Example 4: ubiattach -m 1 -b 25 - attach /dev/mtd1 to UBI and reserve
           25*C/1024 eraseblocks for bad block handling, where C is the flash
           is total flash chip eraseblocks count, that is flash chip size in
           eraseblocks (including bad eraseblocks). E.g., if the flash chip
           has 4096 PEBs, 100 will be reserved.

-d, --devn=<number>   the number to assign to the newly created UBI device
                      (assigned automatically if this is not specified)
-p, --dev-path=<path> path to MTD device node to attach
-m, --mtdn=<number>   MTD device number to attach (alternative method, e.g
                      if the character device node does not exist)
-O, --vid-hdr-offset  VID header offset (do not specify this unless you really
                      know what you are doing, the default should be optimal)
-b, --max-beb-per1024 maximum expected bad block number per 1024 eraseblock.
                      The default value is correct for most NAND devices.
                      Allowed range is 0-768, 0 means the default kernel value.
-h, --help            print help message
-V, --version         print program version

ubi attach mtd设备的作用

根据mtd_dev_param参数信息,创建ubi设备与对应的mtd设备进行一一对应绑定。整个过程将会根据mtd设备的erasesize、size、writesize等信息,结合mtd设备的扫描信息,初始化好ubi_device、ubi_volume等实例。

ubi attach mtd设备的流程

1)通过 ubi_mtd_param_parse 解析ubi参数配置好mtd_dev_param参数信息;

2)通过 open_mtd_device找到对应的mtd设备实例——mtd_info;

3)通过 io_init函数,根据mtd_info的IO属性对ubi中的IO属性进行初始化;

4)scan_all扫描ubi设备中所有的PEB,判断其是否为bad,同时获取每个PEB的EC、VID等信息;

5)ubi_read_volume_table创建vtbl,并初始化好逻辑卷volume;

6)ubi_wl_init磨损平衡初始化;

7)ubi_eba_init LEB 与 PEB映射关系初始化,实例为eba_tbl;

8)autoresize重新计算卷大小;

ubi_init()
   |--->open_mtd_device()
   |--->ubi_attach_mtd_dev()
   |				|--->io_init()
   |				|--->ubi_attach()
   |				|		|--->scan_all()
   |				|		|		|--->scan_peb()
   |				|		|--->ubi_read_volume_table()
   |				|		|			|--->create_empty_lvol()
   |				|		|			|--->process_lvol()
   |				|		|			|--->init_volumes()
   |				|		|--->ubi_wl_init()
   |				|		|--->ubi_eba_init()
   |				|--->autoresize()
   |				|--->uif_init()
   |				|--->ubi_debugfs_init_dev()
   |--->ubiblock_init()

ubi保留PEB数量如何配置?

默认情况下,大约 2% 的整个芯片大小 (20/1024 PEB) 被保留用于坏块处理。如果坏块的数量超过了分配的数量,就会打印一条错误消息,并且 UBI 将切换到只读模式。

NandFlash设备在出厂时可能包含一些无效块,并且规定了总可用块中的最小有效块数(Minimum number of Valid Blocks ,NVB)约总块数的98%。无效块是指其中至少包含一个页面的错误位数超过最小所需的 ECC 能够纠正的错误位数。在使用过程中可能会出现额外的坏块。然而,在产品的耐久寿命内,总可用块数不会低于 NVB。

  • 1)kernel默认配置
Device Drivers  --->
       <*> Memory Technology Device (MTD) support  --->
                <*>   Enable UBI - Unsorted block images  ---> 
                          --- Enable UBI - Unsorted block images                                     
                            (20)  Maximum expected bad eraseblock count per 1024 eraseblocks

CONFIG_MTD_UBI_BEB_LIMIT:指定UBI在MTD设备上期望的最大坏物理擦除块数(每1024擦除块),默认值:20,即:2%

  • 2)引导参数配置

    详见:《启动参数法》

  • 3)ubiattach工具配置

    详见:《mtd-utils工具法》

ubi内LEB & PEB如何建立映射?

/* linux-4.19.132/drivers/mtd/ubi/ubi.h */
struct ubi_volume {
	......
	struct ubi_device *ubi; // reference to the UBI device description object
	int vol_id;				// volume ID
	......
	int reserved_pebs;		// how many physical eraseblocks are reserved for this volume
	int vol_type;			// volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
	......
	int name_len;			// volume name length
	char name[UBI_VOL_NAME_MAX + 1];	// volume name
	......
	struct ubi_eba_table *eba_tbl;	// EBA table of this volume (LEB->PEB mapping)
	......
};

ubi_volume结构体中的eba_tbl用于记录volume使用了哪些逻辑擦写块,以及逻辑擦写块到物理擦写块的映射; eba_tbl 的数据类型为struct ubi_eba_table,结构体定义如下所示:

/*
 * struct ubi_eba_entry - structure encoding a single LEB -> PEB association
 */
struct ubi_eba_entry {
	int pnum; // the physical eraseblock number attached to the LEB
};

/*
 * struct ubi_eba_table - LEB -> PEB association information
 */
struct ubi_eba_table {
	struct ubi_eba_entry *entries; // the LEB to PEB mapping (one entry per LEB)
};

ubi_eba_table结构体中的entries是个数组,数组长度为ubi_volume结构体中的reserved_pebs,即为这个volume分配的物理擦写块个数;数组元素类型为 struct ubi_eba_entry,这个结构体只包含一个成员pnum;

问题:逻辑擦写块如何映射到物理擦写块?struct ubi_eba_entry结构体中的pnum是什么?

以nand flash来举例说明,假设nand flash的erase block size=128KB,这个nand flash上有一个96MB的mtd分区,假设这个分区名称为mtd1,ubi attach到mtd1;则mtd1总共包含有 96MB/128KB=768个erase block;

如果要读取pnum=12的物理擦写块的内容,则pnum=12在mtd1分区的offset=12*(erase block size)=12*128KB=1536KB,有了offset后就可以通过mtd提供的接口把这个物理擦写块的内容读出来;

如果给定逻辑擦写块lnum=0,通过ubi_eba_table结构体中的entries[lnum].pnum 获取到对应的pnum(因为mtd1有768个erase block,这个值的取值范围:0~767),假设entries[lnum].pnum=12,则lnum=0被映射到pnum=12,即通过逻辑擦写块lnum=0可以读写物理擦写块pnum=12(mtd1分区offset=1536KB)的数据;

在这里插入图片描述

ubi上如何使用只读块设备?

UBI允许在卷之上创建块设备,但是有以下限制:

Ø 只读操作

Ø 连续的IO操作,请记住NAND驱动核心已经将所有的IO连续了。

尽管有这么多的限制,挂载一个只读的块设备仍然非常有作用。比如被压缩的文件系统(squashfs),它就可以作为一个轻量级的只读根文件系统放在NAND设备上。UBI层将负责管理像bit-flips和损耗均衡这一类的事情。

使用方法

生成和销毁UBI卷之上的块设备和将MTD设备和UBI关联起来有些相似。既可以使用UBI模块参数block,也可以使用用户空间工具“ubiblock”.

为了在启动的时候就创建一个块设备,可以指定block参数为内核启动参数:

ubi.mtd=5 ubi.block=0,0 root=/dev/ubiblock0_0
  • 方式一:引导参数

Ø 使用UBI卷路径

ubi.block=/dev/ubi0_0

Ø 使用UBI设备和卷名:

ubi.block=0,rootfs

Ø 使用UBI设备号和UBI卷号:

ubi.block=0,0
  • 方式二:模块参数

如果已经将UBI创建为一个模块,在模块加载时可以使用以下参数:

$ modprobe ubi mtd=/dev/mtd5 block=/dev/ubi0_0
  • 方式三:ubiblock工具

使用用户空间工具ubiblock,块设备也可以在运行时被动态的创建和移除

$ ubiblock --create /dev/ubi0_0
$ ubiblock --remove /dev/ubi0_0

示例——squashfs做rootfs

ubi.mtd=rootfs  ubi.mtd=firmware ubi.mtd=data ubi.block=0,rootfs root=/dev/ubiblock0_0 rootfstype=squashfs mtdparts=spi0.1:1m(boot)ro,1m(misc),1m(pstore),1m(factory),1m(rp1),1m(rp2),6m(system1)ro,6m(system2)ro,6m(rootfs)ro,32m(firmware),-(data)

参数含义:

  • ubi.mtd=XXX:ubi attach mtd设备

  • ubi.block=0,rootfs:为指定的ubi设备的卷创建块设备,即为ubi0的rootfs卷创建一个ubi块设备

  • root=/dev/ubiblock0_0:指定根文件系统

  • rootfstype=squashfs:根文件系统类型

ubi上如何使用ubifs做rootfs?

用法同上,差异点如下:

ubi.mtd=rootfs  ubi.mtd=firmware ubi.mtd=data root=ubi0:rootfs rw rootwait rootfstype=ubifs 

ubi上如何使用fastmap?

fastmap工作原理

快速映射是一个试验的可选的UBI特征,可以将CONFIG_MTD_UBI_FASTMAP设置为y来使能该功能。一旦被使能,UBI将评估模块参数”fm_autoconvert”。如果它被设置为1(默认为0),UBI将为每一个被关联镜像(attachedimage)自动使能快速映射。这意味着UBI用快速映射的数据创建了一个新的内部卷,以便下次快速关联模式可以使用这些数据。
在默认配置下,UBI将会使用存储在快速映射卷里面的信息,以此来加速关联(attach)过程。如果想测试快速映射,设置fm_autoconver为1并将其关联(attach)到一个卷。

以下是可进行的配置:

CONFIG_MTD_UBI_FASTMAPFm_autoconvertresultn
n0快速映射完全被屏蔽
y0如果镜像上存在一个快速映射,它将附在(attach)UBI上,但是如果没有快速映射,也就不会有快速映射会被安装在镜像上。
y1如果镜像上存在一个快速映射,它将附在(attach)UBI上,快速映射会自动的被安装在所有依附(attach)的镜像上。
技术实现

一个磁盘存储的快速映射包含所有的需要附加到整个镜像的信息,也就是说所有的擦除计数值,所有的PEB列表和他们的状态,所有卷的列表和他们当前的EBA……为了避免对快速映射的太多次的写入,快速映射有一个PEB列表,这些PEB是已经更改过的或者需要在附加时进行全扫描的。这个表叫作快速映射池,并且有一个固定的大小,PEB总数的5%。仅当UBI对快速映射进行写入,并且快速映射池里没有空闲的PEB时,才会使用到这个技术。否则,每当一个卷的EBA改变时,UBI都会写入到快速映射。

快速映射有一个超级块(也叫作PEB锚),并且可以负载任何PEB上的数据。PEB锚必须在MTD设备的前64个PEB中,它有一个指向其它剩余PEB的指针,而这些PEB才是真正的装载实际的快速映射数据。在现在的NAND flash芯片中,整个快速映射是放在一个单独的PEB中的,因此,PEB锚指向它自己。在加载快速映射数据以后,UBI将据此来生成信息结构。

attach 流程如下
Ø UBI试图找到快速映射PEB锚,如果没有找到PEB锚,UBI将进行一个传统的全扫描
Ø 根据存储在PEB锚中的指针读取快速映射的负载数据
Ø 仅把池中的PEB执行一个传统的扫描,而不是所有的PEB。

如果UBI检测到使用的快速映射是无效的,它将自动退回扫描模式并执行一个全扫描。使用CRC32的checksum和一致性来校验内部的UBI结构体,以此来判断快速映射是否有效。

每当快速映射池满,快速映射将会被写入设备,卷层将改变或者镜像被detach。也许会疑问,为什么在detach的时候需要被写入,如果UBI在detach的时候不写一个新的快速映射,所有的擦除计数将发生修改当上一个快速映射写入已丢失。

开销

如果使能了快速映射,UBI将存储足够的PEB来装载两个完整的快速映射。在实际当中,NAND flash芯片有两个PEB是为快速映射预留的。

也有一些运行时的开销,为了确保新的快速映射是有效的,UBI将管理所有那些将导致EBA更改的IO,这将消耗一秒。所以,快速映射在大flash芯片,也就是进行一次全扫描需要较长时间的芯片上使用才会有意义。比如一个4G的NAND flash芯片进行一次全扫描需要好几秒,而一个快速的attach仅需要不到一秒的时间。

备注

启用Fastmap并不保证每个attach过程都会在最短时间内完成。在某些情况下,仍然需要进行完整扫描。这可能发生在两种情况下:

(i) 如果在写入Fastmap到闪存时发生意外重启;

(ii) 在写入Fastmap时UBI用尽了PEBs。

后一种情况可能发生在写入时发生大量I/O错误,并且UBI找不到足够可用的PEBs。

使用方法

  • 使用CONFIG_UBI_FASTMAP配置编译内核

  • 使用ubi.fm_autoconvert = 1内核参数至少引导一次系统。

  • 以干净的方式重启系统

  • 保证正常启动一次系统后可以删除ubi.fm_autoconvert = 1

fastmap优化效果

128MB spinand与32MB spinor测试对比

阶段耗时(uint:S)Spinor启动时间
过程启动fastmap关闭fastmap
Boot阶段Brom0.4——
Spl1.20.4
Uboot1.31.4
总计2.9001.744
Kernel阶段自解压2.8882.8783.091
Nand init1.0211.1030
Ubi attach0.7072.1250
Ubifs mount1.3301.2351.175
总计7.5748.8306.762
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值