Commit 784c1454 authored by Artem Bityutskiy's avatar Artem Bityutskiy

UBI: fix error handling in erase worker

Do not switch to read-only mode in case of -EINTR and some
other obvious cases. Switch to RO mode only when we do not
know what is the error.
Reported-by: default avatarVinit Agnihotri <vinit.agnihotri@gmail.com>
Signed-off-by: default avatarArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
parent 63b6c1ed
...@@ -1060,9 +1060,8 @@ out_unlock: ...@@ -1060,9 +1060,8 @@ out_unlock:
static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
int cancel) int cancel)
{ {
int err;
struct ubi_wl_entry *e = wl_wrk->e; struct ubi_wl_entry *e = wl_wrk->e;
int pnum = e->pnum; int pnum = e->pnum, err, need;
if (cancel) { if (cancel) {
dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
...@@ -1097,24 +1096,32 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -1097,24 +1096,32 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
kfree(wl_wrk); kfree(wl_wrk);
kmem_cache_free(wl_entries_slab, e); kmem_cache_free(wl_entries_slab, e);
if (err != -EIO) { if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
err == -EBUSY) {
int err1;
/* Re-schedule the LEB for erasure */
err1 = schedule_erase(ubi, e, 0);
if (err1) {
err = err1;
goto out_ro;
}
return err;
} else if (err != -EIO) {
/* /*
* If this is not %-EIO, we have no idea what to do. Scheduling * If this is not %-EIO, we have no idea what to do. Scheduling
* this physical eraseblock for erasure again would cause * this physical eraseblock for erasure again would cause
* errors again and again. Well, lets switch to RO mode. * errors again and again. Well, lets switch to RO mode.
*/ */
ubi_ro_mode(ubi); goto out_ro;
return err;
} }
/* It is %-EIO, the PEB went bad */ /* It is %-EIO, the PEB went bad */
if (!ubi->bad_allowed) { if (!ubi->bad_allowed) {
ubi_err("bad physical eraseblock %d detected", pnum); ubi_err("bad physical eraseblock %d detected", pnum);
ubi_ro_mode(ubi); goto out_ro;
err = -EIO; }
} else {
int need;
spin_lock(&ubi->volumes_lock); spin_lock(&ubi->volumes_lock);
need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1; need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
...@@ -1130,18 +1137,15 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -1130,18 +1137,15 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
if (ubi->beb_rsvd_pebs == 0) { if (ubi->beb_rsvd_pebs == 0) {
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
ubi_err("no reserved physical eraseblocks"); ubi_err("no reserved physical eraseblocks");
ubi_ro_mode(ubi); goto out_ro;
return -EIO;
} }
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
ubi_msg("mark PEB %d as bad", pnum); ubi_msg("mark PEB %d as bad", pnum);
err = ubi_io_mark_bad(ubi, pnum); err = ubi_io_mark_bad(ubi, pnum);
if (err) { if (err)
ubi_ro_mode(ubi); goto out_ro;
return err;
}
spin_lock(&ubi->volumes_lock); spin_lock(&ubi->volumes_lock);
ubi->beb_rsvd_pebs -= 1; ubi->beb_rsvd_pebs -= 1;
...@@ -1151,9 +1155,12 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -1151,9 +1155,12 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
if (ubi->beb_rsvd_pebs == 0) if (ubi->beb_rsvd_pebs == 0)
ubi_warn("last PEB from the reserved pool was used"); ubi_warn("last PEB from the reserved pool was used");
spin_unlock(&ubi->volumes_lock); spin_unlock(&ubi->volumes_lock);
}
return err; return err;
out_ro:
ubi_ro_mode(ubi);
return err;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment