mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
UBI: Preserve torture flag when rescheduling failed erasures
In __erase_worker(), when ubi_sync_erase() returns -EINTR, -ENOMEM,
-EAGAIN, or -EBUSY, the physical eraseblock is rescheduled for erasure
via schedule_erase() with the torture flag hardcoded to 0. This
unconditionally drops the torture request.
If the error occurred before torture_peb() completed (e.g., -ENOMEM
from the ec_hdr allocation in ubi_sync_erase(), errors from
self_check_not_bad()/nor_erase_prepare() in ubi_io_sync_erase(), or
torture_peb() failing mid-test because its internal do_sync_erase()/
ubi_io_read()/ubi_io_write() returned one of the above error codes),
the torture test was never finished. Such a PEB may reach the free
pool without being tortured, defeating the purpose of the torture
test for detecting marginally-bad eraseblocks.
If the error occurred after torture_peb() succeeded (the final
do_sync_erase() in ubi_io_sync_erase() or ubi_io_write_ec_hdr() in
ubi_sync_erase() failed), the torture has already been done and need
not be repeated.
Pass the torture flag by pointer to ubi_sync_erase() and
ubi_io_sync_erase(), and clear it to zero once torture_peb() has
completed successfully. __erase_worker() then forwards the updated
wl_wrk->torture to schedule_erase(): torture already done is dropped,
torture not completed is preserved across the reschedule.
Fixes: 784c145444 ("UBI: fix error handling in erase worker")
Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
parent
4e5e02340a
commit
420477a84f
|
|
@ -771,7 +771,7 @@ void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av)
|
|||
static int early_erase_peb(struct ubi_device *ubi,
|
||||
const struct ubi_attach_info *ai, int pnum, int ec)
|
||||
{
|
||||
int err;
|
||||
int err, torture = 0;
|
||||
struct ubi_ec_hdr *ec_hdr;
|
||||
|
||||
if ((long long)ec >= UBI_MAX_ERASECOUNTER) {
|
||||
|
|
@ -790,7 +790,7 @@ static int early_erase_peb(struct ubi_device *ubi,
|
|||
|
||||
ec_hdr->ec = cpu_to_be64(ec);
|
||||
|
||||
err = ubi_io_sync_erase(ubi, pnum, 0);
|
||||
err = ubi_io_sync_erase(ubi, pnum, &torture);
|
||||
if (err < 0)
|
||||
goto out_free;
|
||||
|
||||
|
|
|
|||
|
|
@ -1488,7 +1488,7 @@ static void return_fm_pebs(struct ubi_device *ubi,
|
|||
*/
|
||||
int ubi_update_fastmap(struct ubi_device *ubi)
|
||||
{
|
||||
int ret, i, j;
|
||||
int ret, i, j, torture = 0;
|
||||
struct ubi_fastmap_layout *new_fm, *old_fm;
|
||||
struct ubi_wl_entry *tmp_e;
|
||||
|
||||
|
|
@ -1526,7 +1526,7 @@ int ubi_update_fastmap(struct ubi_device *ubi)
|
|||
|
||||
if (!tmp_e) {
|
||||
if (old_fm && old_fm->e[i]) {
|
||||
ret = ubi_sync_erase(ubi, old_fm->e[i], 0);
|
||||
ret = ubi_sync_erase(ubi, old_fm->e[i], &torture);
|
||||
if (ret < 0) {
|
||||
ubi_err(ubi, "could not erase old fastmap PEB");
|
||||
|
||||
|
|
@ -1578,7 +1578,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 = ubi_sync_erase(ubi, old_fm->e[0], 0);
|
||||
ret = ubi_sync_erase(ubi, old_fm->e[0], &torture);
|
||||
if (ret < 0) {
|
||||
ubi_err(ubi, "could not erase old anchor PEB");
|
||||
|
||||
|
|
|
|||
|
|
@ -519,8 +519,10 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
|
|||
/**
|
||||
* ubi_io_sync_erase - synchronously erase a physical eraseblock.
|
||||
* @ubi: UBI device description object
|
||||
* @pnum: physical eraseblock number to erase
|
||||
* @torture: if this physical eraseblock has to be tortured
|
||||
* @pnum: the physical eraseblock number to erase
|
||||
* @torture: if this physical eraseblock has to be tortured; cleared to zero
|
||||
* once the torture test has completed successfully so that a retry
|
||||
* of the erase does not torture the physical eraseblock again
|
||||
*
|
||||
* This function synchronously erases physical eraseblock @pnum. If @torture
|
||||
* flag is not zero, the physical eraseblock is checked by means of writing
|
||||
|
|
@ -532,7 +534,7 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
|
|||
* codes in case of other errors. Note, %-EIO means that the physical
|
||||
* eraseblock is bad.
|
||||
*/
|
||||
int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
|
||||
int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int *torture)
|
||||
{
|
||||
int err, ret = 0;
|
||||
|
||||
|
|
@ -560,10 +562,11 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
|
|||
return err;
|
||||
}
|
||||
|
||||
if (torture) {
|
||||
if (*torture) {
|
||||
ret = torture_peb(ubi, pnum);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*torture = 0;
|
||||
}
|
||||
|
||||
err = do_sync_erase(ubi, pnum);
|
||||
|
|
|
|||
|
|
@ -901,7 +901,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap,
|
|||
struct ubi_attach_info *ai_scan);
|
||||
|
||||
/* wl.c */
|
||||
int ubi_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int torture);
|
||||
int ubi_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int *torture);
|
||||
int ubi_wl_get_peb(struct ubi_device *ubi);
|
||||
int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
|
||||
int pnum, int torture);
|
||||
|
|
@ -923,7 +923,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
|
|||
int len);
|
||||
int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
|
||||
int len);
|
||||
int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture);
|
||||
int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int *torture);
|
||||
int ubi_io_is_bad(const struct ubi_device *ubi, int pnum);
|
||||
int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum);
|
||||
int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
|
||||
|
|
|
|||
|
|
@ -443,12 +443,14 @@ static int prot_queue_del(struct ubi_device *ubi, int pnum)
|
|||
* ubi_sync_erase - synchronously erase a physical eraseblock.
|
||||
* @ubi: UBI device description object
|
||||
* @e: the physical eraseblock to erase
|
||||
* @torture: if the physical eraseblock has to be tortured
|
||||
* @torture: if the physical eraseblock has to be tortured; cleared to zero
|
||||
* once the torture test has completed successfully so that a retry
|
||||
* of the erase does not torture the physical eraseblock again
|
||||
*
|
||||
* This function returns zero in case of success and a negative error code in
|
||||
* case of failure.
|
||||
*/
|
||||
int ubi_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int torture)
|
||||
int ubi_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int *torture)
|
||||
{
|
||||
int err;
|
||||
struct ubi_ec_hdr *ec_hdr;
|
||||
|
|
@ -1113,7 +1115,7 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk)
|
|||
dbg_wl("erase PEB %d EC %d LEB %d:%d",
|
||||
pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum);
|
||||
|
||||
err = ubi_sync_erase(ubi, e, wl_wrk->torture);
|
||||
err = ubi_sync_erase(ubi, e, &wl_wrk->torture);
|
||||
if (!err) {
|
||||
spin_lock(&ubi->wl_lock);
|
||||
|
||||
|
|
@ -1150,7 +1152,8 @@ static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk)
|
|||
int err1;
|
||||
|
||||
/* Re-schedule the LEB for erasure */
|
||||
err1 = schedule_erase(ubi, e, vol_id, lnum, 0, true);
|
||||
err1 = schedule_erase(ubi, e, vol_id, lnum, wl_wrk->torture,
|
||||
true);
|
||||
if (err1) {
|
||||
spin_lock(&ubi->wl_lock);
|
||||
wl_entry_destroy(ubi, e);
|
||||
|
|
@ -1757,7 +1760,7 @@ static void shutdown_work(struct ubi_device *ubi)
|
|||
static int erase_aeb(struct ubi_device *ubi, struct ubi_ainf_peb *aeb, bool sync)
|
||||
{
|
||||
struct ubi_wl_entry *e;
|
||||
int err;
|
||||
int err, torture = 0;
|
||||
|
||||
e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
|
||||
if (!e)
|
||||
|
|
@ -1768,7 +1771,7 @@ static int erase_aeb(struct ubi_device *ubi, struct ubi_ainf_peb *aeb, bool sync
|
|||
ubi->lookuptbl[e->pnum] = e;
|
||||
|
||||
if (sync) {
|
||||
err = ubi_sync_erase(ubi, e, false);
|
||||
err = ubi_sync_erase(ubi, e, &torture);
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user