
From: Zhihao Cheng <chengzhihao1@huawei.com> mainline inclusion from mainline-v6.13-rc1 commit c4595fe394a289927077e3da561db27811919ee0 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IBS8G5 CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- Since commit 14072ee33d5a ("ubi: fastmap: Check wl_pool for free peb before wear leveling"), wear_leveling_worker() won't schedule fm_work if wear-leveling pool is empty, which could temporarily disable the wear-leveling until the fastmap is updated(eg. pool becomes empty). Fix it by scheduling fm_work if wl_pool is empty during wear-leveing. Fixes: 14072ee33d5a ("ubi: fastmap: Check wl_pool for free peb before wear leveling") Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com> Signed-off-by: Richard Weinberger <richard@nod.at> Signed-off-by: Wang Zhaolong <wangzhaolong1@huawei.com> --- drivers/mtd/ubi/fastmap-wl.c | 19 ++++++++++++++++--- drivers/mtd/ubi/wl.c | 2 +- drivers/mtd/ubi/wl.h | 3 ++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c index 2a9cc9413c42..9bdb6525f128 100644 --- a/drivers/mtd/ubi/fastmap-wl.c +++ b/drivers/mtd/ubi/fastmap-wl.c @@ -344,18 +344,31 @@ int ubi_wl_get_peb(struct ubi_device *ubi) /** * next_peb_for_wl - returns next PEB to be used internally by the * WL sub-system. * * @ubi: UBI device description object + * @need_fill: whether to fill wear-leveling pool when no PEBs are found */ -static struct ubi_wl_entry *next_peb_for_wl(struct ubi_device *ubi) +static struct ubi_wl_entry *next_peb_for_wl(struct ubi_device *ubi, + bool need_fill) { struct ubi_fm_pool *pool = &ubi->fm_wl_pool; int pnum; - if (pool->used == pool->size) + if (pool->used == pool->size) { + if (need_fill && !ubi->fm_work_scheduled) { + /* + * We cannot update the fastmap here because this + * function is called in atomic context. + * Let's fail here and refill/update it as soon as + * possible. + */ + ubi->fm_work_scheduled = 1; + schedule_work(&ubi->fm_work); + } return NULL; + } pnum = pool->pebs[pool->used]; return ubi->lookuptbl[pnum]; } @@ -373,11 +386,11 @@ static bool need_wear_leveling(struct ubi_device *ubi) struct ubi_wl_entry *e; if (!ubi->used.rb_node) return false; - e = next_peb_for_wl(ubi); + e = next_peb_for_wl(ubi, false); if (!e) { if (!ubi->free.rb_node) return false; e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF, 0); ec = e->ec; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index b60eea10f68f..97b86fab1466 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -681,11 +681,11 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, spin_lock(&ubi->wl_lock); ubi_assert(!ubi->move_from && !ubi->move_to); ubi_assert(!ubi->move_to_put); #ifdef CONFIG_MTD_UBI_FASTMAP - if (!next_peb_for_wl(ubi) || + if (!next_peb_for_wl(ubi, true) || #else if (!ubi->free.rb_node || #endif (!ubi->used.rb_node && !ubi->scrub.rb_node)) { /* diff --git a/drivers/mtd/ubi/wl.h b/drivers/mtd/ubi/wl.h index 7b6715ef6d4a..a69169c35e31 100644 --- a/drivers/mtd/ubi/wl.h +++ b/drivers/mtd/ubi/wl.h @@ -3,11 +3,12 @@ #define UBI_WL_H #ifdef CONFIG_MTD_UBI_FASTMAP static void update_fastmap_work_fn(struct work_struct *wrk); static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root); static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi); -static struct ubi_wl_entry *next_peb_for_wl(struct ubi_device *ubi); +static struct ubi_wl_entry *next_peb_for_wl(struct ubi_device *ubi, + bool need_fill); static bool need_wear_leveling(struct ubi_device *ubi); static void ubi_fastmap_close(struct ubi_device *ubi); static inline void ubi_fastmap_init(struct ubi_device *ubi, int *count) { if (ubi->fm_disabled) -- 2.34.3