Patchwork [14/21] UBI: Fastmap: Erase PEBs synchronous in wear_leveling_worker()

login
register
mail settings
Submitter Richard Weinberger
Date June 13, 2012, 10:42 a.m.
Message ID <1339584138-69914-15-git-send-email-richard@nod.at>
Download mbox | patch
Permalink /patch/164630/
State New
Headers show

Comments

Richard Weinberger - June 13, 2012, 10:42 a.m.
Fastmap calls ubi_wl_flush() to ensure that no PEBs are in flight.
But if ubi_wl_flush() runs the WL-worker the worker may inject
new erase work which runs later.
This PEBs are not visible to fastmap and leak.
So solve this erase PEBs synchronous in wear_leveling_worker().

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/ubi/wl.c |   23 ++++++++++++++++++++---
 1 files changed, 20 insertions(+), 3 deletions(-)

Patch

diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 8fb8b41..def6a88 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -804,6 +804,23 @@  static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
 	return 0;
 }
 
+static int do_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
+			 int torture)
+{
+	struct ubi_work *wl_wrk;
+
+	ubi_msg("sync erase of PEB %i", e->pnum);
+
+	wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
+	if (!wl_wrk)
+		return -ENOMEM;
+
+	wl_wrk->e = e;
+	wl_wrk->torture = torture;
+
+	return erase_worker(ubi, wl_wrk, 0);
+}
+
 /**
  * ubi_wl_put_fm_peb - returns a PEB used in a fastmap to the wear-leveling
  * sub-system.
@@ -1035,7 +1052,7 @@  static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
 	ubi->move_to_put = ubi->wl_scheduled = 0;
 	spin_unlock(&ubi->wl_lock);
 
-	err = schedule_erase(ubi, e1, 0);
+	err = do_sync_erase(ubi, e1, 0);
 	if (err) {
 		kmem_cache_free(ubi_wl_entry_slab, e1);
 		if (e2)
@@ -1050,7 +1067,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",
 		       e2->pnum, vol_id, lnum);
-		err = schedule_erase(ubi, e2, 0);
+		err = do_sync_erase(ubi, e2, 0);
 		if (err) {
 			kmem_cache_free(ubi_wl_entry_slab, e2);
 			goto out_ro;
@@ -1089,7 +1106,7 @@  out_not_moved:
 	spin_unlock(&ubi->wl_lock);
 
 	ubi_free_vid_hdr(ubi, vid_hdr);
-	err = schedule_erase(ubi, e2, torture);
+	err = do_sync_erase(ubi, e2, torture);
 	if (err) {
 		kmem_cache_free(ubi_wl_entry_slab, e2);
 		goto out_ro;