Skip to content

Commit f9c34bb

Browse files
saschahauerrichardweinberger
authored andcommitted
ubi: Fix producing anchor PEBs
When a new fastmap is about to be written UBI must make sure it has a free block for a fastmap anchor available. For this ubi_update_fastmap() calls ubi_ensure_anchor_pebs(). This stopped working with 2e8f08d ("ubi: Fix races around ubi_refill_pools()"), with this commit the wear leveling code is blocked and can no longer produce free PEBs. UBI then more often than not falls back to write the new fastmap anchor to the same block it was already on which means the same erase block gets erased during each fastmap write and wears out quite fast. As the locking prevents us from producing the anchor PEB when we actually need it, this patch changes the strategy for creating the anchor PEB. We no longer create it on demand right before we want to write a fastmap, but instead we create an anchor PEB right after we have written a fastmap. This gives us enough time to produce a new anchor PEB before it is needed. To make sure we have an anchor PEB for the very first fastmap write we call ubi_ensure_anchor_pebs() during initialisation as well. Fixes: 2e8f08d ("ubi: Fix races around ubi_refill_pools()") Signed-off-by: Sascha Hauer <[email protected]> Signed-off-by: Richard Weinberger <[email protected]>
1 parent 6abf572 commit f9c34bb

File tree

5 files changed

+41
-43
lines changed

5 files changed

+41
-43
lines changed

drivers/mtd/ubi/fastmap-wl.c

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,6 @@ static void return_unused_pool_pebs(struct ubi_device *ubi,
5757
}
5858
}
5959

60-
static int anchor_pebs_available(struct rb_root *root)
61-
{
62-
struct rb_node *p;
63-
struct ubi_wl_entry *e;
64-
65-
ubi_rb_for_each_entry(p, e, root, u.rb)
66-
if (e->pnum < UBI_FM_MAX_START)
67-
return 1;
68-
69-
return 0;
70-
}
71-
7260
/**
7361
* ubi_wl_get_fm_peb - find a physical erase block with a given maximal number.
7462
* @ubi: UBI device description object
@@ -277,8 +265,26 @@ static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi)
277265
int ubi_ensure_anchor_pebs(struct ubi_device *ubi)
278266
{
279267
struct ubi_work *wrk;
268+
struct ubi_wl_entry *anchor;
280269

281270
spin_lock(&ubi->wl_lock);
271+
272+
/* Do we already have an anchor? */
273+
if (ubi->fm_anchor) {
274+
spin_unlock(&ubi->wl_lock);
275+
return 0;
276+
}
277+
278+
/* See if we can find an anchor PEB on the list of free PEBs */
279+
anchor = ubi_wl_get_fm_peb(ubi, 1);
280+
if (anchor) {
281+
ubi->fm_anchor = anchor;
282+
spin_unlock(&ubi->wl_lock);
283+
return 0;
284+
}
285+
286+
/* No luck, trigger wear leveling to produce a new anchor PEB */
287+
ubi->fm_do_produce_anchor = 1;
282288
if (ubi->wl_scheduled) {
283289
spin_unlock(&ubi->wl_lock);
284290
return 0;
@@ -294,7 +300,6 @@ int ubi_ensure_anchor_pebs(struct ubi_device *ubi)
294300
return -ENOMEM;
295301
}
296302

297-
wrk->anchor = 1;
298303
wrk->func = &wear_leveling_worker;
299304
__schedule_ubi_work(ubi, wrk);
300305
return 0;

drivers/mtd/ubi/fastmap.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,14 +1540,6 @@ int ubi_update_fastmap(struct ubi_device *ubi)
15401540
return 0;
15411541
}
15421542

1543-
ret = ubi_ensure_anchor_pebs(ubi);
1544-
if (ret) {
1545-
up_write(&ubi->fm_eba_sem);
1546-
up_write(&ubi->work_sem);
1547-
up_write(&ubi->fm_protect);
1548-
return ret;
1549-
}
1550-
15511543
new_fm = kzalloc(sizeof(*new_fm), GFP_KERNEL);
15521544
if (!new_fm) {
15531545
up_write(&ubi->fm_eba_sem);
@@ -1618,7 +1610,8 @@ int ubi_update_fastmap(struct ubi_device *ubi)
16181610
}
16191611

16201612
spin_lock(&ubi->wl_lock);
1621-
tmp_e = ubi_wl_get_fm_peb(ubi, 1);
1613+
tmp_e = ubi->fm_anchor;
1614+
ubi->fm_anchor = NULL;
16221615
spin_unlock(&ubi->wl_lock);
16231616

16241617
if (old_fm) {
@@ -1670,6 +1663,9 @@ int ubi_update_fastmap(struct ubi_device *ubi)
16701663
up_write(&ubi->work_sem);
16711664
up_write(&ubi->fm_protect);
16721665
kfree(old_fm);
1666+
1667+
ubi_ensure_anchor_pebs(ubi);
1668+
16731669
return ret;
16741670

16751671
err:

drivers/mtd/ubi/ubi.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,8 @@ struct ubi_debug_info {
491491
* @fm_work: fastmap work queue
492492
* @fm_work_scheduled: non-zero if fastmap work was scheduled
493493
* @fast_attach: non-zero if UBI was attached by fastmap
494+
* @fm_anchor: The next anchor PEB to use for fastmap
495+
* @fm_do_produce_anchor: If true produce an anchor PEB in wl
494496
*
495497
* @used: RB-tree of used physical eraseblocks
496498
* @erroneous: RB-tree of erroneous used physical eraseblocks
@@ -599,6 +601,8 @@ struct ubi_device {
599601
struct work_struct fm_work;
600602
int fm_work_scheduled;
601603
int fast_attach;
604+
struct ubi_wl_entry *fm_anchor;
605+
int fm_do_produce_anchor;
602606

603607
/* Wear-leveling sub-system's stuff */
604608
struct rb_root used;
@@ -789,7 +793,6 @@ struct ubi_attach_info {
789793
* @vol_id: the volume ID on which this erasure is being performed
790794
* @lnum: the logical eraseblock number
791795
* @torture: if the physical eraseblock has to be tortured
792-
* @anchor: produce a anchor PEB to by used by fastmap
793796
*
794797
* The @func pointer points to the worker function. If the @shutdown argument is
795798
* not zero, the worker has to free the resources and exit immediately as the
@@ -805,7 +808,6 @@ struct ubi_work {
805808
int vol_id;
806809
int lnum;
807810
int torture;
808-
int anchor;
809811
};
810812

811813
#include "debug.h"

drivers/mtd/ubi/wl.c

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -339,13 +339,6 @@ static struct ubi_wl_entry *find_wl_entry(struct ubi_device *ubi,
339339
}
340340
}
341341

342-
/* If no fastmap has been written and this WL entry can be used
343-
* as anchor PEB, hold it back and return the second best WL entry
344-
* such that fastmap can use the anchor PEB later. */
345-
if (prev_e && !ubi->fm_disabled &&
346-
!ubi->fm && e->pnum < UBI_FM_MAX_START)
347-
return prev_e;
348-
349342
return e;
350343
}
351344

@@ -656,9 +649,6 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
656649
{
657650
int err, scrubbing = 0, torture = 0, protect = 0, erroneous = 0;
658651
int erase = 0, keep = 0, vol_id = -1, lnum = -1;
659-
#ifdef CONFIG_MTD_UBI_FASTMAP
660-
int anchor = wrk->anchor;
661-
#endif
662652
struct ubi_wl_entry *e1, *e2;
663653
struct ubi_vid_io_buf *vidb;
664654
struct ubi_vid_hdr *vid_hdr;
@@ -698,11 +688,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
698688
}
699689

700690
#ifdef CONFIG_MTD_UBI_FASTMAP
701-
/* Check whether we need to produce an anchor PEB */
702-
if (!anchor)
703-
anchor = !anchor_pebs_available(&ubi->free);
704-
705-
if (anchor) {
691+
if (ubi->fm_do_produce_anchor) {
706692
e1 = find_anchor_wl_entry(&ubi->used);
707693
if (!e1)
708694
goto out_cancel;
@@ -719,6 +705,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
719705
self_check_in_wl_tree(ubi, e1, &ubi->used);
720706
rb_erase(&e1->u.rb, &ubi->used);
721707
dbg_wl("anchor-move PEB %d to PEB %d", e1->pnum, e2->pnum);
708+
ubi->fm_do_produce_anchor = 0;
722709
} else if (!ubi->scrub.rb_node) {
723710
#else
724711
if (!ubi->scrub.rb_node) {
@@ -1051,7 +1038,6 @@ static int ensure_wear_leveling(struct ubi_device *ubi, int nested)
10511038
goto out_cancel;
10521039
}
10531040

1054-
wrk->anchor = 0;
10551041
wrk->func = &wear_leveling_worker;
10561042
if (nested)
10571043
__schedule_ubi_work(ubi, wrk);
@@ -1093,8 +1079,15 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk)
10931079
err = sync_erase(ubi, e, wl_wrk->torture);
10941080
if (!err) {
10951081
spin_lock(&ubi->wl_lock);
1096-
wl_tree_add(e, &ubi->free);
1097-
ubi->free_count++;
1082+
1083+
if (!ubi->fm_anchor && e->pnum < UBI_FM_MAX_START) {
1084+
ubi->fm_anchor = e;
1085+
ubi->fm_do_produce_anchor = 0;
1086+
} else {
1087+
wl_tree_add(e, &ubi->free);
1088+
ubi->free_count++;
1089+
}
1090+
10981091
spin_unlock(&ubi->wl_lock);
10991092

11001093
/*
@@ -1882,6 +1875,9 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
18821875
if (err)
18831876
goto out_free;
18841877

1878+
#ifdef CONFIG_MTD_UBI_FASTMAP
1879+
ubi_ensure_anchor_pebs(ubi);
1880+
#endif
18851881
return 0;
18861882

18871883
out_free:

drivers/mtd/ubi/wl.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#ifndef UBI_WL_H
33
#define UBI_WL_H
44
#ifdef CONFIG_MTD_UBI_FASTMAP
5-
static int anchor_pebs_available(struct rb_root *root);
65
static void update_fastmap_work_fn(struct work_struct *wrk);
76
static struct ubi_wl_entry *find_anchor_wl_entry(struct rb_root *root);
87
static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi);

0 commit comments

Comments
 (0)