diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c index 5412974..d6fe43b 100644 --- a/drivers/mtd/ubi/attach.c +++ b/drivers/mtd/ubi/attach.c @@ -1429,8 +1429,10 @@ struct ubi_attach_info *scan_ai; scan_ai = alloc_ai("ubi_ckh_aeb_slab_cache"); - if (!scan_ai) + if (!scan_ai) { + err = -ENOMEM; goto out_wl; + } err = scan_all(ubi, scan_ai, 0); if (err) { diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index de68c32..8f29430 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -127,7 +127,7 @@ if (vol_id > av->vol_id) p = &(*p)->rb_left; - else if (vol_id > av->vol_id) + else p = &(*p)->rb_right; } @@ -422,7 +422,7 @@ pnum, err); ret = err > 0 ? UBI_BAD_FASTMAP : err; goto out; - } else if (ret == UBI_IO_BITFLIPS) + } else if (err == UBI_IO_BITFLIPS) scrub = 1; /* @@ -462,8 +462,8 @@ } } if (found_orphan) { - kfree(tmp_aeb); list_del(&tmp_aeb->u.list); + kfree(tmp_aeb); } new_aeb = kzalloc(sizeof(*new_aeb), GFP_KERNEL); @@ -835,16 +835,16 @@ ret = UBI_BAD_FASTMAP; fail: list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &used, u.list) { - free(tmp_aeb); list_del(&tmp_aeb->u.list); + free(tmp_aeb); } list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &eba_orphans, u.list) { - free(tmp_aeb); list_del(&tmp_aeb->u.list); + free(tmp_aeb); } list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &lfree, u.list) { - free(tmp_aeb); list_del(&tmp_aeb->u.list); + free(tmp_aeb); } return ret; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index f9f9738..e55dfc5 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -473,10 +473,12 @@ */ static int nor_erase_prepare(struct ubi_device *ubi, int pnum) { - int err, err1; + int err; size_t written; loff_t addr; uint32_t data = 0; + struct ubi_ec_hdr ec_hdr; + /* * Note, we cannot generally define VID header buffers on stack, * because of the way we deal with these buffers (see the header @@ -487,50 +489,38 @@ struct ubi_vid_hdr vid_hdr; /* + * If VID or EC is valid, we have to corrupt them before erasing. * It is important to first invalidate the EC header, and then the VID * header. Otherwise a power cut may lead to valid EC header and * invalid VID header, in which case UBI will treat this PEB as * corrupted and will try to preserve it, and print scary warnings. */ addr = (loff_t)pnum * ubi->peb_size; - err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data); - if (!err) { + err = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0); + if (err != UBI_IO_BAD_HDR_EBADMSG && err != UBI_IO_BAD_HDR && + err != UBI_IO_FF){ + err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data); + if(err) + goto error; + } + + err = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0); + if (err != UBI_IO_BAD_HDR_EBADMSG && err != UBI_IO_BAD_HDR && + err != UBI_IO_FF){ addr += ubi->vid_hdr_aloffset; err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data); - if (!err) - return 0; + if (err) + goto error; } + return 0; +error: /* - * We failed to write to the media. This was observed with Spansion - * S29GL512N NOR flash. Most probably the previously eraseblock erasure - * was interrupted at a very inappropriate moment, so it became - * unwritable. In this case we probably anyway have garbage in this - * PEB. + * The PEB contains a valid VID or EC header, but we cannot invalidate + * it. Supposedly the flash media or the driver is screwed up, so + * return an error. */ - err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0); - if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR || - err1 == UBI_IO_FF) { - struct ubi_ec_hdr ec_hdr; - - err1 = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0); - if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR || - err1 == UBI_IO_FF) - /* - * Both VID and EC headers are corrupted, so we can - * safely erase this PEB and not afraid that it will be - * treated as a valid PEB in case of an unclean reboot. - */ - return 0; - } - - /* - * The PEB contains a valid VID header, but we cannot invalidate it. - * Supposedly the flash media or the driver is screwed up, so return an - * error. - */ - ubi_err("cannot invalidate PEB %d, write returned %d read returned %d", - pnum, err, err1); + ubi_err("cannot invalidate PEB %d, write returned %d", pnum, err); ubi_dump_flash(ubi, pnum, 0, ubi->peb_size); return -EIO; } diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 48b2915..c15809a 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -580,7 +580,7 @@ /* Static volumes only */ av = ubi_find_av(ai, i); - if (!av) { + if (!av || !av->leb_count) { /* * No eraseblocks belonging to this volume found. We * don't actually know whether this static volume is diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index c083cac..4c20e90 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -635,6 +635,8 @@ e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF); self_check_in_wl_tree(ubi, e, &ubi->free); + ubi->free_count--; + ubi_assert(ubi->free_count >= 0); rb_erase(&e->u.rb, &ubi->free); return e; @@ -646,6 +648,9 @@ peb = __wl_get_peb(ubi); + if (peb < 0) + return peb; + err = ubi_self_check_all_ff(ubi, peb, ubi->vid_hdr_aloffset, ubi->peb_size - ubi->vid_hdr_aloffset); if (err) { @@ -1015,6 +1020,7 @@ /* Give the unused PEB back */ wl_tree_add(e2, &ubi->free); + ubi->free_count++; goto out_cancel; } self_check_in_wl_tree(ubi, e1, &ubi->used); @@ -1611,10 +1617,10 @@ vol_id, lnum, ubi->works_count); while (found) { - struct ubi_work *wrk; + struct ubi_work *wrk, *tmp; found = 0; - list_for_each_entry(wrk, &ubi->works, list) { + list_for_each_entry_safe(wrk, tmp, &ubi->works, list) { if ((vol_id == UBI_ALL || wrk->vol_id == vol_id) && (lnum == UBI_ALL || wrk->lnum == lnum)) { list_del(&wrk->list);