mtd/fs/jffs2 erase.c, 1.59, 1.60 os-linux.h, 1.44, 1.45 wbuf.c, 1.66, 1.67

dbrown at infradead.org dbrown at infradead.org
Wed Jun 30 13:26:18 EDT 2004


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

Modified Files:
	erase.c os-linux.h wbuf.c 
Log Message:
Changes to NAND bad block marking behavior.


Index: erase.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/erase.c,v
retrieving revision 1.59
retrieving revision 1.60
diff -u -r1.59 -r1.60
--- erase.c	26 May 2004 12:28:12 -0000	1.59
+++ erase.c	30 Jun 2004 17:26:15 -0000	1.60
@@ -28,7 +28,7 @@
 #ifndef __ECOS
 static void jffs2_erase_callback(struct erase_info *);
 #endif
-static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
 static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
@@ -36,6 +36,7 @@
 void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
 	int ret;
+	uint32_t bad_offset;
 #ifdef __ECOS
        ret = jffs2_flash_erase(c, jeb);
        if (!ret) {
@@ -65,6 +66,7 @@
 	instr->len = c->sector_size;
 	instr->callback = jffs2_erase_callback;
 	instr->priv = (unsigned long)(&instr[1]);
+	instr->fail_addr = 0xffffffff;
 	
 	((struct erase_priv_struct *)instr->priv)->jeb = jeb;
 	((struct erase_priv_struct *)instr->priv)->c = c;
@@ -73,6 +75,7 @@
 	if (!ret)
 		return;
 
+	bad_offset = instr->fail_addr;
 	kfree(instr);
 #endif /* __ECOS */
 
@@ -94,7 +97,7 @@
 	else
 		printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret);
 
-	jffs2_erase_failed(c, jeb);
+	jffs2_erase_failed(c, jeb, bad_offset);
 }
 
 void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
@@ -162,16 +165,34 @@
 	jffs2_erase_pending_trigger(c);
 }
 
-static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset)
 {
-	 spin_lock(&c->erase_completion_lock);
-	 c->erasing_size -= c->sector_size;
-	 c->bad_size += c->sector_size;
-	 list_del(&jeb->list);
-	 list_add(&jeb->list, &c->bad_list);
-	 c->nr_erasing_blocks--;
-	 spin_unlock(&c->erase_completion_lock);
-	 wake_up(&c->erase_wait);
+	/* For NAND, if the failure did not occur at the device level for a
+	   specific physical page, don't bother updating the bad block table. */
+	if (jffs2_cleanmarker_oob(c) && (bad_offset != 0xffffffff)) {
+		/* We had a device-level failure to erase.  Let's see if we've
+		   failed too many times. */
+		if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) {
+			/* We'd like to give this block another try. */
+			spin_lock(&c->erase_completion_lock);
+			list_del(&jeb->list);
+			list_add(&jeb->list, &c->erase_pending_list);
+			c->erasing_size -= c->sector_size;
+			c->dirty_size += c->sector_size;
+			jeb->dirty_size = c->sector_size;
+			spin_unlock(&c->erase_completion_lock);
+			return;
+		}
+	}
+
+	spin_lock(&c->erase_completion_lock);
+	c->erasing_size -= c->sector_size;
+	c->bad_size += c->sector_size;
+	list_del(&jeb->list);
+	list_add(&jeb->list, &c->bad_list);
+	c->nr_erasing_blocks--;
+	spin_unlock(&c->erase_completion_lock);
+	wake_up(&c->erase_wait);
 }	 
 
 #ifndef __ECOS
@@ -181,7 +202,7 @@
 
 	if(instr->state != MTD_ERASE_DONE) {
 		printk(KERN_WARNING "Erase at 0x%08x finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", instr->addr, instr->state);
-		jffs2_erase_failed(priv->c, priv->jeb);
+		jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr);
 	} else {
 		jffs2_erase_succeeded(priv->c, priv->jeb);
 	}	
@@ -285,6 +306,7 @@
 	unsigned char *ebuf;
 	size_t retlen;
 	int ret;
+	uint32_t bad_offset;
 
 	if (!jffs2_cleanmarker_oob(c)) {
 		marker_ref = jffs2_alloc_raw_node_ref();
@@ -309,6 +331,8 @@
 			uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
 			int i;
 
+			bad_offset = ofs;
+
 			ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
 			if (ret) {
 				printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
@@ -322,22 +346,21 @@
 				/* It's OK. We know it's properly aligned */
 				unsigned long datum = *(unsigned long *)(&ebuf[i]);
 				if (datum + 1) {
-					printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, ofs + i);
+					bad_offset += i;
+					printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset);
 				bad: 
 					if (!jffs2_cleanmarker_oob(c))
 						jffs2_free_raw_node_ref(marker_ref);
-					else 
-						jffs2_write_nand_badblock( c ,jeb );
 					kfree(ebuf);
 				bad2:
 					spin_lock(&c->erase_completion_lock);
-					c->erasing_size -= c->sector_size;
-					c->bad_size += c->sector_size;
-
-					list_add_tail(&jeb->list, &c->bad_list);
-					c->nr_erasing_blocks--;
+					/* Stick it on a list (any list) so
+					   erase_failed can take it right off
+					   again.  Silly, but shouldn't happen
+					   often. */
+					list_add(&jeb->list, &c->erasing_list);
 					spin_unlock(&c->erase_completion_lock);
-					wake_up(&c->erase_wait);
+					jffs2_erase_failed(c, jeb, bad_offset);
 					return;
 				}
 			}
@@ -346,7 +369,9 @@
 		}
 		kfree(ebuf);
 	}
-					
+
+	bad_offset = jeb->offset;
+
 	/* Write the erase complete marker */	
 	D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset));
 	if (jffs2_cleanmarker_oob(c)) {

Index: os-linux.h
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/os-linux.h,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -r1.44 -r1.45
--- os-linux.h	26 May 2004 12:28:12 -0000	1.44
+++ os-linux.h	30 Jun 2004 17:26:15 -0000	1.45
@@ -105,7 +105,7 @@
 #define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf))
 #define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; })
 #define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; })
-#define jffs2_write_nand_badblock(c,jeb) do { ; } while(0)
+#define jffs2_write_nand_badblock(c,jeb,bad_offset) (1)
 #define jffs2_nand_flash_setup(c) (0)
 #define jffs2_nand_flash_cleanup(c) do {} while(0)
 #define jffs2_wbuf_dirty(c) (0)
@@ -130,7 +130,7 @@
 int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,int mode);
 int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
 void jffs2_wbuf_timeout(unsigned long data);
 void jffs2_wbuf_process(void *data);
 int jffs2_nand_flash_setup(struct jffs2_sb_info *c);

Index: wbuf.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/wbuf.c,v
retrieving revision 1.66
retrieving revision 1.67
diff -u -r1.66 -r1.67
--- wbuf.c	17 Jun 2004 17:09:10 -0000	1.66
+++ wbuf.c	30 Jun 2004 17:26:15 -0000	1.67
@@ -999,7 +999,7 @@
  * a bootloader or something like that.
  */
 
-int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset)
 {
 	int 	ret;
 
@@ -1007,13 +1007,17 @@
 	if( ++jeb->bad_count < MAX_ERASE_FAILURES)
 		return 0;
 
-	ret = c->mtd->block_markbad(c->mtd, jeb->offset);
+	if (!c->mtd->block_markbad)
+		return 1; // What else can we do?
+
+	D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Marking bad block at %08x\n", bad_offset));
+	ret = c->mtd->block_markbad(c->mtd, bad_offset);
 	
 	if (ret) {
 		D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
 		return ret;
 	}
-	return 0;
+	return 1;
 }
 
 #define NAND_JFFS2_OOB16_FSDALEN	8





More information about the linux-mtd-cvs mailing list