Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

UBI: avoid program operation on NOR flash after erasure interrupted

nor_erase_prepare() will be called before erase a NOR flash, it will program '0'
into a block to mark this block. But program data into a erasure interrupted block
can cause program timtout(several minutes at most) error, could impact other
operation on NOR flash. So UBIFS can read this block first to avoid unneeded
program operation.

This patch try to put read operation at head of write operation in
nor_erase_prepare(), read out the data.
If the data is already corrupt, then no need to program any data into this block,
just go to erase this block.

This patch is validated on Micron NOR flash, part number is:JS28F512M29EWHA

Signed-off-by: Qi Wang <qiwang@micron.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>

authored by

Qi Wang 王起 (qiwang) and committed by
Artem Bityutskiy
2c7ca5cc b6b44e0a

+23 -33
+23 -33
drivers/mtd/ubi/io.c
··· 495 495 */ 496 496 static int nor_erase_prepare(struct ubi_device *ubi, int pnum) 497 497 { 498 - int err, err1; 498 + int err; 499 499 size_t written; 500 500 loff_t addr; 501 501 uint32_t data = 0; 502 + struct ubi_ec_hdr ec_hdr; 503 + 502 504 /* 503 505 * Note, we cannot generally define VID header buffers on stack, 504 506 * because of the way we deal with these buffers (see the header ··· 511 509 struct ubi_vid_hdr vid_hdr; 512 510 513 511 /* 512 + * If VID or EC is valid, we have to corrupt them before erasing. 514 513 * It is important to first invalidate the EC header, and then the VID 515 514 * header. Otherwise a power cut may lead to valid EC header and 516 515 * invalid VID header, in which case UBI will treat this PEB as 517 516 * corrupted and will try to preserve it, and print scary warnings. 518 517 */ 519 518 addr = (loff_t)pnum * ubi->peb_size; 520 - err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data); 521 - if (!err) { 519 + err = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0); 520 + if (err != UBI_IO_BAD_HDR_EBADMSG && err != UBI_IO_BAD_HDR && 521 + err != UBI_IO_FF){ 522 + err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data); 523 + if(err) 524 + goto error; 525 + } 526 + 527 + err = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0); 528 + if (err != UBI_IO_BAD_HDR_EBADMSG && err != UBI_IO_BAD_HDR && 529 + err != UBI_IO_FF){ 522 530 addr += ubi->vid_hdr_aloffset; 523 531 err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data); 524 - if (!err) 525 - return 0; 532 + if (err) 533 + goto error; 526 534 } 535 + return 0; 527 536 537 + error: 528 538 /* 529 - * We failed to write to the media. This was observed with Spansion 530 - * S29GL512N NOR flash. Most probably the previously eraseblock erasure 531 - * was interrupted at a very inappropriate moment, so it became 532 - * unwritable. In this case we probably anyway have garbage in this 533 - * PEB. 539 + * The PEB contains a valid VID or EC header, but we cannot invalidate 540 + * it. Supposedly the flash media or the driver is screwed up, so 541 + * return an error. 534 542 */ 535 - err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0); 536 - if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR || 537 - err1 == UBI_IO_FF) { 538 - struct ubi_ec_hdr ec_hdr; 539 - 540 - err1 = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0); 541 - if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR || 542 - err1 == UBI_IO_FF) 543 - /* 544 - * Both VID and EC headers are corrupted, so we can 545 - * safely erase this PEB and not afraid that it will be 546 - * treated as a valid PEB in case of an unclean reboot. 547 - */ 548 - return 0; 549 - } 550 - 551 - /* 552 - * The PEB contains a valid VID header, but we cannot invalidate it. 553 - * Supposedly the flash media or the driver is screwed up, so return an 554 - * error. 555 - */ 556 - ubi_err("cannot invalidate PEB %d, write returned %d read returned %d", 557 - pnum, err, err1); 543 + ubi_err("cannot invalidate PEB %d, write returned %d", pnum, err); 558 544 ubi_dump_flash(ubi, pnum, 0, ubi->peb_size); 559 545 return -EIO; 560 546 }