aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/ubi/wl.c
diff options
context:
space:
mode:
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2010-09-03 16:08:15 -0400
committerArtem Bityutskiy <Artem.Bityutskiy@nokia.com>2010-10-19 10:19:57 -0400
commit5fc01ab6934c43b42c41bc753fe1123c16d7f38f (patch)
tree174a1e1a0d283ec8ca4c756d7f354a475ac46a36 /drivers/mtd/ubi/wl.c
parentfeeba4b872e5166ca64c44fbb5bbec234dfce199 (diff)
UBI: preserve corrupted PEBs
Currently UBI erases all corrupted eraseblocks, irrespectively of the nature of corruption: corruption due to power cuts and non-power cut corruption. The former case is OK, but the latter is not, because UBI may destroy potentially important data. With this patch, during scanning, when UBI hits a PEB with corrupted VID header, it checks whether this PEB contains only 0xFF data. If yes, it is safe to erase this PEB and it is put to the 'erase' list. If not, this may be important data and it is better to avoid erasing this PEB. Instead, UBI puts it to the corr list and moves out of the pool of available PEB. IOW, UBI preserves this PEB. Such corrupted PEB lessen the amount of available PEBs. So the more of them we accumulate, the less PEBs are available. The maximum amount of non-power cut corrupted PEBs is 8. This patch is a response to UBIFS problem where reporter (Matthew L. Creech <mlcreech@gmail.com>) observes that UBIFS index points to an unmapped LEB. The theory is that corresponding PEB somehow got corrupted and UBI wiped it. This patch (actually a series of patches) tries to make sure such PEBs are preserved - this would make it is easier to analyze the corruption. Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd/ubi/wl.c')
-rw-r--r--drivers/mtd/ubi/wl.c19
1 files changed, 3 insertions, 16 deletions
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 605ecb1e22bb..655bbbe415d9 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1478,22 +1478,6 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
1478 ubi->lookuptbl[e->pnum] = e; 1478 ubi->lookuptbl[e->pnum] = e;
1479 } 1479 }
1480 1480
1481 list_for_each_entry(seb, &si->corr, u.list) {
1482 cond_resched();
1483
1484 e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
1485 if (!e)
1486 goto out_free;
1487
1488 e->pnum = seb->pnum;
1489 e->ec = seb->ec;
1490 ubi->lookuptbl[e->pnum] = e;
1491 if (schedule_erase(ubi, e, 0)) {
1492 kmem_cache_free(ubi_wl_entry_slab, e);
1493 goto out_free;
1494 }
1495 }
1496
1497 ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { 1481 ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
1498 ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { 1482 ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
1499 cond_resched(); 1483 cond_resched();
@@ -1520,6 +1504,9 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
1520 if (ubi->avail_pebs < WL_RESERVED_PEBS) { 1504 if (ubi->avail_pebs < WL_RESERVED_PEBS) {
1521 ubi_err("no enough physical eraseblocks (%d, need %d)", 1505 ubi_err("no enough physical eraseblocks (%d, need %d)",
1522 ubi->avail_pebs, WL_RESERVED_PEBS); 1506 ubi->avail_pebs, WL_RESERVED_PEBS);
1507 if (ubi->corr_peb_count)
1508 ubi_err("%d PEBs are corrupted and not used",
1509 ubi->corr_peb_count);
1523 goto out_free; 1510 goto out_free;
1524 } 1511 }
1525 ubi->avail_pebs -= WL_RESERVED_PEBS; 1512 ubi->avail_pebs -= WL_RESERVED_PEBS;