[MTD] [NOR] fix cfi_cmdset_0001 FL_SYNCING race (take 2)

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Fri Sep 26 20:59:02 EDT 2008


Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=3afe7eb37f4d47f31d30a81c1b42ca02eab01e44
Commit:     3afe7eb37f4d47f31d30a81c1b42ca02eab01e44
Parent:     ef89a8801321e0d0665c327c9d77d602ef764c87
Author:     Alexander Belyakov <abelyako at mail.ru>
AuthorDate: Thu Sep 25 17:53:24 2008 +0400
Committer:  David Woodhouse <David.Woodhouse at intel.com>
CommitDate: Fri Sep 26 18:56:18 2008 -0600

    [MTD] [NOR] fix cfi_cmdset_0001 FL_SYNCING race (take 2)
    
    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 at googlemail.com>
    Acked-by: Nicolas Pitre <nico at cam.org>
    Signed-off-by: David Woodhouse <David.Woodhouse at intel.com>
---
 drivers/mtd/chips/cfi_cmdset_0001.c |   17 +++++++++++++++--
 1 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 5157e3c..c93a8be 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -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);
 		}
 



More information about the linux-mtd-cvs mailing list