Commit d36e59e6 authored by Joel Reardon's avatar Joel Reardon Committed by Artem Bityutskiy

UBI: add lnum and vol_id to struct ubi_work

This is part of a multipart patch to allow UBI to force the erasure of
particular logical eraseblock numbers. In this patch, the volume id and LEB
number are added to ubi_work data structure, and both are also passed as a
parameter to schedule erase to set it appropriately. Whenever ubi_wl_put_peb
is called, the lnum is also passed to be forwarded to schedule erase. Later,
a new ubi_sync_lnum will be added to execute immediately all work related to
that lnum.

This was tested by outputting the vol_id and lnum during the schedule of
erasure. The ubi thread was disabled and two ubifs drives on separate
partitions repeated changed a small number of LEBs. The ubi module was readded,
and all the erased LEBs, corresponding to the volumes, were added to the
schedule erase queue.

Artem: minor tweaks
Signed-off-by: default avatarJoel Reardon <reardonj@inf.ethz.ch>
Signed-off-by: default avatarArtem Bityutskiy <artem.bityutskiy@linux.intel.com>
parent 6dd3bc7e
...@@ -341,7 +341,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -341,7 +341,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum); dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum);
vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED; vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED;
err = ubi_wl_put_peb(ubi, pnum, 0); err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 0);
out_unlock: out_unlock:
leb_write_unlock(ubi, vol_id, lnum); leb_write_unlock(ubi, vol_id, lnum);
...@@ -550,7 +550,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, ...@@ -550,7 +550,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
ubi_free_vid_hdr(ubi, vid_hdr); ubi_free_vid_hdr(ubi, vid_hdr);
vol->eba_tbl[lnum] = new_pnum; vol->eba_tbl[lnum] = new_pnum;
ubi_wl_put_peb(ubi, pnum, 1); ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
ubi_msg("data was successfully recovered"); ubi_msg("data was successfully recovered");
return 0; return 0;
...@@ -558,7 +558,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, ...@@ -558,7 +558,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
out_unlock: out_unlock:
mutex_unlock(&ubi->buf_mutex); mutex_unlock(&ubi->buf_mutex);
out_put: out_put:
ubi_wl_put_peb(ubi, new_pnum, 1); ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
ubi_free_vid_hdr(ubi, vid_hdr); ubi_free_vid_hdr(ubi, vid_hdr);
return err; return err;
...@@ -568,7 +568,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, ...@@ -568,7 +568,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
* get another one. * get another one.
*/ */
ubi_warn("failed to write to PEB %d", new_pnum); ubi_warn("failed to write to PEB %d", new_pnum);
ubi_wl_put_peb(ubi, new_pnum, 1); ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
if (++tries > UBI_IO_RETRIES) { if (++tries > UBI_IO_RETRIES) {
ubi_free_vid_hdr(ubi, vid_hdr); ubi_free_vid_hdr(ubi, vid_hdr);
return err; return err;
...@@ -686,7 +686,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, ...@@ -686,7 +686,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
* eraseblock, so just put it and request a new one. We assume that if * eraseblock, so just put it and request a new one. We assume that if
* this physical eraseblock went bad, the erase code will handle that. * this physical eraseblock went bad, the erase code will handle that.
*/ */
err = ubi_wl_put_peb(ubi, pnum, 1); err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
if (err || ++tries > UBI_IO_RETRIES) { if (err || ++tries > UBI_IO_RETRIES) {
ubi_ro_mode(ubi); ubi_ro_mode(ubi);
leb_write_unlock(ubi, vol_id, lnum); leb_write_unlock(ubi, vol_id, lnum);
...@@ -804,7 +804,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -804,7 +804,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
return err; return err;
} }
err = ubi_wl_put_peb(ubi, pnum, 1); err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
if (err || ++tries > UBI_IO_RETRIES) { if (err || ++tries > UBI_IO_RETRIES) {
ubi_ro_mode(ubi); ubi_ro_mode(ubi);
leb_write_unlock(ubi, vol_id, lnum); leb_write_unlock(ubi, vol_id, lnum);
...@@ -901,7 +901,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -901,7 +901,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
} }
if (vol->eba_tbl[lnum] >= 0) { if (vol->eba_tbl[lnum] >= 0) {
err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 0); err = ubi_wl_put_peb(ubi, vol_id, lnum, vol->eba_tbl[lnum], 0);
if (err) if (err)
goto out_leb_unlock; goto out_leb_unlock;
} }
...@@ -926,7 +926,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, ...@@ -926,7 +926,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
goto out_leb_unlock; goto out_leb_unlock;
} }
err = ubi_wl_put_peb(ubi, pnum, 1); err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
if (err || ++tries > UBI_IO_RETRIES) { if (err || ++tries > UBI_IO_RETRIES) {
ubi_ro_mode(ubi); ubi_ro_mode(ubi);
goto out_leb_unlock; goto out_leb_unlock;
......
...@@ -667,7 +667,8 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai); ...@@ -667,7 +667,8 @@ int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai);
/* wl.c */ /* wl.c */
int ubi_wl_get_peb(struct ubi_device *ubi); int ubi_wl_get_peb(struct ubi_device *ubi);
int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture); int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
int pnum, int torture);
int ubi_wl_flush(struct ubi_device *ubi); int ubi_wl_flush(struct ubi_device *ubi);
int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum); int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum);
int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai); int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai);
......
...@@ -140,6 +140,8 @@ ...@@ -140,6 +140,8 @@
* @list: a link in the list of pending works * @list: a link in the list of pending works
* @func: worker function * @func: worker function
* @e: physical eraseblock to erase * @e: physical eraseblock to erase
* @vol_id: the volume ID on which this erasure is being performed
* @lnum: the logical eraseblock number
* @torture: if the physical eraseblock has to be tortured * @torture: if the physical eraseblock has to be tortured
* *
* The @func pointer points to the worker function. If the @cancel argument is * The @func pointer points to the worker function. If the @cancel argument is
...@@ -152,6 +154,8 @@ struct ubi_work { ...@@ -152,6 +154,8 @@ struct ubi_work {
int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel); int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel);
/* The below fields are only relevant to erasure works */ /* The below fields are only relevant to erasure works */
struct ubi_wl_entry *e; struct ubi_wl_entry *e;
int vol_id;
int lnum;
int torture; int torture;
}; };
...@@ -579,13 +583,15 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -579,13 +583,15 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
* schedule_erase - schedule an erase work. * schedule_erase - schedule an erase work.
* @ubi: UBI device description object * @ubi: UBI device description object
* @e: the WL entry of the physical eraseblock to erase * @e: the WL entry of the physical eraseblock to erase
* @vol_id: the volume ID that last used this PEB
* @lnum: the last used logical eraseblock number for the PEB
* @torture: if the physical eraseblock has to be tortured * @torture: if the physical eraseblock has to be tortured
* *
* This function returns zero in case of success and a %-ENOMEM in case of * This function returns zero in case of success and a %-ENOMEM in case of
* failure. * failure.
*/ */
static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
int torture) int vol_id, int lnum, int torture)
{ {
struct ubi_work *wl_wrk; struct ubi_work *wl_wrk;
...@@ -598,6 +604,8 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, ...@@ -598,6 +604,8 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
wl_wrk->func = &erase_worker; wl_wrk->func = &erase_worker;
wl_wrk->e = e; wl_wrk->e = e;
wl_wrk->vol_id = vol_id;
wl_wrk->lnum = lnum;
wl_wrk->torture = torture; wl_wrk->torture = torture;
schedule_ubi_work(ubi, wl_wrk); schedule_ubi_work(ubi, wl_wrk);
...@@ -798,7 +806,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, ...@@ -798,7 +806,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
ubi->move_to_put = ubi->wl_scheduled = 0; ubi->move_to_put = ubi->wl_scheduled = 0;
spin_unlock(&ubi->wl_lock); spin_unlock(&ubi->wl_lock);
err = schedule_erase(ubi, e1, 0); err = schedule_erase(ubi, e1, vol_id, lnum, 0);
if (err) { if (err) {
kmem_cache_free(ubi_wl_entry_slab, e1); kmem_cache_free(ubi_wl_entry_slab, e1);
if (e2) if (e2)
...@@ -813,7 +821,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, ...@@ -813,7 +821,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
*/ */
dbg_wl("PEB %d (LEB %d:%d) was put meanwhile, erase", dbg_wl("PEB %d (LEB %d:%d) was put meanwhile, erase",
e2->pnum, vol_id, lnum); e2->pnum, vol_id, lnum);
err = schedule_erase(ubi, e2, 0); err = schedule_erase(ubi, e2, vol_id, lnum, 0);
if (err) { if (err) {
kmem_cache_free(ubi_wl_entry_slab, e2); kmem_cache_free(ubi_wl_entry_slab, e2);
goto out_ro; goto out_ro;
...@@ -852,7 +860,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, ...@@ -852,7 +860,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
spin_unlock(&ubi->wl_lock); spin_unlock(&ubi->wl_lock);
ubi_free_vid_hdr(ubi, vid_hdr); ubi_free_vid_hdr(ubi, vid_hdr);
err = schedule_erase(ubi, e2, torture); err = schedule_erase(ubi, e2, vol_id, lnum, torture);
if (err) { if (err) {
kmem_cache_free(ubi_wl_entry_slab, e2); kmem_cache_free(ubi_wl_entry_slab, e2);
goto out_ro; goto out_ro;
...@@ -971,6 +979,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -971,6 +979,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
{ {
struct ubi_wl_entry *e = wl_wrk->e; struct ubi_wl_entry *e = wl_wrk->e;
int pnum = e->pnum, err, need; int pnum = e->pnum, err, need;
int vol_id = wl_wrk->vol_id;
int lnum = wl_wrk->lnum;
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);
...@@ -979,7 +989,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -979,7 +989,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
return 0; return 0;
} }
dbg_wl("erase PEB %d EC %d", pnum, e->ec); dbg_wl("erase PEB %d EC %d LEB %d:%d",
pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum);
err = sync_erase(ubi, e, wl_wrk->torture); err = sync_erase(ubi, e, wl_wrk->torture);
if (!err) { if (!err) {
...@@ -1009,7 +1020,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -1009,7 +1020,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
int err1; int err1;
/* Re-schedule the LEB for erasure */ /* Re-schedule the LEB for erasure */
err1 = schedule_erase(ubi, e, 0); err1 = schedule_erase(ubi, e, vol_id, lnum, 0);
if (err1) { if (err1) {
err = err1; err = err1;
goto out_ro; goto out_ro;
...@@ -1077,6 +1088,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -1077,6 +1088,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
/** /**
* ubi_wl_put_peb - return a PEB to the wear-leveling sub-system. * ubi_wl_put_peb - return a PEB to the wear-leveling sub-system.
* @ubi: UBI device description object * @ubi: UBI device description object
* @vol_id: the volume ID that last used this PEB
* @lnum: the last used logical eraseblock number for the PEB
* @pnum: physical eraseblock to return * @pnum: physical eraseblock to return
* @torture: if this physical eraseblock has to be tortured * @torture: if this physical eraseblock has to be tortured
* *
...@@ -1085,7 +1098,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -1085,7 +1098,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
* occurred to this @pnum and it has to be tested. This function returns zero * occurred to this @pnum and it has to be tested. This function returns zero
* in case of success, and a negative error code in case of failure. * in case of success, and a negative error code in case of failure.
*/ */
int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
int pnum, int torture)
{ {
int err; int err;
struct ubi_wl_entry *e; struct ubi_wl_entry *e;
...@@ -1151,7 +1165,7 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) ...@@ -1151,7 +1165,7 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
} }
spin_unlock(&ubi->wl_lock); spin_unlock(&ubi->wl_lock);
err = schedule_erase(ubi, e, torture); err = schedule_erase(ubi, e, vol_id, lnum, torture);
if (err) { if (err) {
spin_lock(&ubi->wl_lock); spin_lock(&ubi->wl_lock);
wl_tree_add(e, &ubi->used); wl_tree_add(e, &ubi->used);
...@@ -1416,7 +1430,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai) ...@@ -1416,7 +1430,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
e->pnum = aeb->pnum; e->pnum = aeb->pnum;
e->ec = aeb->ec; e->ec = aeb->ec;
ubi->lookuptbl[e->pnum] = e; ubi->lookuptbl[e->pnum] = e;
if (schedule_erase(ubi, e, 0)) { if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) {
kmem_cache_free(ubi_wl_entry_slab, e); kmem_cache_free(ubi_wl_entry_slab, e);
goto out_free; goto out_free;
} }
......
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