summaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2016-10-11 08:26:52 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2016-10-11 08:44:12 +0200
commit57cebc46f727055b8e7513e37cc88bc033852cb7 (patch)
treeabb650fda81b37a2c99aa337310d55fae0e7a13e /drivers/mtd
parentd8c2022d5d05289694a0f322f7f90ba6ccafabe2 (diff)
downloadbarebox-57cebc46f727055b8e7513e37cc88bc033852cb7.tar.gz
barebox-57cebc46f727055b8e7513e37cc88bc033852cb7.tar.xz
mtd: ubi: Fix scrubbing during attach
ensure_wear_leveling() is called at the end of ubi_wl_init() and may come to the decision to scrub some blocks. In the Kernel this is done in a separate thread, but in barebox we do this synchronously. The problem is that during ubi_wl_init() the EBA system is not yet initialized (ubi_eba_init() is not yet called), so the wear level worker hits a NULL pointer deref when the fastmap needs to be updated and ubi_write_fastmap() accesses vol->eba_tbl. Solve this by honoring the ubi->thread_enabled flag which is only set to true when UBI is sufficiently initialized. This means we now can have multiple works queued, so we can no longer simply do one work when queued, but instead have to continue to do work until all work is done. The best place to do so is a ubi_thread() function which behaves similar to the Kernel function with the same name, but is called synchronously in barebox. To make sure that the initially queued works are done, the call to (no-op) wake_up_process() at the end of ubi_attach_mtd_dev() is replaced with a call to ubi_thread(). While at it also honor the ubi->ro_mode flag to make sure we do not do any wear leveling work on readonly UBI devices. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/ubi/build.c4
-rw-r--r--drivers/mtd/ubi/ubi.h2
-rw-r--r--drivers/mtd/ubi/wl.c25
3 files changed, 28 insertions, 3 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 5953e36bce..617c63e5ac 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -668,7 +668,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
* checks @ubi->thread_enabled. Otherwise we may fail to wake it up.
*/
ubi->thread_enabled = 1;
- wake_up_process(ubi->bgt_thread);
+
+ /* No threading, call ubi_thread directly */
+ ubi_thread(ubi);
ubi_devices[ubi_num] = ubi;
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 89e3347012..1f0ad386b4 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -788,7 +788,7 @@ int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum);
int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum);
int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai);
void ubi_wl_close(struct ubi_device *ubi);
-int ubi_thread(void *u);
+int ubi_thread(struct ubi_device *ubi);
struct ubi_wl_entry *ubi_wl_get_fm_peb(struct ubi_device *ubi, int anchor);
int ubi_wl_put_fm_peb(struct ubi_device *ubi, struct ubi_wl_entry *used_e,
int lnum, int torture);
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index f24c219819..a368bf9108 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -523,7 +523,7 @@ static void __schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk)
ubi->works_count += 1;
/* No threading in barebox, so do work synchronously */
- do_work(ubi);
+ ubi_thread(ubi);
}
/**
@@ -1329,6 +1329,29 @@ static void tree_destroy(struct ubi_device *ubi, struct rb_root *root)
}
/**
+ * ubi_thread - UBI background thread.
+ * @ubi: UBI device description object
+ *
+ * for barebox this is no thread, instead it's called synchronously from
+ * __schedule_ubi_work(). This is the place that makes sure all pending
+ * work is done.
+ */
+int ubi_thread(struct ubi_device *ubi)
+{
+ while (!list_empty(&ubi->works)) {
+ if (!ubi->thread_enabled)
+ return 0;
+
+ if (ubi->ro_mode)
+ return 0;
+
+ do_work(ubi);
+ }
+
+ return 0;
+}
+
+/**
* shutdown_work - shutdown all pending works.
* @ubi: UBI device description object
*/