Commit 5d00e317 authored by Zhihao Cheng's avatar Zhihao Cheng Committed by Zheng Zengkai
Browse files

ubi: fastmap: Don't reserve beb_rsvd_pebs while filling fm pool

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 c4d51010 ("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: c4d51010 ("ubi: fastmap: Fix high cpu ... not empty")
Signed-off-by: default avatarZhihao Cheng <chengzhihao1@huawei.com>
Reviewed-by: default avatarJason Yan <yanaijie@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parent cc284ecd
Loading
Loading
Loading
Loading
+10 −4
Original line number Diff line number Diff line
@@ -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);