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