UBI: fix missing scrub when there is a bit-flip
authorBhavesh Parekh <bparekh@nvidia.com>
Wed, 30 Nov 2011 12:13:42 +0000 (17:43 +0530)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 26 Jan 2012 01:24:37 +0000 (17:24 -0800)
commit e801e128b2200c40a0ec236cf2330b2586b6e05a upstream.

Under some cases, when scrubbing the PEB if we did not get the lock on
the PEB it fails to scrub. Add that PEB again to the scrub list

Artem: minor amendments.

Signed-off-by: Bhavesh Parekh <bparekh@nvidia.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/mtd/ubi/eba.c
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/wl.c

index 4be671815014ee3b054f2ba8f704781dfbc1f032..c696c9481c95674ebc3a9284487eab7e1dd2e24f 100644 (file)
@@ -1028,12 +1028,14 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
         * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are
         * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the
         * LEB is already locked, we just do not move it and return
-        * %MOVE_CANCEL_RACE, which means that UBI will re-try, but later.
+        * %MOVE_RETRY. Note, we do not return %MOVE_CANCEL_RACE here because
+        * we do not know the reasons of the contention - it may be just a
+        * normal I/O on this LEB, so we want to re-try.
         */
        err = leb_write_trylock(ubi, vol_id, lnum);
        if (err) {
                dbg_wl("contention on LEB %d:%d, cancel", vol_id, lnum);
-               return MOVE_CANCEL_RACE;
+               return MOVE_RETRY;
        }
 
        /*
index c6c22295898e97ef3fdbfa16fd4171ec650fb55a..bbfa88d459e03fbe7ca83b599ab51accb4fc5779 100644 (file)
@@ -121,6 +121,7 @@ enum {
  *                     PEB
  * MOVE_CANCEL_BITFLIPS: canceled because a bit-flip was detected in the
  *                       target PEB
+ * MOVE_RETRY: retry scrubbing the PEB
  */
 enum {
        MOVE_CANCEL_RACE = 1,
@@ -128,6 +129,7 @@ enum {
        MOVE_TARGET_RD_ERR,
        MOVE_TARGET_WR_ERR,
        MOVE_CANCEL_BITFLIPS,
+       MOVE_RETRY,
 };
 
 /**
index ff2c4956eeff0aa08bbe0e528151104dd04fba68..f268adeb95e5bbdd06145268ba41303ec739d05b 100644 (file)
@@ -792,7 +792,10 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                        protect = 1;
                        goto out_not_moved;
                }
-
+               if (err == MOVE_RETRY) {
+                       scrubbing = 1;
+                       goto out_not_moved;
+               }
                if (err == MOVE_CANCEL_BITFLIPS || err == MOVE_TARGET_WR_ERR ||
                    err == MOVE_TARGET_RD_ERR) {
                        /*