power loss results in mounting failure on SLC NAND

Richard Weinberger richard.weinberger at gmail.com
Wed Mar 14 05:53:39 PDT 2018


On Fri, Mar 9, 2018 at 9:12 PM, Richard Weinberger <richard at nod.at> wrote:
> Martin,
>
> Am Freitag, 9. März 2018, 20:39:27 CET schrieb martin bayern:
>> Hi
>>
>> I encountered one issue on my board during power loss immunity testing. It
>> has SLC Nand and Linux 4.2. From my initial analysis, seems the issue is
>> related to fastmap.
>>
>> When disabling fastmap, the corrupted PEB, which was damaged by power-cut
>> when erasing it, can be re-erased during Ubi attaching. So, in the end, I
>> can’t see mounting failure.
>>
>> But, if enable fastmap, I will see mounting failure.
>>
>> I tracked Ubi source code, during attaching, Ubi will scan every PEB, and
>> read EC&Vid pages if both pages are damaged, will erase it later due to
>> uncompleted erase before.  While for the fastmap case, it doesn’t scan each
>> PEB, so, maybe it will miss re-erase corrupted PEB?
>
> So, in this case the upper layer, namely UBIFS, will be unhappy because it
> cannot deal with the ECC error, right?
> I fear fastmap changed the semantics of UBI a bit and UBIFS trips over that.
>
> Does the following patch make UBIFS happy again?
> If so, we need to improve it further, to be more smart and check every mapping
> only once.
>
> diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
> index 250e30fac61b..617742948442 100644
> --- a/drivers/mtd/ubi/eba.c
> +++ b/drivers/mtd/ubi/eba.c
> @@ -490,6 +490,37 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct
> ubi_volume *vol,
>         return err;
>  }
>
> +int fixup_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
> int *pnum)
> +{
> +       int err;
> +       struct ubi_vid_io_buf *vidb;
> +
> +       if (!ubi->fast_attach)
> +               return 0;
> +
> +       vidb = ubi_alloc_vid_buf(ubi, GFP_NOFS);
> +       if (!vidb)
> +               return -ENOMEM;
> +
> +       err = ubi_io_read_vid_hdr(ubi, *pnum, vidb, 0);
> +       if (err > 0 && err != UBI_IO_BITFLIPS) {
> +               int torture = 0;
> +
> +               if (err == UBI_IO_BAD_HDR_EBADMSG || err == UBI_IO_FF_BITFLIPS)
> +                       torture = 1;
> +
> +               down_read(&ubi->fm_eba_sem);
> +               vol->eba_tbl->entries[lnum].pnum = UBI_LEB_UNMAPPED;
> +               up_read(&ubi->fm_eba_sem);
> +               ubi_wl_put_peb(ubi, vol->vol_id, lnum, *pnum, torture);
> +
> +               *pnum = -1;
> +       }
> +
> +       ubi_free_vid_buf(vidb);
> +       return 0;
> +}
> +
>  /**
>   * ubi_eba_read_leb - read data.
>   * @ubi: UBI device description object
> @@ -522,6 +553,13 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct
> ubi_volume *vol, int lnum,
>                 return err;
>
>         pnum = vol->eba_tbl->entries[lnum].pnum;
> +
> +       if (pnum >= 0) {
> +               err = fixup_mapping(ubi, vol, lnum, &pnum);
> +               if (err < 0)
> +                       goto out_unlock;
> +       }
> +
>         if (pnum < 0) {
>                 /*
>                  * The logical eraseblock is not mapped, fill the whole buffer
> @@ -931,6 +969,12 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct
> ubi_volume *vol, int lnum,
>
>         pnum = vol->eba_tbl->entries[lnum].pnum;
>         if (pnum >= 0) {
> +               err = fixup_mapping(ubi, vol, lnum, &pnum);
> +               if (err < 0)
> +                       goto out;
> +       }
> +
> +       if (pnum >= 0) {
>                 dbg_eba("write %d bytes at offset %d of LEB %d:%d, PEB %d",
>                         len, offset, vol_id, lnum, pnum);
>

Did this help?

-- 
Thanks,
//richard



More information about the linux-mtd mailing list