aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhihao Cheng <chengzhihao1@huawei.com>2023-08-28 14:38:34 +0800
committerRichard Weinberger <richard@nod.at>2023-10-28 22:30:01 +0200
commit4d18b5a57b16c21cf868369ca555068722c32b2d (patch)
tree2ea73bcdb16c8bb5a38eed33c166081adccd0644
parent60f2f4a81d486348587a6901e744ca8f22dd9637 (diff)
downloadubifs-4d18b5a57b16c21cf868369ca555068722c32b2d.tar.gz
ubi: fastmap: Fix missed ec updating after erasing old fastmap data block
After running fsstress on ubifs for a long time, UBI(16384 blocks, fastmap takes 2 blocks) has an erase block with different erase counters displayed from two views: From ubiscan view: PEB 8031 has erase counter 31581 ========================================================= from to count min avg max --------------------------------------------------------- 0 .. 9: 0 0 0 0 10 .. 99: 0 0 0 0 100 .. 999: 16383 290 315 781 1000 .. 9999: 0 0 0 0 10000 .. 99999: 1 31581 31581 31581 100000 .. inf: 0 0 0 0 --------------------------------------------------------- Total : 16384 290 317 31581 From detailed_erase_block_info view: PEB 8031 has erase counter 7 physical_block_number erase_count 8030 421 8031 7 # mem info is different from disk info 8032 434 8033 425 8034 431 Following process missed updating erase counter in wl_entry(in memory): ubi_update_fastmap for (i = 1; i < new_fm->used_blocks; i++) // update fastmap data if (!tmp_e) if (old_fm && old_fm->e[i]) erase_block(ubi, old_fm->e[i]->pnum) ret = ubi_io_sync_erase(ubi, pnum, 0) ec = be64_to_cpu(ec_hdr->ec) ec += ret ec_hdr->ec = cpu_to_be64(ec) ubi_io_write_ec_hdr(ubi, pnum, ec_hdr) // ec is updated on flash // ec is not updated in old_fm->e[i] (in memory) Fix it by passing wl_enter into erase_block() and updating erase counter in erase_block(). Fixes: dbb7d2a88d2a ("UBI: Add fastmap core") Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com> Signed-off-by: Richard Weinberger <richard@nod.at>
-rw-r--r--drivers/mtd/ubi/fastmap.c25
1 files changed, 15 insertions, 10 deletions
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index 28c8151a0725d5..f8c230acc55e74 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -1392,11 +1392,12 @@ out:
/**
* erase_block - Manually erase a PEB.
* @ubi: UBI device object
- * @pnum: PEB to be erased
+ * @e: the physical eraseblock to erase
*
- * Returns the new EC value on success, < 0 indicates an internal error.
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
*/
-static int erase_block(struct ubi_device *ubi, int pnum)
+static int erase_block(struct ubi_device *ubi, struct ubi_wl_entry *e)
{
int ret;
struct ubi_ec_hdr *ec_hdr;
@@ -1406,7 +1407,7 @@ static int erase_block(struct ubi_device *ubi, int pnum)
if (!ec_hdr)
return -ENOMEM;
- ret = ubi_io_read_ec_hdr(ubi, pnum, ec_hdr, 0);
+ ret = ubi_io_read_ec_hdr(ubi, e->pnum, ec_hdr, 0);
if (ret < 0)
goto out;
else if (ret && ret != UBI_IO_BITFLIPS) {
@@ -1414,7 +1415,7 @@ static int erase_block(struct ubi_device *ubi, int pnum)
goto out;
}
- ret = ubi_io_sync_erase(ubi, pnum, 0);
+ ret = ubi_io_sync_erase(ubi, e->pnum, 0);
if (ret < 0)
goto out;
@@ -1426,11 +1427,16 @@ static int erase_block(struct ubi_device *ubi, int pnum)
}
ec_hdr->ec = cpu_to_be64(ec);
- ret = ubi_io_write_ec_hdr(ubi, pnum, ec_hdr);
+ ret = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr);
if (ret < 0)
goto out;
- ret = ec;
+ e->ec = ec;
+ spin_lock(&ubi->wl_lock);
+ if (e->ec > ubi->max_ec)
+ ubi->max_ec = e->ec;
+ spin_unlock(&ubi->wl_lock);
+
out:
kfree(ec_hdr);
return ret;
@@ -1576,7 +1582,7 @@ int ubi_update_fastmap(struct ubi_device *ubi)
if (!tmp_e) {
if (old_fm && old_fm->e[i]) {
- ret = erase_block(ubi, old_fm->e[i]->pnum);
+ ret = erase_block(ubi, old_fm->e[i]);
if (ret < 0) {
ubi_err(ubi, "could not erase old fastmap PEB");
@@ -1628,7 +1634,7 @@ int ubi_update_fastmap(struct ubi_device *ubi)
if (old_fm) {
/* no fresh anchor PEB was found, reuse the old one */
if (!tmp_e) {
- ret = erase_block(ubi, old_fm->e[0]->pnum);
+ ret = erase_block(ubi, old_fm->e[0]);
if (ret < 0) {
ubi_err(ubi, "could not erase old anchor PEB");
@@ -1640,7 +1646,6 @@ int ubi_update_fastmap(struct ubi_device *ubi)
goto err;
}
new_fm->e[0] = old_fm->e[0];
- new_fm->e[0]->ec = ret;
old_fm->e[0] = NULL;
} else {
/* we've got a new anchor PEB, return the old one */