• Linux UBI子系统设计初探


    问题领域

     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

    --EOF--

  • 相关阅读:
    Java Spring Boot VS .NetCore (十) Java Interceptor vs .NetCore Interceptor
    Java Spring Boot VS .NetCore (九) Spring Security vs .NetCore Security
    IdentityServer4 And AspNetCore.Identity Get AccessToken 问题
    Java Spring Boot VS .NetCore (八) Java 注解 vs .NetCore Attribute
    Java Spring Boot VS .NetCore (七) 配置文件
    Java Spring Boot VS .NetCore (六) UI thymeleaf vs cshtml
    Java Spring Boot VS .NetCore (五)MyBatis vs EFCore
    Java Spring Boot VS .NetCore (四)数据库操作 Spring Data JPA vs EFCore
    Java Spring Boot VS .NetCore (三)Ioc容器处理
    Java Spring Boot VS .NetCore (二)实现一个过滤器Filter
  • 原文地址:https://www.cnblogs.com/wahaha02/p/4814698.html
Copyright © 2020-2023  润新知