[PATCH v2] mtd: nand: write bad block marker even with BBT

Brian Norris computersforpeace at gmail.com
Mon Dec 19 17:03:51 EST 2011


Currently, the flash-based BBT implementation writes bad block data only
to its flash-based table and not to the OOB marker area. Then, as new
bad blocks are marked over time, the OOB markers become out of date and
the flash-based table becomes the only source of current bad block
information. This can be a problem when:

 * bootloader cannot read the flash-based BBT format
 * BBT is corrupted and the flash must be rescanned for bad
   blocks; we want to remember bad blocks that were marked from Linux

In an attempt to keep the bad block markers in sync with the flash-based
BBT, this patch changes the default so that we write bad block markers
to the proper OOB area on each block in addition to flash-based BBT.

Theoretically, the bad block table and the OOB markers can still get out
of sync if the system experiences a power cut between writing the BBT to
flash and writing the OOB marker to a newly-marked bad block. However,
this is a relatively unlikely event, as new bad blocks shouldn't appear
frequently.

Note that this is a change from the previous default flash-based BBT
behavior. If any contributors rely on the old behavior, they are welcome
to introduce an option flag for it.

Adapted from code by Matthieu Castet.

Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
v2: Explain potential power cut issues and remove option for retaining
    old behavior. I CC'd various MTD contributors; speak up if the new
    default is unacceptable!

drivers/mtd/nand/nand_base.c |   59 +++++++++++++++++++++++------------------
 1 files changed, 33 insertions(+), 26 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 35b4565..dfa017e 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -393,6 +393,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 	struct nand_chip *chip = mtd->priv;
 	uint8_t buf[2] = { 0, 0 };
 	int block, ret, i = 0;
+	struct mtd_oob_ops ops;
 
 	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
 		ofs += mtd->erasesize - mtd->writesize;
@@ -403,34 +404,40 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
 		chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
 
 	/* Do we have a flash based bad block table? */
-	if (chip->bbt_options & NAND_BBT_USE_FLASH)
+	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
 		ret = nand_update_bbt(mtd, ofs);
-	else {
-		struct mtd_oob_ops ops;
+		if (ret)
+			return ret;
+	}
 
-		nand_get_device(chip, mtd, FL_WRITING);
+	/*
+	 * Write bad block marker to OOB
+	 * Note that a flash-based BBT (when used) can become out of sync with
+	 * OOB markers if a power cut occurs here. See:
+	 *   http://lists.infradead.org/pipermail/linux-mtd/2011-December/038851.html
+	 */
 
-		/*
-		 * Write to first two pages if necessary. If we write to more
-		 * than one location, the first error encountered quits the
-		 * procedure. We write two bytes per location, so we dont have
-		 * to mess with 16 bit access.
-		 */
-		ops.len = ops.ooblen = 2;
-		ops.datbuf = NULL;
-		ops.oobbuf = buf;
-		ops.ooboffs = chip->badblockpos & ~0x01;
-		ops.mode = MTD_OPS_PLACE_OOB;
-		do {
-			ret = nand_do_write_oob(mtd, ofs, &ops);
-
-			i++;
-			ofs += mtd->writesize;
-		} while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) &&
-				i < 2);
+	nand_get_device(chip, mtd, FL_WRITING);
+
+	/*
+	 * Write to first two pages if necessary. If we write to more than one
+	 * location, the first error encountered quits the procedure. We write
+	 * two bytes per location, so we dont have to mess with 16 bit access.
+	 */
+	ops.len = ops.ooblen = 2;
+	ops.datbuf = NULL;
+	ops.oobbuf = buf;
+	ops.ooboffs = chip->badblockpos & ~0x01;
+	ops.mode = MTD_OPS_PLACE_OOB;
+	do {
+		ret = nand_do_write_oob(mtd, ofs, &ops);
+
+		i++;
+		ofs += mtd->writesize;
+	} while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
+
+	nand_release_device(mtd);
 
-		nand_release_device(mtd);
-	}
 	if (!ret)
 		mtd->ecc_stats.badblocks++;
 
-- 
1.7.5.4




More information about the linux-mtd mailing list