Skip to content

Commit 761893b

Browse files
Zhihao Chengrichardweinberger
authored andcommitted
ubi: fastmap: Get wl PEB even ec beyonds the 'max' if free PEBs are run out
This is the part 2 to fix cyclically reusing single fastmap data PEBs. Consider one situation, if there are four free PEBs for fm_anchor, pool, wl_pool and fastmap data PEB with erase counter 100, 100, 100, 5096 (ubi->beb_rsvd_pebs is 0). PEB with erase counter 5096 is always picked for fastmap data according to the realization of find_wl_entry(), since fastmap data PEB is not scheduled for wl, finally there are two PEBs (fm data) with great erase counter than other PEBS. Get wl PEB even its erase counter exceeds the 'max' in find_wl_entry() when free PEBs are run out after filling pools and fm data. Then the PEB with biggest erase conter is taken as wl PEB, it can be scheduled for wl. Fixes: dbb7d2a ("UBI: Add fastmap core") Link: https://bugzilla.kernel.org/show_bug.cgi?id=217787 Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com> Signed-off-by: Richard Weinberger <richard@nod.at>
1 parent eada823 commit 761893b

File tree

2 files changed

+44
-16
lines changed

2 files changed

+44
-16
lines changed

drivers/mtd/ubi/fastmap-wl.c

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -138,23 +138,44 @@ static void wait_free_pebs_for_pool(struct ubi_device *ubi)
138138
}
139139

140140
/*
141-
* has_enough_free_count - whether ubi has enough free pebs to fill fm pools
141+
* left_free_count - returns the number of free pebs to fill fm pools
142142
* @ubi: UBI device description object
143143
*
144-
* This helper function checks whether there are enough free pebs (deducted
144+
* This helper function returns the number of free pebs (deducted
145145
* by fastmap pebs) to fill fm_pool and fm_wl_pool.
146146
*/
147-
static bool has_enough_free_count(struct ubi_device *ubi)
147+
static int left_free_count(struct ubi_device *ubi)
148148
{
149149
int fm_used = 0; // fastmap non anchor pebs.
150150

151151
if (!ubi->free.rb_node)
152-
return false;
152+
return 0;
153153

154154
if (!ubi->ro_mode && !ubi->fm_disabled)
155155
fm_used = ubi->fm_size / ubi->leb_size - 1;
156156

157-
return ubi->free_count > fm_used;
157+
return ubi->free_count - fm_used;
158+
}
159+
160+
/*
161+
* can_fill_pools - whether free PEBs will be left after filling pools
162+
* @ubi: UBI device description object
163+
* @free: current number of free PEBs
164+
*
165+
* Return %1 if there are still left free PEBs after filling pools,
166+
* otherwise %0 is returned.
167+
*/
168+
static int can_fill_pools(struct ubi_device *ubi, int free)
169+
{
170+
struct ubi_fm_pool *wl_pool = &ubi->fm_wl_pool;
171+
struct ubi_fm_pool *pool = &ubi->fm_pool;
172+
int pool_need = pool->max_size - pool->size +
173+
wl_pool->max_size - wl_pool->size;
174+
175+
if (free - pool_need < 1)
176+
return 0;
177+
178+
return 1;
158179
}
159180

160181
/**
@@ -199,7 +220,7 @@ void ubi_refill_pools_and_lock(struct ubi_device *ubi)
199220
for (;;) {
200221
enough = 0;
201222
if (pool->size < pool->max_size) {
202-
if (!has_enough_free_count(ubi))
223+
if (left_free_count(ubi) <= 0)
203224
break;
204225

205226
e = wl_get_wle(ubi);
@@ -212,10 +233,13 @@ void ubi_refill_pools_and_lock(struct ubi_device *ubi)
212233
enough++;
213234

214235
if (wl_pool->size < wl_pool->max_size) {
215-
if (!has_enough_free_count(ubi))
236+
int left_free = left_free_count(ubi);
237+
238+
if (left_free <= 0)
216239
break;
217240

218-
e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
241+
e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF,
242+
!can_fill_pools(ubi, left_free));
219243
self_check_in_wl_tree(ubi, e, &ubi->free);
220244
rb_erase(&e->u.rb, &ubi->free);
221245
ubi->free_count--;
@@ -355,12 +379,12 @@ static bool need_wear_leveling(struct ubi_device *ubi)
355379
if (!e) {
356380
if (!ubi->free.rb_node)
357381
return false;
358-
e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
382+
e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF, 0);
359383
ec = e->ec;
360384
} else {
361385
ec = e->ec;
362386
if (ubi->free.rb_node) {
363-
e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
387+
e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF, 0);
364388
ec = max(ec, e->ec);
365389
}
366390
}

drivers/mtd/ubi/wl.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -317,12 +317,14 @@ static void prot_queue_add(struct ubi_device *ubi, struct ubi_wl_entry *e)
317317
* @ubi: UBI device description object
318318
* @root: the RB-tree where to look for
319319
* @diff: maximum possible difference from the smallest erase counter
320+
* @pick_max: pick PEB even its erase counter beyonds 'min_ec + @diff'
320321
*
321322
* This function looks for a wear leveling entry with erase counter closest to
322323
* min + @diff, where min is the smallest erase counter.
323324
*/
324325
static struct ubi_wl_entry *find_wl_entry(struct ubi_device *ubi,
325-
struct rb_root *root, int diff)
326+
struct rb_root *root, int diff,
327+
int pick_max)
326328
{
327329
struct rb_node *p;
328330
struct ubi_wl_entry *e;
@@ -336,9 +338,11 @@ static struct ubi_wl_entry *find_wl_entry(struct ubi_device *ubi,
336338
struct ubi_wl_entry *e1;
337339

338340
e1 = rb_entry(p, struct ubi_wl_entry, u.rb);
339-
if (e1->ec >= max)
341+
if (e1->ec >= max) {
342+
if (pick_max)
343+
e = e1;
340344
p = p->rb_left;
341-
else {
345+
} else {
342346
p = p->rb_right;
343347
e = e1;
344348
}
@@ -375,7 +379,7 @@ static struct ubi_wl_entry *find_mean_wl_entry(struct ubi_device *ubi,
375379
*/
376380
e = may_reserve_for_fm(ubi, e, root);
377381
} else
378-
e = find_wl_entry(ubi, root, WL_FREE_MAX_DIFF/2);
382+
e = find_wl_entry(ubi, root, WL_FREE_MAX_DIFF/2, 0);
379383

380384
return e;
381385
}
@@ -1048,7 +1052,7 @@ static int ensure_wear_leveling(struct ubi_device *ubi, int nested)
10481052
* %UBI_WL_THRESHOLD.
10491053
*/
10501054
e1 = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, u.rb);
1051-
e2 = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
1055+
e2 = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF, 0);
10521056

10531057
if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD))
10541058
goto out_unlock;
@@ -2079,7 +2083,7 @@ static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi)
20792083
{
20802084
struct ubi_wl_entry *e;
20812085

2082-
e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
2086+
e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF, 0);
20832087
self_check_in_wl_tree(ubi, e, &ubi->free);
20842088
ubi->free_count--;
20852089
ubi_assert(ubi->free_count >= 0);

0 commit comments

Comments
 (0)