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: dbb7d2a88d ("UBI: Add fastmap core")
Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
committed by
Richard Weinberger
parent
60f2f4a81d
commit
4d18b5a57b
+15
-10
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user