From: Zhihao Cheng chengzhihao1@huawei.com
hulk inclusion category: bugfix bugzilla: 186690, https://gitee.com/openeuler/kernel/issues/I56U8P
--------------------------------
Following script will cause a ENOSPC error while creating ubi volume: ID="0x20,0xa5,0x00,0x16" # 2G-size 128KB-PEB modprobe nandsim id_bytes=$ID modprobe ubi ubiattach -m0 ubimkvol /dev/ubi0 -N test -s 400MiB # ENOSPC returned
Commit c4d51010ef6c32 ("ubi: fastmap: Fix high cpu usage of ubi_bgt by making sure wl_pool not empty") fills free PEBs into fm pool after reserving 'beb_rsvd_pebs', which will cause that there maybe no enough free PEBs filled into fm pool (Especially when the UBI device has just been initialized). Then, ubimkvol could get ENOSPC after ubi attached. Fix it by filling fm pool without reserving 'beb_rsvd_pebs'.
Fixes: c4d51010ef6c32 ("ubi: fastmap: Fix high cpu ... not empty") Signed-off-by: Zhihao Cheng chengzhihao1@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/mtd/ubi/fastmap-wl.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c index 21ea5ca8270b..053ab52668e8 100644 --- a/drivers/mtd/ubi/fastmap-wl.c +++ b/drivers/mtd/ubi/fastmap-wl.c @@ -100,22 +100,28 @@ struct ubi_wl_entry *ubi_wl_get_fm_peb(struct ubi_device *ubi, int anchor) /* * has_enough_free_count - whether ubi has enough free pebs to fill fm pools * @ubi: UBI device description object + * @is_wl_pool: whether UBI is filling wear leveling pool * * This helper function checks whether there are enough free pebs (deducted * by fastmap pebs) to fill fm_pool and fm_wl_pool, above rule works after * there is at least one of free pebs is filled into fm_wl_pool. + * For wear leveling pool, UBI should also reserve free pebs for bad pebs + * handling, because there maybe no enough free pebs for user volumes after + * producing new bad pebs. */ -static bool has_enough_free_count(struct ubi_device *ubi) +static bool has_enough_free_count(struct ubi_device *ubi, bool is_wl_pool) { int fm_used = 0; // fastmap non anchor pebs. + int beb_rsvd_pebs;
if (!ubi->free.rb_node) return false;
+ beb_rsvd_pebs = is_wl_pool ? ubi->beb_rsvd_pebs : 0; if (ubi->fm_wl_pool.size > 0 && !(ubi->ro_mode || ubi->fm_disabled)) fm_used = ubi->fm_size / ubi->leb_size - 1;
- return ubi->free_count - ubi->beb_rsvd_pebs > fm_used; + return ubi->free_count - beb_rsvd_pebs > fm_used; }
/** @@ -151,7 +157,7 @@ void ubi_refill_pools(struct ubi_device *ubi) for (;;) { enough = 0; if (pool->size < pool->max_size) { - if (!has_enough_free_count(ubi)) + if (!has_enough_free_count(ubi, false)) break;
e = wl_get_wle(ubi); @@ -164,7 +170,7 @@ void ubi_refill_pools(struct ubi_device *ubi) enough++;
if (wl_pool->size < wl_pool->max_size) { - if (!has_enough_free_count(ubi)) + if (!has_enough_free_count(ubi, true)) break;
e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);