]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
[MTD] [NOR] fix cfi_cmdset_0001 FL_SYNCING race (take 2)
authorAlexander Belyakov <abelyako@mail.ru>
Thu, 25 Sep 2008 13:53:24 +0000 (17:53 +0400)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Sat, 27 Sep 2008 00:56:18 +0000 (18:56 -0600)
The patch fixes CFI issue with multipartitional devices leading to the
set of errors or even deadlock. The problem is CFI FL_SYNCING state race
with flash operations (e.g. erase suspend). It is reproduced by running
intensive writes on one JFFS2 partition and simultaneously performing
mount/unmount cycle on another partition of the same chip.

Signed-off-by: Alexander Belyakov <abelyako@googlemail.com>
Acked-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
drivers/mtd/chips/cfi_cmdset_0001.c

index 5157e3cb4b9e73f13609baf126ef6a40561c3beb..c93a8be5d5f1f541e96c6e104d5d10f4997bf451 100644 (file)
@@ -725,6 +725,10 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
        struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
        unsigned long timeo = jiffies + HZ;
 
+       /* Prevent setting state FL_SYNCING for chip in suspended state. */
+       if (mode == FL_SYNCING && chip->oldstate != FL_READY)
+               goto sleep;
+
        switch (chip->state) {
 
        case FL_STATUS:
@@ -830,8 +834,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
        DECLARE_WAITQUEUE(wait, current);
 
  retry:
-       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING
-                          || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) {
+       if (chip->priv &&
+           (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE
+           || mode == FL_SHUTDOWN) && chip->state != FL_SYNCING) {
                /*
                 * OK. We have possibility for contention on the write/erase
                 * operations which are global to the real chip and not per
@@ -881,6 +886,14 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                                return ret;
                        }
                        spin_lock(&shared->lock);
+
+                       /* We should not own chip if it is already
+                        * in FL_SYNCING state. Put contender and retry. */
+                       if (chip->state == FL_SYNCING) {
+                               put_chip(map, contender, contender->start);
+                               spin_unlock(contender->mutex);
+                               goto retry;
+                       }
                        spin_unlock(contender->mutex);
                }