diff options
author | Arne Edholm <arne.edholm@axis.com> | 2020-01-13 17:56:22 +0300 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2020-06-02 23:53:05 +0300 |
commit | 4b68bf9a69d22dd512d61d5f0ba01b065b01ede6 (patch) | |
tree | 9396f6f7e636d2296d21f3bdbdbcd6b77119e62c /drivers/mtd/ubi/fastmap-wl.c | |
parent | 3d77e6a8804abcc0504c904bd6e5cdf3a5cf8162 (diff) | |
download | linux-4b68bf9a69d22dd512d61d5f0ba01b065b01ede6.tar.xz |
ubi: Select fastmap anchor PEBs considering wear level rules
There is a risk that the fastmap anchor PEB is alternating between
just two PEBs, the current anchor and the previous anchor that was just
deleted. As the fastmap pools gets the first take on free PEBs, the
pools may leave no free PEBs to be selected as the new anchor,
resulting in the two PEBs alternating behaviour. If the anchor PEBs gets
a high erase count the PEBs will not be used by the pools but remain in
ubi->free, even more increasing the likelihood they will be used as
anchors.
Getting stuck using only a couple of PEBs continuously will result in an
uneven wear, eventually leading to failure.
To fix this:
- Choose the fastmap anchor when the most free PEBs are available. This is
during rebuilding of the fastmap pools, after the unused pool PEBs are
added to ubi->free but before the pools are populated again from the
free PEBs. Also reserve an additional second best PEB as a candidate
for the next time the fast map anchor is updated. If a better PEB is
found the next time the fast map anchor is updated, the candidate is
made available for building the pools.
- Enable anchor move within the anchor area again as it is useful for
distributing wear.
- The anchor candidate for the next fastmap update is the most suited free
PEB. Check this PEB's erase count during wear leveling. If the wear
leveling limit is exceeded, the PEB is considered unsuitable for now. As
all other non used anchor area PEBs should be even worse, free up the
used anchor area PEB with the lowest erase count.
Signed-off-by: Arne Edholm <arne.edholm@axis.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'drivers/mtd/ubi/fastmap-wl.c')
-rw-r--r-- | drivers/mtd/ubi/fastmap-wl.c | 39 |
1 files changed, 24 insertions, 15 deletions
diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c index b486250923c5..83afc00e365a 100644 --- a/drivers/mtd/ubi/fastmap-wl.c +++ b/drivers/mtd/ubi/fastmap-wl.c @@ -116,6 +116,21 @@ void ubi_refill_pools(struct ubi_device *ubi) wl_pool->size = 0; pool->size = 0; + if (ubi->fm_anchor) { + wl_tree_add(ubi->fm_anchor, &ubi->free); + ubi->free_count++; + } + if (ubi->fm_next_anchor) { + wl_tree_add(ubi->fm_next_anchor, &ubi->free); + ubi->free_count++; + } + + /* All available PEBs are in ubi->free, now is the time to get + * the best anchor PEBs. + */ + ubi->fm_anchor = ubi_wl_get_fm_peb(ubi, 1); + ubi->fm_next_anchor = ubi_wl_get_fm_peb(ubi, 1); + for (;;) { enough = 0; if (pool->size < pool->max_size) { @@ -271,26 +286,20 @@ static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi) int ubi_ensure_anchor_pebs(struct ubi_device *ubi) { struct ubi_work *wrk; - struct ubi_wl_entry *anchor; spin_lock(&ubi->wl_lock); - /* Do we already have an anchor? */ - if (ubi->fm_anchor) { - spin_unlock(&ubi->wl_lock); - return 0; - } - - /* See if we can find an anchor PEB on the list of free PEBs */ - anchor = ubi_wl_get_fm_peb(ubi, 1); - if (anchor) { - ubi->fm_anchor = anchor; - spin_unlock(&ubi->wl_lock); - return 0; + /* Do we have a next anchor? */ + if (!ubi->fm_next_anchor) { + ubi->fm_next_anchor = ubi_wl_get_fm_peb(ubi, 1); + if (!ubi->fm_next_anchor) + /* Tell wear leveling to produce a new anchor PEB */ + ubi->fm_do_produce_anchor = 1; } - /* No luck, trigger wear leveling to produce a new anchor PEB */ - ubi->fm_do_produce_anchor = 1; + /* Do wear leveling to get a new anchor PEB or check the + * existing next anchor candidate. + */ if (ubi->wl_scheduled) { spin_unlock(&ubi->wl_lock); return 0; |