diff options
Diffstat (limited to 'drivers/mtd/ubi/wl.c')
-rw-r--r-- | drivers/mtd/ubi/wl.c | 28 |
1 files changed, 19 insertions, 9 deletions
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 5146cce5fe32..27636063ed1b 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -687,20 +687,27 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, } #ifdef CONFIG_MTD_UBI_FASTMAP + e1 = find_anchor_wl_entry(&ubi->used); + if (e1 && ubi->fm_next_anchor && + (ubi->fm_next_anchor->ec - e1->ec >= UBI_WL_THRESHOLD)) { + ubi->fm_do_produce_anchor = 1; + /* fm_next_anchor is no longer considered a good anchor + * candidate. + * NULL assignment also prevents multiple wear level checks + * of this PEB. + */ + wl_tree_add(ubi->fm_next_anchor, &ubi->free); + ubi->fm_next_anchor = NULL; + ubi->free_count++; + } + if (ubi->fm_do_produce_anchor) { - e1 = find_anchor_wl_entry(&ubi->used); if (!e1) goto out_cancel; e2 = get_peb_for_wl(ubi); if (!e2) goto out_cancel; - /* - * Anchor move within the anchor area is useless. - */ - if (e2->pnum < UBI_FM_MAX_START) - goto out_cancel; - self_check_in_wl_tree(ubi, e1, &ubi->used); rb_erase(&e1->u.rb, &ubi->used); dbg_wl("anchor-move PEB %d to PEB %d", e1->pnum, e2->pnum); @@ -1079,8 +1086,11 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk) if (!err) { spin_lock(&ubi->wl_lock); - if (!ubi->fm_anchor && e->pnum < UBI_FM_MAX_START) { - ubi->fm_anchor = e; + if (!ubi->fm_next_anchor && e->pnum < UBI_FM_MAX_START) { + /* Abort anchor production, if needed it will be + * enabled again in the wear leveling started below. + */ + ubi->fm_next_anchor = e; ubi->fm_do_produce_anchor = 0; } else { wl_tree_add(e, &ubi->free); |