mtd/fs/jffs2 background.c,1.24,1.25 build.c,1.33,1.34 gc.c,1.70,1.71 nodelist.h,1.70,1.71 nodemgmt.c,1.66,1.67 scan.c,1.73,1.74

David Woodhouse dwmw2 at infradead.org
Fri May 10 17:09:06 EDT 2002


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

Modified Files:
	background.c build.c gc.c nodelist.h nodemgmt.c scan.c 
Log Message:
Add new very_dirty_list for blocks with more than 50% dirty space. We favour this
list over the normal dirty_list in picking blocks to GC from. This means GC is
_far_ more likely to actually make progress. We might want to add a 
'slightly_dirty_list' too, for blocks with less than 25% or something.

I don't want to sort the node lists because that screws up the randomness that we
want for wear levelling purposes -- we sometimes _do_ pick blocks from all lists
and sorting the lists would make this a pain. Perhaps we could have a single sorted
list but pick a block from <N> items into the list, where N is a pseudo-random number
suitably weighted to favour blocks near the start of the list?


Index: background.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/background.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- background.c	28 Apr 2002 13:43:03 -0000	1.24
+++ background.c	10 May 2002 21:09:03 -0000	1.25
@@ -178,10 +178,18 @@
 
 static int thread_should_wake(struct jffs2_sb_info *c)
 {
-	D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x\n", 
-		  c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size));
+	uint32_t gcnodeofs = 0;
+
+	/* Don't count any progress we've already made through the gcblock
+	   as dirty space, for the purposes of this calculation */
+	if (c->gcblock && c->gcblock->gc_node)
+		gcnodeofs = c->gcblock->gc_node->flash_offset & ~3 & (c->sector_size-1);
+
+	D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x (mod 0x%x\n", 
+		  c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size,
+		  c->dirty_size - gcnodeofs));
 	if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER &&
-	    c->dirty_size > c->sector_size)
+	    (c->dirty_size - gcnodeofs) > c->sector_size)
 		return 1;
 	else 
 		return 0;

Index: build.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/build.c,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -r1.33 -r1.34
--- build.c	15 Mar 2002 11:00:36 -0000	1.33
+++ build.c	10 May 2002 21:09:03 -0000	1.34
@@ -307,6 +307,7 @@
 	spin_lock_init(&c->inocache_lock);
 
 	INIT_LIST_HEAD(&c->clean_list);
+	INIT_LIST_HEAD(&c->very_dirty_list);
 	INIT_LIST_HEAD(&c->dirty_list);
 	INIT_LIST_HEAD(&c->erasable_list);
 	INIT_LIST_HEAD(&c->erasing_list);

Index: gc.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/gc.c,v
retrieving revision 1.70
retrieving revision 1.71
diff -u -r1.70 -r1.71
--- gc.c	10 May 2002 19:14:46 -0000	1.70
+++ gc.c	10 May 2002 21:09:03 -0000	1.71
@@ -75,8 +75,11 @@
 		   So don't favour the erasable_list _too_ much. */
 		D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next\n"));
 		nextlist = &c->erasable_list;
+	} else if (n < 110 && !list_empty(&c->very_dirty_list)) {
+		/* Most of the time, pick one off the very_dirty list */
+		D1(printk(KERN_DEBUG "Picking block from very_dirty_list to GC next\n"));
+		nextlist = &c->very_dirty_list;
 	} else if (n < 126 && !list_empty(&c->dirty_list)) {
-		/* Most of the time, pick one off the dirty list */
 		D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next\n"));
 		nextlist = &c->dirty_list;
 	} else if (!list_empty(&c->clean_list)) {
@@ -86,12 +89,15 @@
 		D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next (clean_list was empty)\n"));
 
 		nextlist = &c->dirty_list;
+	} else if (!list_empty(&c->very_dirty_list)) {
+		D1(printk(KERN_DEBUG "Picking block from very_dirty_list to GC next (clean_list and dirty_list were empty)\n"));
+		nextlist = &c->very_dirty_list;
 	} else if (!list_empty(&c->erasable_list)) {
-		D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and dirty_list were empty)\n"));
+		D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n"));
 
 		nextlist = &c->erasable_list;
 	} else {
-		/* Eep. Both were empty */
+		/* Eep. All were empty */
 		printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n");
 		return NULL;
 	}
@@ -104,7 +110,7 @@
 		printk(KERN_WARNING "Eep. ret->gc_node for block at 0x%08x is NULL\n", ret->offset);
 		BUG();
 	}
-	D1(printk("Picked block at %08x, used_size %08x, dirty_size %08x, free_size %08x\n", ret->offset, ret->used_size, ret->dirty_size, ret->free_size));
+
 	D1(jffs2_dump_block_lists(c));
 	return ret;
 }
@@ -144,7 +150,9 @@
 		return -EIO;
 	}
 
-	D1(printk(KERN_DEBUG "garbage collect from block at phys 0x%08x\n", jeb->offset));
+	D1(printk(KERN_DEBUG "GC from block %08x, used_size %08x, dirty_size %08x, free_size %08x\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size));
+	D1(if (c->nextblock)
+	   printk(KERN_DEBUG "Nextblock at  %08x, used_size %08x, dirty_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->free_size));
 
 	if (!jeb->used_size)
 		goto eraseit;

Index: nodelist.h
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/nodelist.h,v
retrieving revision 1.70
retrieving revision 1.71
diff -u -r1.70 -r1.71
--- nodelist.h	10 May 2002 19:14:46 -0000	1.70
+++ nodelist.h	10 May 2002 21:09:03 -0000	1.71
@@ -240,6 +240,9 @@
 #define JFFS2_RESERVED_BLOCKS_GCMERGE (JFFS2_RESERVED_BLOCKS_BASE)		/* ... merge pages when garbage collecting */
 
 
+/* How much dirty space before it goes on the very_dirty_list */
+#define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2))
+
 #define PAD(x) (((x)+3)&~3)
 
 static inline int jffs2_raw_ref_to_inum(struct jffs2_raw_node_ref *raw)

Index: nodemgmt.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/nodemgmt.c,v
retrieving revision 1.66
retrieving revision 1.67
diff -u -r1.66 -r1.67
--- nodemgmt.c	10 May 2002 19:14:46 -0000	1.66
+++ nodemgmt.c	10 May 2002 21:09:03 -0000	1.67
@@ -158,9 +158,15 @@
 		c->free_size -= jeb->free_size;
 		jeb->dirty_size += jeb->free_size;
 		jeb->free_size = 0;
-		D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
+		if (VERYDIRTY(c, jeb->dirty_size)) {
+			D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
 			  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
-		list_add_tail(&jeb->list, &c->dirty_list);
+			list_add_tail(&jeb->list, &c->very_dirty_list);
+		} else {
+			D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
+			  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
+			list_add_tail(&jeb->list, &c->dirty_list);
+		}
 		c->nextblock = jeb = NULL;
 	}
 	
@@ -442,6 +448,12 @@
 		list_del(&jeb->list);
 		D1(printk(KERN_DEBUG "...and adding to dirty_list\n"));
 		list_add_tail(&jeb->list, &c->dirty_list);
+	} else if (VERYDIRTY(c, jeb->dirty_size) &&
+		   !VERYDIRTY(c, jeb->dirty_size - ref->totlen)) {
+		D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is now very dirty. Removing from dirty list...\n", jeb->offset));
+		list_del(&jeb->list);
+		D1(printk(KERN_DEBUG "...and adding to very_dirty_list\n"));
+		list_add_tail(&jeb->list, &c->very_dirty_list);
 	}
 
 	spin_unlock_bh(&c->erase_completion_lock);
@@ -480,6 +492,7 @@
 		return;
 	}
 }
+
 #if CONFIG_JFFS2_FS_DEBUG > 0
 void jffs2_dump_block_lists(struct jffs2_sb_info *c)
 {
@@ -511,6 +524,16 @@
 		list_for_each(this, &c->clean_list) {
 			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
 			printk(KERN_DEBUG "clean_list: %08x (used %08x, dirty %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size);
+		}
+	}
+	if (list_empty(&c->very_dirty_list)) {
+		printk(KERN_DEBUG "very_dirty_list: empty\n");
+	} else {
+		struct list_head *this;
+
+		list_for_each(this, &c->very_dirty_list) {
+			struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+			printk(KERN_DEBUG "very_dirty_list: %08x (used %08x, dirty %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size);
 		}
 	}
 	if (list_empty(&c->dirty_list)) {

Index: scan.c
===================================================================
RCS file: /home/cvs/mtd/fs/jffs2/scan.c,v
retrieving revision 1.73
retrieving revision 1.74
diff -u -r1.73 -r1.74
--- scan.c	28 Mar 2002 09:58:11 -0000	1.73
+++ scan.c	10 May 2002 21:09:03 -0000	1.74
@@ -143,11 +143,20 @@
 			    (jffs2_can_mark_obsolete(c) || jeb->free_size > c->wbuf_pagesize) &&
 			    (!c->nextblock || c->nextblock->free_size < jeb->free_size)) {
                                 /* Better candidate for the next writes to go to */
-                                if (c->nextblock) 
-					list_add(&c->nextblock->list, &c->dirty_list);
+                                if (c->nextblock) {
+					if (VERYDIRTY(c, c->nextblock->dirty_size)) {
+						list_add(&c->nextblock->list, &c->very_dirty_list);
+					} else {
+						list_add(&c->nextblock->list, &c->dirty_list);
+					}
+				}
                                 c->nextblock = jeb;
                         } else {
-				list_add(&jeb->list, &c->dirty_list);
+				if (VERYDIRTY(c, jeb->dirty_size)) {
+					list_add(&jeb->list, &c->very_dirty_list);
+				} else {
+					list_add(&jeb->list, &c->dirty_list);
+				}
                         }
 			break;
 
@@ -846,6 +855,19 @@
 			  list_entry(c->clean_list.next, struct jffs2_eraseblock, list)->offset));
 	} else {
 		D1(printk(KERN_DEBUG "Not rotating empty clean_list\n"));
+	}
+
+	x = count_list(&c->very_dirty_list);
+	if (x) {
+		rotateby = pseudo_random % x;
+		D1(printk(KERN_DEBUG "Rotating very_dirty_list by %d\n", rotateby));
+
+		rotate_list((&c->very_dirty_list), rotateby);
+
+		D1(printk(KERN_DEBUG "Erase block at front of very_dirty_list is at %08x\n",
+			  list_entry(c->very_dirty_list.next, struct jffs2_eraseblock, list)->offset));
+	} else {
+		D1(printk(KERN_DEBUG "Not rotating empty very_dirty_list\n"));
 	}
 
 	x = count_list(&c->dirty_list);





More information about the linux-mtd-cvs mailing list