diff options
author | Zhihao Cheng <chengzhihao1@huawei.com> | 2023-08-28 09:38:41 +0300 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2023-10-28 23:49:14 +0300 |
commit | eada823e6a6fb856548f6e0c7a343cd5c41bb9d3 (patch) | |
tree | 5f70ef0ba95926b2f4fd6439ceee00015aa4023a | |
parent | 415e4723c4325464d489c1ef3335eb6679905471 (diff) | |
download | linux-eada823e6a6fb856548f6e0c7a343cd5c41bb9d3.tar.xz |
ubi: fastmap: may_reserve_for_fm: Don't reserve PEB if fm_anchor exists
This is the part 1 to fix cyclically reusing single fastmap data PEBs.
After running fsstress on UBIFS for a while, UBI (16384 blocks, fastmap
takes 2 blocks) has an erase block(PEB: 8031) with big erase counter
greater than any other pebs:
=========================================================
from to count min avg max
---------------------------------------------------------
0 .. 9: 0 0 0 0
10 .. 99: 532 84 92 99
100 .. 999: 15787 100 147 229
1000 .. 9999: 64 4699 4765 4826
10000 .. 99999: 0 0 0 0
100000 .. inf: 1 272935 272935 272935
---------------------------------------------------------
Total : 16384 84 180 272935
Not like fm_anchor, there is no candidate PEBs for fastmap data area,
so old fastmap data pebs will be reused after all free pebs are filled
into pool/wl_pool:
ubi_update_fastmap
for (i = 1; i < new_fm->used_blocks; i++)
erase_block(ubi, old_fm->e[i]->pnum)
new_fm->e[i] = old_fm->e[i]
According to wear leveling algorithm, UBI selects one small erase
counter PEB from ubi->used and one big erase counter PEB from wl_pool,
the reused fastmap data PEB is not in these trees. UBI won't schedule
this PEB for wl even it is in ubi->used because wl algorithm expects
small erase counter for used PEB.
Don't reserve PEB for fastmap in may_reserve_for_fm() if fm_anchor
already exists. Otherwise, when UBI is running out of free PEBs,
the only one free PEB (pnum < 64) will be skipped and fastmap data
will be written on the same old PEB.
Fixes: dbb7d2a88d2a ("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>
-rw-r--r-- | drivers/mtd/ubi/fastmap-wl.c | 2 | ||||
-rw-r--r-- | drivers/mtd/ubi/wl.c | 9 |
2 files changed, 7 insertions, 4 deletions
diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c index 7c4cfd80da31..490514da1e00 100644 --- a/drivers/mtd/ubi/fastmap-wl.c +++ b/drivers/mtd/ubi/fastmap-wl.c @@ -521,7 +521,7 @@ static void ubi_fastmap_close(struct ubi_device *ubi) static struct ubi_wl_entry *may_reserve_for_fm(struct ubi_device *ubi, struct ubi_wl_entry *e, struct rb_root *root) { - if (e && !ubi->fm_disabled && !ubi->fm && + if (e && !ubi->fm_disabled && !ubi->fm && !ubi->fm_anchor && e->pnum < UBI_FM_MAX_START) e = rb_entry(rb_next(root->rb_node), struct ubi_wl_entry, u.rb); diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 14edb65ce6a6..40a1c306b8af 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -367,9 +367,12 @@ static struct ubi_wl_entry *find_mean_wl_entry(struct ubi_device *ubi, if (last->ec - first->ec < WL_FREE_MAX_DIFF) { e = rb_entry(root->rb_node, struct ubi_wl_entry, u.rb); - /* If no fastmap has been written and this WL entry can be used - * as anchor PEB, hold it back and return the second best - * WL entry such that fastmap can use the anchor PEB later. */ + /* + * If no fastmap has been written and fm_anchor is not + * reserved and this WL entry can be used as anchor PEB + * hold it back and return the second best WL entry such + * that fastmap can use the anchor PEB later. + */ e = may_reserve_for_fm(ubi, e, root); } else e = find_wl_entry(ubi, root, WL_FREE_MAX_DIFF/2); |