Merge tag 'for-linus-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw...
[sfrench/cifs-2.6.git] / drivers / mtd / ubi / wl.c
index 5146cce5fe32115d46c3e4735777b22df991489a..27636063ed1bb1358ac4daf84713d1ac92c99719 100644 (file)
@@ -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);