Commit 3bef22ee authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'upstream-4.4-rc7' of git://git.infradead.org/linux-ubifs

Pull UBI bug fixes from Richard Weinberger:
 "This contains four bug fixes for UBI"

* tag 'upstream-4.4-rc7' of git://git.infradead.org/linux-ubifs:
  mtd: ubi: don't leak e if schedule_erase() fails
  mtd: ubi: fixup error correction in do_sync_erase()
  UBI: fix use of "VID" vs. "EC" in header self-check
  UBI: fix return error code
parents e2b0a161 6b238de1
...@@ -236,7 +236,7 @@ int ubi_debugfs_init(void) ...@@ -236,7 +236,7 @@ int ubi_debugfs_init(void)
dfs_rootdir = debugfs_create_dir("ubi", NULL); dfs_rootdir = debugfs_create_dir("ubi", NULL);
if (IS_ERR_OR_NULL(dfs_rootdir)) { if (IS_ERR_OR_NULL(dfs_rootdir)) {
int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir); int err = dfs_rootdir ? PTR_ERR(dfs_rootdir) : -ENODEV;
pr_err("UBI error: cannot create \"ubi\" debugfs directory, error %d\n", pr_err("UBI error: cannot create \"ubi\" debugfs directory, error %d\n",
err); err);
......
...@@ -1299,7 +1299,7 @@ static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) ...@@ -1299,7 +1299,7 @@ static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err)) if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))
goto exit; goto exit;
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC); crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
hdr_crc = be32_to_cpu(vid_hdr->hdr_crc); hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
if (hdr_crc != crc) { if (hdr_crc != crc) {
ubi_err(ubi, "bad VID header CRC at PEB %d, calculated %#08x, read %#08x", ubi_err(ubi, "bad VID header CRC at PEB %d, calculated %#08x, read %#08x",
......
...@@ -603,6 +603,7 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, ...@@ -603,6 +603,7 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
return 0; return 0;
} }
static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk);
/** /**
* do_sync_erase - run the erase worker synchronously. * do_sync_erase - run the erase worker synchronously.
* @ubi: UBI device description object * @ubi: UBI device description object
...@@ -615,20 +616,16 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, ...@@ -615,20 +616,16 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
static int do_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, static int do_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
int vol_id, int lnum, int torture) int vol_id, int lnum, int torture)
{ {
struct ubi_work *wl_wrk; struct ubi_work wl_wrk;
dbg_wl("sync erase of PEB %i", e->pnum); dbg_wl("sync erase of PEB %i", e->pnum);
wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS); wl_wrk.e = e;
if (!wl_wrk) wl_wrk.vol_id = vol_id;
return -ENOMEM; wl_wrk.lnum = lnum;
wl_wrk.torture = torture;
wl_wrk->e = e;
wl_wrk->vol_id = vol_id;
wl_wrk->lnum = lnum;
wl_wrk->torture = torture;
return erase_worker(ubi, wl_wrk, 0); return __erase_worker(ubi, &wl_wrk);
} }
/** /**
...@@ -1014,7 +1011,7 @@ static int ensure_wear_leveling(struct ubi_device *ubi, int nested) ...@@ -1014,7 +1011,7 @@ static int ensure_wear_leveling(struct ubi_device *ubi, int nested)
} }
/** /**
* erase_worker - physical eraseblock erase worker function. * __erase_worker - physical eraseblock erase worker function.
* @ubi: UBI device description object * @ubi: UBI device description object
* @wl_wrk: the work object * @wl_wrk: the work object
* @shutdown: non-zero if the worker has to free memory and exit * @shutdown: non-zero if the worker has to free memory and exit
...@@ -1025,8 +1022,7 @@ static int ensure_wear_leveling(struct ubi_device *ubi, int nested) ...@@ -1025,8 +1022,7 @@ static int ensure_wear_leveling(struct ubi_device *ubi, int nested)
* needed. Returns zero in case of success and a negative error code in case of * needed. Returns zero in case of success and a negative error code in case of
* failure. * failure.
*/ */
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 shutdown)
{ {
struct ubi_wl_entry *e = wl_wrk->e; struct ubi_wl_entry *e = wl_wrk->e;
int pnum = e->pnum; int pnum = e->pnum;
...@@ -1034,21 +1030,11 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -1034,21 +1030,11 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
int lnum = wl_wrk->lnum; int lnum = wl_wrk->lnum;
int err, available_consumed = 0; int err, available_consumed = 0;
if (shutdown) {
dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
kfree(wl_wrk);
wl_entry_destroy(ubi, e);
return 0;
}
dbg_wl("erase PEB %d EC %d LEB %d:%d", dbg_wl("erase PEB %d EC %d LEB %d:%d",
pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum); 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) {
/* Fine, we've erased it successfully */
kfree(wl_wrk);
spin_lock(&ubi->wl_lock); spin_lock(&ubi->wl_lock);
wl_tree_add(e, &ubi->free); wl_tree_add(e, &ubi->free);
ubi->free_count++; ubi->free_count++;
...@@ -1066,7 +1052,6 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -1066,7 +1052,6 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
} }
ubi_err(ubi, "failed to erase PEB %d, error %d", pnum, err); ubi_err(ubi, "failed to erase PEB %d, error %d", pnum, err);
kfree(wl_wrk);
if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
err == -EBUSY) { err == -EBUSY) {
...@@ -1075,6 +1060,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -1075,6 +1060,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
/* Re-schedule the LEB for erasure */ /* Re-schedule the LEB for erasure */
err1 = schedule_erase(ubi, e, vol_id, lnum, 0); err1 = schedule_erase(ubi, e, vol_id, lnum, 0);
if (err1) { if (err1) {
wl_entry_destroy(ubi, e);
err = err1; err = err1;
goto out_ro; goto out_ro;
} }
...@@ -1150,6 +1136,25 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ...@@ -1150,6 +1136,25 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
return err; return err;
} }
static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
int shutdown)
{
int ret;
if (shutdown) {
struct ubi_wl_entry *e = wl_wrk->e;
dbg_wl("cancel erasure of PEB %d EC %d", e->pnum, e->ec);
kfree(wl_wrk);
wl_entry_destroy(ubi, e);
return 0;
}
ret = __erase_worker(ubi, wl_wrk);
kfree(wl_wrk);
return ret;
}
/** /**
* 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
......
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