diff -Narup mtd2/fs/jffs2/build.c mtd/fs/jffs2/build.c
--- mtd2/fs/jffs2/build.c	2005-07-30 17:29:27.000000000 +0200
+++ mtd/fs/jffs2/build.c	2005-08-22 14:55:39.000000000 +0200
@@ -350,6 +350,10 @@ int jffs2_do_mount_fs(struct jffs2_sb_in
 	INIT_LIST_HEAD(&c->bad_list);
 	INIT_LIST_HEAD(&c->bad_used_list);
 	c->highest_ino = 1;
+	c->summary = NULL;
+
+	if (jffs2_sum_init(c))
+		return -ENOMEM;
 
 	if (jffs2_build_filesystem(c)) {
 		D1(printk(KERN_DEBUG "build_fs failed\n"));
@@ -357,11 +361,11 @@ int jffs2_do_mount_fs(struct jffs2_sb_in
 		jffs2_free_raw_node_refs(c);
 #ifndef __ECOS
 		if (c->mtd->flags & MTD_NO_VIRTBLOCKS) 
-                    vfree(c->blocks);
+			vfree(c->blocks);
 		else 
 #endif
-                    kfree(c->blocks);
-		
+			kfree(c->blocks);
+
 		return -EIO;
 	}
 
diff -Narup mtd2/fs/jffs2/dir.c mtd/fs/jffs2/dir.c
--- mtd2/fs/jffs2/dir.c	2005-08-17 15:46:22.000000000 +0200
+++ mtd/fs/jffs2/dir.c	2005-08-22 12:29:08.000000000 +0200
@@ -310,7 +310,8 @@ static int jffs2_symlink (struct inode *
 	 * Just the node will do for now, though 
 	 */
 	namelen = dentry->d_name.len;
-	ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen,
+				ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
 
 	if (ret) {
 		jffs2_free_raw_inode(ri);
@@ -370,7 +371,8 @@ static int jffs2_symlink (struct inode *
 	up(&f->sem);
 
 	jffs2_complete_reservation(c);
-	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+				ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
 	if (ret) {
 		/* Eep. */
 		jffs2_clear_inode(inode);
@@ -455,7 +457,8 @@ static int jffs2_mkdir (struct inode *di
 	 * Just the node will do for now, though 
 	 */
 	namelen = dentry->d_name.len;
-	ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
+	ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL,
+				JFFS2_SUMMARY_INODE_SIZE);
 
 	if (ret) {
 		jffs2_free_raw_inode(ri);
@@ -498,7 +501,8 @@ static int jffs2_mkdir (struct inode *di
 	up(&f->sem);
 
 	jffs2_complete_reservation(c);
-	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+				ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
 	if (ret) {
 		/* Eep. */
 		jffs2_clear_inode(inode);
@@ -607,7 +611,8 @@ static int jffs2_mknod (struct inode *di
 	 * Just the node will do for now, though 
 	 */
 	namelen = dentry->d_name.len;
-	ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen,
+				ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
 
 	if (ret) {
 		jffs2_free_raw_inode(ri);
@@ -652,7 +657,8 @@ static int jffs2_mknod (struct inode *di
 	up(&f->sem);
 
 	jffs2_complete_reservation(c);
-	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+				ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
 	if (ret) {
 		/* Eep. */
 		jffs2_clear_inode(inode);
diff -Narup mtd2/fs/jffs2/file.c mtd/fs/jffs2/file.c
--- mtd2/fs/jffs2/file.c	2005-07-06 14:13:09.000000000 +0200
+++ mtd/fs/jffs2/file.c	2005-08-22 12:29:08.000000000 +0200
@@ -137,7 +137,8 @@ static int jffs2_prepare_write (struct f
 		D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
 			  (unsigned int)inode->i_size, pageofs));
 
-		ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, ALLOC_NORMAL);
+		ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len,
+					ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
 		if (ret)
 			return ret;
 
diff -Narup mtd2/fs/jffs2/fs.c mtd/fs/jffs2/fs.c
--- mtd2/fs/jffs2/fs.c	2005-08-06 06:51:30.000000000 +0200
+++ mtd/fs/jffs2/fs.c	2005-08-22 12:29:08.000000000 +0200
@@ -74,7 +74,8 @@ static int jffs2_do_setattr (struct inod
 		return -ENOMEM;
 	}
 		
-	ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen,
+				ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
 	if (ret) {
 		jffs2_free_raw_inode(ri);
 		if (S_ISLNK(inode->i_mode & S_IFMT))
diff -Narup mtd2/fs/jffs2/gc.c mtd/fs/jffs2/gc.c
--- mtd2/fs/jffs2/gc.c	2005-08-17 15:46:22.000000000 +0200
+++ mtd/fs/jffs2/gc.c	2005-08-22 12:29:08.000000000 +0200
@@ -513,8 +513,11 @@ static int jffs2_garbage_collect_pristin
 	/* Ask for a small amount of space (or the totlen if smaller) because we
 	   don't want to force wastage of the end of a block if splitting would
 	   work. */
-	ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, 
-					      rawlen), &phys_ofs, &alloclen);
+	ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) +
+				JFFS2_MIN_DATA_LEN, rawlen), &phys_ofs, &alloclen, rawlen);
+				/* this is not the exact summary size of it,
+					it is only an upper estimation */
+
 	if (ret)
 		return ret;
 
@@ -622,7 +625,9 @@ static int jffs2_garbage_collect_pristin
 			jffs2_dbg_acct_sanity_check(c,jeb);
 			jffs2_dbg_acct_paranoia_check(c, jeb);
 
-			ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy);
+			ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy, rawlen);
+						/* this is not the exact summary size of it,
+							it is only an upper estimation */
 
 			if (!ret) {
 				D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));
@@ -701,7 +706,8 @@ static int jffs2_garbage_collect_metadat
 
 	}
 	
-	ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen);
+	ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen,
+				JFFS2_SUMMARY_INODE_SIZE);
 	if (ret) {
 		printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n",
 		       sizeof(ri)+ mdatalen, ret);
@@ -781,7 +787,8 @@ static int jffs2_garbage_collect_dirent(
 	rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8));
 	rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize));
 	
-	ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen);
+	ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen,
+				JFFS2_SUMMARY_DIRENT_SIZE(rd.nsize));
 	if (ret) {
 		printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n",
 		       sizeof(rd)+rd.nsize, ret);
@@ -994,7 +1001,8 @@ static int jffs2_garbage_collect_hole(st
 	ri.data_crc = cpu_to_je32(0);
 	ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
 
-	ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen);
+	ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen,
+				JFFS2_SUMMARY_INODE_SIZE);
 	if (ret) {
 		printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n",
 		       sizeof(ri), ret);
@@ -1219,7 +1227,8 @@ static int jffs2_garbage_collect_dnode(s
 		uint32_t cdatalen;
 		uint16_t comprtype = JFFS2_COMPR_NONE;
 
-		ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen);
+		ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs,
+					&alloclen, JFFS2_SUMMARY_INODE_SIZE);
 
 		if (ret) {
 			printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n",
@@ -1276,4 +1285,3 @@ static int jffs2_garbage_collect_dnode(s
 	jffs2_gc_release_page(c, pg_ptr, &pg);
 	return ret;
 }
-
diff -Narup mtd2/fs/jffs2/Makefile.common mtd/fs/jffs2/Makefile.common
--- mtd2/fs/jffs2/Makefile.common	2005-07-17 08:56:20.000000000 +0200
+++ mtd/fs/jffs2/Makefile.common	2005-08-22 12:29:08.000000000 +0200
@@ -15,3 +15,4 @@ jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER)	+= 
 jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
 jffs2-$(CONFIG_JFFS2_ZLIB)	+= compr_zlib.o
+jffs2-$(CONFIG_JFFS2_SUMMARY)   += summary.o
diff -Narup mtd2/fs/jffs2/nodelist.h mtd/fs/jffs2/nodelist.h
--- mtd2/fs/jffs2/nodelist.h	2005-08-17 15:46:23.000000000 +0200
+++ mtd/fs/jffs2/nodelist.h	2005-08-22 12:29:08.000000000 +0200
@@ -20,6 +20,7 @@
 #include <linux/jffs2.h>
 #include <linux/jffs2_fs_sb.h>
 #include <linux/jffs2_fs_i.h>
+#include "summary.h"
 
 #ifdef __ECOS
 #include "os-ecos.h"
@@ -321,8 +322,10 @@ int jffs2_add_older_frag_to_fragtree(str
 
 /* nodemgmt.c */
 int jffs2_thread_should_wake(struct jffs2_sb_info *c);
-int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio);
-int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len);
+int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
+			uint32_t *len, int prio, uint32_t sumsize);
+int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
+			uint32_t *len, uint32_t sumsize);
 int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new);
 void jffs2_complete_reservation(struct jffs2_sb_info *c);
 void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw);
@@ -381,6 +384,10 @@ char *jffs2_getlink(struct jffs2_sb_info
 /* scan.c */
 int jffs2_scan_medium(struct jffs2_sb_info *c);
 void jffs2_rotate_lists(struct jffs2_sb_info *c);
+int jffs2_fill_scan_buf(struct jffs2_sb_info *c, void *buf,
+				uint32_t ofs, uint32_t len);
+struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino);
+int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 
 /* build.c */
 int jffs2_do_mount_fs(struct jffs2_sb_info *c);
diff -Narup mtd2/fs/jffs2/nodemgmt.c mtd/fs/jffs2/nodemgmt.c
--- mtd2/fs/jffs2/nodemgmt.c	2005-07-20 17:32:28.000000000 +0200
+++ mtd/fs/jffs2/nodemgmt.c	2005-08-23 13:00:15.000000000 +0200
@@ -38,9 +38,11 @@
  *	for the requested allocation.
  */
 
-static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  uint32_t minsize, uint32_t *ofs, uint32_t *len);
+static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  uint32_t minsize,
+					uint32_t *ofs, uint32_t *len, uint32_t sumsize);
 
-int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio)
+int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
+			uint32_t *len, int prio, uint32_t sumsize)
 {
 	int ret = -EAGAIN;
 	int blocksneeded = c->resv_blocks_write;
@@ -129,7 +131,7 @@ int jffs2_reserve_space(struct jffs2_sb_
 			spin_lock(&c->erase_completion_lock);
 		}
 
-		ret = jffs2_do_reserve_space(c, minsize, ofs, len);
+		ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize);
 		if (ret) {
 			D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret));
 		}
@@ -140,7 +142,8 @@ int jffs2_reserve_space(struct jffs2_sb_
 	return ret;
 }
 
-int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len)
+int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
+			uint32_t *len, uint32_t sumsize)
 {
 	int ret = -EAGAIN;
 	minsize = PAD(minsize);
@@ -149,7 +152,7 @@ int jffs2_reserve_space_gc(struct jffs2_
 
 	spin_lock(&c->erase_completion_lock);
 	while(ret == -EAGAIN) {
-		ret = jffs2_do_reserve_space(c, minsize, ofs, len);
+		ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize);
 		if (ret) {
 		        D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
 		}
@@ -158,105 +161,183 @@ int jffs2_reserve_space_gc(struct jffs2_
 	return ret;
 }
 
-/* Called with alloc sem _and_ erase_completion_lock */
-static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  uint32_t minsize, uint32_t *ofs, uint32_t *len)
+
+/* Classify nextblock (clean, dirty of verydirty) and force to select an other one */
+
+static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
-	struct jffs2_eraseblock *jeb = c->nextblock;
+
+	/* Check, if we have a dirty block now, or if it was dirty already */
+	if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
+		c->dirty_size += jeb->wasted_size;
+		c->wasted_size -= jeb->wasted_size;
+		jeb->dirty_size += jeb->wasted_size;
+		jeb->wasted_size = 0;
+		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->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);
+		}
+	} else { 
+		D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_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->clean_list);
+	}
+	c->nextblock = NULL;
+
+	jffs2_sum_reset_collected(c->summary); /* reset collected summary */
+}
+
+/* Select a new jeb for nextblock */
+
+static int jffs2_find_nextblock(struct jffs2_sb_info *c)
+{
+	struct list_head *next;
 	
- restart:
-	if (jeb && minsize > jeb->free_size) {
-		/* Skip the end of this block and file it as having some dirty space */
-		/* If there's a pending write to it, flush now */
-		if (jffs2_wbuf_dirty(c)) {
+	/* Take the next block off the 'free' list */
+
+	if (list_empty(&c->free_list)) {
+
+		if (!c->nr_erasing_blocks &&
+			!list_empty(&c->erasable_list)) {
+			struct jffs2_eraseblock *ejeb;
+
+			ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list);
+			list_del(&ejeb->list);
+			list_add_tail(&ejeb->list, &c->erase_pending_list);
+			c->nr_erasing_blocks++;
+			jffs2_erase_pending_trigger(c);
+			D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n",
+				  ejeb->offset));
+		}
+
+		if (!c->nr_erasing_blocks &&
+			!list_empty(&c->erasable_pending_wbuf_list)) {
+			D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
+			/* c->nextblock is NULL, no update to c->nextblock allowed */			    
 			spin_unlock(&c->erase_completion_lock);
-			D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));			    
 			jffs2_flush_wbuf_pad(c);
 			spin_lock(&c->erase_completion_lock);
-			jeb = c->nextblock;
-			goto restart;
+			/* Have another go. It'll be on the erasable_list now */
+			return -EAGAIN;
 		}
-		c->wasted_size += jeb->free_size;
-		c->free_size -= jeb->free_size;
-		jeb->wasted_size += jeb->free_size;
-		jeb->free_size = 0;
-		
-		/* Check, if we have a dirty block now, or if it was dirty already */
-		if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
-			c->dirty_size += jeb->wasted_size;
-			c->wasted_size -= jeb->wasted_size;
-			jeb->dirty_size += jeb->wasted_size;
-			jeb->wasted_size = 0;
-			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->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);
-			}
-		} else { 
-			D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_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->clean_list);
+
+		if (!c->nr_erasing_blocks) {
+			/* Ouch. We're in GC, or we wouldn't have got here.
+			   And there's no space left. At all. */
+			printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", 
+				   c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no", 
+				   list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
+			return -ENOSPC;
 		}
-		c->nextblock = jeb = NULL;
+
+		spin_unlock(&c->erase_completion_lock);
+		/* Don't wait for it; just erase one right now */
+		jffs2_erase_pending_blocks(c, 1);
+		spin_lock(&c->erase_completion_lock);
+
+		/* An erase may have failed, decreasing the
+		   amount of free space available. So we must
+		   restart from the beginning */
+		return -EAGAIN;
 	}
-	
-	if (!jeb) {
-		struct list_head *next;
-		/* Take the next block off the 'free' list */
 
-		if (list_empty(&c->free_list)) {
+	next = c->free_list.next;
+	list_del(next);
+	c->nextblock = list_entry(next, struct jffs2_eraseblock, list);
+	c->nr_free_blocks--;
 
-			if (!c->nr_erasing_blocks && 
-			    !list_empty(&c->erasable_list)) {
-				struct jffs2_eraseblock *ejeb;
-
-				ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list);
-				list_del(&ejeb->list);
-				list_add_tail(&ejeb->list, &c->erase_pending_list);
-				c->nr_erasing_blocks++;
-				jffs2_erase_pending_trigger(c);
-				D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n",
-					  ejeb->offset));
+	return 0;
+}
+
+/* Called with alloc sem _and_ erase_completion_lock */
+static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, uint32_t sumsize)
+{
+	struct jffs2_eraseblock *jeb = c->nextblock;
+	uint32_t reserved_size; 			/* for summary information at the end of the jeb */
+	int ret;
+
+ restart:
+	reserved_size = 0;
+
+	if (jffs2_sum_active() && (sumsize != JFFS2_SUMMARY_NOSUM_SIZE)) {
+							/* NOSUM_SIZE means not to generate summary */
+
+		if (jeb) {
+			reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE);
+		}
+
+		D1(if (jeb) printk(KERN_DEBUG "JFFS2: minsize %d , jeb->free(%d) ,"
+						"summary->size(%d) , sumsize(%d)\n", minsize,
+						jeb->free_size, c->summary->sum_size, sumsize));
+
+		/* Is there enough space for writing out the current node, or we have to
+		   write out summary information now, close this jeb and select new nextblock? */
+		if (jeb && (PAD(minsize) + PAD(c->summary->sum_size + sumsize +
+					JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size)) {
+
+			/* Has summary been disabled for this jeb? */
+			if (c->summary->sum_size == JFFS2_SUMMARY_NOSUM_SIZE) {
+				sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
+				/* Free collected information (if there is any) */
+				jffs2_sum_clean_collected(c->summary);
+				goto restart;
 			}
 
-			if (!c->nr_erasing_blocks && 
-			    !list_empty(&c->erasable_pending_wbuf_list)) {
-				D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
-				/* c->nextblock is NULL, no update to c->nextblock allowed */			    
+			D1(printk(KERN_DEBUG "JFFS2: generating summary for 0x%08x.\n", jeb->offset));
+			/* Writing out the collected summary information */
+			ret = jffs2_sum_write_sumnode(c);
+
+			if (ret)
+				return ret;
+
+			if (c->summary->sum_size == JFFS2_SUMMARY_NOSUM_SIZE) {
+				/* jffs2_write_sumnode() couldn't write out the summary information 
+				   diabling summary for this jeb and free the collected information
+				 */
+				sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
+				jffs2_sum_clean_collected(c->summary);
+				goto restart;
+			}
+
+			jffs2_close_nextblock(c, jeb);
+			jeb = NULL;
+		}
+	} else {
+		if (jeb && minsize > jeb->free_size) {
+			/* Skip the end of this block and file it as having some dirty space */
+			/* If there's a pending write to it, flush now */
+
+			if (jffs2_wbuf_dirty(c)) {
 				spin_unlock(&c->erase_completion_lock);
+				D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
 				jffs2_flush_wbuf_pad(c);
 				spin_lock(&c->erase_completion_lock);
-				/* Have another go. It'll be on the erasable_list now */
-				return -EAGAIN;
+				jeb = c->nextblock;
+				goto restart;
 			}
 
-			if (!c->nr_erasing_blocks) {
-				/* Ouch. We're in GC, or we wouldn't have got here.
-				   And there's no space left. At all. */
-				printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", 
-				       c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no", 
-				       list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
-				return -ENOSPC;
-			}
+			c->wasted_size += jeb->free_size;
+			c->free_size -= jeb->free_size;
+			jeb->wasted_size += jeb->free_size;
+			jeb->free_size = 0;
 
-			spin_unlock(&c->erase_completion_lock);
-			/* Don't wait for it; just erase one right now */
-			jffs2_erase_pending_blocks(c, 1);
-			spin_lock(&c->erase_completion_lock);
-
-			/* An erase may have failed, decreasing the
-			   amount of free space available. So we must
-			   restart from the beginning */
-			return -EAGAIN;
+			jffs2_close_nextblock(c, jeb);
+			jeb = NULL;
 		}
+	}
+
+	if (!jeb) {
+
+		ret = jffs2_find_nextblock(c);
+		if (ret)
+			return ret;
 
-		next = c->free_list.next;
-		list_del(next);
-		c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list);
-		c->nr_free_blocks--;
+		jeb = c->nextblock;
 
 		if (jeb->free_size != c->sector_size - c->cleanmarker_size) {
 			printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
@@ -266,7 +347,7 @@ static int jffs2_do_reserve_space(struct
 	/* OK, jeb (==c->nextblock) is now pointing at a block which definitely has
 	   enough space */
 	*ofs = jeb->offset + (c->sector_size - jeb->free_size);
-	*len = jeb->free_size;
+	*len = jeb->free_size - reserved_size;
 
 	if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size &&
 	    !jeb->first_node->next_in_ino) {
diff -Narup mtd2/fs/jffs2/os-linux.h mtd/fs/jffs2/os-linux.h
--- mtd2/fs/jffs2/os-linux.h	2005-08-06 06:51:30.000000000 +0200
+++ mtd/fs/jffs2/os-linux.h	2005-08-22 12:29:08.000000000 +0200
@@ -67,12 +67,18 @@ static inline void jffs2_init_inode_info
 
 #ifndef CONFIG_JFFS2_FS_WRITEBUFFER
 #define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
+
+#ifdef CONFIG_JFFS2_SUMMARY
+#define jffs2_can_mark_obsolete(c) (0)
+#else
 #define jffs2_can_mark_obsolete(c) (1)
+#endif
+
 #define jffs2_is_writebuffered(c) (0)
 #define jffs2_cleanmarker_oob(c) (0)
 #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
 
-#define jffs2_flash_write(c, ofs, len, retlen, buf) ((c)->mtd->write((c)->mtd, ofs, len, retlen, buf))
+#define jffs2_flash_write(c, ofs, len, retlen, buf) jffs2_flash_direct_write(c, ofs, len, retlen, buf)
 #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; })
@@ -97,9 +103,15 @@ static inline void jffs2_init_inode_info
 
 #define jffs2_is_writebuffered(c) (c->wbuf != NULL)
 #define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size )
+
+#ifdef CONFIG_JFFS2_SUMMARY
+#define jffs2_can_mark_obsolete(c) (0)
+#else
 #define jffs2_can_mark_obsolete(c) \
   ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & (MTD_ECC|MTD_PROGRAM_REGIONS))) || \
    c->mtd->type == MTD_RAM)
+#endif
+
 #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
 
 #define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
@@ -192,7 +204,8 @@ void jffs2_flash_cleanup(struct jffs2_sb
 /* writev.c */
 int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, 
 		       unsigned long count, loff_t to, size_t *retlen);
-
+int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
+			size_t *retlen, const u_char *buf);
 
 #endif /* __JFFS2_OS_LINUX_H__ */
 
diff -Narup mtd2/fs/jffs2/scan.c mtd/fs/jffs2/scan.c
--- mtd2/fs/jffs2/scan.c	2005-07-20 17:32:28.000000000 +0200
+++ mtd/fs/jffs2/scan.c	2005-08-23 11:43:14.000000000 +0200
@@ -18,22 +18,10 @@
 #include <linux/crc32.h>
 #include <linux/compiler.h>
 #include "nodelist.h"
+#include "summary.h"
 
 #define DEFAULT_EMPTY_SCAN_SIZE 1024
 
-#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
-		c->free_size -= _x; c->dirty_size += _x; \
-		jeb->free_size -= _x ; jeb->dirty_size += _x; \
-		}while(0)
-#define USED_SPACE(x) do { typeof(x) _x = (x); \
-		c->free_size -= _x; c->used_size += _x; \
-		jeb->free_size -= _x ; jeb->used_size += _x; \
-		}while(0)
-#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
-		c->free_size -= _x; c->unchecked_size += _x; \
-		jeb->free_size -= _x ; jeb->unchecked_size += _x; \
-		}while(0)
-
 #define noisy_printk(noise, args...) do { \
 	if (*(noise)) { \
 		printk(KERN_NOTICE args); \
@@ -47,23 +35,16 @@
 static uint32_t pseudo_random;
 
 static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-				  unsigned char *buf, uint32_t buf_size);
+				  unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s);
 
 /* These helper functions _must_ increase ofs and also do the dirty/used space accounting. 
  * Returning an error will abort the mount - bad checksums etc. should just mark the space
  * as dirty.
  */
 static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
-				 struct jffs2_raw_inode *ri, uint32_t ofs);
+				 struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s);
 static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-				 struct jffs2_raw_dirent *rd, uint32_t ofs);
-
-#define BLK_STATE_ALLFF		0
-#define BLK_STATE_CLEAN		1
-#define BLK_STATE_PARTDIRTY	2
-#define BLK_STATE_CLEANMARKER	3
-#define BLK_STATE_ALLDIRTY	4
-#define BLK_STATE_BADBLOCK	5
+				 struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s);
 
 static inline int min_free(struct jffs2_sb_info *c)
 {
@@ -89,6 +70,7 @@ int jffs2_scan_medium(struct jffs2_sb_in
 	uint32_t empty_blocks = 0, bad_blocks = 0;
 	unsigned char *flashbuf = NULL;
 	uint32_t buf_size = 0;
+	struct jffs2_summary *s = NULL; /* summary info collected by the scan process */
 #ifndef __ECOS
 	size_t pointlen;
 
@@ -122,10 +104,24 @@ int jffs2_scan_medium(struct jffs2_sb_in
 			return -ENOMEM;
 	}
 
+	if (jffs2_sum_active()) {
+		s = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
+		if (!s) {
+			printk(KERN_WARNING "%s(): can't allocate memory for "
+								"summary\n",__FUNCTION__);
+			return -ENOMEM;
+		}
+		memset(s, 0, sizeof(struct jffs2_summary));
+	}
+
 	for (i=0; i<c->nr_blocks; i++) {
 		struct jffs2_eraseblock *jeb = &c->blocks[i];
 
-		ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size);
+		/* reset summary info for next eraseblock scan */
+		jffs2_sum_reset_collected(s);
+
+		ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
+						buf_size, s);
 
 		if (ret < 0)
 			goto out;
@@ -162,18 +158,18 @@ int jffs2_scan_medium(struct jffs2_sb_in
 			break;
 
 		case BLK_STATE_CLEAN:
-                        /* Full (or almost full) of clean data. Clean list */
-                        list_add(&jeb->list, &c->clean_list);
+			/* Full (or almost full) of clean data. Clean list */
+			list_add(&jeb->list, &c->clean_list);
 			break;
 
 		case BLK_STATE_PARTDIRTY:
-                        /* Some data, but not full. Dirty list. */
-                        /* We want to remember the block with most free space
-                           and stick it in the 'nextblock' position to start writing to it. */
-                        if (jeb->free_size > min_free(c) && 
-			    (!c->nextblock || c->nextblock->free_size < jeb->free_size)) {
-                                /* Better candidate for the next writes to go to */
-                                if (c->nextblock) {
+			/* Some data, but not full. Dirty list. */
+			/* We want to remember the block with most free space
+			and stick it in the 'nextblock' position to start writing to it. */
+			if (jeb->free_size > min_free(c) &&
+					(!c->nextblock || c->nextblock->free_size < jeb->free_size)) {
+				/* Better candidate for the next writes to go to */
+				if (c->nextblock) {
 					c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
 					c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
 					c->free_size -= c->nextblock->free_size;
@@ -184,9 +180,13 @@ int jffs2_scan_medium(struct jffs2_sb_in
 					} else {
 						list_add(&c->nextblock->list, &c->dirty_list);
 					}
+					/* deleting summary information of the old nextblock */
+					jffs2_sum_reset_collected(c->summary);
 				}
-                                c->nextblock = jeb;
-                        } else {
+				/* update collected summary infromation for the current nextblock */
+				jffs2_sum_move_collected(c, s);
+				c->nextblock = jeb;
+			} else {
 				jeb->dirty_size += jeb->free_size + jeb->wasted_size;
 				c->dirty_size += jeb->free_size + jeb->wasted_size;
 				c->free_size -= jeb->free_size;
@@ -197,30 +197,33 @@ int jffs2_scan_medium(struct jffs2_sb_in
 				} else {
 					list_add(&jeb->list, &c->dirty_list);
 				}
-                        }
+			}
 			break;
 
 		case BLK_STATE_ALLDIRTY:
 			/* Nothing valid - not even a clean marker. Needs erasing. */
-                        /* For now we just put it on the erasing list. We'll start the erases later */
+			/* For now we just put it on the erasing list. We'll start the erases later */
 			D1(printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset));
-                        list_add(&jeb->list, &c->erase_pending_list);
+			list_add(&jeb->list, &c->erase_pending_list);
 			c->nr_erasing_blocks++;
 			break;
-			
+
 		case BLK_STATE_BADBLOCK:
 			D1(printk(KERN_NOTICE "JFFS2: Block at 0x%08x is bad\n", jeb->offset));
-                        list_add(&jeb->list, &c->bad_list);
+			list_add(&jeb->list, &c->bad_list);
 			c->bad_size += c->sector_size;
 			c->free_size -= c->sector_size;
 			bad_blocks++;
 			break;
 		default:
 			printk(KERN_WARNING "jffs2_scan_medium(): unknown block state\n");
-			BUG();	
+			BUG();
 		}
 	}
-	
+
+	if (jffs2_sum_active() && s)
+		kfree(s);
+
 	/* Nextblock dirty is always seen as wasted, because we cannot recycle it now */
 	if (c->nextblock && (c->nextblock->dirty_size)) {
 		c->nextblock->wasted_size += c->nextblock->dirty_size;
@@ -265,7 +268,7 @@ int jffs2_scan_medium(struct jffs2_sb_in
 	return ret;
 }
 
-static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf,
+int jffs2_fill_scan_buf (struct jffs2_sb_info *c, void *buf,
 				uint32_t ofs, uint32_t len)
 {
 	int ret;
@@ -286,14 +289,36 @@ static int jffs2_fill_scan_buf (struct j
 	return 0;
 }
 
+int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+{
+	if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size
+		&& (!jeb->first_node || !jeb->first_node->next_phys) )
+		return BLK_STATE_CLEANMARKER;
+
+	/* move blocks with max 4 byte dirty space to cleanlist */
+	else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) {
+		c->dirty_size -= jeb->dirty_size;
+		c->wasted_size += jeb->dirty_size;
+		jeb->wasted_size += jeb->dirty_size;
+		jeb->dirty_size = 0;
+		return BLK_STATE_CLEAN;
+	} else if (jeb->used_size || jeb->unchecked_size)
+		return BLK_STATE_PARTDIRTY;
+	else
+		return BLK_STATE_ALLDIRTY;
+}
+
 static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-				  unsigned char *buf, uint32_t buf_size) {
+				unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) {
 	struct jffs2_unknown_node *node;
 	struct jffs2_unknown_node crcnode;
+	struct jffs2_sum_marker *sm;
 	uint32_t ofs, prevofs;
 	uint32_t hdr_crc, buf_ofs, buf_len;
 	int err;
 	int noise = 0;
+
+
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
 	int cleanmarkerfound = 0;
 #endif
@@ -319,10 +344,46 @@ static int jffs2_scan_eraseblock (struct
 		}
 	}
 #endif
+
+	if (jffs2_sum_active()) {
+		sm = kmalloc(sizeof(struct jffs2_sum_marker), GFP_KERNEL);
+		if (!sm) {
+			return -ENOMEM;
+		}
+
+		err = jffs2_fill_scan_buf(c, (unsigned char *) sm, jeb->offset + c->sector_size -
+					sizeof(struct jffs2_sum_marker), sizeof(struct jffs2_sum_marker));
+		if (err) {
+			kfree(sm);
+			return err;
+		}
+
+		if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC ) {
+			err = jffs2_sum_scan_sumnode(c, jeb, je32_to_cpu(sm->offset), &pseudo_random);
+			if (err) {
+				kfree(sm);
+				return err;
+			}
+		}
+
+		kfree(sm);
+
+		ofs = jeb->offset;
+		prevofs = jeb->offset - 1;
+	}
+
 	buf_ofs = jeb->offset;
 
 	if (!buf_size) {
 		buf_len = c->sector_size;
+
+		if (jffs2_sum_active()) {
+			/* must reread because of summary test */
+			err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
+			if (err)
+				return err;
+		}
+
 	} else {
 		buf_len = EMPTY_SCAN_SIZE(c->sector_size);
 		err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
@@ -367,6 +428,8 @@ static int jffs2_scan_eraseblock (struct
 
 	noise = 10;
 
+	D1(printk(KERN_DEBUG "JFFS2: no summary found in jeb 0x%08x. Apply original scan.\n",jeb->offset));
+
 scan_more:	
 	while(ofs < jeb->offset + c->sector_size) {
 
@@ -532,7 +595,7 @@ scan_more:	
 				buf_ofs = ofs;
 				node = (void *)buf;
 			}
-			err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs);
+			err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs, s);
 			if (err) return err;
 			ofs += PAD(je32_to_cpu(node->totlen));
 			break;
@@ -548,7 +611,7 @@ scan_more:	
 				buf_ofs = ofs;
 				node = (void *)buf;
 			}
-			err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs);
+			err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs, s);
 			if (err) return err;
 			ofs += PAD(je32_to_cpu(node->totlen));
 			break;
@@ -582,6 +645,8 @@ scan_more:	
 			break;
 
 		case JFFS2_NODETYPE_PADDING:
+			if (jffs2_sum_active())
+				jffs2_sum_add_padding_mem(s, je32_to_cpu(node->totlen));
 			DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
 			ofs += PAD(je32_to_cpu(node->totlen));
 			break;
@@ -616,6 +681,15 @@ scan_more:	
 		}
 	}
 
+	if (jffs2_sum_active()) {
+		if (PAD(s->sum_size + JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size) {
+			D1(printk(KERN_WARNING "JFFS2 SUMMARY: There is not enough space for "
+				"summary information, freeing up summary info!\n"));
+			jffs2_sum_clean_collected(s);
+			/* disabling summary for this jeb */
+			s->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
+		}
+	}
 
 	D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, 
 		  jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size));
@@ -628,24 +702,10 @@ scan_more:	
 		jeb->wasted_size = 0;
 	}
 
-	if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size 
-		&& (!jeb->first_node || !jeb->first_node->next_phys) )
-		return BLK_STATE_CLEANMARKER;
-		
-	/* move blocks with max 4 byte dirty space to cleanlist */	
-	else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) {
-		c->dirty_size -= jeb->dirty_size;
-		c->wasted_size += jeb->dirty_size; 
-		jeb->wasted_size += jeb->dirty_size;
-		jeb->dirty_size = 0;
-		return BLK_STATE_CLEAN;
-	} else if (jeb->used_size || jeb->unchecked_size)
-		return BLK_STATE_PARTDIRTY;
-	else
-		return BLK_STATE_ALLDIRTY;
+	return jffs2_scan_classify_jeb(c, jeb);
 }
 
-static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
+struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
 {
 	struct jffs2_inode_cache *ic;
 
@@ -672,7 +732,7 @@ static struct jffs2_inode_cache *jffs2_s
 }
 
 static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
-				 struct jffs2_raw_inode *ri, uint32_t ofs)
+				 struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s)
 {
 	struct jffs2_raw_node_ref *raw;
 	struct jffs2_inode_cache *ic;
@@ -739,11 +799,16 @@ static int jffs2_scan_inode_node(struct 
 	pseudo_random += je32_to_cpu(ri->version);
 
 	UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen)));
+
+	if (jffs2_sum_active()) {
+		jffs2_sum_add_inode_mem(s, ri, ofs - jeb->offset);
+	}
+
 	return 0;
 }
 
 static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
-				  struct jffs2_raw_dirent *rd, uint32_t ofs)
+				  struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s)
 {
 	struct jffs2_raw_node_ref *raw;
 	struct jffs2_full_dirent *fd;
@@ -817,6 +882,10 @@ static int jffs2_scan_dirent_node(struct
 	USED_SPACE(PAD(je32_to_cpu(rd->totlen)));
 	jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
 
+	if (jffs2_sum_active()) {
+		jffs2_sum_add_dirent_mem(s, rd, ofs - jeb->offset);
+	}
+
 	return 0;
 }
 
diff -Narup mtd2/fs/jffs2/summary.c mtd/fs/jffs2/summary.c
--- mtd2/fs/jffs2/summary.c	1970-01-01 01:00:00.000000000 +0100
+++ mtd/fs/jffs2/summary.c	2005-08-23 11:31:13.000000000 +0200
@@ -0,0 +1,709 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                     Patrik Kluba <pajko@halom.u-szeged.hu>,
+ *                     University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id$
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/pagemap.h>
+#include <linux/crc32.h>
+#include <linux/compiler.h>
+#include <linux/vmalloc.h>
+#include "nodelist.h"
+
+int jffs2_sum_init(struct jffs2_sb_info *c)
+{
+	c->summary = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
+
+	if (!c->summary) {
+		printk(KERN_WARNING "JFFS2: can't allocate memory for summary information!\n");
+		return -ENOMEM;
+	}
+
+	memset(c->summary, 0, sizeof(struct jffs2_summary));
+
+	c->summary->sum_buf = vmalloc(c->sector_size);
+
+	if (!c->summary->sum_buf) {
+		printk(KERN_WARNING "JFFS2: can't allocate buffer for writing out summary information!\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void jffs2_sum_exit(struct jffs2_sb_info *c)
+{
+	jffs2_sum_clean_collected(c->summary);
+
+	vfree(c->summary->sum_buf);
+	c->summary->sum_buf = NULL;
+
+	kfree(c->summary);
+	c->summary = NULL;
+}
+
+static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item)
+{
+	if (!s->sum_list_head)
+		s->sum_list_head = (union jffs2_sum_mem *) item;
+	if (s->sum_list_tail)
+		s->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
+	s->sum_list_tail = (union jffs2_sum_mem *) item;
+
+	switch (je16_to_cpu(item->u.nodetype)) {
+		case JFFS2_NODETYPE_INODE:
+			s->sum_size += JFFS2_SUMMARY_INODE_SIZE;
+			s->sum_num++;
+			break;
+		case JFFS2_NODETYPE_DIRENT:
+			s->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
+			s->sum_num++;
+			break;
+		default:
+			printk(KERN_WARNING "__jffs2_add_sum_mem(): UNKNOWN node type %d\n",
+						je16_to_cpu(item->u.nodetype));
+			return 1;
+	}
+	return 0;
+}
+
+
+/* The following 3 functions are called from scan.c to collect summary info for not closed jeb */
+
+int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size)
+{
+	s->sum_padded += size;
+	return 0;
+}
+
+int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri,
+				uint32_t ofs)
+{
+	struct jffs2_sum_inode_mem *temp = kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
+
+	if (!temp)
+		return -ENOMEM;
+
+	temp->nodetype = ri->nodetype;
+	temp->inode = ri->ino;
+	temp->version = ri->version;
+	temp->offset = cpu_to_je32(ofs);	/* relative offset from the begining of the jeb */
+	temp->totlen = ri->totlen;
+	temp->next = NULL;
+
+	return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
+}
+
+int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd,
+				uint32_t ofs)
+{
+	struct jffs2_sum_dirent_mem *temp =
+		kmalloc(sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL);
+
+	if (!temp)
+		return -ENOMEM;
+
+	temp->nodetype = rd->nodetype;
+	temp->totlen = rd->totlen;
+	temp->offset = cpu_to_je32(ofs);	/* relative from the begining of the jeb */
+	temp->pino = rd->pino;
+	temp->version = rd->version;
+	temp->ino = rd->ino;
+	temp->nsize = rd->nsize;
+	temp->type = rd->type;
+	temp->next = NULL;
+
+	memcpy(temp->name, rd->name, rd->nsize);
+
+	return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
+}
+
+/* Cleanup every collected summary information */
+
+void jffs2_sum_clean_collected(struct jffs2_summary *s)
+{
+	union jffs2_sum_mem *temp;
+
+	if (s) {
+		while (s->sum_list_head) {
+			temp = s->sum_list_head;
+			s->sum_list_head = s->sum_list_head->u.next;
+			kfree(temp);
+		}
+
+		s->sum_list_tail = NULL;
+		s->sum_padded = 0;
+		s->sum_num = 0;
+	}
+}
+
+void jffs2_sum_reset_collected(struct jffs2_summary *s)
+{
+	if (s) {
+		jffs2_sum_clean_collected(s);
+		s->sum_size = 0;
+	}
+}
+
+/* Move the collected summary information into sb (called from scan.c) */
+
+void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s)
+{
+	c->summary->sum_size = s->sum_size;
+	c->summary->sum_num = s->sum_num;
+	c->summary->sum_padded = s->sum_padded;
+	c->summary->sum_list_head = s->sum_list_head;
+	c->summary->sum_list_tail = s->sum_list_tail;
+
+	s->sum_list_head = s->sum_list_tail = NULL;
+}
+
+/* Called from wbuf.c to collect writed node info */
+
+int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
+				unsigned long count, uint32_t ofs)
+{
+	union jffs2_node_union *node;
+	struct jffs2_eraseblock *jeb;
+
+	node = invecs[0].iov_base;
+	jeb = &c->blocks[ofs / c->sector_size];
+	ofs -= jeb->offset;
+
+	switch (je16_to_cpu(node->u.nodetype)) {
+		case JFFS2_NODETYPE_INODE: {
+			struct jffs2_sum_inode_mem *temp =
+				kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
+
+			if (!temp)
+				goto no_mem;
+
+			temp->nodetype = node->i.nodetype;
+			temp->inode = node->i.ino;
+			temp->version = node->i.version;
+			temp->offset = cpu_to_je32(ofs);
+			temp->totlen = node->i.totlen;
+			temp->next = NULL;
+
+			return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
+		}
+
+		case JFFS2_NODETYPE_DIRENT: {
+			struct jffs2_sum_dirent_mem *temp =
+				kmalloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL);
+
+			if (!temp)
+				goto no_mem;
+
+			temp->nodetype = node->d.nodetype;
+			temp->totlen = node->d.totlen;
+			temp->offset = cpu_to_je32(ofs);
+			temp->pino = node->d.pino;
+			temp->version = node->d.version;
+			temp->ino = node->d.ino;
+			temp->nsize = node->d.nsize;
+			temp->type = node->d.type;
+			temp->next = NULL;
+
+			switch (count) {
+				case 1:
+					memcpy(temp->name,node->d.name,node->d.nsize);
+					break;
+
+				case 2:
+					memcpy(temp->name,invecs[1].iov_base,node->d.nsize);
+					break;
+
+				default:
+					BUG();	/* impossible count value */
+					break;
+			}
+
+			return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
+		}
+
+		case JFFS2_NODETYPE_PADDING:
+			D1(printk(KERN_DEBUG "jffs2_sum_add_kvec(): Node PADDING\n"));
+			c->summary->sum_padded += je32_to_cpu(node->u.totlen);
+			break;
+
+		case JFFS2_NODETYPE_CLEANMARKER:
+			D1(printk(KERN_DEBUG "jffs2_sum_add_kvec(): Node CLEANMARKER\n"));
+			break;
+
+		case JFFS2_NODETYPE_SUMMARY:
+			D1(printk(KERN_DEBUG "jffs2_sum_add_kvec(): Node SUMMARY\n"));
+			break;
+
+		default:
+			/* If you implement a new node type you should also implement
+			   summary support for it or disable summary.
+			*/
+			BUG();
+			break;
+	}
+
+	return 0;
+
+no_mem:
+	printk("jffs2_sum_add_kvec(): MEMORY ALLOCATION ERROR!");
+	return -ENOMEM;
+}
+
+
+/* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */
+
+static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+				struct jffs2_summary_node *summary, uint32_t *pseudo_random)
+{
+	struct jffs2_raw_node_ref *raw;
+	struct jffs2_inode_cache *ic;
+	struct jffs2_full_dirent *fd;
+	void *sp;
+	int i, ino;
+
+	sp = summary->sum;
+
+	for (i=0; i<je32_to_cpu(summary->sum_num); i++) {
+		D1(printk(KERN_DEBUG "%s(): Processing summary "
+							"information %d\n",__FUNCTION__, i));
+
+		switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
+			case JFFS2_NODETYPE_INODE: {
+				struct jffs2_sum_inode_flash *spi;
+				spi = sp;
+
+				ino = je32_to_cpu(spi->inode);
+				D1(printk(KERN_DEBUG "%s(): Inode at 0x%08x\n",__FUNCTION__,
+							jeb->offset + je32_to_cpu(spi->offset)));
+				raw = jffs2_alloc_raw_node_ref();
+				if (!raw) {
+					printk(KERN_NOTICE "%s(): allocation of node reference "
+							"failed\n",__FUNCTION__);
+					kfree(summary);
+					return -ENOMEM;
+				}
+
+				ic = jffs2_scan_make_ino_cache(c, ino);
+				if (!ic) {
+					printk(KERN_NOTICE "%s(): scan_make_ino_cache failed\n",
+							__FUNCTION__);
+					jffs2_free_raw_node_ref(raw);
+					kfree(summary);
+					return -ENOMEM;
+				}
+
+				raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED;
+				raw->__totlen = PAD(je32_to_cpu(spi->totlen));
+				raw->next_phys = NULL;
+				raw->next_in_ino = ic->nodes;
+
+				ic->nodes = raw;
+				if (!jeb->first_node)
+					jeb->first_node = raw;
+				if (jeb->last_node)
+					jeb->last_node->next_phys = raw;
+				jeb->last_node = raw;
+				*pseudo_random += je32_to_cpu(spi->version);
+
+				UNCHECKED_SPACE(PAD(je32_to_cpu(spi->totlen)));
+
+				sp += JFFS2_SUMMARY_INODE_SIZE;
+
+				break;
+			}
+
+			case JFFS2_NODETYPE_DIRENT: {
+				struct jffs2_sum_dirent_flash *spd;
+				spd = sp;
+
+				fd = jffs2_alloc_full_dirent(spd->nsize+1);
+				if (!fd) {
+					kfree(summary);
+					return -ENOMEM;
+				}
+
+				memcpy(&fd->name, spd->name, spd->nsize);
+				fd->name[spd->nsize] = 0;
+
+				raw = jffs2_alloc_raw_node_ref();
+				if (!raw) {
+					jffs2_free_full_dirent(fd);
+					printk(KERN_NOTICE "%s(): allocation of node reference "
+							"failed\n",__FUNCTION__);
+					kfree(summary);
+					return -ENOMEM;
+				}
+
+				ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino));
+				if (!ic) {
+					jffs2_free_full_dirent(fd);
+					jffs2_free_raw_node_ref(raw);
+					kfree(summary);
+					return -ENOMEM;
+				}
+
+				raw->__totlen = PAD(je32_to_cpu(spd->totlen));
+				raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE;
+				raw->next_phys = NULL;
+				raw->next_in_ino = ic->nodes;
+				ic->nodes = raw;
+				if (!jeb->first_node)
+					jeb->first_node = raw;
+				if (jeb->last_node)
+					jeb->last_node->next_phys = raw;
+				jeb->last_node = raw;
+
+				fd->raw = raw;
+				fd->next = NULL;
+				fd->version = je32_to_cpu(spd->version);
+				fd->ino = je32_to_cpu(spd->ino);
+				fd->nhash = full_name_hash(fd->name, spd->nsize);
+				fd->type = spd->type;
+				USED_SPACE(PAD(je32_to_cpu(spd->totlen)));
+				jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
+
+				*pseudo_random += je32_to_cpu(spd->version);
+
+				sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
+
+				break;
+			}
+
+			default : {
+				printk(KERN_WARNING "%s(): Unsupported node type found in summary! "
+									"Exiting...",__FUNCTION__);
+				kfree(summary);
+				return -EIO;
+			}
+		}
+	}
+
+	kfree(summary);
+	return 0;
+}
+
+/* Process the summary node - called from jffs2_scan_eraseblock() */
+
+int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+				uint32_t ofs, uint32_t *pseudo_random)
+{
+	struct jffs2_unknown_node crcnode;
+	struct jffs2_raw_node_ref *cache_ref;
+	struct jffs2_summary_node *summary;
+	int ret, sumsize;
+	uint32_t crc;
+
+	sumsize = c->sector_size - ofs;
+	ofs += jeb->offset;
+
+	D1(printk(KERN_DEBUG "JFFS2: summary found for 0x%08x at 0x%08x (0x%x bytes)\n",
+			jeb->offset, ofs, sumsize));
+
+	summary = kmalloc(sumsize, GFP_KERNEL);
+
+	if (!summary) {
+		return -ENOMEM;
+	}
+
+	ret = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize);
+
+	if (ret) {
+		kfree(summary);
+		return ret;
+	}
+
+	/* OK, now check for node validity and CRC */
+	crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
+	crcnode.totlen = summary->totlen;
+	crc = crc32(0, &crcnode, sizeof(crcnode)-4);
+
+	if (je32_to_cpu(summary->hdr_crc) != crc) {
+		D1(printk(KERN_DEBUG "%s(): Summary node header is corrupt (bad CRC or "
+				"no summary at all)\n",__FUNCTION__));
+		goto crc_err;
+	}
+
+	if (je32_to_cpu(summary->totlen) != sumsize) {
+		D1(printk(KERN_DEBUG "%s(): Summary node is corrupt (wrong erasesize "
+				"?)\n",__FUNCTION__));
+		goto crc_err;
+	}
+
+	crc = crc32(0, summary, sizeof(struct jffs2_summary_node)-8);
+
+	if (je32_to_cpu(summary->node_crc) != crc) {
+		D1(printk(KERN_DEBUG "%s(): Summary node is corrupt (bad CRC)\n",
+				__FUNCTION__));
+		goto crc_err;
+	}
+
+	crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_summary_node));
+
+	if (je32_to_cpu(summary->sum_crc) != crc) {
+		D1(printk(KERN_DEBUG "%s(): Summary node data is corrupt (bad CRC)\n",
+				__FUNCTION__));
+		goto crc_err;
+	}
+
+	if ( je32_to_cpu(summary->cln_mkr) ) {
+
+		D1(printk(KERN_DEBUG "Summary : CLEANMARKER node \n"));
+
+		if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) {
+			D1(printk(KERN_DEBUG "CLEANMARKER node has totlen 0x%x != normal 0x%x\n",
+				je32_to_cpu(summary->cln_mkr), c->cleanmarker_size));
+			UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr)));
+		} else if (jeb->first_node) {
+			D1(printk(KERN_DEBUG "CLEANMARKER node not first node in block "
+					"(0x%08x)\n", jeb->offset));
+			UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr)));
+		} else {
+			struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
+
+			if (!marker_ref) {
+				D1(printk(KERN_NOTICE "Failed to allocate node ref for clean marker\n"));
+				kfree(summary);
+				return -ENOMEM;
+			}
+
+			marker_ref->next_in_ino = NULL;
+			marker_ref->next_phys = NULL;
+			marker_ref->flash_offset = jeb->offset | REF_NORMAL;
+			marker_ref->__totlen = je32_to_cpu(summary->cln_mkr);
+			jeb->first_node = jeb->last_node = marker_ref;
+
+			USED_SPACE( PAD(je32_to_cpu(summary->cln_mkr)) );
+		}
+	}
+
+	if (je32_to_cpu(summary->padded)) {
+		DIRTY_SPACE(je32_to_cpu(summary->padded));
+	}
+
+	ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random);
+	if (ret)
+		return ret;
+
+	/* for PARANOIA_CHECK */
+	cache_ref = jffs2_alloc_raw_node_ref();
+
+	if (!cache_ref) {
+		printk(KERN_NOTICE "Failed to allocate node ref for cache\n");
+		return -ENOMEM;
+	}
+
+	cache_ref->next_in_ino = NULL;
+	cache_ref->next_phys = NULL;
+	cache_ref->flash_offset = ofs | REF_NORMAL;
+	cache_ref->__totlen = sumsize;
+
+	if (!jeb->first_node)
+		jeb->first_node = cache_ref;
+	if (jeb->last_node)
+		jeb->last_node->next_phys = cache_ref;
+	jeb->last_node = cache_ref;
+
+	USED_SPACE(sumsize);
+
+	jeb->wasted_size += jeb->free_size;
+	c->wasted_size += jeb->free_size;
+	c->free_size -= jeb->free_size;
+	jeb->free_size = 0;
+
+	return jffs2_scan_classify_jeb(c, jeb);
+
+crc_err:
+	printk(KERN_WARNING "Summary node crc error, skipping summary information.\n");
+
+	return 0;
+}
+
+/* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */
+
+static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+					uint32_t infosize, uint32_t datasize, int padsize)
+{
+	struct jffs2_summary_node isum;
+	union jffs2_sum_mem *temp;
+	struct jffs2_sum_marker *sm;
+	struct kvec vecs[2];
+	void *wpage;
+	int ret;
+	size_t retlen;
+
+	memset(c->summary->sum_buf, 0xff, datasize);
+	memset(&isum, 0, sizeof(isum));
+
+	isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
+	isum.totlen = cpu_to_je32(infosize);
+	isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
+	isum.padded = cpu_to_je32(c->summary->sum_padded);
+	isum.cln_mkr = cpu_to_je32(c->cleanmarker_size);
+	isum.sum_num = cpu_to_je32(c->summary->sum_num);
+	wpage = c->summary->sum_buf;
+
+	while (c->summary->sum_num) { // write sum_data 
+
+		switch (je16_to_cpu(c->summary->sum_list_head->u.nodetype)) {
+			case JFFS2_NODETYPE_INODE: {
+				struct jffs2_sum_inode_flash *sino_ptr = wpage;
+
+				sino_ptr->nodetype = c->summary->sum_list_head->i.nodetype;
+				sino_ptr->inode = c->summary->sum_list_head->i.inode;
+				sino_ptr->version = c->summary->sum_list_head->i.version;
+				sino_ptr->offset = c->summary->sum_list_head->i.offset;
+				sino_ptr->totlen = c->summary->sum_list_head->i.totlen;
+
+				wpage += JFFS2_SUMMARY_INODE_SIZE;
+
+				break;
+			}
+
+			case JFFS2_NODETYPE_DIRENT: {
+				struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
+
+				sdrnt_ptr->nodetype = c->summary->sum_list_head->d.nodetype;
+				sdrnt_ptr->totlen = c->summary->sum_list_head->d.totlen;
+				sdrnt_ptr->offset = c->summary->sum_list_head->d.offset;
+				sdrnt_ptr->pino = c->summary->sum_list_head->d.pino;
+				sdrnt_ptr->version = c->summary->sum_list_head->d.version;
+				sdrnt_ptr->ino = c->summary->sum_list_head->d.ino;
+				sdrnt_ptr->nsize = c->summary->sum_list_head->d.nsize;
+				sdrnt_ptr->type = c->summary->sum_list_head->d.type;
+
+				memcpy(sdrnt_ptr->name, c->summary->sum_list_head->d.name, 
+							c->summary->sum_list_head->d.nsize);
+
+				wpage += JFFS2_SUMMARY_DIRENT_SIZE(c->summary->sum_list_head->d.nsize);
+
+				break;
+			}
+
+			default : {
+				BUG();	/* unknown node in summary information */
+			}
+		}
+
+		temp = c->summary->sum_list_head;
+		c->summary->sum_list_head = c->summary->sum_list_head->u.next;
+		kfree(temp);
+
+		c->summary->sum_num--;
+	}
+
+	jffs2_sum_reset_collected(c->summary);
+
+	wpage += padsize;
+
+	sm = wpage;
+	sm->offset = cpu_to_je32(c->sector_size - jeb->free_size);
+	sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC);
+
+	isum.sum_crc = cpu_to_je32(crc32(0, c->summary->sum_buf, datasize));
+	isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8));
+
+	vecs[0].iov_base = &isum;
+	vecs[0].iov_len = sizeof(isum);
+	vecs[1].iov_base = c->summary->sum_buf;
+	vecs[1].iov_len = datasize;
+
+	D1(printk(KERN_DEBUG "JFFS2: writing out data to flash to pos : 0x%08x\n",
+			jeb->offset + c->sector_size - jeb->free_size));
+
+	spin_unlock(&c->erase_completion_lock);
+	ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size -
+				jeb->free_size, &retlen, 0);
+	spin_lock(&c->erase_completion_lock);
+
+
+	if (ret || (retlen != infosize)) {
+		printk(KERN_WARNING "JFFS2: write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
+			infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen);
+
+		c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
+		WASTED_SPACE(infosize);
+
+		return 1;
+	}
+
+	return 0;
+}
+
+/* Write out summary information - called from jffs2_do_reserve_space */
+
+int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
+{
+	struct jffs2_raw_node_ref *summary_ref;
+	int datasize, infosize, padsize, ret;
+	struct jffs2_eraseblock *jeb;
+
+	D2(printk(KERN_DEBUG "jffs2_sum_write_sumnode()\n"));
+
+	jeb = c->nextblock;
+
+	if (!c->summary->sum_num || !c->summary->sum_list_head) {
+		printk(KERN_WARNING "JFFS2: jffs2_sum_write_sumnode(): empty summary info!!!\n");
+		BUG();
+	}
+
+	datasize = c->summary->sum_size + sizeof(struct jffs2_sum_marker);
+	infosize = sizeof(struct jffs2_summary_node) + datasize;
+	padsize = jeb->free_size - infosize;
+	infosize += padsize; 
+	datasize += padsize;
+
+	/* Is there enough space for summary? */
+	if (padsize < 0) {
+
+		jffs2_sum_clean_collected(c->summary);
+		/* don't try to write out summary for this node */
+		c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
+
+		printk(KERN_WARNING "JFFS2: not enough space for summary, padsize = %d\n",padsize);
+		return 0;
+	}
+
+	ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize);
+	if (ret)
+		return 0; /* can't write out summary, block is marked as NOSUM_SIZE */
+
+	/* for ACCT_PARANOIA_CHECK */
+	spin_unlock(&c->erase_completion_lock);
+	summary_ref = jffs2_alloc_raw_node_ref();
+	spin_lock(&c->erase_completion_lock);
+
+	if (!summary_ref) {
+		printk(KERN_NOTICE "Failed to allocate node ref for summary\n");
+		return -ENOMEM;
+	}
+
+	summary_ref->next_in_ino = NULL;
+	summary_ref->next_phys = NULL;
+	summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL;
+	summary_ref->__totlen = infosize;
+
+	if (!jeb->first_node)
+		jeb->first_node = summary_ref;
+	if (jeb->last_node)
+		jeb->last_node->next_phys = summary_ref;
+	jeb->last_node = summary_ref;
+
+	USED_SPACE(infosize);
+
+	return 0;
+}
diff -Narup mtd2/fs/jffs2/summary.h mtd/fs/jffs2/summary.h
--- mtd2/fs/jffs2/summary.h	1970-01-01 01:00:00.000000000 +0100
+++ mtd/fs/jffs2/summary.h	2005-08-23 12:17:30.000000000 +0200
@@ -0,0 +1,181 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                     Patrik Kluba <pajko@halom.u-szeged.hu>,
+ *                     University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id$
+ *
+ */
+
+#ifndef JFFS2_SUMMARY_H
+#define JFFS2_SUMMARY_H
+
+#include <linux/uio.h>
+#include <linux/jffs2.h>
+
+#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
+		c->free_size -= _x; c->dirty_size += _x; \
+		jeb->free_size -= _x ; jeb->dirty_size += _x; \
+		}while(0)
+#define USED_SPACE(x) do { typeof(x) _x = (x); \
+		c->free_size -= _x; c->used_size += _x; \
+		jeb->free_size -= _x ; jeb->used_size += _x; \
+		}while(0)
+#define WASTED_SPACE(x) do { typeof(x) _x = (x); \
+		c->free_size -= _x; c->wasted_size += _x; \
+		jeb->free_size -= _x ; jeb->wasted_size += _x; \
+		}while(0)
+#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
+		c->free_size -= _x; c->unchecked_size += _x; \
+		jeb->free_size -= _x ; jeb->unchecked_size += _x; \
+		}while(0)
+
+#define BLK_STATE_ALLFF		0
+#define BLK_STATE_CLEAN		1
+#define BLK_STATE_PARTDIRTY	2
+#define BLK_STATE_CLEANMARKER	3
+#define BLK_STATE_ALLDIRTY	4
+#define BLK_STATE_BADBLOCK	5
+
+#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
+#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
+#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
+
+/* Summary structures used on flash */
+
+struct jffs2_sum_unknown_flash
+{
+	jint16_t nodetype;	/* node type */
+};
+
+struct jffs2_sum_inode_flash
+{
+	jint16_t nodetype;	/* node type */
+	jint32_t inode;		/* inode number */
+	jint32_t version;	/* inode version */
+	jint32_t offset;	/* offset on jeb */
+	jint32_t totlen; 	/* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_flash
+{
+	jint16_t nodetype;	/* == JFFS_NODETYPE_DIRENT */
+	jint32_t totlen;	/* record length */
+	jint32_t offset;	/* ofset on jeb */
+	jint32_t pino;		/* parent inode */
+	jint32_t version;	/* dirent version */
+	jint32_t ino; 		/* == zero for unlink */
+	uint8_t nsize;		/* dirent name size */
+	uint8_t type;		/* dirent type */
+	uint8_t name[0];	/* dirent name */
+} __attribute__((packed));
+
+union jffs2_sum_flash
+{
+	struct jffs2_sum_unknown_flash u;
+	struct jffs2_sum_inode_flash i;
+	struct jffs2_sum_dirent_flash d;
+};
+
+/* Summary structures used in the memory */
+
+struct jffs2_sum_unknown_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* node type */
+};
+
+struct jffs2_sum_inode_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* node type */
+	jint32_t inode;		/* inode number */
+	jint32_t version;	/* inode version */
+	jint32_t offset;	/* offset on jeb */
+	jint32_t totlen; 	/* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* == JFFS_NODETYPE_DIRENT */
+	jint32_t totlen;	/* record length */
+	jint32_t offset;	/* ofset on jeb */
+	jint32_t pino;		/* parent inode */
+	jint32_t version;	/* dirent version */
+	jint32_t ino; 		/* == zero for unlink */
+	uint8_t nsize;		/* dirent name size */
+	uint8_t type;		/* dirent type */
+	uint8_t name[0];	/* dirent name */
+} __attribute__((packed));
+
+union jffs2_sum_mem
+{
+	struct jffs2_sum_unknown_mem u;
+	struct jffs2_sum_inode_mem i;
+	struct jffs2_sum_dirent_mem d;
+};
+
+/* Summary related information stored in superblock */
+
+struct jffs2_summary
+{
+	uint32_t sum_size;      /* collected summary information for nextblock */
+	uint32_t sum_num;
+	uint32_t sum_padded;
+	union jffs2_sum_mem *sum_list_head;
+	union jffs2_sum_mem *sum_list_tail;
+
+	jint32_t *sum_buf;	/* buffer for writing out summary */
+};
+
+/* Summary marker is stored at the end of every sumarized erase block */
+
+struct jffs2_sum_marker
+{
+	jint32_t offset;	/* offset of the summary node in the jeb */
+	jint32_t magic; 	/* == JFFS2_SUM_MAGIC */
+};
+
+#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_summary_node) + sizeof(struct jffs2_sum_marker))
+
+#ifdef CONFIG_JFFS2_SUMMARY	/* SUMMARY SUPPORT ENABLED */
+
+#define jffs2_sum_active() (1)
+int jffs2_sum_init(struct jffs2_sb_info *c);
+void jffs2_sum_exit(struct jffs2_sb_info *c);
+void jffs2_sum_clean_collected(struct jffs2_summary *s);
+void jffs2_sum_reset_collected(struct jffs2_summary *s);
+void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s);
+int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
+			unsigned long count,  uint32_t to);
+int jffs2_sum_write_sumnode(struct jffs2_sb_info *c);
+int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size);
+int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs);
+int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs);
+int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+			uint32_t ofs, uint32_t *pseudo_random);
+
+#else				/* SUMMARY DISABLED */
+
+#define jffs2_sum_active() (0)
+#define jffs2_sum_init(a) (0)
+#define jffs2_sum_exit(a)
+#define jffs2_sum_reset_collected(a)
+#define jffs2_sum_add_kvec(a,b,c,d) (0)
+#define jffs2_sum_clean_collected(a)
+#define jffs2_sum_move_collected(a,b)
+#define jffs2_sum_write_sumnode(a) (0)
+#define jffs2_sum_add_padding_mem(a,b)
+#define jffs2_sum_add_inode_mem(a,b,c)
+#define jffs2_sum_add_dirent_mem(a,b,c)
+#define jffs2_sum_scan_sumnode(a,b,c,d) (0)
+
+#endif /* CONFIG_JFFS2_SUMMARY */
+
+#endif /* JFFS2_SUMMARY_H */
diff -Narup mtd2/fs/jffs2/super.c mtd/fs/jffs2/super.c
--- mtd2/fs/jffs2/super.c	2005-07-12 18:37:08.000000000 +0200
+++ mtd/fs/jffs2/super.c	2005-08-22 12:29:08.000000000 +0200
@@ -282,6 +282,9 @@ static void jffs2_put_super (struct supe
 	down(&c->alloc_sem);
 	jffs2_flush_wbuf_pad(c);
 	up(&c->alloc_sem);
+
+	jffs2_sum_exit(c);
+
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
 	if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
@@ -321,6 +324,9 @@ static int __init init_jffs2_fs(void)
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
 	       " (NAND)"
 #endif
+#ifdef CONFIG_JFFS2_SUMMARY
+	       " (SUMMARY) "
+#endif
 	       " (C) 2001-2003 Red Hat, Inc.\n");
 
 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
diff -Narup mtd2/fs/jffs2/super-v24.c mtd/fs/jffs2/super-v24.c
--- mtd2/fs/jffs2/super-v24.c	2005-07-20 16:21:40.000000000 +0200
+++ mtd/fs/jffs2/super-v24.c	2005-08-22 12:29:08.000000000 +0200
@@ -24,6 +24,7 @@
 #include <linux/mtd/mtd.h>
 #include "compr.h"
 #include "nodelist.h"
+#include "summary.h"
 
 #ifndef MTD_BLOCK_MAJOR
 #define MTD_BLOCK_MAJOR 31
@@ -97,6 +98,9 @@ static void jffs2_put_super (struct supe
 	down(&c->alloc_sem);
 	jffs2_flush_wbuf_pad(c);
 	up(&c->alloc_sem);
+
+	jffs2_sum_exit(c);
+
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
 	if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
@@ -122,6 +126,9 @@ static int __init init_jffs2_fs(void)
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
 	       " (NAND)"
 #endif
+#ifdef CONFIG_JFFS2_SUMMARY
+	       " (SUMMARY)"
+#endif
 	       " (C) 2001-2003 Red Hat, Inc.\n");
 
 #ifdef JFFS2_OUT_OF_KERNEL
diff -Narup mtd2/fs/jffs2/wbuf.c mtd/fs/jffs2/wbuf.c
--- mtd2/fs/jffs2/wbuf.c	2005-08-06 06:51:30.000000000 +0200
+++ mtd/fs/jffs2/wbuf.c	2005-08-23 10:40:38.000000000 +0200
@@ -263,7 +263,7 @@ static void jffs2_wbuf_recover(struct jf
 
 
 	/* ... and get an allocation of space from a shiny new block instead */
-	ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len);
+	ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len, JFFS2_SUMMARY_NOSUM_SIZE);
 	if (ret) {
 		printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
 		kfree(buf);
@@ -834,6 +834,12 @@ int jffs2_flash_writev(struct jffs2_sb_i
 alldone:
 	*retlen = donelen;
 
+	if (jffs2_sum_active()) {
+		int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to);
+		if (res)
+			return res;
+	}
+
 	if (c->wbuf_len && ino)
 		jffs2_wbuf_dirties_inode(c, ino);
 
@@ -853,7 +859,7 @@ int jffs2_flash_write(struct jffs2_sb_in
 	struct kvec vecs[1];
 
 	if (!jffs2_is_writebuffered(c))
-		return c->mtd->write(c->mtd, ofs, len, retlen, buf);
+		return jffs2_flash_direct_write(c, ofs, len, retlen, buf);
 
 	vecs[0].iov_base = (unsigned char *) buf;
 	vecs[0].iov_len = len;
diff -Narup mtd2/fs/jffs2/write.c mtd/fs/jffs2/write.c
--- mtd2/fs/jffs2/write.c	2005-08-17 15:46:23.000000000 +0200
+++ mtd/fs/jffs2/write.c	2005-08-22 12:29:08.000000000 +0200
@@ -153,13 +153,15 @@ struct jffs2_full_dnode *jffs2_write_dno
 			jffs2_dbg_acct_paranoia_check(c, jeb);
 
 			if (alloc_mode == ALLOC_GC) {
-				ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, &dummy);
+				ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs,
+							&dummy, JFFS2_SUMMARY_INODE_SIZE);
 			} else {
 				/* Locking pain */
 				up(&f->sem);
 				jffs2_complete_reservation(c);
 			
-				ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, &dummy, alloc_mode);
+				ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs,
+							&dummy, alloc_mode, JFFS2_SUMMARY_INODE_SIZE);
 				down(&f->sem);
 			}
 
@@ -299,13 +301,15 @@ struct jffs2_full_dirent *jffs2_write_di
 			jffs2_dbg_acct_paranoia_check(c, jeb);
 
 			if (alloc_mode == ALLOC_GC) {
-				ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, &dummy);
+				ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs,
+							&dummy, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
 			} else {
 				/* Locking pain */
 				up(&f->sem);
 				jffs2_complete_reservation(c);
 			
-				ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, &dummy, alloc_mode);
+				ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs,
+							&dummy, alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
 				down(&f->sem);
 			}
 
@@ -362,7 +366,8 @@ int jffs2_write_inode_range(struct jffs2
 	retry:
 		D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset));
 
-		ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL);
+		ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs,
+					&alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
 		if (ret) {
 			D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
 			break;
@@ -449,7 +454,8 @@ int jffs2_do_create(struct jffs2_sb_info
 	/* Try to reserve enough space for both node and dirent. 
 	 * Just the node will do for now, though 
 	 */
-	ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
+	ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL,
+				JFFS2_SUMMARY_INODE_SIZE);
 	D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
 	if (ret) {
 		up(&f->sem);
@@ -478,7 +484,8 @@ int jffs2_do_create(struct jffs2_sb_info
 
 	up(&f->sem);
 	jffs2_complete_reservation(c);
-	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+				ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
 		
 	if (ret) {
 		/* Eep. */
@@ -549,7 +556,8 @@ int jffs2_do_unlink(struct jffs2_sb_info
 		if (!rd)
 			return -ENOMEM;
 
-		ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION);
+		ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+					ALLOC_DELETION, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
 		if (ret) {
 			jffs2_free_raw_dirent(rd);
 			return ret;
@@ -658,7 +666,8 @@ int jffs2_do_link (struct jffs2_sb_info 
 	if (!rd)
 		return -ENOMEM;
 
-	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+	ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+				ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
 	if (ret) {
 		jffs2_free_raw_dirent(rd);
 		return ret;
diff -Narup mtd2/fs/jffs2/writev.c mtd/fs/jffs2/writev.c
--- mtd2/fs/jffs2/writev.c	2004-11-16 21:36:12.000000000 +0100
+++ mtd/fs/jffs2/writev.c	2005-08-23 10:38:38.000000000 +0200
@@ -44,7 +44,38 @@ int jffs2_flash_direct_writev(struct jff
 {
 	if (c->mtd->writev)
 		return c->mtd->writev(c->mtd, vecs, count, to, retlen);
-	else
+	else {
+		if (jffs2_sum_active()) {
+			int res;
+
+			D1(printk("jffs2_flash_direct_writev(): calles without NAND support (summary)\n"));
+			res = jffs2_sum_add_kvec(c, vecs, count, (uint32_t) to);
+			if (res) {
+				return res;
+			}
+		}
+
 		return mtd_fake_writev(c->mtd, vecs, count, to, retlen);
+	}
 }
 
+int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
+			size_t *retlen, const u_char *buf)
+{
+	int ret;
+	ret = c->mtd->write(c->mtd, ofs, len, retlen, buf);
+
+	if (jffs2_sum_active()) {
+		struct kvec vecs[1];
+		int res;
+
+		vecs[0].iov_base = (unsigned char *) buf;
+		vecs[0].iov_len = len;
+
+		res = jffs2_sum_add_kvec(c, vecs, 1, (uint32_t) ofs);
+		if (res) {
+			return res;
+		}
+	}
+	return ret;
+}
diff -Narup mtd2/fs/Kconfig mtd/fs/Kconfig
--- mtd2/fs/Kconfig	2005-05-09 10:16:08.000000000 +0200
+++ mtd/fs/Kconfig	2005-08-23 12:50:16.000000000 +0200
@@ -64,6 +64,19 @@ config JFFS2_FS_WRITEBUFFER
 	    - NOR flash with transparent ECC
 	    - DataFlash
 
+config JFFS2_SUMMARY
+	bool "JFFS2 summary support (EXPERIMENTAL)"
+	depends on JFFS2_FS && EXPERIMENTAL
+	default n
+	help
+	  This feature makes it possible to use summary information
+	  for faster filesystem mount.
+
+	  The summary information can be inserted into a filesystem image
+	  by the utility 'sumtool'.
+
+	  If unsure, say 'N'.
+
 config JFFS2_COMPRESSION_OPTIONS
 	bool "Advanced compression options for JFFS2"
 	default n
diff -Narup mtd2/include/linux/jffs2_fs_sb.h mtd/include/linux/jffs2_fs_sb.h
--- mtd2/include/linux/jffs2_fs_sb.h	2005-05-19 18:12:17.000000000 +0200
+++ mtd/include/linux/jffs2_fs_sb.h	2005-08-23 15:06:12.000000000 +0200
@@ -112,6 +112,8 @@ struct jffs2_sb_info {
 	uint32_t fsdata_len;
 #endif
 
+	struct jffs2_summary *summary;		/* Summary information */
+
 	/* OS-private pointer for getting back to master superblock info */
 	void *os_priv;
 };
diff -Narup mtd2/include/linux/jffs2.h mtd/include/linux/jffs2.h
--- mtd2/include/linux/jffs2.h	2005-07-26 15:19:36.000000000 +0200
+++ mtd/include/linux/jffs2.h	2005-08-22 12:29:08.000000000 +0200
@@ -28,6 +28,9 @@
 #define JFFS2_EMPTY_BITMASK 0xffff
 #define JFFS2_DIRTY_BITMASK 0x0000
 
+/* Summary node MAGIC marker */
+#define JFFS2_SUM_MAGIC	0x02851885
+
 /* We only allow a single char for length, and 0xFF is empty flash so
    we don't want it confused with a real length. Hence max 254.
 */
@@ -60,6 +63,8 @@
 #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
 #define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
 
+#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
+
 // Maybe later...
 //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
 //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
@@ -146,10 +151,24 @@ struct jffs2_raw_inode
 	uint8_t data[0];
 } __attribute__((packed));
 
+struct jffs2_summary_node{
+	jint16_t magic;
+	jint16_t nodetype; 	/* = JFFS2_NODETYPE_INODE_SUM */
+	jint32_t totlen;
+	jint32_t hdr_crc;
+	jint32_t sum_num;	/* number of sum entries*/
+	jint32_t cln_mkr;	/* clean marker size, 0 = no cleanmarker */
+	jint32_t padded;	/* sum of the size of padding nodes */
+	jint32_t sum_crc;	/* summary information crc */
+	jint32_t node_crc; 	/* node crc */
+	jint32_t sum[0]; 	/* inode summary info */
+} __attribute__((packed));
+
 union jffs2_node_union {
 	struct jffs2_raw_inode i;
 	struct jffs2_raw_dirent d;
 	struct jffs2_unknown_node u;
+	struct jffs2_summary_node s;
 };
 
 #endif /* __LINUX_JFFS2_H__ */
diff -Narup mtd2/util/jffs2dump.c mtd/util/jffs2dump.c
--- mtd2/util/jffs2dump.c	2005-01-21 12:52:22.000000000 +0100
+++ mtd/util/jffs2dump.c	2005-08-22 12:29:08.000000000 +0200
@@ -34,6 +34,7 @@
 #include <byteswap.h>
 #include <getopt.h>
 #include "crc32.h"
+#include "summary.h"
 
 #define PROGRAM "jffs2dump"
 #define VERSION "$Revision: 1.8 $"
@@ -177,7 +178,7 @@ void process_options (int argc, char *ar
  */
 void do_dumpcontent (void) 
 {
-	char			*p = data;
+	char			*p = data, *p_free_begin;
 	union jffs2_node_union 	*node;
 	int			empty = 0, dirty = 0;
 	char			name[256];
@@ -186,16 +187,23 @@ void do_dumpcontent (void) 
 	int			bitchbitmask = 0;
 	int			obsolete;
 
+	p_free_begin = NULL;
 	while ( p < (data + imglen)) {
 		node = (union jffs2_node_union*) p;
 		
 		/* Skip empty space */
+		if (!p_free_begin)
+			p_free_begin = p;
 		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
 			p += 4;
 			empty += 4;
 			continue;
 		}
 		
+		if (p != p_free_begin)
+			printf("Empty space found from 0x%08x to 0x%08x\n", p_free_begin-data, p-data);
+		p_free_begin = NULL;
+
 		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK)	{
 			if (!bitchbitmask++)
     			    printf ("Wrong bitmask  at  0x%08x, 0x%04x\n", p - data, je16_to_cpu (node->u.magic));
@@ -278,6 +286,99 @@ void do_dumpcontent (void) 
 			p += PAD(je32_to_cpu (node->d.totlen));						
 			break;
 	
+		case JFFS2_NODETYPE_SUMMARY: {
+
+			int i;
+			struct jffs2_sum_marker * sm;
+
+			printf("%8s Inode Sum  node at 0x%08x, totlen 0x%08x, sum_num  %5d, cleanmarker size %5d\n",
+					obsolete ? "Obsolete" : "",
+					p - data,
+					je32_to_cpu (node->s.totlen),
+					je32_to_cpu (node->s.sum_num),
+					je32_to_cpu (node->s.cln_mkr));
+
+			crc = crc32 (0, node, sizeof (struct jffs2_summary_node) - 8);
+			if (crc != je32_to_cpu (node->s.node_crc)) {
+				printf ("Wrong node_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.node_crc), crc);
+				p += PAD(je32_to_cpu (node->s.totlen));
+				dirty += PAD(je32_to_cpu (node->s.totlen));;
+				continue;
+			}
+
+			crc = crc32(0, p + sizeof (struct jffs2_summary_node),  je32_to_cpu (node->s.totlen) - sizeof(struct jffs2_summary_node));
+			if (crc != je32_to_cpu(node->s.sum_crc)) {
+				printf ("Wrong data_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - data, je32_to_cpu (node->s.sum_crc), crc);
+				p += PAD(je32_to_cpu (node->s.totlen));
+				dirty += PAD(je32_to_cpu (node->s.totlen));;
+				continue;
+			}
+
+			if (verbose) {
+				void *sp;
+				sp = (p + sizeof(struct jffs2_summary_node));
+
+				for(i=0; i<je32_to_cpu(node->s.sum_num); i++) {
+
+					switch(je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
+						case JFFS2_NODETYPE_INODE : {
+
+							struct jffs2_sum_inode_flash *spi;
+							spi = sp;
+
+							printf ("%14s #ino  %5d,  version %5d, offset 0x%08x, totlen 0x%08x\n",
+							"",
+							je32_to_cpu (spi->inode),
+							je32_to_cpu (spi->version),
+							je32_to_cpu (spi->offset),
+							je32_to_cpu (spi->totlen));
+
+							sp += JFFS2_SUMMARY_INODE_SIZE;
+							break;
+						}
+
+						case JFFS2_NODETYPE_DIRENT : {
+
+							char name[255];
+							struct jffs2_sum_dirent_flash *spd;
+							spd = sp;
+
+							memcpy(name,spd->name,spd->nsize);
+							name [spd->nsize] = 0x0;
+
+							printf ("%14s dirent offset 0x%08x, totlen 0x%08x, #pino  %5d,  version %5d, #ino  %8d, nsize %8d, name %s \n",
+							"",
+							je32_to_cpu (spd->offset),
+							je32_to_cpu (spd->totlen),
+							je32_to_cpu (spd->pino),
+							je32_to_cpu (spd->version),
+							je32_to_cpu (spd->ino),
+							spd->nsize,
+							name);
+
+							sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
+							break;
+						}
+
+						default :
+							printf("Unknown summary node!\n");
+							break;
+					}
+				}
+
+				sm = (struct jffs2_sum_marker *) ((char *)p + je32_to_cpu(node->s.totlen) - sizeof(struct jffs2_sum_marker));
+
+				printf("%14s Sum Node Offset  0x%08x, Magic 0x%08x, Padded size 0x%08x\n",
+					"",
+					je32_to_cpu(sm->offset),
+					je32_to_cpu(sm->magic),
+					je32_to_cpu(node->s.padded));
+			}
+
+			p += PAD(je32_to_cpu (node->s.totlen));
+			break;
+		}
+
 		case JFFS2_NODETYPE_CLEANMARKER:
 			if (verbose) {
 				printf ("%8s Cleanmarker     at 0x%08x, totlen 0x%08x\n", 
@@ -435,7 +536,85 @@ void do_endianconvert (void) 
 				
 			p += PAD(je32_to_cpu (node->u.totlen));						
 			break;
-	
+
+		case JFFS2_NODETYPE_SUMMARY : {
+			struct jffs2_sum_marker *sm_ptr;
+			int i,sum_len;
+			int counter = 0;
+
+			newnode.s.magic = cnv_e16 (node->s.magic);
+			newnode.s.nodetype = cnv_e16 (node->s.nodetype);
+			newnode.s.totlen = cnv_e32 (node->s.totlen);
+			newnode.s.hdr_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_unknown_node) - 4));
+			newnode.s.sum_num = cnv_e32 (node->s.sum_num);
+			newnode.s.cln_mkr = cnv_e32 (node->s.cln_mkr);
+			newnode.s.padded = cnv_e32 (node->s.padded);
+
+			newnode.s.node_crc = cpu_to_e32 (crc32 (0, &newnode, sizeof (struct jffs2_summary_node) - 8));
+
+			// summary header
+			p += sizeof (struct jffs2_summary_node);
+
+			// summary data
+			sum_len = je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_summary_node) - sizeof (struct jffs2_sum_marker);
+
+			for (i=0; i<je32_to_cpu (node->s.sum_num); i++) {
+				union jffs2_sum_flash *fl_ptr;
+
+				fl_ptr = (union jffs2_sum_flash *) p;
+
+				switch (je16_to_cpu (fl_ptr->u.nodetype)) {
+					case JFFS2_NODETYPE_INODE:
+
+						fl_ptr->i.nodetype = cnv_e16 (fl_ptr->i.nodetype);
+						fl_ptr->i.inode = cnv_e32 (fl_ptr->i.inode);
+						fl_ptr->i.version = cnv_e32 (fl_ptr->i.version);
+						fl_ptr->i.offset = cnv_e32 (fl_ptr->i.offset);
+						fl_ptr->i.totlen = cnv_e32 (fl_ptr->i.totlen);
+						p += sizeof (struct jffs2_sum_inode_flash);
+						counter += sizeof (struct jffs2_sum_inode_flash);
+						break;
+
+					case JFFS2_NODETYPE_DIRENT:
+						fl_ptr->d.nodetype = cnv_e16 (fl_ptr->d.nodetype);
+						fl_ptr->d.totlen = cnv_e32 (fl_ptr->d.totlen);
+						fl_ptr->d.offset = cnv_e32 (fl_ptr->d.offset);
+						fl_ptr->d.pino = cnv_e32 (fl_ptr->d.pino);
+						fl_ptr->d.version = cnv_e32 (fl_ptr->d.version);
+						fl_ptr->d.ino = cnv_e32 (fl_ptr->d.ino);
+						p += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
+						counter += sizeof (struct jffs2_sum_dirent_flash) + fl_ptr->d.nsize;
+						break;
+
+					default :
+						printf("Unknown node in summary information!!! nodetype(%x)\n", je16_to_cpu (fl_ptr->u.nodetype));
+						exit(EXIT_FAILURE);
+						break;
+				}
+
+			}
+
+			//pad
+			p += sum_len - counter;
+
+			// summary marker
+			sm_ptr = (struct jffs2_sum_marker *) p;
+			sm_ptr->offset = cnv_e32 (sm_ptr->offset);
+			sm_ptr->magic = cnv_e32 (sm_ptr->magic);
+			p += sizeof (struct jffs2_sum_marker);
+
+			// generate new crc on sum data
+			newnode.s.sum_crc = cpu_to_e32 ( crc32(0, ((char *) node) + sizeof (struct jffs2_summary_node), 
+				je32_to_cpu (node->s.totlen) - sizeof (struct jffs2_summary_node)));
+
+			// write out new node header
+			write(fd, &newnode, sizeof (struct jffs2_summary_node));
+			// write out new summary data
+			write(fd, &node->s.sum, sum_len + sizeof (struct jffs2_sum_marker));
+
+			break;
+		}
+
 		case 0xffff:
 			write (fd, p, 4);
 			p += 4;
diff -Narup mtd2/util/Makefile mtd/util/Makefile
--- mtd2/util/Makefile	2005-08-18 10:40:50.000000000 +0200
+++ mtd/util/Makefile	2005-08-22 12:29:08.000000000 +0200
@@ -16,7 +16,7 @@ TARGETS = ftl_format flash_erase flash_e
 	jffs2dump \
 	nftldump nftl_format docfdisk \
 	rfddump rfdformat \
-	#jffs2reader 
+	sumtool #jffs2reader 
 
 SYMLINKS = 
 
@@ -51,6 +51,9 @@ jffs2reader: jffs2reader.o
 jffs2dump: jffs2dump.o crc32.o
 	$(CC) $(LDFLAGS) -o $@ $^
 
+sumtool: sumtool.o crc32.o
+	$(CC) $(LDFLAGS) -o $@ $^
+
 install: ${TARGETS}
 	mkdir -p ${DESTDIR}/${SBINDIR}
 	install -m0755 -oroot -groot ${TARGETS} ${DESTDIR}/${SBINDIR}/
diff -Narup mtd2/util/summary.h mtd/util/summary.h
--- mtd2/util/summary.h	1970-01-01 01:00:00.000000000 +0100
+++ mtd/util/summary.h	2005-08-23 12:16:29.000000000 +0200
@@ -0,0 +1,143 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                     Patrik Kluba <pajko@halom.u-szeged.hu>,
+ *                     University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id$
+ *
+ */
+
+#ifndef JFFS2_SUMMARY_H
+#define JFFS2_SUMMARY_H
+
+#include <linux/uio.h>
+#include <linux/jffs2.h>
+
+#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
+		c->free_size -= _x; c->dirty_size += _x; \
+		jeb->free_size -= _x ; jeb->dirty_size += _x; \
+		}while(0)
+#define USED_SPACE(x) do { typeof(x) _x = (x); \
+		c->free_size -= _x; c->used_size += _x; \
+		jeb->free_size -= _x ; jeb->used_size += _x; \
+		}while(0)
+#define WASTED_SPACE(x) do { typeof(x) _x = (x); \
+		c->free_size -= _x; c->wasted_size += _x; \
+		jeb->free_size -= _x ; jeb->wasted_size += _x; \
+		}while(0)
+#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
+		c->free_size -= _x; c->unchecked_size += _x; \
+		jeb->free_size -= _x ; jeb->unchecked_size += _x; \
+		}while(0)
+
+#define BLK_STATE_ALLFF		0
+#define BLK_STATE_CLEAN		1
+#define BLK_STATE_PARTDIRTY	2
+#define BLK_STATE_CLEANMARKER	3
+#define BLK_STATE_ALLDIRTY	4
+#define BLK_STATE_BADBLOCK	5
+
+#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
+#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
+#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
+
+/* Summary structures used on flash */
+
+struct jffs2_sum_unknown_flash
+{
+	jint16_t nodetype;	/* node type */
+};
+
+struct jffs2_sum_inode_flash
+{
+	jint16_t nodetype;	/* node type */
+	jint32_t inode;		/* inode number */
+	jint32_t version;	/* inode version */
+	jint32_t offset;	/* offset on jeb */
+	jint32_t totlen; 	/* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_flash
+{
+	jint16_t nodetype;	/* == JFFS_NODETYPE_DIRENT */
+	jint32_t totlen;	/* record length */
+	jint32_t offset;	/* ofset on jeb */
+	jint32_t pino;		/* parent inode */
+	jint32_t version;	/* dirent version */
+	jint32_t ino; 		/* == zero for unlink */
+	uint8_t nsize;		/* dirent name size */
+	uint8_t type;		/* dirent type */
+	uint8_t name[0];	/* dirent name */
+} __attribute__((packed));
+
+union jffs2_sum_flash
+{
+	struct jffs2_sum_unknown_flash u;
+	struct jffs2_sum_inode_flash i;
+	struct jffs2_sum_dirent_flash d;
+};
+
+/* Summary structures used in the memory */
+
+struct jffs2_sum_unknown_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* node type */
+};
+
+struct jffs2_sum_inode_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* node type */
+	jint32_t inode;		/* inode number */
+	jint32_t version;	/* inode version */
+	jint32_t offset;	/* offset on jeb */
+	jint32_t totlen; 	/* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_mem
+{
+	union jffs2_sum_mem *next;
+	jint16_t nodetype;	/* == JFFS_NODETYPE_DIRENT */
+	jint32_t totlen;	/* record length */
+	jint32_t offset;	/* ofset on jeb */
+	jint32_t pino;		/* parent inode */
+	jint32_t version;	/* dirent version */
+	jint32_t ino; 		/* == zero for unlink */
+	uint8_t nsize;		/* dirent name size */
+	uint8_t type;		/* dirent type */
+	uint8_t name[0];	/* dirent name */
+} __attribute__((packed));
+
+union jffs2_sum_mem 
+{
+	struct jffs2_sum_unknown_mem u;
+	struct jffs2_sum_inode_mem i;
+	struct jffs2_sum_dirent_mem d;
+};
+
+struct jffs2_summary
+{
+	uint32_t sum_size;
+	uint32_t sum_num;
+	uint32_t sum_padded;
+	union jffs2_sum_mem *sum_list_head;
+	union jffs2_sum_mem *sum_list_tail;
+};
+
+/* Summary marker is stored at the end of every sumarized erase block */
+
+struct jffs2_sum_marker
+{
+	jint32_t offset;	/* offset of the summary node in the jeb */
+	jint32_t magic; 	/* == JFFS2_SUM_MAGIC */
+};
+
+#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_summary_node) + sizeof(struct jffs2_sum_marker))
+
+#endif
diff -Narup mtd2/util/sumtool.c mtd/util/sumtool.c
--- mtd2/util/sumtool.c	1970-01-01 01:00:00.000000000 +0100
+++ mtd/util/sumtool.c	2005-08-23 12:48:58.000000000 +0200
@@ -0,0 +1,820 @@
+/*
+ *  sumtool.c
+ *
+ *  Copyright (C) 2004 Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                     Ferenc Havasi <havasi@inf.u-szeged.hu>
+ *                     University of Szeged, Hungary
+ *
+ * $Id$
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Overview:
+ *   This is a utility insert summary information into JFFS2 image for 
+ *   faster mount time
+ *
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <asm/types.h>
+#include <dirent.h>
+#include <mtd/jffs2-user.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <getopt.h>
+#include "crc32.h"
+#include "summary.h"
+
+#define PAD(x) (((x)+3)&~3)
+
+static const char *const app_name = "sumtool2";
+
+static struct jffs2_summary *sum_collected = NULL;
+
+static int verbose = 0;
+static int padto = 0;				/* pad the output with 0xFF to the end of the final eraseblock */
+static int add_cleanmarkers = 1;		/* add cleanmarker to output */
+static int use_input_cleanmarker_size = 1;	/* use input file's cleanmarker size (default) */
+static int found_cleanmarkers = 0;		/* cleanmarker found in input file */
+static struct jffs2_unknown_node cleanmarker;
+static int cleanmarker_size = sizeof(cleanmarker);
+static const char *short_options = "o:i:e:hvVblnc:p";
+static int erase_block_size = 65536;
+static int target_endian = __BYTE_ORDER;
+static int out_fd = -1;
+static int in_fd = -1;
+
+static uint8_t *data_buffer = NULL; 		/* buffer for inodes */
+static unsigned int data_ofs = 0;	 	/* inode buffer offset */
+
+static uint8_t *file_buffer = NULL;		/* file buffer contains the actual erase block*/
+static unsigned int file_ofs = 0;		/* position in the buffer */
+
+static struct option long_options[] = {
+	{"output", 1, NULL, 'o'},
+	{"input", 1, NULL, 'i'},
+	{"eraseblock", 1, NULL, 'e'},
+	{"help", 0, NULL, 'h'},
+	{"verbose", 0, NULL, 'v'},
+	{"version", 0, NULL, 'V'},
+	{"bigendian", 0, NULL, 'b'},
+	{"littleendian", 0, NULL, 'l'},
+	{"no-cleanmarkers", 0, NULL, 'n'},
+	{"cleanmarker", 1, NULL, 'c'},
+	{"pad", 0, NULL, 'p'},
+	{NULL, 0, NULL, 0}
+};
+
+static char *helptext =
+	"Usage: sumtool [OPTIONS] -i inputfile -o outputfile\n\n"
+	"Convert the input JFFS2 image to a summarized JFFS2 image\n"
+	"Summary makes mounting faster - if summary support enabled in your kernel\n\n"
+	"Options:\n"
+	"  -e, --eraseblock=SIZE     Use erase block size SIZE (default: 64KiB)\n"
+	"                            (usually 16KiB on NAND)\n"
+	"  -c, --cleanmarker=SIZE    Size of cleanmarker (default 12).\n"
+	"                            (usually 16 bytes on NAND, and will be set to\n"
+	"                            this value if left at the default 12). Will be\n"
+	"                            stored in OOB after each physical page composing\n"
+	"                            a physical eraseblock.\n"
+	"  -n, --no-cleanmarkers     Don't add a cleanmarker to every eraseblock\n"
+	"  -o, --output=FILE         Output to FILE \n"
+	"  -i, --input=FILE          Input from FILE \n"
+	"  -b, --bigendian           Image is big endian\n"
+	"  -l  --littleendian        Image is little endian\n"
+	"  -h, --help                Display this help text\n"
+	"  -v, --verbose             Verbose operation\n"
+	"  -V, --version             Display version information\n"
+	"  -p, --pad                 Pad the OUTPUT with 0xFF to the end of the final\n"
+	"                            eraseblock\n\n";
+
+
+static char *revtext = "$Revision: 1.3 $";
+
+static unsigned char ffbuf[16] = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static void verror_msg(const char *s, va_list p)
+{
+	fflush(stdout);
+	fprintf(stderr, "%s: ", app_name);
+	vfprintf(stderr, s, p);
+}
+
+static void error_msg_and_die(const char *s, ...)
+{
+	va_list p;
+
+	va_start(p, s);
+	verror_msg(s, p);
+	va_end(p);
+	putc('\n', stderr);
+	exit(EXIT_FAILURE);
+}
+
+static void vperror_msg(const char *s, va_list p)
+{
+	int err = errno;
+
+	if (s == 0)
+		s = "";
+	verror_msg(s, p);
+	if (*s)
+		s = ": ";
+	fprintf(stderr, "%s%s\n", s, strerror(err));
+}
+
+static void perror_msg_and_die(const char *s, ...)
+{
+	va_list p;
+
+	va_start(p, s);
+	vperror_msg(s, p);
+	va_end(p);
+	exit(EXIT_FAILURE);
+}
+
+
+
+static void full_write(void *target_buff, const void *buf, int len);
+
+void setup_cleanmarker()
+{
+	cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
+	cleanmarker.totlen = cpu_to_je32(cleanmarker_size);
+	cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
+}
+
+void process_options (int argc, char **argv)
+{
+	int opt,c;
+
+	while ((opt = getopt_long(argc, argv, short_options, long_options, &c)) >= 0) {
+		switch (opt) {
+			case 'o':
+				if (out_fd != -1)
+					error_msg_and_die("output filename specified more than once");
+				out_fd = open(optarg, O_CREAT | O_TRUNC | O_RDWR, 0644);
+				if (out_fd == -1)
+					perror_msg_and_die("open output file");
+				break;
+
+			case 'i':
+				if (in_fd != -1)
+					error_msg_and_die("input filename specified more than once");
+				in_fd = open(optarg, O_RDONLY);
+				if (in_fd == -1)
+					perror_msg_and_die("open input file");
+				break;
+			case 'b':
+				target_endian = __BIG_ENDIAN;
+				break;
+			case 'l':
+				target_endian = __LITTLE_ENDIAN;
+				break;
+			case 'h':
+			case '?':
+				error_msg_and_die(helptext);
+			case 'v':
+				verbose = 1;
+				break;
+
+			case 'V':
+				error_msg_and_die("revision %.*s\n",
+						(int) strlen(revtext) - 13, revtext + 11);
+
+			case 'e': {
+				char *next;
+				unsigned units = 0;
+				erase_block_size = strtol(optarg, &next, 0);
+				if (!erase_block_size)
+					error_msg_and_die("Unrecognisable erase size\n");
+
+				if (*next) {
+					if (!strcmp(next, "KiB")) {
+						units = 1024;
+					} else if (!strcmp(next, "MiB")) {
+						units = 1024 * 1024;
+					} else {
+						error_msg_and_die("Unknown units in erasesize\n");
+					}
+				} else {
+					if (erase_block_size < 0x1000)
+						units = 1024;
+					else
+						units = 1;
+				}
+				erase_block_size *= units;
+
+				/* If it's less than 8KiB, they're not allowed */
+				if (erase_block_size < 0x2000) {
+					fprintf(stderr, "Erase size 0x%x too small. Increasing to 8KiB minimum\n",
+						erase_block_size);
+					erase_block_size = 0x2000;
+				}
+				break;
+			}
+
+			case 'n':
+				add_cleanmarkers = 0;
+				break;
+			case 'c':
+				cleanmarker_size = strtol(optarg, NULL, 0);
+
+				if (cleanmarker_size < sizeof(cleanmarker)) {
+					error_msg_and_die("cleanmarker size must be >= 12");
+				}
+				if (cleanmarker_size >= erase_block_size) {
+					error_msg_and_die("cleanmarker size must be < eraseblock size");
+				}
+
+				use_input_cleanmarker_size = 0;
+				found_cleanmarkers = 1;
+				setup_cleanmarker();
+
+				break;
+			case 'p':
+				padto = 1;
+				break;
+		}
+	}
+}
+
+
+void init_buffers()
+{
+	data_buffer = malloc(erase_block_size);
+
+	if (!data_buffer) {
+		perror("out of memory");
+		close (in_fd);
+		close (out_fd);
+		exit(1);
+	}
+
+	file_buffer = malloc(erase_block_size);
+
+	if (!file_buffer) {
+		perror("out of memory");
+		close (in_fd);
+		close (out_fd);
+		exit(1);
+	}
+}
+
+void init_sumlist()
+{
+	sum_collected = (struct jffs2_summary *) malloc (sizeof(struct jffs2_summary));
+
+	if (!sum_collected)
+		error_msg_and_die("Can't allocate memory for jffs2_summary!\n");
+
+	memset(sum_collected, 0, sizeof(struct jffs2_summary));
+}
+
+void clean_buffers()
+{
+	if (data_buffer)
+		free(data_buffer);
+	if (file_buffer)
+		free(file_buffer);
+}
+
+void clean_sumlist()
+{
+	union jffs2_sum_mem *temp;
+
+	if (sum_collected) {
+
+		while (sum_collected->sum_list_head) {
+			temp = sum_collected->sum_list_head;
+			sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
+			free(temp);
+			sum_collected->sum_num--;
+		}
+
+		if (sum_collected->sum_num != 0)
+			printf("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???");
+
+		free(sum_collected);
+	}
+}
+
+int load_next_block()
+{
+	int ret;
+	ret = read(in_fd, file_buffer, erase_block_size);
+	file_ofs = 0;
+
+	if (verbose)
+		printf("Load next block : %d bytes read\n",ret);
+
+	return ret;
+}
+
+void write_buff_to_file()
+{
+	int ret;
+	int len = data_ofs;
+
+	uint8_t *buf = NULL;
+
+	buf = data_buffer;
+	while (len > 0) {
+		ret = write(out_fd, buf, len);
+
+		if (ret < 0)
+			perror_msg_and_die("write");
+
+		if (ret == 0)
+			perror_msg_and_die("write returned zero");
+
+		len -= ret;
+		buf += ret;
+	}
+
+	data_ofs = 0;
+}
+
+void dump_sum_records()
+{
+
+	struct jffs2_summary_node isum;
+	struct jffs2_sum_marker *sm;
+	union jffs2_sum_mem *temp;
+	jint32_t offset;
+	void *wpage;
+	int datasize, infosize, padsize;
+	jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
+
+	if (!sum_collected->sum_num || !sum_collected->sum_list_head)
+		return; 
+
+	datasize = sum_collected->sum_size + sizeof(struct jffs2_sum_marker);
+	infosize = sizeof(struct jffs2_summary_node) + datasize;
+	padsize = erase_block_size - data_ofs - infosize;
+	infosize += padsize; datasize += padsize;
+	offset = cpu_to_je32(data_ofs);
+
+	jint32_t *tpage = (jint32_t *) malloc(datasize);
+
+	if(!tpage)
+		error_msg_and_die("Can't allocate memory to dump summary information!\n");
+
+	memset(tpage, 0xff, datasize);
+	memset(&isum, 0, sizeof(isum));
+
+	isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+	isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
+	isum.totlen = cpu_to_je32(infosize);
+	isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
+	isum.padded = cpu_to_je32(0);
+
+	if (add_cleanmarkers && found_cleanmarkers) {
+		isum.cln_mkr = cpu_to_je32(cleanmarker_size);
+	} else {
+		isum.cln_mkr = cpu_to_je32(0);
+	}
+
+	isum.sum_num = cpu_to_je32(sum_collected->sum_num);
+	wpage = tpage;
+
+	while (sum_collected->sum_num) {
+		switch(je16_to_cpu(sum_collected->sum_list_head->u.nodetype)) {
+
+			case JFFS2_NODETYPE_INODE : {
+				struct jffs2_sum_inode_flash *sino_ptr = wpage;
+
+				sino_ptr->nodetype = sum_collected->sum_list_head->i.nodetype;
+				sino_ptr->inode = sum_collected->sum_list_head->i.inode;
+				sino_ptr->version = sum_collected->sum_list_head->i.version;
+				sino_ptr->offset = sum_collected->sum_list_head->i.offset;
+				sino_ptr->totlen = sum_collected->sum_list_head->i.totlen;
+
+				wpage += JFFS2_SUMMARY_INODE_SIZE;
+				break;
+			}
+
+			case JFFS2_NODETYPE_DIRENT : {
+				struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
+
+				sdrnt_ptr->nodetype = sum_collected->sum_list_head->d.nodetype;
+				sdrnt_ptr->totlen = sum_collected->sum_list_head->d.totlen;
+				sdrnt_ptr->offset = sum_collected->sum_list_head->d.offset;
+				sdrnt_ptr->pino = sum_collected->sum_list_head->d.pino;
+				sdrnt_ptr->version = sum_collected->sum_list_head->d.version;
+				sdrnt_ptr->ino = sum_collected->sum_list_head->d.ino;
+				sdrnt_ptr->nsize = sum_collected->sum_list_head->d.nsize;
+				sdrnt_ptr->type = sum_collected->sum_list_head->d.type;
+
+				memcpy(sdrnt_ptr->name, sum_collected->sum_list_head->d.name,
+						sum_collected->sum_list_head->d.nsize);
+
+				wpage += JFFS2_SUMMARY_DIRENT_SIZE(sum_collected->sum_list_head->d.nsize);
+				break;
+			}
+
+			default : {
+				printf("Unknown node type!\n");
+			}
+		}
+
+		temp = sum_collected->sum_list_head;
+		sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
+		free(temp);
+
+		sum_collected->sum_num--;
+	}
+
+	sum_collected->sum_size = 0;
+	sum_collected->sum_num = 0;
+	sum_collected->sum_list_tail = NULL;
+
+	wpage += padsize;
+
+	sm = wpage;
+	sm->offset = offset;
+	sm->magic = magic;
+
+	isum.sum_crc = cpu_to_je32(crc32(0, tpage, datasize));
+	isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8));
+
+	full_write(data_buffer + data_ofs, &isum, sizeof(isum));
+	full_write(data_buffer + data_ofs, tpage, datasize);
+
+	free(tpage);
+}
+
+static void full_write(void *target_buff, const void *buf, int len)
+{
+	memcpy(target_buff, buf, len);
+	data_ofs += len;
+}
+
+static void pad(int req)
+{
+	while (req) {
+		if (req > sizeof(ffbuf)) {
+			full_write(data_buffer + data_ofs, ffbuf, sizeof(ffbuf));
+			req -= sizeof(ffbuf);
+		} else {
+			full_write(data_buffer + data_ofs, ffbuf, req);
+			req = 0;
+		}
+	}
+}
+
+static inline void padword()
+{
+	if (data_ofs % 4)
+		full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4));
+}
+
+
+static inline void pad_block_if_less_than(int req,int plus)
+{
+
+	int datasize = req + plus + sum_collected->sum_size + sizeof(struct jffs2_summary_node) + 8;
+	datasize += (4 - (datasize % 4)) % 4;
+
+	if (data_ofs + req > erase_block_size - datasize) {
+		dump_sum_records();
+		write_buff_to_file();
+	}
+
+	if (add_cleanmarkers && found_cleanmarkers) {
+		if (!data_ofs) {
+			full_write(data_buffer, &cleanmarker, sizeof(cleanmarker));
+			pad(cleanmarker_size - sizeof(cleanmarker));
+			padword();
+		}
+	}
+}
+
+void flush_buffers()
+{
+
+	if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */
+		if (data_ofs != cleanmarker_size) {	/* INODE BUFFER */
+
+			int datasize = sum_collected->sum_size + sizeof(struct jffs2_summary_node) + 8;
+			datasize += (4 - (datasize % 4)) % 4;
+
+			/* If we have a full inode buffer, then write out inode and summary data  */
+			if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
+				dump_sum_records();
+				write_buff_to_file();
+			} else {	/* else just write out inode data */
+				if (padto)
+					pad(erase_block_size - data_ofs);
+				write_buff_to_file();
+			}
+		}
+	} else { /* NO CLEANMARKER */
+		if (data_ofs != 0) { /* INODE BUFFER */
+
+			int datasize = sum_collected->sum_size + sizeof(struct jffs2_summary_node) + 8;
+			datasize += (4 - (datasize % 4)) % 4;
+
+			/* If we have a full inode buffer, then write out inode and summary data */
+			if (data_ofs + sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
+				dump_sum_records();
+				write_buff_to_file();
+			} else {	/* Else just write out inode data */
+				if(padto)
+					pad(erase_block_size - data_ofs);
+				write_buff_to_file();
+			}
+		}
+	}
+}
+
+int add_sum_mem(union jffs2_sum_mem *item)
+{
+
+	if (!sum_collected->sum_list_head)
+		sum_collected->sum_list_head = (union jffs2_sum_mem *) item;
+	if (sum_collected->sum_list_tail)
+		sum_collected->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
+	sum_collected->sum_list_tail = (union jffs2_sum_mem *) item;
+
+	switch (je16_to_cpu(item->u.nodetype)) {
+		case JFFS2_NODETYPE_INODE:
+			sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE;
+			sum_collected->sum_num++;
+			break;
+
+		case JFFS2_NODETYPE_DIRENT:
+			sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
+			sum_collected->sum_num++;
+			break;
+
+		default:
+			error_msg_and_die("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype));
+	}
+	return 0;
+}
+
+void add_sum_inode_mem(union jffs2_node_union *node)
+{
+	struct jffs2_sum_inode_mem *temp = (struct jffs2_sum_inode_mem *) malloc(sizeof(struct jffs2_sum_inode_mem));
+
+	if (!temp)
+		error_msg_and_die("Can't allocate memory for summary information!\n");
+
+	temp->nodetype = node->i.nodetype;
+	temp->inode = node->i.ino;
+	temp->version = node->i.version;
+	temp->offset = cpu_to_je32(data_ofs);
+	temp->totlen = node->i.totlen;
+	temp->next = NULL;
+
+	add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void add_sum_dirent_mem(union jffs2_node_union *node)
+{
+	struct jffs2_sum_dirent_mem *temp = (struct jffs2_sum_dirent_mem *)
+			malloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize);
+
+	if (!temp)
+		error_msg_and_die("Can't allocate memory for summary information!\n");
+
+	temp->nodetype = node->d.nodetype;
+	temp->totlen = node->d.totlen;
+	temp->offset = cpu_to_je32(data_ofs);
+	temp->pino = node->d.pino;
+	temp->version = node->d.version;
+	temp->ino = node->d.ino;
+	temp->nsize = node->d.nsize;
+	temp->type = node->d.type;
+	temp->next = NULL;
+
+	memcpy(temp->name,node->d.name,node->d.nsize);
+	add_sum_mem((union jffs2_sum_mem *) temp);
+}
+
+void write_dirent_to_buff(union jffs2_node_union *node)
+{
+	pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize));
+	add_sum_dirent_mem(node);
+	full_write(data_buffer + data_ofs, &(node->d), je32_to_cpu (node->d.totlen));
+	padword();
+}
+
+
+void write_inode_to_buff(union jffs2_node_union *node)
+{
+	pad_block_if_less_than(je32_to_cpu (node->i.totlen),JFFS2_SUMMARY_INODE_SIZE);
+	add_sum_inode_mem(node);	/* Add inode summary mem to summary list */
+	full_write(data_buffer + data_ofs, &(node->i), je32_to_cpu (node->i.totlen));	/* Write out the inode to inode_buffer */
+	padword();
+}
+
+void create_summed_image(int inp_size)
+{
+	uint8_t *p = file_buffer;
+	union jffs2_node_union *node;
+	uint32_t crc;
+	uint16_t type;
+	int bitchbitmask = 0;
+	int obsolete;
+	char name[256];
+
+	while ( p < (file_buffer + inp_size)) {
+
+		node = (union jffs2_node_union *) p;
+
+		/* Skip empty space */
+		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
+			p += 4;
+			continue;
+		}
+
+		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
+			if (!bitchbitmask++)
+				printf ("Wrong bitmask  at  0x%08x, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic));
+			p += 4;
+			continue;
+		}
+
+		bitchbitmask = 0;
+
+		type = je16_to_cpu(node->u.nodetype);
+		if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
+			obsolete = 1;
+			type |= JFFS2_NODE_ACCURATE;
+		} else {
+			obsolete = 0;
+		}
+
+		node->u.nodetype = cpu_to_je16(type);
+
+		crc = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
+		if (crc != je32_to_cpu (node->u.hdr_crc)) {
+			printf ("Wrong hdr_crc  at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc);
+			p += 4;
+			continue;
+		}
+
+		switch(je16_to_cpu(node->u.nodetype)) {
+			case JFFS2_NODETYPE_INODE:
+				if (verbose)
+					printf ("%8s Inode      node at 0x%08x, totlen 0x%08x, #ino  %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
+						je32_to_cpu ( node->i.version), je32_to_cpu (node->i.isize), 
+						je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
+
+				crc = crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
+				if (crc != je32_to_cpu (node->i.node_crc)) {
+					printf ("Wrong node_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->i.node_crc), crc);
+					p += PAD(je32_to_cpu (node->i.totlen));
+					continue;
+				}
+
+				crc = crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
+				if (crc != je32_to_cpu(node->i.data_crc)) {
+					printf ("Wrong data_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->i.data_crc), crc);
+					p += PAD(je32_to_cpu (node->i.totlen));
+					continue;
+				}
+
+				write_inode_to_buff(node);
+
+				p += PAD(je32_to_cpu (node->i.totlen));
+				break;
+
+			case JFFS2_NODETYPE_DIRENT:
+				memcpy (name, node->d.name, node->d.nsize);
+				name [node->d.nsize] = 0x0;
+
+				if (verbose)
+					printf ("%8s Dirent     node at 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino  %8d, nsize %8d, name %s\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
+						je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
+						node->d.nsize, name);
+
+				crc = crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
+				if (crc != je32_to_cpu (node->d.node_crc)) {
+					printf ("Wrong node_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->d.node_crc), crc);
+					p += PAD(je32_to_cpu (node->d.totlen));
+					continue;
+				}
+
+				crc = crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
+				if (crc != je32_to_cpu(node->d.name_crc)) {
+					printf ("Wrong name_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->d.name_crc), crc);
+					p += PAD(je32_to_cpu (node->d.totlen));
+					continue;
+				}
+
+				write_dirent_to_buff(node);
+
+				p += PAD(je32_to_cpu (node->d.totlen));
+				break;
+
+			case JFFS2_NODETYPE_CLEANMARKER:
+				if (verbose) {
+					printf ("%8s Cleanmarker     at 0x%08x, totlen 0x%08x\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+
+				if (!found_cleanmarkers) {
+					found_cleanmarkers = 1;
+
+					if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1){
+						cleanmarker_size = je32_to_cpu (node->u.totlen);
+						setup_cleanmarker();
+					}
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case JFFS2_NODETYPE_PADDING:
+				if (verbose) {
+					printf ("%8s Padding    node at 0x%08x, totlen 0x%08x\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+				p += PAD(je32_to_cpu (node->u.totlen));
+				break;
+
+			case 0xffff:
+				p += 4;
+				break;
+
+			default:
+				if (verbose) {
+					printf ("%8s Unknown    node at 0x%08x, totlen 0x%08x\n",
+						obsolete ? "Obsolete" : "",
+						p - file_buffer, je32_to_cpu (node->u.totlen));
+				}
+
+				p += PAD(je32_to_cpu (node->u.totlen));
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int ret;
+
+	process_options(argc,argv);
+
+	if ((in_fd == -1) || (out_fd == -1)) {
+		if(in_fd != -1)
+			close(in_fd);
+		if(out_fd != -1)
+			close(out_fd);
+		fprintf(stderr,helptext);
+		error_msg_and_die("You must specify input and output files!\n");
+	}
+
+	init_buffers();
+	init_sumlist();
+
+	while ((ret = load_next_block())) {
+		create_summed_image(ret);
+	}
+
+	flush_buffers();
+	clean_buffers();
+	clean_sumlist();
+
+	if (in_fd != -1)
+		close(in_fd);
+	if (out_fd != -1)
+		close(out_fd);
+
+	return 0;
+}
