mtd/fs/jffs3 wbuf.c,3.10,3.11

hammache at infradead.org hammache at infradead.org
Mon Jan 24 16:27:02 EST 2005


Update of /home/cvs/mtd/fs/jffs3
In directory phoenix.infradead.org:/tmp/cvs-serv25838/mtd/fs/jffs3

Modified Files:
	wbuf.c 
Log Message:
JFFS3 and NAND failure:
- block refiling when writing directly to flash a buffer
which is bigger than wbuf
- retry cases for flushing wbuf


Index: wbuf.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs3/wbuf.c,v
retrieving revision 3.10
retrieving revision 3.11
diff -u -r3.10 -r3.11
--- wbuf.c	21 Jan 2005 10:55:42 -0000	3.10
+++ wbuf.c	24 Jan 2005 21:26:59 -0000	3.11
@@ -124,7 +124,10 @@
 	}
 }
 
-static void jffs3_block_refile(struct jffs3_sb_info *c, struct jffs3_eraseblock *jeb)
+#define REFILE_NOTEMPTY 0
+#define REFILE_ANYWAY   1
+
+static void jffs3_block_refile(struct jffs3_sb_info *c, struct jffs3_eraseblock *jeb, int allow_empty)
 {
 	DBG_WBUF(1, "About to refile bad block at %08x\n", jeb->offset);
 
@@ -141,7 +144,8 @@
 		DBG_WBUF(1, "Refiling block at %08x to bad_used_list\n", jeb->offset);
 		list_add(&jeb->list, &c->bad_used_list);
 	} else {
-		BUG();
+		if (allow_empty == REFILE_NOTEMPTY)
+			BUG();
 		/* It has to have had some nodes or we couldn't be here */
 		DBG_WBUF(1, "Refiling block at %08x to erase_pending_list\n", jeb->offset);
 		list_add(&jeb->list, &c->erase_pending_list);
@@ -180,7 +184,7 @@
 
 	jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
 
-	jffs3_block_refile(c, jeb);
+	jffs3_block_refile(c, jeb, REFILE_NOTEMPTY);
 
 	/* Find the first node to be recovered, by skipping over every
 	   node which ends before the wbuf starts, or which is obsolete. */
@@ -268,12 +272,12 @@
 		return;
 	}
 	if (end-start >= c->wbuf_pagesize) {
-		/* Need to do another write immediately. This, btw,
-		 means that we'll be writing from 'buf' and not from
-		 the wbuf. Since if we're writing from the wbuf there
-		 won't be more than a wbuf full of data, now will
-		 there? :) */
-
+		/* Need to do another write immediately, but it's possible
+		that this is just because the wbuf itself is completely
+		full, and there's nothing earlier read back from the 
+		flash. Hence 'buf' isn't necessarily what we're writing 
+		from. */
+		unsigned char *rewrite_buf = buf?:c->wbuf;
 		uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize);
 
 		DBG_WBUF(1, "Write 0x%x bytes at 0x%08x in wbuf recover\n",
@@ -281,14 +285,15 @@
 
 		if (jffs3_cleanmarker_oob(c))
 			ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
-						buf, NULL, c->oobinfo);
+						rewrite_buf, NULL, c->oobinfo);
 		else
-			ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, buf);
+			ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf);
 
 		if (ret || retlen != towrite) {
 			/* Argh. We tried. Really we did. */
 			WARNING_MSG("Recovery of wbuf failed due to a second write error\n");
-			kfree(buf);
+			if (buf)
+				kfree(buf);
 
 			if (retlen) {
 				struct jffs3_raw_node_ref *raw2;
@@ -313,10 +318,10 @@
 
 		c->wbuf_len = (end - start) - towrite;
 		c->wbuf_ofs = ofs + towrite;
-		memcpy(c->wbuf, buf + towrite, c->wbuf_len);
+		memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len);
 		/* Don't muck about with c->wbuf_inodes. False positives are harmless. */
-
-		kfree(buf);
+		if (buf)
+			kfree(buf);
 	} else {
 		/* OK, now we're left with the dregs in whichever buffer we're using */
 		if (buf) {
@@ -530,6 +535,12 @@
 		DBG_WBUF(1, "Padding. Not finished checking\n");
 		down_write(&c->wbuf_sem);
 		ret = __jffs3_flush_wbuf(c, PAD_ACCOUNTING);
+		/* retry flushing wbuf in case jffs3_wbuf_recover
+		   left some data in the wbuf */
+		if (ret)
+		{
+			ret = __jffs3_flush_wbuf(c, PAD_ACCOUNTING);
+		}
 		up_write(&c->wbuf_sem);
 	} else while (old_wbuf_len &&
 		      old_wbuf_ofs == c->wbuf_ofs) {
@@ -544,6 +555,12 @@
 			down(&c->alloc_sem);
 			down_write(&c->wbuf_sem);
 			ret = __jffs3_flush_wbuf(c, PAD_ACCOUNTING);
+			/* retry flushing wbuf in case jffs3_wbuf_recover
+			   left some data in the wbuf */
+			if (ret)
+			{
+				ret = __jffs3_flush_wbuf(c, PAD_ACCOUNTING);
+			}
 			up_write(&c->wbuf_sem);
 			break;
 		}
@@ -563,6 +580,9 @@
 
 	down_write(&c->wbuf_sem);
 	ret = __jffs3_flush_wbuf(c, PAD_NOACCOUNT);
+	/* retry - maybe wbuf recover left some data in wbuf. */
+	if (ret)
+		ret = __jffs3_flush_wbuf(c, PAD_NOACCOUNT);
 	up_write(&c->wbuf_sem);
 
 	return ret;
@@ -746,9 +766,19 @@
 
 		if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
 			/* At this point we have no problem,
-			   c->wbuf is empty.
+			   c->wbuf is empty. However refile nextblock to avoid
+			   writing again to same address.
 			*/
-			*retlen = donelen;
+			struct jffs3_eraseblock *jeb;
+
+			spin_lock(&c->erase_completion_lock);
+
+			jeb = &c->blocks[outvec_to / c->sector_size];
+			jffs3_block_refile(c, jeb, REFILE_ANYWAY);
+
+			*retlen = 0;
+			spin_unlock(&c->erase_completion_lock);
+
 			goto exit;
 		}
 





More information about the linux-mtd-cvs mailing list