Skip to content

Commit 14072ee

Browse files
Zhihao Chengrichardweinberger
authored andcommitted
ubi: fastmap: Check wl_pool for free peb before wear leveling
UBI fetches free peb from wl_pool during wear leveling, so UBI should check wl_pool's empty status before wear leveling. Otherwise, UBI will miss wear leveling chances when free pebs are run out. Signed-off-by: Zhihao Cheng <[email protected]> Signed-off-by: Richard Weinberger <[email protected]>
1 parent d09e9a2 commit 14072ee

File tree

3 files changed

+66
-2
lines changed

3 files changed

+66
-2
lines changed

drivers/mtd/ubi/fastmap-wl.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,58 @@ int ubi_wl_get_peb(struct ubi_device *ubi)
275275
return ret;
276276
}
277277

278+
/**
279+
* next_peb_for_wl - returns next PEB to be used internally by the
280+
* WL sub-system.
281+
*
282+
* @ubi: UBI device description object
283+
*/
284+
static struct ubi_wl_entry *next_peb_for_wl(struct ubi_device *ubi)
285+
{
286+
struct ubi_fm_pool *pool = &ubi->fm_wl_pool;
287+
int pnum;
288+
289+
if (pool->used == pool->size)
290+
return NULL;
291+
292+
pnum = pool->pebs[pool->used];
293+
return ubi->lookuptbl[pnum];
294+
}
295+
296+
/**
297+
* need_wear_leveling - checks whether to trigger a wear leveling work.
298+
* UBI fetches free PEB from wl_pool, we check free PEBs from both 'wl_pool'
299+
* and 'ubi->free', because free PEB in 'ubi->free' tree maybe moved into
300+
* 'wl_pool' by ubi_refill_pools().
301+
*
302+
* @ubi: UBI device description object
303+
*/
304+
static bool need_wear_leveling(struct ubi_device *ubi)
305+
{
306+
int ec;
307+
struct ubi_wl_entry *e;
308+
309+
if (!ubi->used.rb_node)
310+
return false;
311+
312+
e = next_peb_for_wl(ubi);
313+
if (!e) {
314+
if (!ubi->free.rb_node)
315+
return false;
316+
e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
317+
ec = e->ec;
318+
} else {
319+
ec = e->ec;
320+
if (ubi->free.rb_node) {
321+
e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
322+
ec = max(ec, e->ec);
323+
}
324+
}
325+
e = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, u.rb);
326+
327+
return ec - e->ec >= UBI_WL_THRESHOLD;
328+
}
329+
278330
/* get_peb_for_wl - returns a PEB to be used internally by the WL sub-system.
279331
*
280332
* @ubi: UBI device description object

drivers/mtd/ubi/wl.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,11 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
670670
ubi_assert(!ubi->move_from && !ubi->move_to);
671671
ubi_assert(!ubi->move_to_put);
672672

673+
#ifdef CONFIG_MTD_UBI_FASTMAP
674+
if (!next_peb_for_wl(ubi) ||
675+
#else
673676
if (!ubi->free.rb_node ||
677+
#endif
674678
(!ubi->used.rb_node && !ubi->scrub.rb_node)) {
675679
/*
676680
* No free physical eraseblocks? Well, they must be waiting in
@@ -1003,8 +1007,6 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
10031007
static int ensure_wear_leveling(struct ubi_device *ubi, int nested)
10041008
{
10051009
int err = 0;
1006-
struct ubi_wl_entry *e1;
1007-
struct ubi_wl_entry *e2;
10081010
struct ubi_work *wrk;
10091011

10101012
spin_lock(&ubi->wl_lock);
@@ -1017,6 +1019,13 @@ static int ensure_wear_leveling(struct ubi_device *ubi, int nested)
10171019
* the WL worker has to be scheduled anyway.
10181020
*/
10191021
if (!ubi->scrub.rb_node) {
1022+
#ifdef CONFIG_MTD_UBI_FASTMAP
1023+
if (!need_wear_leveling(ubi))
1024+
goto out_unlock;
1025+
#else
1026+
struct ubi_wl_entry *e1;
1027+
struct ubi_wl_entry *e2;
1028+
10201029
if (!ubi->used.rb_node || !ubi->free.rb_node)
10211030
/* No physical eraseblocks - no deal */
10221031
goto out_unlock;
@@ -1032,6 +1041,7 @@ static int ensure_wear_leveling(struct ubi_device *ubi, int nested)
10321041

10331042
if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD))
10341043
goto out_unlock;
1044+
#endif
10351045
dbg_wl("schedule wear-leveling");
10361046
} else
10371047
dbg_wl("schedule scrubbing");

drivers/mtd/ubi/wl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
static void update_fastmap_work_fn(struct work_struct *wrk);
66
static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root);
77
static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi);
8+
static struct ubi_wl_entry *next_peb_for_wl(struct ubi_device *ubi);
9+
static bool need_wear_leveling(struct ubi_device *ubi);
810
static void ubi_fastmap_close(struct ubi_device *ubi);
911
static inline void ubi_fastmap_init(struct ubi_device *ubi, int *count)
1012
{

0 commit comments

Comments
 (0)