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

UBI: fix corrupted PEB detection for NOR flash

My new shiny code for corrupted PEB detection has NOR specific bug.
We tread PEB as corrupted and preserve it, if

1. EC header is OK.
2. VID header is corrupted.
3. data area is not "all 0xFFs"

In case of NOR we have 'nor_erase_prepare()' quirk, which invalidates
the headers before erasing the PEB. And we invalidate first the VID
header, and then the EC header. So if a power cut happens after we have
invalidated the VID header, but before we have invalidated the EC
header, we end up with a PEB which satisfies the above 3 conditions,
and the scanning code will treat it as corrupted, and will print
scary warnings, wrongly.

This patch fixes the issue by firt invalidating the EC header, then
invalidating the VID header. In case of power cut inbetween, we still
just lose the EC header, and UBI can deal with this situation gracefully.

Thanks to Anatolij Gustschin <agust@denx.de> for tracking this down.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Reported-by: Anatolij Gustschin <agust@denx.de>
Tested-by: Anatolij Gustschin <agust@denx.de>

+29 -12
+25 -12
drivers/mtd/ubi/io.c
··· 482 482 uint32_t data = 0; 483 483 struct ubi_vid_hdr vid_hdr; 484 484 485 - addr = (loff_t)pnum * ubi->peb_size + ubi->vid_hdr_aloffset; 485 + /* 486 + * It is important to first invalidate the EC header, and then the VID 487 + * header. Otherwise a power cut may lead to valid EC header and 488 + * invalid VID header, in which case UBI will treat this PEB as 489 + * corrupted and will try to preserve it, and print scary warnings (see 490 + * the header comment in scan.c for more information). 491 + */ 492 + addr = (loff_t)pnum * ubi->peb_size; 486 493 err = ubi->mtd->write(ubi->mtd, addr, 4, &written, (void *)&data); 487 494 if (!err) { 488 - addr -= ubi->vid_hdr_aloffset; 495 + addr += ubi->vid_hdr_aloffset; 489 496 err = ubi->mtd->write(ubi->mtd, addr, 4, &written, 490 497 (void *)&data); 491 498 if (!err) ··· 501 494 502 495 /* 503 496 * We failed to write to the media. This was observed with Spansion 504 - * S29GL512N NOR flash. Most probably the eraseblock erasure was 505 - * interrupted at a very inappropriate moment, so it became unwritable. 506 - * In this case we probably anyway have garbage in this PEB. 497 + * S29GL512N NOR flash. Most probably the previously eraseblock erasure 498 + * was interrupted at a very inappropriate moment, so it became 499 + * unwritable. In this case we probably anyway have garbage in this 500 + * PEB. 507 501 */ 508 502 err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0); 509 - if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR) 510 - /* 511 - * The VID header is corrupted, so we can safely erase this 512 - * PEB and not afraid that it will be treated as a valid PEB in 513 - * case of an unclean reboot. 514 - */ 515 - return 0; 503 + if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR) { 504 + struct ubi_ec_hdr ec_hdr; 505 + 506 + err1 = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0); 507 + if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR) 508 + /* 509 + * Both VID and EC headers are corrupted, so we can 510 + * safely erase this PEB and not afraid that it will be 511 + * treated as a valid PEB in case of an unclean reboot. 512 + */ 513 + return 0; 514 + } 516 515 517 516 /* 518 517 * The PEB contains a valid VID header, but we cannot invalidate it.
+4
drivers/mtd/ubi/scan.c
··· 953 953 * impossible to distinguish it from a PEB which just 954 954 * contains garbage because of a power cut during erase 955 955 * operation. So we just schedule this PEB for erasure. 956 + * 957 + * Besides, in case of NOR flash, we deliberatly 958 + * corrupt both headers because NOR flash erasure is 959 + * slow and can start from the end. 956 960 */ 957 961 err = 0; 958 962 else