power loss results in mounting failure on SLC NAND

Richard Weinberger richard at nod.at
Fri Mar 9 12:12:26 PST 2018


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);

Thanks,
//richard



More information about the linux-mtd mailing list