linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] UBI: ubi_eba_read_leb: Remove in vain variable assignment
@ 2014-09-22  8:45 Richard Weinberger
  2014-09-22  8:45 ` [PATCH 2/3] UBI: wl: Rename cancel flag to shutdown Richard Weinberger
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Richard Weinberger @ 2014-09-22  8:45 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd, linux-kernel, Richard Weinberger

There is no need to set err, it will be overwritten in any case
later at:
        if (scrub)
                err = ubi_wl_scrub_peb(ubi, pnum);

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/ubi/eba.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 0e11671d..2402d3b 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -441,10 +441,9 @@ retry:
 
 	err = ubi_io_read_data(ubi, buf, pnum, offset, len);
 	if (err) {
-		if (err == UBI_IO_BITFLIPS) {
+		if (err == UBI_IO_BITFLIPS)
 			scrub = 1;
-			err = 0;
-		} else if (mtd_is_eccerr(err)) {
+		else if (mtd_is_eccerr(err)) {
 			if (vol->vol_type == UBI_DYNAMIC_VOLUME)
 				goto out_unlock;
 			scrub = 1;
-- 
1.8.4.5


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/3] UBI: wl: Rename cancel flag to shutdown
  2014-09-22  8:45 [PATCH 1/3] UBI: ubi_eba_read_leb: Remove in vain variable assignment Richard Weinberger
@ 2014-09-22  8:45 ` Richard Weinberger
  2014-09-22  8:45 ` [PATCH 3/3] UBI: Fix possible deadlock in erase_worker() Richard Weinberger
  2014-09-26 10:46 ` [PATCH 1/3] UBI: ubi_eba_read_leb: Remove in vain variable assignment Artem Bityutskiy
  2 siblings, 0 replies; 6+ messages in thread
From: Richard Weinberger @ 2014-09-22  8:45 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd, linux-kernel, Richard Weinberger

It confused me more than once that the cancel flag of the
work function does not indicate the cancellation of a single work.
In fact it indicates the WL sub-system shutdown and therefore
worker functions have to free their wl_entries too.
That's why you cannot cancel a single work, you can only shutdown
all works.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/ubi/ubi.h |  9 +++++----
 drivers/mtd/ubi/wl.c  | 24 +++++++++++++-----------
 2 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 7bf4163..7dad704 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -713,14 +713,15 @@ struct ubi_attach_info {
  * @torture: if the physical eraseblock has to be tortured
  * @anchor: produce a anchor PEB to by used by fastmap
  *
- * The @func pointer points to the worker function. If the @cancel argument is
- * not zero, the worker has to free the resources and exit immediately. The
- * worker has to return zero in case of success and a negative error code in
+ * The @func pointer points to the worker function. If the @shutdown argument is
+ * not zero, the worker has to free the resources and exit immediately as the
+ * WL sub-system is shutting down.
+ * The worker has to return zero in case of success and a negative error code in
  * case of failure.
  */
 struct ubi_work {
 	struct list_head list;
-	int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel);
+	int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int shutdown);
 	/* The below fields are only relevant to erasure works */
 	struct ubi_wl_entry *e;
 	int vol_id;
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 20f4917..253ec9b 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -864,7 +864,7 @@ static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk)
 }
 
 static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
-			int cancel);
+			int shutdown);
 
 #ifdef CONFIG_MTD_UBI_FASTMAP
 /**
@@ -990,14 +990,15 @@ int ubi_wl_put_fm_peb(struct ubi_device *ubi, struct ubi_wl_entry *fm_e,
  * wear_leveling_worker - wear-leveling worker function.
  * @ubi: UBI device description object
  * @wrk: the work object
- * @cancel: non-zero if the worker has to free memory and exit
+ * @shutdown: non-zero if the worker has to free memory and exit
+ * because the WL-subsystem is shutting down
  *
  * This function copies a more worn out physical eraseblock to a less worn out
  * one. Returns zero in case of success and a negative error code in case of
  * failure.
  */
 static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
-				int cancel)
+				int shutdown)
 {
 	int err, scrubbing = 0, torture = 0, protect = 0, erroneous = 0;
 	int vol_id = -1, uninitialized_var(lnum);
@@ -1008,7 +1009,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
 	struct ubi_vid_hdr *vid_hdr;
 
 	kfree(wrk);
-	if (cancel)
+	if (shutdown)
 		return 0;
 
 	vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
@@ -1407,7 +1408,8 @@ int ubi_ensure_anchor_pebs(struct ubi_device *ubi)
  * erase_worker - physical eraseblock erase worker function.
  * @ubi: UBI device description object
  * @wl_wrk: the work object
- * @cancel: non-zero if the worker has to free memory and exit
+ * @shutdown: non-zero if the worker has to free memory and exit
+ * because the WL sub-system is shutting down
  *
  * This function erases a physical eraseblock and perform torture testing if
  * needed. It also takes care about marking the physical eraseblock bad if
@@ -1415,7 +1417,7 @@ int ubi_ensure_anchor_pebs(struct ubi_device *ubi)
  * failure.
  */
 static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
-			int cancel)
+			int shutdown)
 {
 	struct ubi_wl_entry *e = wl_wrk->e;
 	int pnum = e->pnum;
@@ -1423,7 +1425,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
 	int lnum = wl_wrk->lnum;
 	int err, available_consumed = 0;
 
-	if (cancel) {
+	if (shutdown) {
 		dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
 		kfree(wl_wrk);
 		kmem_cache_free(ubi_wl_entry_slab, e);
@@ -1845,10 +1847,10 @@ int ubi_thread(void *u)
 }
 
 /**
- * cancel_pending - cancel all pending works.
+ * shutdown_work - shutdown all pending works.
  * @ubi: UBI device description object
  */
-static void cancel_pending(struct ubi_device *ubi)
+static void shutdown_work(struct ubi_device *ubi)
 {
 	while (!list_empty(&ubi->works)) {
 		struct ubi_work *wrk;
@@ -1997,7 +1999,7 @@ int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
 	return 0;
 
 out_free:
-	cancel_pending(ubi);
+	shutdown_work(ubi);
 	tree_destroy(&ubi->used);
 	tree_destroy(&ubi->free);
 	tree_destroy(&ubi->scrub);
@@ -2029,7 +2031,7 @@ static void protection_queue_destroy(struct ubi_device *ubi)
 void ubi_wl_close(struct ubi_device *ubi)
 {
 	dbg_wl("close the WL sub-system");
-	cancel_pending(ubi);
+	shutdown_work(ubi);
 	protection_queue_destroy(ubi);
 	tree_destroy(&ubi->used);
 	tree_destroy(&ubi->erroneous);
-- 
1.8.4.5


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/3] UBI: Fix possible deadlock in erase_worker()
  2014-09-22  8:45 [PATCH 1/3] UBI: ubi_eba_read_leb: Remove in vain variable assignment Richard Weinberger
  2014-09-22  8:45 ` [PATCH 2/3] UBI: wl: Rename cancel flag to shutdown Richard Weinberger
@ 2014-09-22  8:45 ` Richard Weinberger
  2014-09-26 10:40   ` Artem Bityutskiy
  2014-09-26 10:46 ` [PATCH 1/3] UBI: ubi_eba_read_leb: Remove in vain variable assignment Artem Bityutskiy
  2 siblings, 1 reply; 6+ messages in thread
From: Richard Weinberger @ 2014-09-22  8:45 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd, linux-kernel, Richard Weinberger

If sync_erase() fails with EINTR, ENOMEM, EAGAIN or
EBUSY erase_worker() re-schedules the failed work.
This will lead to a deadlock because erase_worker() is called
with work_sem held in read mode. And schedule_erase() will take
this lock again.

Signed-off-by: Richard Weinberger <richard@nod.at>
---
 drivers/mtd/ubi/wl.c | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 253ec9b..637ffff 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1421,8 +1421,6 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
 {
 	struct ubi_wl_entry *e = wl_wrk->e;
 	int pnum = e->pnum;
-	int vol_id = wl_wrk->vol_id;
-	int lnum = wl_wrk->lnum;
 	int err, available_consumed = 0;
 
 	if (shutdown) {
@@ -1459,21 +1457,15 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
 	}
 
 	ubi_err("failed to erase PEB %d, error %d", pnum, err);
-	kfree(wl_wrk);
 
 	if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
 	    err == -EBUSY) {
-		int err1;
-
 		/* Re-schedule the LEB for erasure */
-		err1 = schedule_erase(ubi, e, vol_id, lnum, 0);
-		if (err1) {
-			err = err1;
-			goto out_ro;
-		}
+		__schedule_ubi_work(ubi, wl_wrk);
 		return err;
 	}
 
+	kfree(wl_wrk);
 	kmem_cache_free(ubi_wl_entry_slab, e);
 	if (err != -EIO)
 		/*
-- 
1.8.4.5


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] UBI: Fix possible deadlock in erase_worker()
  2014-09-22  8:45 ` [PATCH 3/3] UBI: Fix possible deadlock in erase_worker() Richard Weinberger
@ 2014-09-26 10:40   ` Artem Bityutskiy
  2014-09-29 22:22     ` Richard Weinberger
  0 siblings, 1 reply; 6+ messages in thread
From: Artem Bityutskiy @ 2014-09-26 10:40 UTC (permalink / raw)
  To: Richard Weinberger; +Cc: linux-mtd, linux-kernel

On Mon, 2014-09-22 at 10:45 +0200, Richard Weinberger wrote:
> If sync_erase() fails with EINTR, ENOMEM, EAGAIN or
> EBUSY erase_worker() re-schedules the failed work.
> This will lead to a deadlock because erase_worker() is called
> with work_sem held in read mode. And schedule_erase() will take
> this lock again.
> 
> Signed-off-by: Richard Weinberger <richard@nod.at>

Did you manage to test it?

Why no -stable this time? Not that important, or just something
theoretical and you never actually hit this bug?

Thanks!

-- 
Best Regards,
Artem Bityutskiy


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/3] UBI: ubi_eba_read_leb: Remove in vain variable assignment
  2014-09-22  8:45 [PATCH 1/3] UBI: ubi_eba_read_leb: Remove in vain variable assignment Richard Weinberger
  2014-09-22  8:45 ` [PATCH 2/3] UBI: wl: Rename cancel flag to shutdown Richard Weinberger
  2014-09-22  8:45 ` [PATCH 3/3] UBI: Fix possible deadlock in erase_worker() Richard Weinberger
@ 2014-09-26 10:46 ` Artem Bityutskiy
  2 siblings, 0 replies; 6+ messages in thread
From: Artem Bityutskiy @ 2014-09-26 10:46 UTC (permalink / raw)
  To: Richard Weinberger; +Cc: linux-mtd, linux-kernel

On Mon, 2014-09-22 at 10:45 +0200, Richard Weinberger wrote:
> There is no need to set err, it will be overwritten in any case
> later at:
>         if (scrub)
>                 err = ubi_wl_scrub_peb(ubi, pnum);
> 
> Signed-off-by: Richard Weinberger <richard@nod.at>

Pushed the first 2 patches, thanks!

-- 
Best Regards,
Artem Bityutskiy


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] UBI: Fix possible deadlock in erase_worker()
  2014-09-26 10:40   ` Artem Bityutskiy
@ 2014-09-29 22:22     ` Richard Weinberger
  0 siblings, 0 replies; 6+ messages in thread
From: Richard Weinberger @ 2014-09-29 22:22 UTC (permalink / raw)
  To: dedekind1; +Cc: linux-mtd, linux-kernel

Am 26.09.2014 12:40, schrieb Artem Bityutskiy:
> On Mon, 2014-09-22 at 10:45 +0200, Richard Weinberger wrote:
>> If sync_erase() fails with EINTR, ENOMEM, EAGAIN or
>> EBUSY erase_worker() re-schedules the failed work.
>> This will lead to a deadlock because erase_worker() is called
>> with work_sem held in read mode. And schedule_erase() will take
>> this lock again.
>>
>> Signed-off-by: Richard Weinberger <richard@nod.at>
> 
> Did you manage to test it?
> 
> Why no -stable this time? Not that important, or just something
> theoretical and you never actually hit this bug?

It is something theoretical, I was only able to trigger it by injecting
ENOMEM by hand.

Thanks,
//richard

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-09-29 22:22 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-22  8:45 [PATCH 1/3] UBI: ubi_eba_read_leb: Remove in vain variable assignment Richard Weinberger
2014-09-22  8:45 ` [PATCH 2/3] UBI: wl: Rename cancel flag to shutdown Richard Weinberger
2014-09-22  8:45 ` [PATCH 3/3] UBI: Fix possible deadlock in erase_worker() Richard Weinberger
2014-09-26 10:40   ` Artem Bityutskiy
2014-09-29 22:22     ` Richard Weinberger
2014-09-26 10:46 ` [PATCH 1/3] UBI: ubi_eba_read_leb: Remove in vain variable assignment Artem Bityutskiy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).