Commit 5d2c3a14 authored by Zhihao Cheng's avatar Zhihao Cheng Committed by Wang Zhaolong
Browse files

ubi: fastmap: wl: Schedule fm_work if wear-leveling pool is empty

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/?id=c4595fe394a289927077e3da561db27811919ee0



--------------------------------

Since commit 14072ee3 ("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: 14072ee3 ("ubi: fastmap: Check wl_pool for free peb before wear leveling")
Signed-off-by: default avatarZhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
Signed-off-by: default avatarWang Zhaolong <wangzhaolong1@huawei.com>
parent 2c111a42
Loading
Loading
Loading
Loading
+16 −3
Original line number Diff line number Diff line
@@ -346,14 +346,27 @@ int ubi_wl_get_peb(struct ubi_device *ubi)
 * 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];
@@ -375,7 +388,7 @@ static bool need_wear_leveling(struct ubi_device *ubi)
	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;
+1 −1
Original line number Diff line number Diff line
@@ -683,7 +683,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
	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
+2 −1
Original line number Diff line number Diff line
@@ -5,7 +5,8 @@
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)