summaryrefslogtreecommitdiff
path: root/drivers/mtd/ubi/fastmap-wl.c
diff options
context:
space:
mode:
authorZhihao Cheng <chengzhihao1@huawei.com>2022-05-10 20:31:25 +0800
committerRichard Weinberger <richard@nod.at>2022-05-27 16:49:07 +0200
commit14072ee33d5a2a07d735b667205f99d0a95de9f2 (patch)
tree029651d653978cf6f28c767f4f43a2b4a29b25f6 /drivers/mtd/ubi/fastmap-wl.c
parentd09e9a2bddba6c48e0fddb16c4383172ac593251 (diff)
downloadlinux-14072ee33d5a2a07d735b667205f99d0a95de9f2.tar.gz
ubi: fastmap: Check wl_pool for free peb before wear leveling
UBI fetches free peb from wl_pool during wear leveling, so UBI should check wl_pool's empty status before wear leveling. Otherwise, UBI will miss wear leveling chances when free pebs are run out. Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com> Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'drivers/mtd/ubi/fastmap-wl.c')
-rw-r--r--drivers/mtd/ubi/fastmap-wl.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c
index 053ab52668e8..0ee452275578 100644
--- a/drivers/mtd/ubi/fastmap-wl.c
+++ b/drivers/mtd/ubi/fastmap-wl.c
@@ -275,6 +275,58 @@ out:
return ret;
}
+/**
+ * next_peb_for_wl - returns next PEB to be used internally by the
+ * WL sub-system.
+ *
+ * @ubi: UBI device description object
+ */
+static struct ubi_wl_entry *next_peb_for_wl(struct ubi_device *ubi)
+{
+ struct ubi_fm_pool *pool = &ubi->fm_wl_pool;
+ int pnum;
+
+ if (pool->used == pool->size)
+ return NULL;
+
+ pnum = pool->pebs[pool->used];
+ return ubi->lookuptbl[pnum];
+}
+
+/**
+ * need_wear_leveling - checks whether to trigger a wear leveling work.
+ * UBI fetches free PEB from wl_pool, we check free PEBs from both 'wl_pool'
+ * and 'ubi->free', because free PEB in 'ubi->free' tree maybe moved into
+ * 'wl_pool' by ubi_refill_pools().
+ *
+ * @ubi: UBI device description object
+ */
+static bool need_wear_leveling(struct ubi_device *ubi)
+{
+ int ec;
+ struct ubi_wl_entry *e;
+
+ if (!ubi->used.rb_node)
+ return false;
+
+ e = next_peb_for_wl(ubi);
+ if (!e) {
+ if (!ubi->free.rb_node)
+ return false;
+ e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
+ ec = e->ec;
+ } else {
+ ec = e->ec;
+ if (ubi->free.rb_node) {
+ e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
+ ec = max(ec, e->ec);
+ }
+ }
+ e = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, u.rb);
+
+ return ec - e->ec >= UBI_WL_THRESHOLD;
+}
+
/* get_peb_for_wl - returns a PEB to be used internally by the WL sub-system.
*
* @ubi: UBI device description object