mtd/fs/jffs2 erase.c,1.78,1.79

gleixner at infradead.org gleixner at infradead.org
Thu Jul 14 12:34:39 EDT 2005


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

Modified Files:
	erase.c 
Log Message:
[JFFS2] Fix node allocation leak

When the cleanmarker write failed, the allocated raw node was not
freed. 



Index: erase.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/erase.c,v
retrieving revision 1.78
retrieving revision 1.79
diff -u -r1.78 -r1.79
--- erase.c	14 Jul 2005 14:31:34 -0000	1.78
+++ erase.c	14 Jul 2005 16:34:35 -0000	1.79
@@ -300,20 +300,21 @@
 	jeb->last_node = NULL;
 }
 
-static int jffs2_block_is_erased(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *bad_offset)
+static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *bad_offset)
 {
 	void *ebuf;
 	uint32_t ofs;
 	size_t retlen;
-	int ret = 0;
+	int ret = -1;
 	
 	ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 	if (!ebuf) {
-		printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Assuming it worked\n", jeb->offset);
-		return 1; /* XXX: Not sure who came up with this policy.  If we don't get memory, we just assume the block actually is erased */
+		printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset);
+		return -EAGAIN;
 	}
 
 	D1(printk(KERN_DEBUG "Verifying erase at 0x%08x\n", jeb->offset));
+
 	for (ofs = jeb->offset; ofs < jeb->offset + c->sector_size; ) {
 		uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
 		int i;
@@ -341,7 +342,7 @@
 		ofs += readlen;
 		cond_resched();
 	}
-	ret = 1;
+	ret = 0;
 fail:
 	kfree(ebuf);
 	return ret;
@@ -354,45 +355,31 @@
 	int ret;
 	uint32_t bad_offset;
 
-	if (! jffs2_block_is_erased(c, jeb, &bad_offset))
-		goto bad2;
-
-	if (!jffs2_cleanmarker_oob(c)) {
-		marker_ref = jffs2_alloc_raw_node_ref();
-		if (!marker_ref) {
-			printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n");
-			/* Stick it back on the list from whence it came and come back later */
-			jffs2_erase_pending_trigger(c);
-			spin_lock(&c->erase_completion_lock);
-			list_add(&jeb->list, &c->erase_complete_list);
-			spin_unlock(&c->erase_completion_lock);
-			return;
-		}
+	switch (jffs2_block_check_erase(c, jeb, &bad_offset)) {
+	case -EAGAIN:	goto refile;
+	case -1:	goto filebad;
 	}
 
-	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)) {
+	bad_offset = jeb->offset;
 
-		if (jffs2_write_nand_cleanmarker(c, jeb))
-			goto bad2;
-			
-		jeb->first_node = jeb->last_node = NULL;
+	/* Cleanmarker in oob area or no cleanmarker at all ? */
+	if (jffs2_cleanmarker_oob(c) || c->cleanmarker_size == 0) {
 
-		jeb->free_size = c->sector_size;
-		jeb->used_size = 0;
-		jeb->dirty_size = 0;
-		jeb->wasted_size = 0;
-	} else if (c->cleanmarker_size == 0) {
-		jeb->first_node = jeb->last_node = NULL;
+		if (jffs2_cleanmarker_oob(c)) {
+			if (jffs2_write_nand_cleanmarker(c, jeb))
+				goto filebad;
+		}
 
+		jeb->first_node = jeb->last_node = NULL;
 		jeb->free_size = c->sector_size;
 		jeb->used_size = 0;
 		jeb->dirty_size = 0;
 		jeb->wasted_size = 0;
+
 	} else {
+
 		struct kvec vecs[1];
 		struct jffs2_unknown_node marker = {
 			.magic =	cpu_to_je16(JFFS2_MAGIC_BITMASK),
@@ -400,21 +387,28 @@
 			.totlen =	cpu_to_je32(c->cleanmarker_size)
 		};
 
+		marker_ref = jffs2_alloc_raw_node_ref();
+		if (!marker_ref) {
+			printk(KERN_WARNING "Failed to allocate raw node ref for clean marker. Refiling\n");
+			goto refile;
+		}
+
 		marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
 
 		vecs[0].iov_base = (unsigned char *) &marker;
 		vecs[0].iov_len = sizeof(marker);
 		ret = jffs2_flash_direct_writev(c, vecs, 1, jeb->offset, &retlen);
 		
-		if (ret) {
-			printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
-			       jeb->offset, ret);
-			goto bad2;
-		}
-		if (retlen != sizeof(marker)) {
-			printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n",
-			       jeb->offset, sizeof(marker), retlen);
-			goto bad2;
+		if (ret || retlen != sizeof(marker)) {
+			if (ret)
+				printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
+				       jeb->offset, ret);
+			else
+				printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n",
+				       jeb->offset, sizeof(marker), retlen);
+
+			jffs2_free_raw_node_ref(marker_ref);
+			goto filebad;
 		}
 
 		marker_ref->next_in_ino = NULL;
@@ -445,18 +439,20 @@
 	wake_up(&c->erase_wait);
 	return;
 
-bad_marker: 
-	if (!jffs2_cleanmarker_oob(c))
-		jffs2_free_raw_node_ref(marker_ref);
-bad2:
+filebad:
 	spin_lock(&c->erase_completion_lock);
-	/* Stick it on a list (any list) so
-	   erase_failed can take it right off
-	   again.  Silly, but shouldn't happen
-	   often. */
+	/* 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);
 	jffs2_erase_failed(c, jeb, bad_offset);
 	return;
-}
 
+refile:
+	/* Stick it back on the list from whence it came and come back later */
+	jffs2_erase_pending_trigger(c);
+	spin_lock(&c->erase_completion_lock);
+	list_add(&jeb->list, &c->erase_complete_list);
+	spin_unlock(&c->erase_completion_lock);
+	return;
+}





More information about the linux-mtd-cvs mailing list