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: Joel Reardon <reardonj@inf.ethz.ch> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
This commit is contained in:
parent
6dd3bc7e60
commit
d36e59e69b
|
@ -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 @@ retry:
|
||||||
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 @@ retry:
|
||||||
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 @@ write_error:
|
||||||
* 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 @@ write_error:
|
||||||
* 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 @@ write_error:
|
||||||
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 @@ retry:
|
||||||
}
|
}
|
||||||
|
|
||||||
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 @@ write_error:
|
||||||
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);
|
||||||
|
|
||||||
/* 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 @@
|
||||||
* @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 {
|
||||||
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,
|
||||||
* 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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
*/
|
*/
|
||||||
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 @@ out_not_moved:
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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,
|
||||||
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 @@ out_ro:
|
||||||
/**
|
/**
|
||||||
* 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 @@ out_ro:
|
||||||
* 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 @@ retry:
|
||||||
}
|
}
|
||||||
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)
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue