ubi子系统的块清洗(scrub)处理

ubi子系统的块清洗(scrub)处理

问题背景

在nand的应用中,普遍存在位翻转的问题。除了nand本身提供硬件ECC保证一定程度的位翻转纠正,当遇到超过设置的位翻转阈值但还能被ECC纠正的物理块,软件上可以做一次物理块移动动作,把数据拷贝到其他物理块,以避免原来的块一段时间之后出现位翻转超出ECC纠正能力而导致数据丢失的问题。
这种软件思路在之前已经做过讨论,是有必要的。在了解内核ubi子系统的源码之后,发现内核已经实现了这种处理,下面把这种处理叫做块清洗处理。

实现原理

参数配置

在mtd数据结构体struct mtd_info中定义了三个参数,与块清洗处理有关。如果没有配置,将无法执行块清洗操作。

struct mtd_info {
...
    /*
     * read ops return -EUCLEAN if max number of bitflips corrected on any
     * one region comprising an ecc step equals or exceeds this value.
     * Settable by driver, else defaults to ecc_strength.  User can override
     * in sysfs.  N.B. The meaning of the -EUCLEAN return code has changed;
     * see Documentation/ABI/testing/sysfs-class-mtd for more detail.
     */
    unsigned int bitflip_threshold;
...
    /* the ecc step size. */
    unsigned int ecc_step_size;



    /* max number of correctible bit errors per ecc step */
    unsigned int ecc_strength;
...
};
  • bitflip_threshold:位翻转阈值,由用户在sysfs配置。代表需要进行块清洗操作的位翻转阈值。
  • ecc_step_size:一次ECC校验的数据段长度,每个page分为多个校验数据段。由nand驱动配置,由mtd nand的core层写入mtd结构体。
  • ecc_strength:代表nand硬件ECC能够纠正的位翻转个数。由nand驱动配置,由mtd nand的core层写入mtd结构体。

触发块清洗的过程

触发块清洗只有一种情况,那就是在读某一个page的时候,从nand驱动获取到的ECC Status(即位纠正个数)超过用户配置的bitflip_threshold。具体函数调用过程如下:

  1. spinand_read_page()返回值大于0,读page成功,ECC校验成功,此时返回值代表经过ECC纠正的位翻转个数。
  2. spinand_mtd_read()返回本次读操作(可能读多个page)的最大位翻转个数。
  3. mtd_read()根据spinand_mtd_read()的返回值判断,如果ecc_strength大于0,并且返回值大于bitflip_threshold,则返回-EUCLEAN。
  4. ubi_io_read()根据mtd子系统的返回值-EUCLEAN,向上返回ubi子系统内部错误码UBI_IO_BITFLIPS。
  5. ubi EBA子系统读逻辑块接口ubi_eba_read_leb()判断ubi_io_read()返回UBI_IO_BITFLIPS后,调用ubi_wl_scrub_peb()请求进行块清洗动作。
/**
* ubi_wl_scrub_peb - schedule a physical eraseblock for scrubbing.
* @ubi: UBI device description object
* @pnum: the physical eraseblock to schedule
*
* If a bit-flip in a physical eraseblock is detected, this physical eraseblock
* needs scrubbing. This function schedules a physical eraseblock for
* scrubbing which is done in background. This function returns zero in case of
* success and a negative error code in case of failure.
*/
int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum)

块清洗的执行模块

ubi模块设计中,进行块清洗的子模块为磨损平衡子模块,这是因为对块清洗的动作与磨损平衡执行的动作是一致的,同样是把一个物理块的数据移动到另一个块。
因此,ubi磨损平衡子模块对所有物理块分为:

  • used:正在使用,指经过擦除和写入EC headr和VID header的PEB,后面可以直接写入数据而不需要擦除。
  • erroneous:已经损坏,在磨损平衡中发现读数据失败的PEB,无法恢复,UBI不再主动移动他。等待UBIFS释放之后,擦除时需要进行额外的读写测试,如果通过才放入free列表。
  • free:空闲状态,在放入free列表时对物理块做擦除,然后写入EC headr和VID header。
  • scrub:需要清洗。

以上四种物理块在ubi模块中都是以红黑树的形式存储,红黑树的节点以擦写次数排列,ec较小的在左边,ec相同的PEB编号小的排左边。

块清洗处理逻辑

  1. 取出scrub树最左边节点e1。
  2. 从free树中找一个合适的节点e2(擦除次数较高)
  3. 读取e1的VID header,如果此时读数据失败,则直接返回结束本次处理。如果读数据没问题,则把e1数据拷贝到e2
  4. 擦除e1物理块,并写入EC headr和VID header。然后把e1放入free树中。

方案集成

  • 内核同步社区4.19.y分支代码:
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1078,6 +1078,10 @@ static int spinand_init(struct spinand_device *spinand)

mtd->oobavail = ret;

+       /* Propagate ECC information to mtd_info */
+       mtd->ecc_strength = nand->eccreq.strength;
+       mtd->ecc_step_size = nand->eccreq.step_size;
+
return 0;
  • 系统启动后,配置bitflip_threshold参数

测试验证

加入到开关机老化测试中,持续观察测试过程和结果。

遗留问题以及展望

在看内核代码的过程中,发现社区6.x内核,spi nand驱动在2023年有大量更新,支持了很多spi-nand,有必要做一些同步。

  • 17
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值