All of lore.kernel.org
 help / color / mirror / Atom feed
* JFFS2 mount time
@ 2004-12-15 23:19 Gareth Bult (Encryptec)
  2004-12-16  0:15 ` Josh Boyer
  2004-12-16 13:43 ` Ferenc Havasi
  0 siblings, 2 replies; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-15 23:19 UTC (permalink / raw)
  To: Linux MTD

Hi,

I've been working on the MTD block driver for JFFS2 and now seem to have
a relatively stable environment with a JFFS2 root filesystem on a USB
flash key device. 
(mtd block device speed now approximates actual device speed on both
read and write)

It seems to be much quicker (generally) than the previous ext2
incarnation.

However, I'm looking at 30secs to mount the root filesystem.

I would be very grateful of some advice on the following before I start
digging through the JFFS2 code itself;

a. Is it possible (conceptually) to background the mount scan so the
system can boot while the scan happens ?
b. Is there an easy way to bypass the scan and does JFFS3 do this ? 

Any help/advice would be much appreciated.

Many thanks,
Gareth.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-15 23:19 JFFS2 mount time Gareth Bult (Encryptec)
@ 2004-12-16  0:15 ` Josh Boyer
  2004-12-16  1:02   ` Gareth Bult (Encryptec)
  2004-12-16 13:43 ` Ferenc Havasi
  1 sibling, 1 reply; 70+ messages in thread
From: Josh Boyer @ 2004-12-16  0:15 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Gareth Bult (Encryptec) wrote:
> Hi,
> 
> I've been working on the MTD block driver for JFFS2 and now seem to have
> a relatively stable environment with a JFFS2 root filesystem on a USB
> flash key device. 
> (mtd block device speed now approximates actual device speed on both
> read and write)

I assume you mean blkmtd here.  The mtdblock driver is used to present 
an IDE type interface to flash, whereas blkmtd is used to present a 
flash interface to an IDE type device.

> 
> It seems to be much quicker (generally) than the previous ext2
> incarnation.
> 
> However, I'm looking at 30secs to mount the root filesystem.

How big of a device?

> a. Is it possible (conceptually) to background the mount scan so the
> system can boot while the scan happens ?

Which version of the code are you using?  Mount time has been 
significantly improved in newer versions of the code.

> b. Is there an easy way to bypass the scan and does JFFS3 do this ? 

Not that I know of, because the code needs to read the node information 
in order to get the versioning of inodes, etc. correct.

JFFS3 is essentially the exact same code base as JFFS2 right now.  It 
was just forked about a week ago.

josh

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-16  0:15 ` Josh Boyer
@ 2004-12-16  1:02   ` Gareth Bult (Encryptec)
  2004-12-16 12:53     ` Josh Boyer
  0 siblings, 1 reply; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-16  1:02 UTC (permalink / raw)
  To: Josh Boyer; +Cc: Linux MTD

Hi,

Sure, the file I've been changing is blkmtd.c.

The device I'm aiming for and testing on is 256Mb with a 128k erase
size.

Currently I'm using the code included in the 2.6.9 kernel source tree
with tools from cvs as of about a week ago.

Is this likely to contain the latest speedups or should I be looking
elsewhere?

tia
Gareth.

On Wed, 2004-12-15 at 18:15 -0600, Josh Boyer wrote:
> Gareth Bult (Encryptec) wrote:
> > Hi,
> > 
> > I've been working on the MTD block driver for JFFS2 and now seem to have
> > a relatively stable environment with a JFFS2 root filesystem on a USB
> > flash key device. 
> > (mtd block device speed now approximates actual device speed on both
> > read and write)
> 
> I assume you mean blkmtd here.  The mtdblock driver is used to present 
> an IDE type interface to flash, whereas blkmtd is used to present a 
> flash interface to an IDE type device.
> 
> > 
> > It seems to be much quicker (generally) than the previous ext2
> > incarnation.
> > 
> > However, I'm looking at 30secs to mount the root filesystem.
> 
> How big of a device?
> 
> > a. Is it possible (conceptually) to background the mount scan so the
> > system can boot while the scan happens ?
> 
> Which version of the code are you using?  Mount time has been 
> significantly improved in newer versions of the code.
> 
> > b. Is there an easy way to bypass the scan and does JFFS3 do this ? 
> 
> Not that I know of, because the code needs to read the node information 
> in order to get the versioning of inodes, etc. correct.
> 
> JFFS3 is essentially the exact same code base as JFFS2 right now.  It 
> was just forked about a week ago.
> 
> josh
> 

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-16  1:02   ` Gareth Bult (Encryptec)
@ 2004-12-16 12:53     ` Josh Boyer
  2004-12-16 21:22       ` Gareth Bult (Encryptec)
  0 siblings, 1 reply; 70+ messages in thread
From: Josh Boyer @ 2004-12-16 12:53 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

On Wed, 2004-12-15 at 19:02, Gareth Bult (Encryptec) wrote:
> Hi,

Quick FYI, don't top post.  The email gremlin will chase you down and
make you read http://david.woodhou.se/email.html if you break too many
rules ;)

> 
> Sure, the file I've been changing is blkmtd.c.

Ok, cool.

> 
> The device I'm aiming for and testing on is 256Mb with a 128k erase
> size.
> 
> Currently I'm using the code included in the 2.6.9 kernel source tree
> with tools from cvs as of about a week ago.

Ok, good.


> Is this likely to contain the latest speedups or should I be looking
> elsewhere?

That should have the speedups I was referring to.  Basically checking
the node CRCs is deferred until after mount time so the mount succeeds
much more quickly.

There is one more feature pending that I know of.  Ferenc Havasi has
some eraseblock summary changes that should help.  I believe the
intention was to commit that to JFFS3, but I haven't seen it go in yet.

josh

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-15 23:19 JFFS2 mount time Gareth Bult (Encryptec)
  2004-12-16  0:15 ` Josh Boyer
@ 2004-12-16 13:43 ` Ferenc Havasi
  2004-12-20 16:01   ` Gareth Bult (Encryptec)
  1 sibling, 1 reply; 70+ messages in thread
From: Ferenc Havasi @ 2004-12-16 13:43 UTC (permalink / raw)
  To: Gareth Bult; +Cc: Linux MTD

[-- Attachment #1: Type: text/plain, Size: 343 bytes --]

Hi Gareth,

> However, I'm looking at 30secs to mount the root filesystem.

Did you try our patch? I send it now again, we made it fresh for the 
current CVS. See its usage in the archive (16th November).

It will part of JFFS3.

This is designed for NAND devices - I don't know too much about your 
environment, but it may help.

Bye,
Ferenc

[-- Attachment #2: jffs2-summary-20041207.patch --]
[-- Type: text/plain, Size: 88751 bytes --]

diff --unified --new-file --recursive mtd/fs/Kconfig mtd-dec07/fs/Kconfig
--- mtd/fs/Kconfig	2004-11-04 00:00:11.000000000 +0100
+++ mtd-dec07/fs/Kconfig	2004-12-07 16:03:02.000000000 +0100
@@ -77,6 +77,19 @@
 		 ECC for JFFS2.  This type of flash chip is not common, however it is
 		 available from STMicro.
 
+config JFFS2_SUMMARY
+        bool "JFFS2 summary support (EXPERIMENTAL)" 
+        depends on JFFS2_FS
+        default n
+        help 
+          This feature makes it possible to use summary information
+          for faster filesystem mount - specially on NAND.
+
+          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 --unified --new-file --recursive mtd/fs/jffs2/Makefile.common mtd-dec07/fs/jffs2/Makefile.common
--- mtd/fs/jffs2/Makefile.common	2004-11-04 00:00:11.000000000 +0100
+++ mtd-dec07/fs/jffs2/Makefile.common	2004-12-07 16:03:02.000000000 +0100
@@ -16,3 +16,4 @@
 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 --unified --new-file --recursive mtd/fs/jffs2/build.c mtd-dec07/fs/jffs2/build.c
--- mtd/fs/jffs2/build.c	2004-11-28 00:00:13.000000000 +0100
+++ mtd-dec07/fs/jffs2/build.c	2004-12-07 16:08:31.000000000 +0100
@@ -331,6 +331,10 @@
 		c->blocks[i].first_node = NULL;
 		c->blocks[i].last_node = NULL;
 		c->blocks[i].bad_count = 0;
+ #ifdef CONFIG_JFFS2_SUMMARY	
+ 		c->blocks[i].sum_collected = NULL;
+ #endif
+
 	}
 
 	init_MUTEX(&c->alloc_sem);
diff --unified --new-file --recursive mtd/fs/jffs2/dir.c mtd-dec07/fs/jffs2/dir.c
--- mtd/fs/jffs2/dir.c	2004-11-17 00:00:14.000000000 +0100
+++ mtd-dec07/fs/jffs2/dir.c	2004-12-07 16:03:02.000000000 +0100
@@ -22,6 +22,7 @@
 #include <linux/time.h>
 #include "nodelist.h"
 
+
 /* Urgh. Please tell me there's a nicer way of doing these. */
 #include <linux/version.h>
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
@@ -314,7 +315,7 @@
 	 * Just the node will do for now, though 
 	 */
 	namelen = dentry->d_name.len;
-	ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL);
+	ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
 
 	if (ret) {
 		jffs2_free_raw_inode(ri);
@@ -360,7 +361,7 @@
 	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);
@@ -445,7 +446,7 @@
 	 * 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);
@@ -488,7 +489,7 @@
 	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);
@@ -597,7 +598,7 @@
 	 * 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);
@@ -642,7 +643,7 @@
 	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);
@@ -796,4 +797,3 @@
 
 	return 0;
 }
-
diff --unified --new-file --recursive mtd/fs/jffs2/file.c mtd-dec07/fs/jffs2/file.c
--- mtd/fs/jffs2/file.c	2004-11-17 00:00:14.000000000 +0100
+++ mtd-dec07/fs/jffs2/file.c	2004-12-07 16:03:02.000000000 +0100
@@ -22,6 +22,7 @@
 #include <linux/jffs2.h>
 #include "nodelist.h"
 
+
 extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
 extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak));
 
@@ -135,7 +136,7 @@
 		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 --unified --new-file --recursive mtd/fs/jffs2/fs.c mtd-dec07/fs/jffs2/fs.c
--- mtd/fs/jffs2/fs.c	2004-11-29 00:00:09.000000000 +0100
+++ mtd-dec07/fs/jffs2/fs.c	2004-12-07 16:03:02.000000000 +0100
@@ -74,7 +74,7 @@
 		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 --unified --new-file --recursive mtd/fs/jffs2/gc.c mtd-dec07/fs/jffs2/gc.c
--- mtd/fs/jffs2/gc.c	2004-11-17 00:00:14.000000000 +0100
+++ mtd-dec07/fs/jffs2/gc.c	2004-12-07 16:03:02.000000000 +0100
@@ -506,7 +506,7 @@
 	   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);
+					      rawlen), &phys_ofs, &alloclen, rawlen); /* this is not optimal yet */
 	if (ret)
 		return ret;
 
@@ -614,7 +614,7 @@
 			ACCT_SANITY_CHECK(c,jeb);
 			D1(ACCT_PARANOIA_CHECK(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 optimal yet */
 
 			if (!ret) {
 				D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));
@@ -692,7 +692,7 @@
 
 	}
 	
-	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);
@@ -759,7 +759,7 @@
 	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);
@@ -961,7 +961,7 @@
 	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);
@@ -1186,7 +1186,7 @@
 		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",
@@ -1243,4 +1243,3 @@
 	jffs2_gc_release_page(c, pg_ptr, &pg);
 	return ret;
 }
-
diff --unified --new-file --recursive mtd/fs/jffs2/nodelist.h mtd-dec07/fs/jffs2/nodelist.h
--- mtd/fs/jffs2/nodelist.h	2004-11-26 15:08:31.000000000 +0100
+++ mtd-dec07/fs/jffs2/nodelist.h	2004-12-07 16:03:02.000000000 +0100
@@ -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"
@@ -194,6 +195,10 @@
 	int bad_count;
 	uint32_t offset;		/* of this block in the MTD */
 
+#ifdef CONFIG_JFFS2_SUMMARY	
+	struct jffs2_sum_info *sum_collected;
+#endif
+	
 	uint32_t unchecked_size;
 	uint32_t used_size;
 	uint32_t dirty_size;
@@ -392,8 +397,8 @@
 
 /* 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);
@@ -455,6 +460,10 @@
 /* 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, unsigned char *buf,
+				uint32_t ofs, uint32_t len);
+struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino);
+
 
 /* build.c */
 int jffs2_do_mount_fs(struct jffs2_sb_info *c);
diff --unified --new-file --recursive mtd/fs/jffs2/nodemgmt.c mtd-dec07/fs/jffs2/nodemgmt.c
--- mtd/fs/jffs2/nodemgmt.c	2004-11-26 15:08:31.000000000 +0100
+++ mtd-dec07/fs/jffs2/nodemgmt.c	2004-12-07 16:03:02.000000000 +0100
@@ -38,9 +38,9 @@
  *	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 +129,7 @@
 			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 +140,7 @@
 	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 +149,7 @@
 
 	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));
 		}
@@ -159,50 +159,112 @@
 }
 
 /* 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)
+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 nofree_size;
 	
  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)) {
-			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;
-		}
-		c->wasted_size += jeb->free_size;
-		c->free_size -= jeb->free_size;
-		jeb->wasted_size += jeb->free_size;
-		jeb->free_size = 0;
+	nofree_size = 0;
+	
+#ifdef CONFIG_JFFS2_SUMMARY
+
+	if (sumsize != JFFS2_SUMMARY_NOSUM_SIZE) {
+		int ret;
+                if (jeb) {
+                        if ((ret=jffs2_sum_care_sum_collected(jeb))) return ret;
+                        nofree_size = sumsize + jeb->sum_collected->sum_size + JFFS2_SUMMARY_FRAME_SIZE;
+                }
 		
-		/* 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",
+		D1(printk(KERN_DEBUG "JFFS2: minsize %d , jeb->free(%d) , sum_collected->size(%d) , sumsize(%d)\n",minsize,jeb->free_size,jeb->sum_collected->sum_size,sumsize));
+		
+		if (jeb && (minsize + jeb->sum_collected->sum_size + sumsize + JFFS2_SUMMARY_FRAME_SIZE > jeb->free_size)) {
+			D1(printk(KERN_DEBUG "JFFS2: generating summary for 0x%08x.\n", jeb->offset));
+			if (jeb->sum_collected->sum_size == JFFS2_SUMMARY_NOSUM_SIZE) {
+				sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
+				jffs2_sum_clean_collected(jeb);
+				goto restart;
+			}
+			
+			ret = jffs2_sum_write_sumnode(c);
+			
+			if (ret)
+				return ret;
+			
+			if (jeb->sum_collected->sum_size == JFFS2_SUMMARY_NOSUM_SIZE) { //jffs2_write_sumnode can't write out the summary information
+				sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
+				jffs2_sum_clean_collected(jeb);
+				goto restart;
+			}
+			
+			/* 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->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",
+				list_add_tail(&jeb->list, &c->clean_list);
+			}
+			c->nextblock = jeb = NULL;
+		}
+	}
+	else {	
+#endif			
+		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);
+				jeb = c->nextblock;
+				goto restart;
+			}
+			
+			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->dirty_list);
+				list_add_tail(&jeb->list, &c->clean_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 = jeb = NULL;
 		}
-		c->nextblock = jeb = NULL;
+#ifdef CONFIG_JFFS2_SUMMARY
 	}
-	
+#endif	
 	if (!jeb) {
 		struct list_head *next;
 		/* Take the next block off the 'free' list */
@@ -266,7 +328,7 @@
 	/* 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 - nofree_size;
 
 	if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size &&
 	    !jeb->first_node->next_in_ino) {
diff --unified --new-file --recursive mtd/fs/jffs2/os-linux.h mtd-dec07/fs/jffs2/os-linux.h
--- mtd/fs/jffs2/os-linux.h	2004-11-17 00:00:14.000000000 +0100
+++ mtd-dec07/fs/jffs2/os-linux.h	2004-12-07 16:03:02.000000000 +0100
@@ -100,7 +100,13 @@
 #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
 
 #if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC)
+
+#ifndef CONFIG_JFFS2_SUMMARY
 #define jffs2_can_mark_obsolete(c) (1)
+#else
+#define jffs2_can_mark_obsolete(c) (0)
+#endif
+
 #define jffs2_cleanmarker_oob(c) (0)
 #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
 
@@ -121,7 +127,12 @@
 
 #else /* NAND and/or ECC'd NOR support present */
 
+#ifndef CONFIG_JFFS2_SUMMARY
 #define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM)
+#else
+#define jffs2_can_mark_obsolete(c) (0)
+#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))
@@ -218,5 +229,3 @@
 
 
 #endif /* __JFFS2_OS_LINUX_H__ */
-
-
diff --unified --new-file --recursive mtd/fs/jffs2/scan.c mtd-dec07/fs/jffs2/scan.c
--- mtd/fs/jffs2/scan.c	2004-11-26 15:08:31.000000000 +0100
+++ mtd-dec07/fs/jffs2/scan.c	2004-12-07 16:03:02.000000000 +0100
@@ -18,22 +18,10 @@
 #include <linux/crc32.h>
 #include <linux/compiler.h>
 #include "nodelist.h"
+#include "summary.h"
 
 #define 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); \
@@ -58,13 +46,6 @@
 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
-
 static inline int min_free(struct jffs2_sb_info *c)
 {
 	uint32_t min = 2 * sizeof(struct jffs2_raw_inode);
@@ -257,7 +238,7 @@
 	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, unsigned char *buf,
 				uint32_t ofs, uint32_t len)
 {
 	int ret;
@@ -286,6 +267,11 @@
 	uint32_t hdr_crc, buf_ofs, buf_len;
 	int err;
 	int noise = 0;
+	
+#ifdef CONFIG_JFFS2_SUMMARY
+	struct jffs2_sum_marker *sm;
+#endif	
+	
 #ifdef CONFIG_JFFS2_FS_NAND
 	int cleanmarkerfound = 0;
 #endif
@@ -311,10 +297,54 @@
 		}
 	}
 #endif
+	
+#ifdef CONFIG_JFFS2_SUMMARY	
+	sm = (struct jffs2_sum_marker *)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 ) {
+
+		if(je32_to_cpu(sm->erase_size) == c->sector_size) {
+			int ret = jffs2_sum_scan_sumnode(c,jeb,je32_to_cpu(sm->offset),&pseudo_random);
+			
+			if (ret) {
+				kfree(sm);
+				return ret;
+			}
+		}
+		
+		printk(KERN_WARNING "FS erase_block_size != JFFS2 erase_block_size => skipping summary information\n");
+		
+	}
+	
+	kfree(sm);
+	
+	ofs = jeb->offset;
+	prevofs = jeb->offset - 1;
+	
+#endif
+	
 	buf_ofs = jeb->offset;
 
 	if (!buf_size) {
 		buf_len = c->sector_size;
+		
+#ifdef CONFIG_JFFS2_SUMMARY
+		/* must reread because of summary test */
+		err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
+		if (err)
+			return err;
+#endif
+
 	} else {
 		buf_len = EMPTY_SCAN_SIZE;
 		err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
@@ -356,6 +386,8 @@
 
 	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) {
 
@@ -571,6 +603,9 @@
 			break;
 
 		case JFFS2_NODETYPE_PADDING:
+#ifdef CONFIG_JFFS2_SUMMARY
+	                jffs2_sum_add_padding_mem(jeb,je32_to_cpu(node->totlen));
+#endif
 			DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
 			ofs += PAD(je32_to_cpu(node->totlen));
 			break;
@@ -634,7 +669,7 @@
 		return BLK_STATE_ALLDIRTY;
 }
 
-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;
 
@@ -728,6 +763,11 @@
 	pseudo_random += je32_to_cpu(ri->version);
 
 	UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen)));
+	
+#ifdef CONFIG_JFFS2_SUMMARY
+	jffs2_sum_add_inode_mem(jeb,ri,ofs);
+#endif
+	
 	return 0;
 }
 
@@ -806,6 +846,10 @@
 	USED_SPACE(PAD(je32_to_cpu(rd->totlen)));
 	jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
 
+#ifdef CONFIG_JFFS2_SUMMARY
+	jffs2_sum_add_dirent_mem(jeb,rd,ofs);
+#endif
+	
 	return 0;
 }
 
diff --unified --new-file --recursive mtd/fs/jffs2/summary.c mtd-dec07/fs/jffs2/summary.c
--- mtd/fs/jffs2/summary.c	1970-01-01 01:00:00.000000000 +0100
+++ mtd-dec07/fs/jffs2/summary.c	2004-12-07 16:03:02.000000000 +0100
@@ -0,0 +1,720 @@
+/*
+ * 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_buf = (jint32_t *) vmalloc(c->sector_size);
+        if (!c->summary_buf) {
+		printk(KERN_WARNING "JFFS2: can't allocate memory to dump summary information!\n");
+                return 1;
+        }
+        return 0;
+}
+
+void jffs2_sum_exit(struct jffs2_sb_info *c) 
+{
+        if (c->summary_buf) {
+                vfree(c->summary_buf);
+                c->summary_buf = NULL;
+        }
+}
+
+int jffs2_sum_care_sum_collected(struct jffs2_eraseblock *jeb)
+{
+	if (!jeb->sum_collected) {
+		jeb->sum_collected = (struct jffs2_sum_info *) kmalloc(sizeof(struct jffs2_sum_info), GFP_KERNEL);
+	
+		if (!jeb->sum_collected)
+			return -ENOMEM;
+			
+		jeb->sum_collected->sum_list = NULL;
+		jeb->sum_collected->sum_num = 0;
+		jeb->sum_collected->sum_size = 0; 
+		jeb->sum_collected->sum_padded = 0; 
+	}
+        return 0;
+}
+
+static int jffs2_sum_add_mem(struct jffs2_eraseblock *jeb, union jffs2_sum_mem *item) 
+{
+	
+	union jffs2_sum_mem *walk;
+        int ret;
+	
+        if ((ret=jffs2_sum_care_sum_collected(jeb))) return ret;
+	
+	if (!jeb->sum_collected->sum_list) {
+		jeb->sum_collected->sum_list = (union jffs2_sum_mem *) item;
+	} 
+	else {
+		walk = jeb->sum_collected->sum_list;
+		
+		while (walk->u.next) {
+			walk = walk->u.next;
+		}
+		walk->u.next = (union jffs2_sum_mem *) item;
+	}
+	switch (je16_to_cpu(item->u.nodetype)) {
+    	    case JFFS2_NODETYPE_INODE:
+		jeb->sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE;
+		jeb->sum_collected->sum_num++;
+		break;
+    	    case JFFS2_NODETYPE_DIRENT:
+		jeb->sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
+		jeb->sum_collected->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;
+}
+
+void jffs2_sum_clean_all_info(struct jffs2_sb_info *c)
+{
+	int i;
+	
+	for (i=0; i<c->nr_blocks; i++) {
+		struct jffs2_eraseblock *jeb = &c->blocks[i];
+		
+		jffs2_sum_clean_collected(jeb);
+		kfree(jeb->sum_collected);
+		jeb->sum_collected = NULL;
+	}
+}
+	
+/* These 3 functions are called from scan.c to collect summary info for not closed jeb */
+
+int jffs2_sum_add_padding_mem(struct jffs2_eraseblock *jeb, uint32_t size)
+{
+        int ret;
+	
+        if ((ret=jffs2_sum_care_sum_collected(jeb))) return ret;
+        jeb->sum_collected->sum_padded += size;
+        return 0;
+}
+
+int jffs2_sum_add_inode_mem(struct jffs2_eraseblock *jeb, struct jffs2_raw_inode *ri, uint32_t ofs) 
+{
+	
+	struct jffs2_sum_inode_mem *temp = (struct jffs2_sum_inode_mem *) kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
+	
+	if (!temp)
+		return -ENOMEM;
+
+        ofs -= jeb->offset;
+	
+	temp->nodetype = ri->nodetype;
+	temp->inode = ri->ino;
+	temp->version = ri->version;
+	temp->offset = cpu_to_je32(ofs); 
+	temp->totlen = ri->totlen;
+	temp->next = NULL;
+	
+	return jffs2_sum_add_mem(jeb, (union jffs2_sum_mem *)temp);
+}
+
+int jffs2_sum_add_dirent_mem(struct jffs2_eraseblock *jeb, struct jffs2_raw_dirent *rd, uint32_t ofs) 
+{
+	
+	struct jffs2_sum_dirent_mem *temp = (struct jffs2_sum_dirent_mem *) 
+			kmalloc(sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL);
+	
+	if (!temp)
+		return -ENOMEM;
+	
+        ofs -= jeb->offset;
+
+	temp->nodetype = rd->nodetype;
+	temp->totlen = rd->totlen;
+	temp->offset = cpu_to_je32(ofs);
+	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(jeb, (union jffs2_sum_mem *)temp);
+}
+
+/* Cleanup every collected summary information */
+
+void jffs2_sum_clean_collected(struct jffs2_eraseblock *jeb) 
+{
+	
+	union jffs2_sum_mem *temp;
+	
+	if(jeb && jeb->sum_collected){
+		
+		while(jeb->sum_collected->sum_list){
+			temp = jeb->sum_collected->sum_list;
+			jeb->sum_collected->sum_list = jeb->sum_collected->sum_list->u.next;
+			kfree(temp);
+			jeb->sum_collected->sum_num--;
+		}
+		
+		if(jeb->sum_collected->sum_num != 0){
+			printk(KERN_WARNING "Ooops, something wrong happened! sum_num != 0, but sum_list = null ???");
+			jeb->sum_collected->sum_num = 0;
+		}
+	}	
+}
+
+/* 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;	
+        int ret;
+	
+	node = (union jffs2_node_union *) invecs[0].iov_base;
+	jeb = &c->blocks[ofs / c->sector_size];
+        ofs -= jeb->offset;
+       
+        if ((ret=jffs2_sum_care_sum_collected(jeb))) return ret;        
+	
+	switch(je16_to_cpu(node->u.nodetype)){
+		case JFFS2_NODETYPE_INODE : {
+			struct jffs2_sum_inode_mem *temp = (struct jffs2_sum_inode_mem *) 
+				kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
+			
+			if (!temp)
+				return -ENOMEM;
+
+			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(jeb, (union jffs2_sum_mem *)temp);
+			
+			break;
+		}
+		
+		case JFFS2_NODETYPE_DIRENT : {
+			struct jffs2_sum_dirent_mem *temp = (struct jffs2_sum_dirent_mem *) 
+				kmalloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL);
+			
+			if (!temp)
+				return -ENOMEM;
+			
+			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;
+			
+			memcpy(temp->name,invecs[1].iov_base,node->d.nsize);
+			
+			return jffs2_sum_add_mem(jeb, (union jffs2_sum_mem *)temp);
+			
+			break;
+		}
+		
+		case JFFS2_NODETYPE_PADDING : {
+			D1(printk(KERN_DEBUG "jffs2_sum_add_kvec(): Node PADDING\n"));
+                        jeb->sum_collected->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 : {
+			printk(KERN_WARNING "jffs2_sum_add_kvec(): Node not supported\n");
+			BUG();
+			break;
+		}
+	}
+	
+	return 0;
+}
+
+/* Process the summary information - 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 *raw;
+	struct jffs2_raw_node_ref *cache_ref;
+	struct jffs2_inode_cache *ic;
+	struct jffs2_full_dirent *fd;
+		
+	int i, err;
+	int bad_sum = 0;
+	int sumsize;
+	uint32_t ino;
+	uint32_t crc;
+	struct jffs2_summary_node *summary;
+		
+	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 = (struct jffs2_summary_node *) kmalloc(sumsize, GFP_KERNEL);
+		
+	if (!summary) {
+			return -ENOMEM;
+	}
+	
+	err = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize);
+	
+	if (err) {
+			kfree(summary);
+			return err;
+	}
+
+	/* 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 "jffs2_scan_eraseblock(): Summary node header is corrupt (bad CRC or no summary at all)\n"));
+			bad_sum = 1;
+	}
+	
+	if ((!bad_sum) && (je32_to_cpu(summary->totlen) != sumsize)) {
+			D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Summary node is corrupt (wrong erasesize?)\n"));
+			bad_sum = 1;
+	}
+	
+	crc = crc32(0, summary, sizeof(struct jffs2_summary_node)-8);
+		
+	if ((!bad_sum) && (je32_to_cpu(summary->node_crc) != crc)) {
+			D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Summary node is corrupt (bad CRC)\n"));
+			bad_sum = 1;
+	}
+	
+	crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_summary_node));
+
+	if ((!bad_sum) && (je32_to_cpu(summary->sum_crc) != crc)) {
+			D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Summary node data is corrupt (bad CRC)\n"));
+			bad_sum = 1;
+	}
+	
+	if (!bad_sum) {
+		
+		struct jffs2_sum_unknown_flash *sp;
+		sp = (struct jffs2_sum_unknown_flash *) summary->sum;
+
+		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));
+                }
+		
+		for(i = 0; i < je16_to_cpu(summary->sum_num); i++) {
+			
+			D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Processing summary information %d\n", i));
+			uint8_t *temp8ptr = NULL;
+			
+			switch (je16_to_cpu(sp->nodetype)) {
+				
+				case JFFS2_NODETYPE_INODE : {
+					struct jffs2_sum_inode_flash *spi;
+					spi = (struct jffs2_sum_inode_flash *) sp;
+						
+					ino = je32_to_cpu(spi->inode);
+					D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Inode at 0x%08x\n", jeb->offset + je32_to_cpu(spi->offset)));
+					raw = jffs2_alloc_raw_node_ref();
+					if (!raw) {
+						printk(KERN_NOTICE "jffs2_scan_eraseblock(): allocation of node reference failed\n");
+						kfree(summary);
+						return -ENOMEM;
+					}
+		
+					ic = jffs2_get_ino_cache(c, ino);
+					if (!ic) {
+						ic = jffs2_scan_make_ino_cache(c, ino);
+						if (!ic) {
+							printk(KERN_NOTICE "jffs2_scan_eraseblock(): scan_make_ino_cache failed\n");
+							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)));
+					
+					temp8ptr = (uint8_t *) sp;
+					temp8ptr += JFFS2_SUMMARY_INODE_SIZE;
+					sp = (struct jffs2_sum_unknown_flash *) temp8ptr;
+					
+					break;
+				}
+					
+				case JFFS2_NODETYPE_DIRENT : {
+					struct jffs2_sum_dirent_flash *spd;
+					spd = (struct jffs2_sum_dirent_flash *) 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 "jffs2_scan_dirent_node(): allocation of node reference failed\n");
+						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);
+					
+					temp8ptr = (uint8_t *) sp;
+					temp8ptr += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); 
+					sp = (struct jffs2_sum_unknown_flash *) temp8ptr;
+					
+					break;
+				}
+				
+				default : {
+					printk(KERN_WARNING "Kernel doesn't support this type of node !!! Exiting");
+					return -EIO;
+					break;			
+				}
+			}
+		}
+		
+		kfree(summary);
+
+		/* for ACCT_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;
+
+		/* somebody check this and all of space accounting in summary support */
+
+		if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size 
+			&& (!jeb->first_node || !jeb->first_node->next_in_ino) ) { 
+				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 0;
+}
+
+/* Write out summary information - called from jffs2_do_reserve_space */
+
+int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
+{
+	struct jffs2_summary_node isum;
+	union jffs2_sum_mem *temp;
+	jint32_t offset;
+	jint32_t *wpage;
+	uint8_t *tempptr;
+	int datasize;
+	int infosize;
+	int padsize;
+	size_t retlen;
+	int ret;
+	struct jffs2_eraseblock *jeb;
+	struct kvec vecs[2];	
+	jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
+		
+	D2(printk(KERN_DEBUG "jffs2_sum_write_sumnode()\n"));
+	
+	jeb = c->nextblock;
+	
+	if (!jeb->sum_collected->sum_num || !jeb->sum_collected->sum_list) {
+		printk(KERN_WARNING "JFFS2: jffs2_sum_write_sumnode(): empty summary info!!!\n");
+		BUG(); 
+	}
+	
+	datasize = jeb->sum_collected->sum_size + sizeof(struct jffs2_sum_marker);
+	infosize = sizeof(struct jffs2_summary_node) + datasize;
+	padsize = jeb->free_size - infosize;
+	infosize += padsize; datasize += padsize;
+	offset = cpu_to_je32(c->sector_size - jeb->free_size);
+	
+	if (padsize < 0) { // if jeb hasn't got enought free space for summary
+		
+		union jffs2_sum_mem *temp;	
+		
+		while(jeb->sum_collected->sum_list){ //cleanup sum_list
+			temp = jeb->sum_collected->sum_list;
+			jeb->sum_collected->sum_list = jeb->sum_collected->sum_list->u.next;
+			kfree(temp);
+			jeb->sum_collected->sum_num--;
+		}
+		
+		jeb->sum_collected->sum_list = NULL;
+		jeb->sum_collected->sum_num = 0;
+		jeb->sum_collected->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; // don't try to write out summary for this node
+		
+		printk(KERN_WARNING "JFFS2: not enough space for summary, padsize = %d\n",padsize);
+                return 0;
+	}
+			
+	memset(c->summary_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(jeb->sum_collected->sum_padded);
+		
+	if (c->cleanmarker_size) {
+		isum.cln_mkr = cpu_to_je32(c->cleanmarker_size);	
+	}
+	else{
+		isum.cln_mkr = cpu_to_je32(0);
+	}
+	
+	isum.sum_num = cpu_to_je16(jeb->sum_collected->sum_num);
+	wpage = c->summary_buf;
+	
+		
+	while (jeb->sum_collected->sum_num) { // write sum_data 
+		
+
+		switch(je16_to_cpu(jeb->sum_collected->sum_list->u.nodetype)){
+			
+			case JFFS2_NODETYPE_INODE : {
+				jint16_t *temp16ptr = (jint16_t *)wpage;
+				
+				*(temp16ptr++) = jeb->sum_collected->sum_list->i.nodetype;
+				wpage = (jint32_t *) temp16ptr;
+				
+				*(wpage++) = jeb->sum_collected->sum_list->i.inode;
+				*(wpage++) = jeb->sum_collected->sum_list->i.version;
+				*(wpage++) = jeb->sum_collected->sum_list->i.offset;
+				*(wpage++) = jeb->sum_collected->sum_list->i.totlen;
+				break;
+			}
+			
+			case JFFS2_NODETYPE_DIRENT : {
+				jint16_t *temp16ptr = (jint16_t *) wpage;
+				uint8_t *temp8ptr = NULL;
+				
+				*(temp16ptr++) = jeb->sum_collected->sum_list->d.nodetype;
+				wpage = (jint32_t *) temp16ptr;
+				
+				*(wpage++) = jeb->sum_collected->sum_list->d.totlen;
+				*(wpage++) = jeb->sum_collected->sum_list->d.offset;
+				*(wpage++) = jeb->sum_collected->sum_list->d.pino;
+				*(wpage++) = jeb->sum_collected->sum_list->d.version;
+				*(wpage++) = jeb->sum_collected->sum_list->d.ino;
+				
+				temp8ptr = (uint8_t *) wpage;
+				*(temp8ptr++) = jeb->sum_collected->sum_list->d.nsize;
+				*(temp8ptr++) = jeb->sum_collected->sum_list->d.type;
+								
+				memcpy(temp8ptr,jeb->sum_collected->sum_list->d.name,jeb->sum_collected->sum_list->d.nsize);
+				temp8ptr += jeb->sum_collected->sum_list->d.nsize;
+				wpage = (jint32_t *) temp8ptr;
+				
+				break;
+			}
+			
+			default : {
+				printk(KERN_WARNING "Unknown node in summary information!!!\n");
+				BUG();
+			}
+		}
+		
+		temp = jeb->sum_collected->sum_list;
+		jeb->sum_collected->sum_list = jeb->sum_collected->sum_list->u.next;
+		kfree(temp);
+		
+		jeb->sum_collected->sum_num--;
+	}
+	
+	jeb->sum_collected->sum_size = 0;
+	
+	tempptr = (uint8_t *) wpage;
+	tempptr += padsize;
+	wpage = (jint32_t *) tempptr;
+	
+	*(wpage++) = offset;
+	*(wpage++) = cpu_to_je32(c->sector_size);
+	*(wpage++) = magic;
+	isum.sum_crc = cpu_to_je32(crc32(0, c->summary_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_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);
+
+		jeb->sum_collected->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
+				
+		WASTED_SPACE(infosize);
+		
+		return 0;
+	}	
+	
+	/*spin_unlock(&c->erase_completion_lock);
+	jffs2_flush_wbuf_pad(c); // summary filled the wbuf
+	spin_lock(&c->erase_completion_lock);*/
+
+	WASTED_SPACE(infosize);
+	
+	return 0;	
+}
diff --unified --new-file --recursive mtd/fs/jffs2/summary.h mtd-dec07/fs/jffs2/summary.h
--- mtd/fs/jffs2/summary.h	1970-01-01 01:00:00.000000000 +0100
+++ mtd-dec07/fs/jffs2/summary.h	2004-12-07 16:03:02.000000000 +0100
@@ -0,0 +1,158 @@
+/*
+ * 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))
+
+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; 
+};
+
+/* list version of jffs2_sum_*flash for kernel and sumtool */
+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_sum_info
+{
+	uint32_t sum_size;
+	uint32_t sum_num;
+        uint32_t sum_padded;
+	union jffs2_sum_mem *sum_list;
+};
+
+struct jffs2_sum_marker
+{
+	jint32_t offset;
+	jint32_t erase_size;
+	jint32_t magic;
+};
+
+#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_summary_node)+sizeof(struct jffs2_sum_marker)+3)
+	
+#if !(defined(SUM_TOOL) || defined(JFFS2DUMP))
+
+int jffs2_sum_init(struct jffs2_sb_info *c);
+void jffs2_sum_exit(struct jffs2_sb_info *c);
+
+int jffs2_sum_care_sum_collected(struct jffs2_eraseblock *jeb);
+
+void jffs2_sum_clean_collected(struct jffs2_eraseblock *jeb);
+void jffs2_sum_clean_all_info(struct jffs2_sb_info *c); /* clean up all summary information in all jeb (umount) */
+
+int jffs2_sum_add_padding_mem(struct jffs2_eraseblock *jeb, uint32_t size);
+int jffs2_sum_add_inode_mem(struct jffs2_eraseblock *jeb, struct jffs2_raw_inode *ri, uint32_t ofs);	
+int jffs2_sum_add_dirent_mem(struct jffs2_eraseblock *jeb, struct jffs2_raw_dirent *rd, uint32_t ofs);	
+int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count,  uint32_t to);	
+
+int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t ofs, uint32_t *pseudo_random);
+int jffs2_sum_write_sumnode(struct jffs2_sb_info *c);	
+
+#endif
+
+#endif /* JFFS2_SUMMARY_H */
diff --unified --new-file --recursive mtd/fs/jffs2/super-v24.c mtd-dec07/fs/jffs2/super-v24.c
--- mtd/fs/jffs2/super-v24.c	2004-11-17 00:00:14.000000000 +0100
+++ mtd-dec07/fs/jffs2/super-v24.c	2004-12-07 16:03:02.000000000 +0100
@@ -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
@@ -72,6 +73,9 @@
 		put_mtd_device(c->mtd);
 		return NULL;
 	}
+#ifdef CONFIG_JFFS2_SUMMARY
+        jffs2_sum_init(c);
+#endif
 
 	return sb;
 }
@@ -88,6 +92,10 @@
 	down(&c->alloc_sem);
 	jffs2_flush_wbuf_pad(c);
 	up(&c->alloc_sem);
+#ifdef CONFIG_JFFS2_SUMMARY
+        jffs2_sum_clean_all_info(c);
+        jffs2_sum_exit(c);
+#endif
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
 	kfree(c->blocks);
@@ -110,6 +118,9 @@
 #ifdef CONFIG_JFFS2_FS_NAND
 	       " (NAND)"
 #endif
+#ifdef CONFIG_JFFS2_SUMMARY
+	       " (SUMMARY)"
+#endif
 	       " (C) 2001-2003 Red Hat, Inc.\n");
 
 #ifdef JFFS2_OUT_OF_KERNEL
diff --unified --new-file --recursive mtd/fs/jffs2/super.c mtd-dec07/fs/jffs2/super.c
--- mtd/fs/jffs2/super.c	2004-11-26 15:08:31.000000000 +0100
+++ mtd-dec07/fs/jffs2/super.c	2004-12-07 16:03:02.000000000 +0100
@@ -152,6 +152,10 @@
 		return ERR_PTR(ret);
 	}
 
+#ifdef CONFIG_JFFS2_SUMMARY
+        jffs2_sum_init(c);
+#endif
+
 	sb->s_flags |= MS_ACTIVE;
 	return sb;
 
@@ -275,6 +279,10 @@
 	down(&c->alloc_sem);
 	jffs2_flush_wbuf_pad(c);
 	up(&c->alloc_sem);
+#ifdef CONFIG_JFFS2_SUMMARY
+        jffs2_sum_clean_all_info(c);
+        jffs2_sum_exit(c);
+#endif
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
 	if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
@@ -312,6 +320,9 @@
 #ifdef CONFIG_JFFS2_FS_NAND
 	       " (NAND)"
 #endif
+#ifdef CONFIG_JFFS2_SUMMARY
+               " (SUMMARY) "
+#endif
 	       " (C) 2001-2003 Red Hat, Inc.\n");
 
 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
diff --unified --new-file --recursive mtd/fs/jffs2/wbuf.c mtd-dec07/fs/jffs2/wbuf.c
--- mtd/fs/jffs2/wbuf.c	2004-11-26 15:08:31.000000000 +0100
+++ mtd-dec07/fs/jffs2/wbuf.c	2004-12-07 16:17:11.000000000 +0100
@@ -261,7 +261,7 @@
 
 
 	/* ... 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");
 		if (buf)
@@ -601,8 +601,15 @@
 	uint32_t outvec_to = to;
 
 	/* If not NAND flash, don't bother */
-	if (!c->wbuf)
+ 	if (!c->wbuf){
+#ifdef CONFIG_JFFS2_SUMMARY
+ 		D1(printk("JFFS2.summary: NOT NAND MEMORY\n"));
+ 		if(jffs2_sum_add_kvec(c,invecs,count,(uint32_t) to)){
+ 			printk("jffs2_sum_add_kvec(): MEMORY ALLOCATION ERROR!");
+ 		}	
+#endif		
 		return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
+	}
 	
 	down_write(&c->wbuf_sem);
 
@@ -801,6 +808,12 @@
 alldone:
 	*retlen = donelen;
 
+#ifdef CONFIG_JFFS2_SUMMARY
+	if(jffs2_sum_add_kvec(c,invecs,count,(uint32_t) to)){
+		printk("jffs2_sum_add_kvec(): MEMORY ALLOCATION ERROR!");
+	}
+#endif
+	
 	if (c->wbuf_len && ino)
 		jffs2_wbuf_dirties_inode(c, ino);
 
diff --unified --new-file --recursive mtd/fs/jffs2/write.c mtd-dec07/fs/jffs2/write.c
--- mtd/fs/jffs2/write.c	2004-11-17 00:00:14.000000000 +0100
+++ mtd-dec07/fs/jffs2/write.c	2004-12-07 16:03:02.000000000 +0100
@@ -173,13 +173,13 @@
 			D1(ACCT_PARANOIA_CHECK(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);
 			}
 
@@ -308,13 +308,13 @@
 			D1(ACCT_PARANOIA_CHECK(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);
 			}
 
@@ -371,7 +371,7 @@
 	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;
@@ -458,7 +458,7 @@
 	/* 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);
@@ -487,7 +487,7 @@
 
 	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. */
@@ -557,7 +557,7 @@
 		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;
@@ -663,7 +663,7 @@
 	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 --unified --new-file --recursive mtd/include/linux/jffs2.h mtd-dec07/include/linux/jffs2.h
--- mtd/include/linux/jffs2.h	2004-11-17 00:00:15.000000000 +0100
+++ mtd-dec07/include/linux/jffs2.h	2004-12-07 16:03:02.000000000 +0100
@@ -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.
 */
@@ -62,6 +65,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)
@@ -148,10 +153,24 @@
 	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;
+	jint16_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 --unified --new-file --recursive mtd/include/linux/jffs2_fs_sb.h mtd-dec07/include/linux/jffs2_fs_sb.h
--- mtd/include/linux/jffs2_fs_sb.h	2004-11-26 15:08:31.000000000 +0100
+++ mtd-dec07/include/linux/jffs2_fs_sb.h	2004-12-07 16:03:02.000000000 +0100
@@ -110,6 +110,9 @@
 	uint32_t fsdata_pos;
 	uint32_t fsdata_len;
 #endif
+#ifdef CONFIG_JFFS2_SUMMARY
+        jint32_t *summary_buf;
+#endif
 
 	/* OS-private pointer for getting back to master superblock info */
 	void *os_priv;
diff --unified --new-file --recursive mtd/util/Makefile mtd-dec07/util/Makefile
--- mtd/util/Makefile	2004-07-14 00:00:18.000000000 +0200
+++ mtd-dec07/util/Makefile	2004-12-07 16:03:02.000000000 +0100
@@ -13,7 +13,7 @@
 TARGETS = ftl_format flash_erase flash_eraseall nanddump doc_loadbios \
 	mkfs.jffs ftl_check mkfs.jffs2 flash_lock flash_unlock \
 	flash_info mtd_debug flashcp nandwrite jffs2dump \
-	nftldump nftl_format docfdisk #jffs2reader
+	nftldump nftl_format docfdisk sumtool #jffs2reader
 
 SYMLINKS = compr_lzari.c compr_lzo.c
 
@@ -48,6 +48,10 @@
 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 --unified --new-file --recursive mtd/util/jffs2dump.c mtd-dec07/util/jffs2dump.c
--- mtd/util/jffs2dump.c	2004-12-03 00:00:10.000000000 +0100
+++ mtd-dec07/util/jffs2dump.c	2004-12-07 16:03:02.000000000 +0100
@@ -35,6 +35,10 @@
 #include <getopt.h>
 #include "crc32.h"
 
+#define CONFIG_JFFS2_SUMMARY
+#define JFFS2DUMP
+#include "../fs/jffs2/summary.h"
+
 #define PROGRAM "jffs2dump"
 #define VERSION "$Revision: 1.7 $"
 
@@ -177,7 +181,7 @@
  */
 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 +190,21 @@
 	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));
@@ -277,7 +286,110 @@
 
 			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),
+					je16_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){
+				struct jffs2_sum_unknown_flash *sp;
+				uint8_t *temp8ptr = NULL;
+				sp = (struct jffs2_sum_unknown_flash *) (p + sizeof (struct jffs2_summary_node));
+					
+				for(i = 0; i < je16_to_cpu (node->s.sum_num); i++){
+					
+					switch(je16_to_cpu(sp->nodetype)){
+						case JFFS2_NODETYPE_INODE : {
+							
+							struct jffs2_sum_inode_flash *spi;
+							spi = (struct jffs2_sum_inode_flash *) 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));
+							
+							temp8ptr = (uint8_t *) sp;
+							temp8ptr += JFFS2_SUMMARY_INODE_SIZE;
+							sp = (struct jffs2_sum_unknown_flash *) temp8ptr;
+							
+							break;	
+						}
+						
+						case JFFS2_NODETYPE_DIRENT : {
+							
+							char name[255];
+							struct jffs2_sum_dirent_flash *spd;
+							spd = (struct jffs2_sum_dirent_flash *) 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);
+							
+							temp8ptr = (uint8_t *) sp;
+							temp8ptr += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); 
+							sp = (struct jffs2_sum_unknown_flash *) temp8ptr;
+							
+							break;
+						}
+						
+						default : {
+							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, Erase_block_size 0x%08x, Magic 0x%08x, Padded size 0x%08x\n" ,
+					"",
+					je32_to_cpu(sm->offset),
+					je32_to_cpu(sm->erase_size),
+					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", 
diff --unified --new-file --recursive mtd/util/sumtool.c mtd-dec07/util/sumtool.c
--- mtd/util/sumtool.c	1970-01-01 01:00:00.000000000 +0100
+++ mtd-dec07/util/sumtool.c	2004-12-07 17:47:31.000000000 +0100
@@ -0,0 +1,857 @@
+/*
+ *  sumtool.c
+ *
+ *  Copyright (C) 2004 Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                     Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                     Patrik Kluba <pajko@halom.u-szeged.hu>,
+ *                     University of Szeged, Hungary
+ *
+ * $Id: sumtool.c,v 1.2 2004/10/20 09:56:08 hafy Exp $
+ * 
+ * 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 to reorder nodes and insert inode summary information
+ *   into JFFS2 image for faster mount time - specially on NAND.
+ *
+ */
+
+#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"
+
+#define CONFIG_JFFS2_SUMMARY
+#define SUM_TOOL
+#include "../fs/jffs2/summary.h"
+
+
+#define PAD(x) (((x)+3)&~3)
+
+static const char *const app_name = "sumtool";
+
+static struct jffs2_sum_info *sum_collected = NULL;/* summary info list */
+
+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"
+	"Convert the input JFFS2 file to a SUM-ed JFFS2 file\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 erase block.\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_sum_info *) malloc (sizeof(struct jffs2_sum_info));
+	
+	if (!sum_collected)
+		error_msg_and_die("Can't allocate memory for jffs2_sum_info!\n");
+	
+	sum_collected->sum_list = NULL;
+	sum_collected->sum_num = 0;
+	sum_collected->sum_size = 0; 
+
+}
+
+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){
+			temp = sum_collected->sum_list;
+			sum_collected->sum_list = sum_collected->sum_list->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;
+    union jffs2_sum_mem *temp;
+	jint32_t offset;
+	jint32_t *wpage;
+	uint8_t *tempptr;
+	int datasize;
+	int infosize;
+	int padsize;
+	jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
+	
+	if (!sum_collected->sum_num || !sum_collected->sum_list) 
+		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_je16(sum_collected->sum_num);
+	wpage = tpage;
+	
+		
+	while (sum_collected->sum_num) {
+		
+
+		switch(je16_to_cpu(sum_collected->sum_list->u.nodetype)){
+			
+			case JFFS2_NODETYPE_INODE : {
+				jint16_t *temp16ptr = (jint16_t *)wpage;
+				
+				*(temp16ptr++) = sum_collected->sum_list->i.nodetype;
+				wpage = (jint32_t *) temp16ptr;
+				
+				*(wpage++) = sum_collected->sum_list->i.inode;
+				*(wpage++) = sum_collected->sum_list->i.version;
+				*(wpage++) = sum_collected->sum_list->i.offset;
+				*(wpage++) = sum_collected->sum_list->i.totlen;
+				break;
+			}
+			
+			case JFFS2_NODETYPE_DIRENT : {
+				jint16_t *temp16ptr = (jint16_t *) wpage;
+				uint8_t *temp8ptr = NULL;
+				
+				*(temp16ptr++) = sum_collected->sum_list->d.nodetype;
+				wpage = (jint32_t *) temp16ptr;
+				
+				*(wpage++) = sum_collected->sum_list->d.totlen;
+				*(wpage++) = sum_collected->sum_list->d.offset;
+				*(wpage++) = sum_collected->sum_list->d.pino;
+				*(wpage++) = sum_collected->sum_list->d.version;
+				*(wpage++) = sum_collected->sum_list->d.ino;
+				
+				temp8ptr = (uint8_t *) wpage;
+				*(temp8ptr++) = sum_collected->sum_list->d.nsize;
+				*(temp8ptr++) = sum_collected->sum_list->d.type;
+				
+				memcpy(temp8ptr,sum_collected->sum_list->d.name,sum_collected->sum_list->d.nsize);
+				temp8ptr += sum_collected->sum_list->d.nsize;
+				wpage = (jint32_t *) temp8ptr;
+				
+				break;
+			}
+			
+			default : {
+				printf("This is not good for me!!!!\n");
+			}
+		}
+		
+		temp = sum_collected->sum_list;
+		sum_collected->sum_list = sum_collected->sum_list->u.next;
+		free(temp);
+		
+		sum_collected->sum_num--;
+	}
+	
+	sum_collected->sum_size = 0;
+	
+	tempptr = (uint8_t *) wpage;
+	tempptr += padsize;
+	wpage = (jint32_t *) tempptr;
+	
+	*(wpage++) = offset;
+	*(wpage++) = cpu_to_je32(erase_block_size);
+	*(wpage++) = 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 just write out inode data */
+			else{
+				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 just write out inode data */
+			else{
+				if(padto)
+					pad(erase_block_size - data_ofs);
+				write_buff_to_file();
+			}
+		}
+	}
+}
+
+int add_sum_mem(union jffs2_sum_mem *item) {
+	
+	union jffs2_sum_mem *walk;
+	
+	if (!sum_collected->sum_list) {
+		sum_collected->sum_list = (union jffs2_sum_mem *) item;
+	} 
+	else {
+		walk = sum_collected->sum_list;
+		
+		while (walk->u.next) {
+			walk = walk->u.next;
+		}
+		walk->u.next = (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));
+				}
+				
+				//write_unknown_to_buff(node);
+				
+				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);
+		
+		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;
+}

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-16 12:53     ` Josh Boyer
@ 2004-12-16 21:22       ` Gareth Bult (Encryptec)
  2004-12-16 21:28         ` Josh Boyer
  0 siblings, 1 reply; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-16 21:22 UTC (permalink / raw)
  To: Josh Boyer; +Cc: Linux MTD

Hi,
> There is one more feature pending that I know of.  Ferenc Havasi has
> some eraseblock summary changes that should help.  I believe the
> intention was to commit that to JFFS3, but I haven't seen it go in yet.

Ok, I have these and will be trying them presently .. 

just wondered if there was any way I could avoid running "patch" .. :)

Tvm
Gareth.



> josh
> 

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-16 21:22       ` Gareth Bult (Encryptec)
@ 2004-12-16 21:28         ` Josh Boyer
  2004-12-16 21:47           ` Gareth Bult (Encryptec)
  0 siblings, 1 reply; 70+ messages in thread
From: Josh Boyer @ 2004-12-16 21:28 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Gareth Bult (Encryptec) wrote:
> Hi,
> 
>>There is one more feature pending that I know of.  Ferenc Havasi has
>>some eraseblock summary changes that should help.  I believe the
>>intention was to commit that to JFFS3, but I haven't seen it go in yet.
> 
> 
> Ok, I have these and will be trying them presently .. 
> 
> just wondered if there was any way I could avoid running "patch" .. :)

Bug Ferenc to commit ;).  I'm not sure if he subscribes to this list or not.

Also, Artem Bityuckiy is working on an inode checkpoint feature for 
JFFS3.  Once he gets it working, it should increase overall performance.

If you have any ideas or patches, feel free to submit them to the list. 
  That's what JFFS3 was cloned for, and there isn't too much concern 
with backwards compatibility.

josh

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-16 21:28         ` Josh Boyer
@ 2004-12-16 21:47           ` Gareth Bult (Encryptec)
  2004-12-17 12:54             ` Josh Boyer
  2004-12-18 16:19             ` Jörn Engel
  0 siblings, 2 replies; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-16 21:47 UTC (permalink / raw)
  To: Josh Boyer; +Cc: Linux MTD

If you have any ideas or patches, feel free to submit them to the list. 
>   That's what JFFS3 was cloned for, and there isn't too much concern 
> with backwards compatibility.

Mmm,

blkmtd.c is pretty much a rewrite, less than half the size and uses the
system buffer cache instead of reading / writing directly to the device.
This boosts performance x 3 on read x lots on write. [I get x 100
faster] (albeit you lose bad block detection on write)

If anyone's interested in the code, let me know and I'll clean it up and
post it .. however it'll be a new file and not a patch.

I've only tested it on USB key flash, but I'm assuming it'll be similar
for any block device / hard disk / whatever ..

Gareth.

On Thu, 2004-12-16 at 15:28 -0600, Josh Boyer wrote:
> Gareth Bult (Encryptec) wrote:
> > Hi,
> > 
> >>There is one more feature pending that I know of.  Ferenc Havasi has
> >>some eraseblock summary changes that should help.  I believe the
> >>intention was to commit that to JFFS3, but I haven't seen it go in yet.
> > 
> > 
> > Ok, I have these and will be trying them presently .. 
> > 
> > just wondered if there was any way I could avoid running "patch" .. :)
> 
> Bug Ferenc to commit ;).  I'm not sure if he subscribes to this list or not.
> 
> Also, Artem Bityuckiy is working on an inode checkpoint feature for 
> JFFS3.  Once he gets it working, it should increase overall performance.
> 
> If you have any ideas or patches, feel free to submit them to the list. 
>   That's what JFFS3 was cloned for, and there isn't too much concern 
> with backwards compatibility.
> 
> josh

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-16 21:47           ` Gareth Bult (Encryptec)
@ 2004-12-17 12:54             ` Josh Boyer
  2004-12-17 15:33               ` Gareth Bult (Encryptec)
  2004-12-18 16:19             ` Jörn Engel
  1 sibling, 1 reply; 70+ messages in thread
From: Josh Boyer @ 2004-12-17 12:54 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

On Thu, 2004-12-16 at 15:47, Gareth Bult (Encryptec) wrote:
> 
> blkmtd.c is pretty much a rewrite, less than half the size and uses the
> system buffer cache instead of reading / writing directly to the device.
> This boosts performance x 3 on read x lots on write. [I get x 100
> faster] (albeit you lose bad block detection on write)

Hm, ok.  An alternative to using the system buffer would be to make
JFFS[23] use a write buffer for those devices.  It's already done on
NAND which has some special handling.  The support for ECC'd NOR
probably matches more closely what you'd want to do.  Take a look at
wbuf.c.

> 
> If anyone's interested in the code, let me know and I'll clean it up and
> post it .. however it'll be a new file and not a patch.

Well, if it's better than the original we can always take yours and
replace what's there.  Send it on, performance gains are always
welcome.  I'm sure there are others interested in what you've done that
will review the code.

josh

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-17 12:54             ` Josh Boyer
@ 2004-12-17 15:33               ` Gareth Bult (Encryptec)
  2004-12-17 16:02                 ` Josh Boyer
  0 siblings, 1 reply; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-17 15:33 UTC (permalink / raw)
  To: Josh Boyer; +Cc: Linux MTD

Hi,

On Fri, 2004-12-17 at 06:54 -0600, Josh Boyer wrote:

> Hm, ok.  An alternative to using the system buffer would be to make
> JFFS[23] use a write buffer for those devices.  

Forgive my ignorance .. but what's the difference between using a write
buffer and using the system buffer ?

>From my pov, the system buffer is there, already 100% reliable and
somewhat larger than any [potential] write buffer ???

(Given the system buffer uses the underlying block devices read / write
routines and the block device emulator will typically sit on a block
device such as a hard drive or USB flash key .. [?])

> It's already done on
> NAND which has some special handling.  The support for ECC'd NOR
> probably matches more closely what you'd want to do.  Take a look at
> wbuf.c.

Mmm, after looking at wbuf.c I'm none the wiser as to what it does or
how it relates ..

> Well, if it's better than the original we can always take yours and
> replace what's there.  Send it on, performance gains are always
> welcome.  I'm sure there are others interested in what you've done that
> will review the code.

I think once I get this FL release out the way I'll have a a more
in-depth look at JFFS*. It seems to be written almost exclusively for
MTD devices .. which is great .. for MTD devices .. but for block
devices and flash (USB for example) presented through a standard
interface (SCSI for example) it seems there is scope for a much
"thinner" filesystem generic devices with a subset of JFFS's feature
set.

Gareth.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-17 15:33               ` Gareth Bult (Encryptec)
@ 2004-12-17 16:02                 ` Josh Boyer
  2004-12-17 16:46                   ` Gareth Bult (Encryptec)
  0 siblings, 1 reply; 70+ messages in thread
From: Josh Boyer @ 2004-12-17 16:02 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Gareth Bult (Encryptec) wrote:>
> 
> Forgive my ignorance .. but what's the difference between using a write
> buffer and using the system buffer ?
> 
>>From my pov, the system buffer is there, already 100% reliable and
> somewhat larger than any [potential] write buffer ???

Perhaps alternative was the wrong word to use on my part.  I'll just 
wait until I see your code.  I'm probably confusing myself by making 
assumptions on what it's doing :).

> 
> Mmm, after looking at wbuf.c I'm none the wiser as to what it does or
> how it relates ..

It might not relate.  IIRC there were some discussions on buffering the 
writes done by JFFS[23] to the size of a sector on the block device so 
that partial writes aren't done unnecessarily.  This is what the wbuf.c 
file does.  NAND and ECC'd NOR require this because you can only write 
to a page once (usually) before an erase is needed to write again.

For disk devices I don't think it's required, but it could help.  Or 
maybe your code does this at the MTD level.  I dunno.  I could be 
spouting nonsense again ;).


> 
> 
> I think once I get this FL release out the way I'll have a a more
> in-depth look at JFFS*. It seems to be written almost exclusively for
> MTD devices .. which is great .. for MTD devices .. but for block
> devices and flash (USB for example) presented through a standard
> interface (SCSI for example) it seems there is scope for a much
> "thinner" filesystem generic devices with a subset of JFFS's feature
> set.

Yes, it is a Journaled _Flash_ File System.  So of course it's written 
for MTD devices.  Not sure why blkmtd.c was originally written.  Test 
vehicle for JFFS2, "why not", "I'm bored", etc.  Who knows? :)

josh

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-17 16:02                 ` Josh Boyer
@ 2004-12-17 16:46                   ` Gareth Bult (Encryptec)
  2004-12-17 17:08                     ` Artem B. Bityuckiy
  2004-12-17 17:10                     ` Josh Boyer
  0 siblings, 2 replies; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-17 16:46 UTC (permalink / raw)
  To: Josh Boyer; +Cc: Linux MTD

On Fri, 2004-12-17 at 10:02 -0600, Josh Boyer wrote:
> For disk devices I don't think it's required, but it could help.  Or 
> maybe your code does this at the MTD level.  I dunno.  I could be 
> spouting nonsense again ;).

Mmm, as long as writes are aligned on 2k pages and are linear / 
unidirectional, I'm not sure anything else is really a problem 
for USB flash drives ..

> Yes, it is a Journaled _Flash_ File System.  So of course it's written 
> for MTD devices.  Not sure why blkmtd.c was originally written.  Test 
> vehicle for JFFS2, "why not", "I'm bored", etc.  Who knows? :)

Mm, my point exactly , Journaled _Flash_ File System - as opposed to
Journaled _MTD_ _Flash_ File System .. !!

USB flash is still flash! - just presented via a generic interface as
opposed to an embedded one .. (AFAIK)

I guess I was sort of hoping blkmtd.c was written to enable JFFS2 to be
more generic and embedded device independent. I suspect however it was
written purely for testing purposes .. :(

As I understand it, the Flash in USB keys is identical to the MTD type
embedded devices, except that the USB keys always come with
micro-controllers that handle and optimise read/write/erase operations
and present them via a generic PC/USB based disk interface. I'm not sure
how fast MTD can be driven, but key manufacturers seem to think that
keys should be able to run at 20Mb/sec read and 10Mb/sec write [for
large block read/writes] which is much faster than is required for a key
to replace a hard disk in a workstation.

I'm thinking that JFFS2 could draw in a huge additional user base if it
catered for (or at least supported) such devices .. (!)

Gareth.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-17 16:46                   ` Gareth Bult (Encryptec)
@ 2004-12-17 17:08                     ` Artem B. Bityuckiy
  2004-12-17 17:10                     ` Josh Boyer
  1 sibling, 0 replies; 70+ messages in thread
From: Artem B. Bityuckiy @ 2004-12-17 17:08 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

On Fri, 17 Dec 2004, Gareth Bult (Encryptec) wrote:

> On Fri, 2004-12-17 at 10:02 -0600, Josh Boyer wrote:
> > For disk devices I don't think it's required, but it could help.  Or 
> > maybe your code does this at the MTD level.  I dunno.  I could be 
> > spouting nonsense again ;).
> 
> Mmm, as long as writes are aligned on 2k pages and are linear / 
> unidirectional, I'm not sure anything else is really a problem 
> for USB flash drives ..
> 
> > Yes, it is a Journaled _Flash_ File System.  So of course it's written 
> > for MTD devices.  Not sure why blkmtd.c was originally written.  Test 
> > vehicle for JFFS2, "why not", "I'm bored", etc.  Who knows? :)
> 
> Mm, my point exactly , Journaled _Flash_ File System - as opposed to
> Journaled _MTD_ _Flash_ File System .. !!
> 
> USB flash is still flash! - just presented via a generic interface as
> opposed to an embedded one .. (AFAIK)
> 
> I guess I was sort of hoping blkmtd.c was written to enable JFFS2 to be
> more generic and embedded device independent. I suspect however it was
> written purely for testing purposes .. :(
> 
> As I understand it, the Flash in USB keys is identical to the MTD type
> embedded devices, except that the USB keys always come with
> micro-controllers that handle and optimise read/write/erase operations
> and present them via a generic PC/USB based disk interface. I'm not sure
> how fast MTD can be driven, but key manufacturers seem to think that
> keys should be able to run at 20Mb/sec read and 10Mb/sec write [for
> large block read/writes] which is much faster than is required for a key
> to replace a hard disk in a workstation.
> 
> I'm thinking that JFFS2 could draw in a huge additional user base if it
> catered for (or at least supported) such devices .. (!

My understanding was that it is only seen as SCSI block device from 
outside. E.g. it is not possible, say, to erase sector, to write one 
page, etc. If so, just foget about JFFS2 on that, IMHO.

> 
> Gareth.
> 
> 
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/
> 

--
Best Regards,
Artem B. Bityuckiy,
St.-Petersburg, Russia.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-17 16:46                   ` Gareth Bult (Encryptec)
  2004-12-17 17:08                     ` Artem B. Bityuckiy
@ 2004-12-17 17:10                     ` Josh Boyer
  2004-12-17 17:26                       ` Gareth Bult (Encryptec)
  1 sibling, 1 reply; 70+ messages in thread
From: Josh Boyer @ 2004-12-17 17:10 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Gareth Bult (Encryptec) wrote:
> 
> Mm, my point exactly , Journaled _Flash_ File System - as opposed to
> Journaled _MTD_ _Flash_ File System .. !!
> 
> USB flash is still flash! - just presented via a generic interface as
> opposed to an embedded one .. (AFAIK)

No, it's really not.  There is no access to the low level flash, so MTD 
cannot directly drive it.  Same principle as the Compact Flash devices, 
which MTD doesn't deal with either (other than via blkmtd).

> 
> I guess I was sort of hoping blkmtd.c was written to enable JFFS2 to be
> more generic and embedded device independent. I suspect however it was
> written purely for testing purposes .. :(

Yes, most likely.

> 
> As I understand it, the Flash in USB keys is identical to the MTD type
> embedded devices, except that the USB keys always come with
> micro-controllers that handle and optimise read/write/erase operations
> and present them via a generic PC/USB based disk interface. I'm not sure
> how fast MTD can be driven, but key manufacturers seem to think that
> keys should be able to run at 20Mb/sec read and 10Mb/sec write [for
> large block read/writes] which is much faster than is required for a key
> to replace a hard disk in a workstation.

The flash used in the devices is identical, but MTD has no access to it.

> 
> I'm thinking that JFFS2 could draw in a huge additional user base if it
> catered for (or at least supported) such devices .. (!)

That's the problem.  There is no filesystem for these "abominations" 
really.  They pretend to be IDE, SCSI, etc. but are really flash 
underneath.  Neither the MTD driver or the IDE drivers (for example) 
deal with them really well, but I'm not sure that they can.

Did you try ext3 on the device with a native driver (IDE, SCSI, USB 
specific) instead of via blkmtd.c?

josh

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-17 17:10                     ` Josh Boyer
@ 2004-12-17 17:26                       ` Gareth Bult (Encryptec)
  2004-12-17 17:35                         ` Josh Boyer
  0 siblings, 1 reply; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-17 17:26 UTC (permalink / raw)
  To: Josh Boyer; +Cc: Linux MTD

On Fri, 2004-12-17 at 11:10 -0600, Josh Boyer wrote:
> That's the problem.  There is no filesystem for these "abominations" 
> really.  They pretend to be IDE, SCSI, etc. but are really flash 
> underneath.  Neither the MTD driver or the IDE drivers (for example) 
> deal with them really well, but I'm not sure that they can.
> 
> Did you try ext3 on the device with a native driver (IDE, SCSI, USB 
> specific) instead of via blkmtd.c?

Sure, ext2 and ext3 work just fine .. however .. as far as I'm aware,
although ext3 is log structured, it's not optimised to run in a linear
fashion and doesn't worry about repeatedly writing to the same block ..
which is likely to cause the USB flash controller to execute an erase
prior to write .. which will quickly wear down the device [?!]

(Am I wrong? in which case why isn't everyone using ext3 instead of
JFFS?)

The other requirement of course is inline compression, which last time I
looked ext3 didn't do out of the box (?)

I'm going to deliberately wear down some blocks on a key a little later
(at block level) to see what the OS makes of it ... (and whether it
takes 100,000 or 1,000,000 cycles .. I see conflicting specs ..

I guess the basic spec for a USB flash key (you may call them
abominations, but you should see the sales stats!) would be;

a. purely log structured fs with linear / circular operation
b. write blocks aligned to 2k (or 4k might be smarter to fit with buffer
page sizes)
c. erase blocks @ 128k
d. inline compression

Strikes me JFFS2 does all this, possibly bar the generic device
support ..

Gareth.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-17 17:26                       ` Gareth Bult (Encryptec)
@ 2004-12-17 17:35                         ` Josh Boyer
  2004-12-17 18:09                           ` Gareth Bult (Encryptec)
  2004-12-18 16:02                           ` Jörn Engel
  0 siblings, 2 replies; 70+ messages in thread
From: Josh Boyer @ 2004-12-17 17:35 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Gareth Bult (Encryptec) wrote:
> 
> 
> Sure, ext2 and ext3 work just fine .. however .. as far as I'm aware,
> although ext3 is log structured, it's not optimised to run in a linear
> fashion and doesn't worry about repeatedly writing to the same block ..
> which is likely to cause the USB flash controller to execute an erase
> prior to write .. which will quickly wear down the device [?!]
> 
> (Am I wrong? in which case why isn't everyone using ext3 instead of
> JFFS?)

Most of the controllers for these devices do the wear leveling 
themselves.  At least that was my understanding.

We don't deal much with these devices, so I'm not sure what everyone 
else uses.  Alot of the CF devices are FAT formatted to work with 
Windows, etc.

> 
> The other requirement of course is inline compression, which last time I
> looked ext3 didn't do out of the box (?)

No, it doesn't.  There are patches for ext2 to make it use compression 
(e2compr), but then you lose the journaling.

> 
> I'm going to deliberately wear down some blocks on a key a little later
> (at block level) to see what the OS makes of it ... (and whether it
> takes 100,000 or 1,000,000 cycles .. I see conflicting specs ..

That probably depends on the actual flash chips used within the device. 
  Not all of them use the same type of flash.

> 
> I guess the basic spec for a USB flash key (you may call them
> abominations, but you should see the sales stats!) would be;

Hey, they certainly are handy.  I'm not arguing with that :).

> 
> a. purely log structured fs with linear / circular operation
> b. write blocks aligned to 2k (or 4k might be smarter to fit with buffer
> page sizes)
> c. erase blocks @ 128k
> d. inline compression

Again, most controllers do all the wear leveling, erasing for you.  So 
you are left with compression, right?

And that is certainly a lacking thing.  A block-based, writeable, 
compressed filesystem that does journalling.  Sounds like a good 
opportunity to me :).

josh

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-17 17:35                         ` Josh Boyer
@ 2004-12-17 18:09                           ` Gareth Bult (Encryptec)
  2004-12-17 19:14                             ` jasmine
  2004-12-18 16:02                           ` Jörn Engel
  1 sibling, 1 reply; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-17 18:09 UTC (permalink / raw)
  To: Josh Boyer; +Cc: Linux MTD

On Fri, 2004-12-17 at 11:35 -0600, Josh Boyer wrote:
> Gareth Bult (Encryptec) wrote:
> Again, most controllers do all the wear leveling, erasing for you.  So 
> you are left with compression, right?
> 
> And that is certainly a lacking thing.  A block-based, writeable, 
> compressed filesystem that does journalling.  Sounds like a good 
> opportunity to me :).

Mmm, sounds a bit like JFFS2 on a block emulator , yeah ?

;-)

Gareth.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-17 18:09                           ` Gareth Bult (Encryptec)
@ 2004-12-17 19:14                             ` jasmine
  2004-12-17 20:55                               ` Gareth Bult (Encryptec)
  0 siblings, 1 reply; 70+ messages in thread
From: jasmine @ 2004-12-17 19:14 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD



On Fri, 17 Dec 2004, Gareth Bult (Encryptec) wrote:

> Mmm, sounds a bit like JFFS2 on a block emulator , yeah ?

Only if you actively enjoy wasting processor cycles (and microjoules) and 
ROM footprint...

-J.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-17 19:14                             ` jasmine
@ 2004-12-17 20:55                               ` Gareth Bult (Encryptec)
  0 siblings, 0 replies; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-17 20:55 UTC (permalink / raw)
  To: jasmine; +Cc: Linux MTD

On Fri, 2004-12-17 at 19:14 +0000, jasmine@linuxgrrls.org wrote:
> On Fri, 17 Dec 2004, Gareth Bult (Encryptec) wrote:
> 
> > Mmm, sounds a bit like JFFS2 on a block emulator , yeah ?
> 
> Only if you actively enjoy wasting processor cycles (and microjoules) and 
> ROM footprint...

Processor cycles, got em to spare ..
Microjoules coming out of my ears ..
ROM footprint .. don't use 'em ..

What's the alternative then .. :)

Gareth.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-17 17:35                         ` Josh Boyer
  2004-12-17 18:09                           ` Gareth Bult (Encryptec)
@ 2004-12-18 16:02                           ` Jörn Engel
  2004-12-20 16:34                             ` Josh Boyer
  1 sibling, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-18 16:02 UTC (permalink / raw)
  To: Josh Boyer; +Cc: Linux MTD, Gareth Bult (Encryptec)

On Fri, 17 December 2004 11:35:04 -0600, Josh Boyer wrote:
> 
> Again, most controllers do all the wear leveling, erasing for you.  So 
> you are left with compression, right?

If you have enough trust in your El Cheapo hardware supplier.  There
is no standard that requires wear leveling and there are reports that
basically tell you to do your own wear leveling on some devices.  With
no good way to distinguish "some" devices from "others", you can read
that as "all". ;)

USB keys and all the various other consumer-type flash devices are
good enough to beat 3 1/2" floppies, that's about it.  But that's
quite good enough for most people.  Floppies sold like crazy after
all.

Jörn

-- 
Simplicity is prerequisite for reliability.
-- Edsger W. Dijkstra

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-16 21:47           ` Gareth Bult (Encryptec)
  2004-12-17 12:54             ` Josh Boyer
@ 2004-12-18 16:19             ` Jörn Engel
  2004-12-18 17:32               ` Gareth Bult (Encryptec)
  1 sibling, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-18 16:19 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

On Thu, 16 December 2004 21:47:49 +0000, Gareth Bult (Encryptec) wrote:
> 
> blkmtd.c is pretty much a rewrite, less than half the size and uses the
> system buffer cache instead of reading / writing directly to the device.
> This boosts performance x 3 on read x lots on write. [I get x 100
> faster] (albeit you lose bad block detection on write)
> 
> If anyone's interested in the code, let me know and I'll clean it up and
> post it .. however it'll be a new file and not a patch.

Sure am!  If the code lives up to your promises I'd like to read it
(might learn something new) and possibly use it sometime soon.

Jörn

-- 
The competent programmer is fully aware of the strictly limited size of
his own skull; therefore he approaches the programming task in full
humility, and among other things he avoids clever tricks like the plague. 
-- Edsger W. Dijkstra

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-18 16:19             ` Jörn Engel
@ 2004-12-18 17:32               ` Gareth Bult (Encryptec)
  2004-12-18 17:52                 ` Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-18 17:32 UTC (permalink / raw)
  To: Jörn Engel; +Cc: Linux MTD

[-- Attachment #1: Type: text/plain, Size: 1098 bytes --]

Ok,

There's a public health warning attached to this code ..

I've not cleaned it up and I've not added any comments ..

(!)

fyi; I don't use mkfs.jffs2 .. I flash_eraseall the device then work
from there with "tar".. there seems to be no benefit [for me] to using
mkfs and it seems a little more reliant on the device size than the
erase program.

Gareth.

On Sat, 2004-12-18 at 17:19 +0100, Jörn Engel wrote:
> On Thu, 16 December 2004 21:47:49 +0000, Gareth Bult (Encryptec) wrote:
> > 
> > blkmtd.c is pretty much a rewrite, less than half the size and uses the
> > system buffer cache instead of reading / writing directly to the device.
> > This boosts performance x 3 on read x lots on write. [I get x 100
> > faster] (albeit you lose bad block detection on write)
> > 
> > If anyone's interested in the code, let me know and I'll clean it up and
> > post it .. however it'll be a new file and not a patch.
> 
> Sure am!  If the code lives up to your promises I'd like to read it
> (might learn something new) and possibly use it sometime soon.
> 
> Jörn
> 

[-- Attachment #2: blkmtd.c --]
[-- Type: text/x-csrc, Size: 16190 bytes --]

/*
 * $Id: blkmtd.c,v 1.23 2004/08/09 14:03:19 dwmw2 Exp $
 *
 * blkmtd.c - use a block device as a fake MTD
 *
 * Author: Simon Evans <spse@secret.org.uk>
 *
 * Copyright (C) 2001,2002 Simon Evans
 *
 * Licence: GPL
 *
 * How it works:
 *	The driver uses raw/io to read/write the device and the page
 *	cache to cache access. Writes update the page cache with the
 *	new data and mark it dirty and add the page into a BIO which
 *	is then written out.
 *
 *	It can be loaded Read-Only to prevent erases and writes to the
 *	medium.
 *
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/bio.h>
#include <linux/pagemap.h>
#include <linux/list.h>
#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/buffer_head.h>

#define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
#define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "blkmtd: " format "\n" , ## arg)
#define crit(format, arg...) printk(KERN_CRIT "blkmtd: " format "\n" , ## arg)


/* Default erase size in K, always make it a multiple of PAGE_SIZE */
#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10)	/* 128KiB */
#define VERSION "$Revision: 1.23 $"

/* Info for the block device */
struct blkmtd_dev {
	struct list_head list;
	struct block_device *blkdev;
	struct mtd_info mtd_info;
	struct semaphore wrbuf_mutex;
};


/* Static info about the MTD, used in cleanup_module */
static LIST_HEAD(blkmtd_device_list);

static void blkmtd_sync(struct mtd_info *mtd);

#define MAX_DEVICES 4

/* Module parameters passed by insmod/modprobe */
char *device[MAX_DEVICES];    /* the block device to use */
int erasesz[MAX_DEVICES];     /* optional default erase size */
int ro[MAX_DEVICES];          /* optional read only flag */
int sync;


MODULE_LICENSE("GPL");
MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
MODULE_DESCRIPTION("Emulate an MTD using a block device");
MODULE_PARM(device, "1-4s");
MODULE_PARM_DESC(device, "block device to use");
MODULE_PARM(erasesz, "1-4i");
MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB.");
MODULE_PARM(ro, "1-4i");
MODULE_PARM_DESC(ro, "1=Read only, writes and erases cause errors");
MODULE_PARM(sync, "i");
MODULE_PARM_DESC(sync, "1=Synchronous writes");

#define PAGE_READAHEAD 64

void cache_readahead(struct address_space *mapping, int index)
{
	filler_t *filler = (filler_t*)(mapping->a_ops->readpage);
	int i,pagei;
	unsigned ret = 0;
	unsigned long end_index;
	struct page *page;
	LIST_HEAD(page_pool);
	struct inode *inode = mapping->host;
	loff_t isize = i_size_read(inode);

	if(!isize) {
		printk(KERN_INFO "iSize=0 in cache_readahead\n");
		return;
	}

	end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);

	spin_lock_irq(&mapping->tree_lock);
	for(i=0;i<PAGE_READAHEAD;i++) {
		pagei=index+i;
		if (pagei > end_index) {
			printk(KERN_INFO "Overrun end of disk in cache readahead\n");
			break;
		}
		page = radix_tree_lookup(&mapping->page_tree, pagei);
		if(page && (!i)) break;
		if(page) continue;
		spin_unlock_irq(&mapping->tree_lock);
		page = page_cache_alloc_cold(mapping);
		spin_lock_irq(&mapping->tree_lock);
		if(!page) break;
		page->index=pagei;
		list_add(&page->lru, &page_pool);
		ret++;
	}
	spin_unlock_irq(&mapping->tree_lock);
	if(ret) {
		read_cache_pages(mapping, &page_pool, filler, NULL);
		//printk(KERN_INFO "Readahead [%d/%d] pages from [%d]\n",ret,PAGE_READAHEAD,index);
	}
}

static struct page* page_readahead(struct address_space *mapping, int index)
{
	filler_t *filler = (filler_t*)(mapping->a_ops->readpage);
	cache_readahead(mapping,index);
	return read_cache_page(mapping, index, filler, NULL);
}
/**
 * write_pages - write block of data to device via the page cache
 * @dev: device to write to
 * @buf: data source or NULL if erase (output is set to 0xff)
 * @to: offset into output device
 * @len: amount to data to write
 * @retlen: amount of data written
 *
 * Grab pages from the page cache and fill them with the source data.
 * Non page aligned start and end result in a readin of the page and
 * part of the page being modified. Pages are added to the bio and then written
 * out.
 */

static int write_pages(struct blkmtd_dev *dev, const u_char *buf, loff_t to, size_t len, size_t *retlen)
{
	struct	page *page;
	struct	address_space *mapping = dev->blkdev->bd_inode->i_mapping;
	//
	int	err	= 0;			// return status
	int	index	= to >> PAGE_SHIFT;	// page index
	int	offset 	= to & ~PAGE_MASK;	// page offset
	//

	static int my_read()
	{
		err=0;
		page = page_readahead(mapping,index);
		if( unlikely(!page) ) {
			crit("unable to read page (%d) in write_pages\n",index);
			err=-ENOMEM;
		}
		//if(IS_ERR(page)) err=-EIO;
		if(err) printk("READ ERROR\n");
		return err;
	}
	//
	static int my_erase()
	{
		int pages = len >> PAGE_SHIFT;
		unsigned char *p;
		unsigned char *max;
		int format;

		while(pages) {
			//printk(KERN_INFO "readahead on index (%d)\n",index);
			if(my_read()) return err;

			max = ((char*)page_address(page)+PAGE_SIZE);
			format = 0;

			for(p=(unsigned char*)page_address(page); p<max; p++) 
				if(*p != 0xff) {
					format=1;
					break;
				}

			if(format) {
				//DEBUG(3, "write_pages: erasing\n");
				lock_page(page);
				memset(page_address(page), 0xff, PAGE_SIZE);
				set_page_dirty(page);
				unlock_page(page);
			}
			page_cache_release(page);
			pages--;
			index++;
		}
		*retlen = len;
		return 0;
	}

	static int my_write()
	{
		int cpylen;

		if(retlen) *retlen = 0;
		//printk(KERN_INFO "Write req: %d\n",len);
		while(len) {
			if((offset+len) > PAGE_SIZE) 
				cpylen = PAGE_SIZE - offset;	// multiple pages
			else	cpylen = len;			// this page
			len = len - cpylen;
			//
			//	Get page
			//
			if(my_read()) return err;
			//
			if(memcmp(page_address(page)+offset,buf,cpylen)) {
				lock_page(page);
				memcpy(page_address(page) + offset,buf, cpylen);
				set_page_dirty(page);
				unlock_page(page);
			}
			page_cache_release(page);

			if(retlen) *retlen += cpylen;
			//
			buf+=cpylen;
			offset = 0;
			index++;
			//
		}
		//printk(KERN_INFO "Write act: %d\n",*retlen);
		return 0;
	}

	err=0;
	down(&dev->wrbuf_mutex);
	err = buf ? my_write() : my_erase();
	up(&dev->wrbuf_mutex);
	return err;
}

/* erase a specified part of the device */
static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
{
	struct blkmtd_dev *dev = mtd->priv;
	struct mtd_erase_region_info *einfo = mtd->eraseregions;
	int numregions = mtd->numeraseregions;
	size_t from;
	u_long len;
	int err = -EIO;
	size_t retlen;

	instr->state = MTD_ERASING;
	from = instr->addr;
	len = instr->len;

	/* check erase region has valid start and length */
	//DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%zx len = 0x%lx\n", mtd->name+9, from, len);
	while(numregions) {
		DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
		      einfo->offset, einfo->erasesize, einfo->numblocks);
		if(from >= einfo->offset
		   && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
			if(len == einfo->erasesize
			   && ( (from - einfo->offset) % einfo->erasesize == 0))
				break;
		}
		numregions--;
		einfo++;
	}

	if(!numregions) {
		/* Not a valid erase block */
		err("erase: invalid erase request 0x%lX @ 0x%08zX", len, from);
		instr->state = MTD_ERASE_FAILED;
		err = -EIO;
	}

	if(instr->state != MTD_ERASE_FAILED) {
		/* do the erase */
		DEBUG(3, "Doing erase from = %zd len = %ld\n", from, len);
		err = write_pages(dev, NULL, from, len, &retlen);
		if(err || retlen != len) {
			err("erase failed err = %d", err);
			instr->state = MTD_ERASE_FAILED;
		} else {
			instr->state = MTD_ERASE_DONE;
		}
	}

	DEBUG(3, "blkmtd: erase: checking callback\n");
	mtd_erase_callback(instr);
	DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
	return err;
}

static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
{
	struct blkmtd_dev *dev = mtd->priv;
	struct page *page;
	//
	int index	= from >> PAGE_SHIFT;
	int offset	= from - (index << PAGE_SHIFT);
	int cpylen;

	if(from > mtd->size) return -EINVAL;
	if(from + len > mtd->size) len = mtd->size - from;

	if(retlen) *retlen = 0;

	while(len) {
		if((offset+len) > PAGE_SIZE) 
			cpylen = PAGE_SIZE - offset;	// multiple pages
		else	cpylen = len;			// this page
		len = len - cpylen;
		//
		//	Get page
		//
		page = page_readahead(dev->blkdev->bd_inode->i_mapping,index);
		if(!page) return -ENOMEM;
		if(IS_ERR(page)) return -EIO;
		//
		memcpy(buf, page_address(page) + offset, cpylen);
		page_cache_release(page);
		//
		if(retlen) *retlen += cpylen;
		buf+=cpylen;
		offset = 0;
		index++;
		//
	}
	return 0;
}


/* write data to the underlying device */
static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
			size_t *retlen, const u_char *buf)
{
	struct blkmtd_dev *dev = mtd->priv;
	int err;

	if(!len) return 0;
	if(to >= mtd->size) return -ENOSPC;
	if(to + len > mtd->size) len = mtd->size - to;

	err = write_pages(dev, buf, to, len, retlen);
	if(err > 0) err = 0;
	return err;
}


/* sync the device - wait until the write queue is empty */
static void blkmtd_sync(struct mtd_info *mtd)
{
	sync_blockdev(((struct blkmtd_dev*)mtd->priv)->blkdev);
	return;
}

static void free_device(struct blkmtd_dev *dev)
{
	DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);
	if(dev) {
		if(dev->mtd_info.eraseregions)
			kfree(dev->mtd_info.eraseregions);
		if(dev->mtd_info.name)
			kfree(dev->mtd_info.name);

		if(dev->blkdev) {
			invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);
			close_bdev_excl(dev->blkdev);
		}
		kfree(dev);
	}
}


/* For a given size and initial erase size, calculate the number
 * and size of each erase region. Goes round the loop twice,
 * once to find out how many regions, then allocates space,
 * then round the loop again to fill it in.
 */
static struct mtd_erase_region_info *calc_erase_regions(
	size_t erase_size, size_t total_size, int *regions)
{
	struct mtd_erase_region_info *info = NULL;

	DEBUG(2, "calc_erase_regions, es = %zd size = %zd regions = %d\n",
	      erase_size, total_size, *regions);
	/* Make any user specified erasesize be a power of 2
	   and at least PAGE_SIZE */
	if(erase_size) {
		int es = erase_size;
		erase_size = 1;
		while(es != 1) {
			es >>= 1;
			erase_size <<= 1;
		}
		if(erase_size < PAGE_SIZE)
			erase_size = PAGE_SIZE;
	} else {
		erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
	}

	*regions = 0;

	do {
		int tot_size = total_size;
		int er_size = erase_size;
		int count = 0, offset = 0, regcnt = 0;

		while(tot_size) {
			count = tot_size / er_size;
			if(count) {
				tot_size = tot_size % er_size;
				if(info) {
					DEBUG(2, "adding to erase info off=%d er=%d cnt=%d\n",
					      offset, er_size, count);
					(info+regcnt)->offset = offset;
					(info+regcnt)->erasesize = er_size;
					(info+regcnt)->numblocks = count;
					(*regions)++;
				}
				regcnt++;
				offset += (count * er_size);
			}
			while(er_size > tot_size)
				er_size >>= 1;
		}
		if(info == NULL) {
			info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
			if(!info)
				break;
		}
	} while(!(*regions));
	DEBUG(2, "calc_erase_regions done, es = %zd size = %zd regions = %d\n",
	      erase_size, total_size, *regions);
	return info;
}


extern dev_t __init name_to_dev_t(const char *line);

static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size)
{
	struct block_device *bdev;
	int mode;
	struct blkmtd_dev *dev;

	if(!devname)
		return NULL;

	/* Get a handle on the device */


#ifdef MODULE
	mode = (readonly) ? O_RDONLY : O_RDWR;
	bdev = open_bdev_excl(devname, mode, NULL);
#else
	mode = (readonly) ? FMODE_READ : FMODE_WRITE;
	bdev = open_by_devnum(name_to_dev_t(devname), mode);
#endif
	if(IS_ERR(bdev)) {
		err("error: cannot open device %s", devname);
		DEBUG(2, "blkmtd: opening bdev returned %ld\n", PTR_ERR(bdev));
		return NULL;
	}

	DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",
	      MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));

	if(MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
		err("attempting to use an MTD device as a block device");
		blkdev_put(bdev);
		return NULL;
	}

	dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
	if(dev == NULL) {
		blkdev_put(bdev);
		return NULL;
	}

	memset(dev, 0, sizeof(struct blkmtd_dev));
	dev->blkdev = bdev;
	atomic_set(&(dev->blkdev->bd_inode->i_mapping->truncate_count), 0);
	if(!readonly) {
		init_MUTEX(&dev->wrbuf_mutex);
	}

	dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;

	/* Setup the MTD structure */
	/* make the name contain the block device in */
	dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL);
	if(dev->mtd_info.name == NULL)
		goto devinit_err;

	sprintf(dev->mtd_info.name, "blkmtd: %s", devname);
	dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size,
							&dev->mtd_info.numeraseregions);
	if(dev->mtd_info.eraseregions == NULL)
		goto devinit_err;

	dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize;
	DEBUG(1, "blkmtd: init: found %d erase regions\n",
	      dev->mtd_info.numeraseregions);

	if(readonly) {
		dev->mtd_info.type = MTD_ROM;
		dev->mtd_info.flags = MTD_CAP_ROM;
	} else {
		dev->mtd_info.type = MTD_RAM;
		dev->mtd_info.flags = MTD_CAP_RAM;
		dev->mtd_info.erase = blkmtd_erase;
		dev->mtd_info.write = blkmtd_write;
		dev->mtd_info.writev = default_mtd_writev;
		dev->mtd_info.sync = blkmtd_sync;
	}
	dev->mtd_info.read = blkmtd_read;
	dev->mtd_info.readv = default_mtd_readv;
	dev->mtd_info.priv = dev;
	dev->mtd_info.owner = THIS_MODULE;

	list_add(&dev->list, &blkmtd_device_list);
	if (add_mtd_device(&dev->mtd_info)) {
		/* Device didnt get added, so free the entry */
		list_del(&dev->list);
		goto devinit_err;
	} else {
		info("mtd%d: [%s] erase_size = %dKiB %s [%ld]",
		     dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),
		     dev->mtd_info.erasesize >> 10,
		     readonly ? "(read-only)" : "", PAGE_SIZE);
	}
	return dev;

 devinit_err:
	free_device(dev);
	return NULL;
}


/* Cleanup and exit - sync the device and kill of the kernel thread */
static void __devexit cleanup_blkmtd(void)
{
	struct list_head *temp1, *temp2;

	/* Remove the MTD devices */
	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
		struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
						    list);
		blkmtd_sync(&dev->mtd_info);
		del_mtd_device(&dev->mtd_info);
		info("mtd%d: [%s] removed", dev->mtd_info.index,
		     dev->mtd_info.name + strlen("blkmtd: "));
		list_del(&dev->list);
		free_device(dev);
	}
}

#ifndef MODULE

/* Handle kernel boot params */


static int __init param_blkmtd_device(char *str)
{
	int i;

	for(i = 0; i < MAX_DEVICES; i++) {
		device[i] = str;
		DEBUG(2, "blkmtd: device setup: %d = %s\n", i, device[i]);
		strsep(&str, ",");
	}
	return 1;
}


static int __init param_blkmtd_erasesz(char *str)
{
	int i;
	for(i = 0; i < MAX_DEVICES; i++) {
		char *val = strsep(&str, ",");
		if(val)
			erasesz[i] = simple_strtoul(val, NULL, 0);
		DEBUG(2, "blkmtd: erasesz setup: %d = %d\n", i, erasesz[i]);
	}

	return 1;
}


static int __init param_blkmtd_ro(char *str)
{
	int i;
	for(i = 0; i < MAX_DEVICES; i++) {
		char *val = strsep(&str, ",");
		if(val)
			ro[i] = simple_strtoul(val, NULL, 0);
		DEBUG(2, "blkmtd: ro setup: %d = %d\n", i, ro[i]);
	}

	return 1;
}


static int __init param_blkmtd_sync(char *str)
{
	if(str[0] == '1')
		sync = 1;
	return 1;
}

__setup("blkmtd_device=", param_blkmtd_device);
__setup("blkmtd_erasesz=", param_blkmtd_erasesz);
__setup("blkmtd_ro=", param_blkmtd_ro);
__setup("blkmtd_sync=", param_blkmtd_sync);

#endif


/* Startup */
static int __init init_blkmtd(void)
{
	int i;

	info("version " VERSION);
	/* Check args - device[0] is the bare minimum*/
	if(!device[0]) {
		err("error: missing `device' name\n");
		return -EINVAL;
	}

	for(i = 0; i < MAX_DEVICES; i++)
		add_device(device[i], ro[i], erasesz[i] << 10);

	if(list_empty(&blkmtd_device_list))
		return -EINVAL;

	return 0;
}

module_init(init_blkmtd);
module_exit(cleanup_blkmtd);

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-18 17:32               ` Gareth Bult (Encryptec)
@ 2004-12-18 17:52                 ` Jörn Engel
  2004-12-18 18:11                   ` Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-18 17:52 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

On Sat, 18 December 2004 17:32:35 +0000, Gareth Bult (Encryptec) wrote:
> 
> There's a public health warning attached to this code ..
> 
> I've not cleaned it up and I've not added any comments ..

I'll wear protective gloves then.  Thanks!

> fyi; I don't use mkfs.jffs2 .. I flash_eraseall the device then work
> from there with "tar".. there seems to be no benefit [for me] to using
> mkfs and it seems a little more reliant on the device size than the
> erase program.

Makes a lot of sense.  Both approaches have some advantages.

Jörn

-- 
The story so far:
In the beginning the Universe was created.  This has made a lot
of people very angry and been widely regarded as a bad move.
-- Douglas Adams?

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-18 17:52                 ` Jörn Engel
@ 2004-12-18 18:11                   ` Jörn Engel
  2004-12-18 20:48                     ` Gareth Bult (Encryptec)
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-18 18:11 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

On Sat, 18 December 2004 18:52:22 +0100, Jörn Engel wrote:
> On Sat, 18 December 2004 17:32:35 +0000, Gareth Bult (Encryptec) wrote:
> > 
> > There's a public health warning attached to this code ..
> > 
> > I've not cleaned it up and I've not added any comments ..
> 
> I'll wear protective gloves then.  Thanks!

Not a pretty.  Looks like quite a few cleanups from phram.c can be
applied to this one as well.  From a first glance:
o Coding style (Lindent?)
o Function length
o #ifdef MODULE
o parameters have an insane interface
o ro-devices.  the same can be achieved with chmod.

But you started the work, which is a good thing.

Jörn

-- 
Public Domain  - Free as in Beer
General Public - Free as in Speech
BSD License    - Free as in Enterprise
Shared Source  - Free as in "Work will make you..."

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-18 18:11                   ` Jörn Engel
@ 2004-12-18 20:48                     ` Gareth Bult (Encryptec)
  2004-12-19  2:44                       ` Jörn Engel
  2004-12-21 13:30                       ` Jörn Engel
  0 siblings, 2 replies; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-18 20:48 UTC (permalink / raw)
  To: Jörn Engel; +Cc: Linux MTD

Like I said, hacked to work [for me] and not to look pretty.

To be honest what's there will do me for now .. although I'd like to
clean it up a little when I get time.

fyi; don't confuse the old and new code.

> o Coding style (Lindent?)

Whatever was there already.

> o Function length

My functions are shorter than the ones that were there, lots can be
cleaned up here.

> o #ifdef MODULE

.. ? I only use it as a module, not of this code was touched.

> o parameters have an insane interface

.. again , parameters and interfaces are all from the original with the
exception of a couple of new routines which mirror existing parameter
lists.

> o ro-devices.  the same can be achieved with chmod.

Again, not touched this.

Gareth.

On Sat, 2004-12-18 at 19:11 +0100, Jörn Engel wrote:
> On Sat, 18 December 2004 18:52:22 +0100, Jörn Engel wrote:
> > On Sat, 18 December 2004 17:32:35 +0000, Gareth Bult (Encryptec) wrote:
> > > 
> > > There's a public health warning attached to this code ..
> > > 
> > > I've not cleaned it up and I've not added any comments ..
> > 
> > I'll wear protective gloves then.  Thanks!
> 
> Not a pretty.  Looks like quite a few cleanups from phram.c can be
> applied to this one as well.  From a first glance:
> o Coding style (Lindent?)
> o Function length
> o #ifdef MODULE
> o parameters have an insane interface
> o ro-devices.  the same can be achieved with chmod.
> 
> But you started the work, which is a good thing.
> 
> Jörn
> 

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-18 20:48                     ` Gareth Bult (Encryptec)
@ 2004-12-19  2:44                       ` Jörn Engel
  2004-12-21 13:30                       ` Jörn Engel
  1 sibling, 0 replies; 70+ messages in thread
From: Jörn Engel @ 2004-12-19  2:44 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

On Sat, 18 December 2004 20:48:50 +0000, Gareth Bult (Encryptec) wrote:
> 
> Like I said, hacked to work [for me] and not to look pretty.
> 
> To be honest what's there will do me for now .. although I'd like to
> clean it up a little when I get time.
> 
> fyi; don't confuse the old and new code.

Sure.  I had a look at tkdiff and there was ~50% unchanged code.
"This code ain't pretty." didn't mean "You sh*thead are stupid and
cannot create decent code."  It was more like "It still ain't pretty,
although you already improved it."

> > o Coding style (Lindent?)
> 
> Whatever was there already.
> 
> > o Function length
> 
> My functions are shorter than the ones that were there, lots can be
> cleaned up here.
> 
> > o #ifdef MODULE
> 
> .. ? I only use it as a module, not of this code was touched.
> 
> > o parameters have an insane interface
> 
> .. again , parameters and interfaces are all from the original with the
> exception of a couple of new routines which mirror existing parameter
> lists.
> 
> > o ro-devices.  the same can be achieved with chmod.
> 
> Again, not touched this.

Yep.  Those five point were the obvious stuff I could find in five
minutes.  Fixing them takes a lot more than five minutes and changing
the parameter interface basically means copying the thing and fixing
the new one.

I did the same with slram/phram.  The slram interface was different
for module/non-module built and insane once you had more than a single
device.  Mtdblock looks quite similar and seems to need the same cure.
So whatever you can improve, please do.

Jörn

-- 
It's just what we asked for, but not what we want!
-- anonymous

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-16 13:43 ` Ferenc Havasi
@ 2004-12-20 16:01   ` Gareth Bult (Encryptec)
  2004-12-20 16:09     ` Ferenc Havasi
  0 siblings, 1 reply; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-20 16:01 UTC (permalink / raw)
  To: Ferenc Havasi; +Cc: Linux MTD

Hi,

I'm afraid this patch seems to be quite a long way from applying cleanly
to my source. I'm using 2.6.9 .. at least half a dozen failures or
more ...

:(

Will look into it in more detail later ...

Gareth.


On Thu, 2004-12-16 at 14:43 +0100, Ferenc Havasi wrote:
> Hi Gareth,
> 
> > However, I'm looking at 30secs to mount the root filesystem.
> 
> Did you try our patch? I send it now again, we made it fresh for the 
> current CVS. See its usage in the archive (16th November).
> 
> It will part of JFFS3.
> 
> This is designed for NAND devices - I don't know too much about your 
> environment, but it may help.
> 
> Bye,
> Ferenc
> plain text document attachment (jffs2-summary-20041207.patch)
> diff --unified --new-file --recursive mtd/fs/Kconfig mtd-dec07/fs/Kconfig
> --- mtd/fs/Kconfig	2004-11-04 00:00:11.000000000 +0100
> +++ mtd-dec07/fs/Kconfig	2004-12-07 16:03:02.000000000 +0100
> @@ -77,6 +77,19 @@
>  		 ECC for JFFS2.  This type of flash chip is not common, however it is
>  		 available from STMicro.
>  
> +config JFFS2_SUMMARY
> +        bool "JFFS2 summary support (EXPERIMENTAL)" 
> +        depends on JFFS2_FS
> +        default n
> +        help 
> +          This feature makes it possible to use summary information
> +          for faster filesystem mount - specially on NAND.
> +
> +          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 --unified --new-file --recursive mtd/fs/jffs2/Makefile.common mtd-dec07/fs/jffs2/Makefile.common
> --- mtd/fs/jffs2/Makefile.common	2004-11-04 00:00:11.000000000 +0100
> +++ mtd-dec07/fs/jffs2/Makefile.common	2004-12-07 16:03:02.000000000 +0100
> @@ -16,3 +16,4 @@
>  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 --unified --new-file --recursive mtd/fs/jffs2/build.c mtd-dec07/fs/jffs2/build.c
> --- mtd/fs/jffs2/build.c	2004-11-28 00:00:13.000000000 +0100
> +++ mtd-dec07/fs/jffs2/build.c	2004-12-07 16:08:31.000000000 +0100
> @@ -331,6 +331,10 @@
>  		c->blocks[i].first_node = NULL;
>  		c->blocks[i].last_node = NULL;
>  		c->blocks[i].bad_count = 0;
> + #ifdef CONFIG_JFFS2_SUMMARY	
> + 		c->blocks[i].sum_collected = NULL;
> + #endif
> +
>  	}
>  
>  	init_MUTEX(&c->alloc_sem);
> diff --unified --new-file --recursive mtd/fs/jffs2/dir.c mtd-dec07/fs/jffs2/dir.c
> --- mtd/fs/jffs2/dir.c	2004-11-17 00:00:14.000000000 +0100
> +++ mtd-dec07/fs/jffs2/dir.c	2004-12-07 16:03:02.000000000 +0100
> @@ -22,6 +22,7 @@
>  #include <linux/time.h>
>  #include "nodelist.h"
>  
> +
>  /* Urgh. Please tell me there's a nicer way of doing these. */
>  #include <linux/version.h>
>  #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
> @@ -314,7 +315,7 @@
>  	 * Just the node will do for now, though 
>  	 */
>  	namelen = dentry->d_name.len;
> -	ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL);
> +	ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
>  
>  	if (ret) {
>  		jffs2_free_raw_inode(ri);
> @@ -360,7 +361,7 @@
>  	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);
> @@ -445,7 +446,7 @@
>  	 * 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);
> @@ -488,7 +489,7 @@
>  	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);
> @@ -597,7 +598,7 @@
>  	 * 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);
> @@ -642,7 +643,7 @@
>  	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);
> @@ -796,4 +797,3 @@
>  
>  	return 0;
>  }
> -
> diff --unified --new-file --recursive mtd/fs/jffs2/file.c mtd-dec07/fs/jffs2/file.c
> --- mtd/fs/jffs2/file.c	2004-11-17 00:00:14.000000000 +0100
> +++ mtd-dec07/fs/jffs2/file.c	2004-12-07 16:03:02.000000000 +0100
> @@ -22,6 +22,7 @@
>  #include <linux/jffs2.h>
>  #include "nodelist.h"
>  
> +
>  extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
>  extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak));
>  
> @@ -135,7 +136,7 @@
>  		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 --unified --new-file --recursive mtd/fs/jffs2/fs.c mtd-dec07/fs/jffs2/fs.c
> --- mtd/fs/jffs2/fs.c	2004-11-29 00:00:09.000000000 +0100
> +++ mtd-dec07/fs/jffs2/fs.c	2004-12-07 16:03:02.000000000 +0100
> @@ -74,7 +74,7 @@
>  		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 --unified --new-file --recursive mtd/fs/jffs2/gc.c mtd-dec07/fs/jffs2/gc.c
> --- mtd/fs/jffs2/gc.c	2004-11-17 00:00:14.000000000 +0100
> +++ mtd-dec07/fs/jffs2/gc.c	2004-12-07 16:03:02.000000000 +0100
> @@ -506,7 +506,7 @@
>  	   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);
> +					      rawlen), &phys_ofs, &alloclen, rawlen); /* this is not optimal yet */
>  	if (ret)
>  		return ret;
>  
> @@ -614,7 +614,7 @@
>  			ACCT_SANITY_CHECK(c,jeb);
>  			D1(ACCT_PARANOIA_CHECK(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 optimal yet */
>  
>  			if (!ret) {
>  				D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));
> @@ -692,7 +692,7 @@
>  
>  	}
>  	
> -	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);
> @@ -759,7 +759,7 @@
>  	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);
> @@ -961,7 +961,7 @@
>  	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);
> @@ -1186,7 +1186,7 @@
>  		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",
> @@ -1243,4 +1243,3 @@
>  	jffs2_gc_release_page(c, pg_ptr, &pg);
>  	return ret;
>  }
> -
> diff --unified --new-file --recursive mtd/fs/jffs2/nodelist.h mtd-dec07/fs/jffs2/nodelist.h
> --- mtd/fs/jffs2/nodelist.h	2004-11-26 15:08:31.000000000 +0100
> +++ mtd-dec07/fs/jffs2/nodelist.h	2004-12-07 16:03:02.000000000 +0100
> @@ -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"
> @@ -194,6 +195,10 @@
>  	int bad_count;
>  	uint32_t offset;		/* of this block in the MTD */
>  
> +#ifdef CONFIG_JFFS2_SUMMARY	
> +	struct jffs2_sum_info *sum_collected;
> +#endif
> +	
>  	uint32_t unchecked_size;
>  	uint32_t used_size;
>  	uint32_t dirty_size;
> @@ -392,8 +397,8 @@
>  
>  /* 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);
> @@ -455,6 +460,10 @@
>  /* 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, unsigned char *buf,
> +				uint32_t ofs, uint32_t len);
> +struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino);
> +
>  
>  /* build.c */
>  int jffs2_do_mount_fs(struct jffs2_sb_info *c);
> diff --unified --new-file --recursive mtd/fs/jffs2/nodemgmt.c mtd-dec07/fs/jffs2/nodemgmt.c
> --- mtd/fs/jffs2/nodemgmt.c	2004-11-26 15:08:31.000000000 +0100
> +++ mtd-dec07/fs/jffs2/nodemgmt.c	2004-12-07 16:03:02.000000000 +0100
> @@ -38,9 +38,9 @@
>   *	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 +129,7 @@
>  			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 +140,7 @@
>  	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 +149,7 @@
>  
>  	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));
>  		}
> @@ -159,50 +159,112 @@
>  }
>  
>  /* 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)
> +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 nofree_size;
>  	
>   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)) {
> -			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;
> -		}
> -		c->wasted_size += jeb->free_size;
> -		c->free_size -= jeb->free_size;
> -		jeb->wasted_size += jeb->free_size;
> -		jeb->free_size = 0;
> +	nofree_size = 0;
> +	
> +#ifdef CONFIG_JFFS2_SUMMARY
> +
> +	if (sumsize != JFFS2_SUMMARY_NOSUM_SIZE) {
> +		int ret;
> +                if (jeb) {
> +                        if ((ret=jffs2_sum_care_sum_collected(jeb))) return ret;
> +                        nofree_size = sumsize + jeb->sum_collected->sum_size + JFFS2_SUMMARY_FRAME_SIZE;
> +                }
>  		
> -		/* 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",
> +		D1(printk(KERN_DEBUG "JFFS2: minsize %d , jeb->free(%d) , sum_collected->size(%d) , sumsize(%d)\n",minsize,jeb->free_size,jeb->sum_collected->sum_size,sumsize));
> +		
> +		if (jeb && (minsize + jeb->sum_collected->sum_size + sumsize + JFFS2_SUMMARY_FRAME_SIZE > jeb->free_size)) {
> +			D1(printk(KERN_DEBUG "JFFS2: generating summary for 0x%08x.\n", jeb->offset));
> +			if (jeb->sum_collected->sum_size == JFFS2_SUMMARY_NOSUM_SIZE) {
> +				sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
> +				jffs2_sum_clean_collected(jeb);
> +				goto restart;
> +			}
> +			
> +			ret = jffs2_sum_write_sumnode(c);
> +			
> +			if (ret)
> +				return ret;
> +			
> +			if (jeb->sum_collected->sum_size == JFFS2_SUMMARY_NOSUM_SIZE) { //jffs2_write_sumnode can't write out the summary information
> +				sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
> +				jffs2_sum_clean_collected(jeb);
> +				goto restart;
> +			}
> +			
> +			/* 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->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",
> +				list_add_tail(&jeb->list, &c->clean_list);
> +			}
> +			c->nextblock = jeb = NULL;
> +		}
> +	}
> +	else {	
> +#endif			
> +		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);
> +				jeb = c->nextblock;
> +				goto restart;
> +			}
> +			
> +			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->dirty_list);
> +				list_add_tail(&jeb->list, &c->clean_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 = jeb = NULL;
>  		}
> -		c->nextblock = jeb = NULL;
> +#ifdef CONFIG_JFFS2_SUMMARY
>  	}
> -	
> +#endif	
>  	if (!jeb) {
>  		struct list_head *next;
>  		/* Take the next block off the 'free' list */
> @@ -266,7 +328,7 @@
>  	/* 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 - nofree_size;
>  
>  	if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size &&
>  	    !jeb->first_node->next_in_ino) {
> diff --unified --new-file --recursive mtd/fs/jffs2/os-linux.h mtd-dec07/fs/jffs2/os-linux.h
> --- mtd/fs/jffs2/os-linux.h	2004-11-17 00:00:14.000000000 +0100
> +++ mtd-dec07/fs/jffs2/os-linux.h	2004-12-07 16:03:02.000000000 +0100
> @@ -100,7 +100,13 @@
>  #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
>  
>  #if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC)
> +
> +#ifndef CONFIG_JFFS2_SUMMARY
>  #define jffs2_can_mark_obsolete(c) (1)
> +#else
> +#define jffs2_can_mark_obsolete(c) (0)
> +#endif
> +
>  #define jffs2_cleanmarker_oob(c) (0)
>  #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
>  
> @@ -121,7 +127,12 @@
>  
>  #else /* NAND and/or ECC'd NOR support present */
>  
> +#ifndef CONFIG_JFFS2_SUMMARY
>  #define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM)
> +#else
> +#define jffs2_can_mark_obsolete(c) (0)
> +#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))
> @@ -218,5 +229,3 @@
>  
> 
>  #endif /* __JFFS2_OS_LINUX_H__ */
> -
> -
> diff --unified --new-file --recursive mtd/fs/jffs2/scan.c mtd-dec07/fs/jffs2/scan.c
> --- mtd/fs/jffs2/scan.c	2004-11-26 15:08:31.000000000 +0100
> +++ mtd-dec07/fs/jffs2/scan.c	2004-12-07 16:03:02.000000000 +0100
> @@ -18,22 +18,10 @@
>  #include <linux/crc32.h>
>  #include <linux/compiler.h>
>  #include "nodelist.h"
> +#include "summary.h"
>  
>  #define 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); \
> @@ -58,13 +46,6 @@
>  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
> -
>  static inline int min_free(struct jffs2_sb_info *c)
>  {
>  	uint32_t min = 2 * sizeof(struct jffs2_raw_inode);
> @@ -257,7 +238,7 @@
>  	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, unsigned char *buf,
>  				uint32_t ofs, uint32_t len)
>  {
>  	int ret;
> @@ -286,6 +267,11 @@
>  	uint32_t hdr_crc, buf_ofs, buf_len;
>  	int err;
>  	int noise = 0;
> +	
> +#ifdef CONFIG_JFFS2_SUMMARY
> +	struct jffs2_sum_marker *sm;
> +#endif	
> +	
>  #ifdef CONFIG_JFFS2_FS_NAND
>  	int cleanmarkerfound = 0;
>  #endif
> @@ -311,10 +297,54 @@
>  		}
>  	}
>  #endif
> +	
> +#ifdef CONFIG_JFFS2_SUMMARY	
> +	sm = (struct jffs2_sum_marker *)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 ) {
> +
> +		if(je32_to_cpu(sm->erase_size) == c->sector_size) {
> +			int ret = jffs2_sum_scan_sumnode(c,jeb,je32_to_cpu(sm->offset),&pseudo_random);
> +			
> +			if (ret) {
> +				kfree(sm);
> +				return ret;
> +			}
> +		}
> +		
> +		printk(KERN_WARNING "FS erase_block_size != JFFS2 erase_block_size => skipping summary information\n");
> +		
> +	}
> +	
> +	kfree(sm);
> +	
> +	ofs = jeb->offset;
> +	prevofs = jeb->offset - 1;
> +	
> +#endif
> +	
>  	buf_ofs = jeb->offset;
>  
>  	if (!buf_size) {
>  		buf_len = c->sector_size;
> +		
> +#ifdef CONFIG_JFFS2_SUMMARY
> +		/* must reread because of summary test */
> +		err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
> +		if (err)
> +			return err;
> +#endif
> +
>  	} else {
>  		buf_len = EMPTY_SCAN_SIZE;
>  		err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
> @@ -356,6 +386,8 @@
>  
>  	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) {
>  
> @@ -571,6 +603,9 @@
>  			break;
>  
>  		case JFFS2_NODETYPE_PADDING:
> +#ifdef CONFIG_JFFS2_SUMMARY
> +	                jffs2_sum_add_padding_mem(jeb,je32_to_cpu(node->totlen));
> +#endif
>  			DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
>  			ofs += PAD(je32_to_cpu(node->totlen));
>  			break;
> @@ -634,7 +669,7 @@
>  		return BLK_STATE_ALLDIRTY;
>  }
>  
> -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;
>  
> @@ -728,6 +763,11 @@
>  	pseudo_random += je32_to_cpu(ri->version);
>  
>  	UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen)));
> +	
> +#ifdef CONFIG_JFFS2_SUMMARY
> +	jffs2_sum_add_inode_mem(jeb,ri,ofs);
> +#endif
> +	
>  	return 0;
>  }
>  
> @@ -806,6 +846,10 @@
>  	USED_SPACE(PAD(je32_to_cpu(rd->totlen)));
>  	jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
>  
> +#ifdef CONFIG_JFFS2_SUMMARY
> +	jffs2_sum_add_dirent_mem(jeb,rd,ofs);
> +#endif
> +	
>  	return 0;
>  }
>  
> diff --unified --new-file --recursive mtd/fs/jffs2/summary.c mtd-dec07/fs/jffs2/summary.c
> --- mtd/fs/jffs2/summary.c	1970-01-01 01:00:00.000000000 +0100
> +++ mtd-dec07/fs/jffs2/summary.c	2004-12-07 16:03:02.000000000 +0100
> @@ -0,0 +1,720 @@
> +/*
> + * 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_buf = (jint32_t *) vmalloc(c->sector_size);
> +        if (!c->summary_buf) {
> +		printk(KERN_WARNING "JFFS2: can't allocate memory to dump summary information!\n");
> +                return 1;
> +        }
> +        return 0;
> +}
> +
> +void jffs2_sum_exit(struct jffs2_sb_info *c) 
> +{
> +        if (c->summary_buf) {
> +                vfree(c->summary_buf);
> +                c->summary_buf = NULL;
> +        }
> +}
> +
> +int jffs2_sum_care_sum_collected(struct jffs2_eraseblock *jeb)
> +{
> +	if (!jeb->sum_collected) {
> +		jeb->sum_collected = (struct jffs2_sum_info *) kmalloc(sizeof(struct jffs2_sum_info), GFP_KERNEL);
> +	
> +		if (!jeb->sum_collected)
> +			return -ENOMEM;
> +			
> +		jeb->sum_collected->sum_list = NULL;
> +		jeb->sum_collected->sum_num = 0;
> +		jeb->sum_collected->sum_size = 0; 
> +		jeb->sum_collected->sum_padded = 0; 
> +	}
> +        return 0;
> +}
> +
> +static int jffs2_sum_add_mem(struct jffs2_eraseblock *jeb, union jffs2_sum_mem *item) 
> +{
> +	
> +	union jffs2_sum_mem *walk;
> +        int ret;
> +	
> +        if ((ret=jffs2_sum_care_sum_collected(jeb))) return ret;
> +	
> +	if (!jeb->sum_collected->sum_list) {
> +		jeb->sum_collected->sum_list = (union jffs2_sum_mem *) item;
> +	} 
> +	else {
> +		walk = jeb->sum_collected->sum_list;
> +		
> +		while (walk->u.next) {
> +			walk = walk->u.next;
> +		}
> +		walk->u.next = (union jffs2_sum_mem *) item;
> +	}
> +	switch (je16_to_cpu(item->u.nodetype)) {
> +    	    case JFFS2_NODETYPE_INODE:
> +		jeb->sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE;
> +		jeb->sum_collected->sum_num++;
> +		break;
> +    	    case JFFS2_NODETYPE_DIRENT:
> +		jeb->sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
> +		jeb->sum_collected->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;
> +}
> +
> +void jffs2_sum_clean_all_info(struct jffs2_sb_info *c)
> +{
> +	int i;
> +	
> +	for (i=0; i<c->nr_blocks; i++) {
> +		struct jffs2_eraseblock *jeb = &c->blocks[i];
> +		
> +		jffs2_sum_clean_collected(jeb);
> +		kfree(jeb->sum_collected);
> +		jeb->sum_collected = NULL;
> +	}
> +}
> +	
> +/* These 3 functions are called from scan.c to collect summary info for not closed jeb */
> +
> +int jffs2_sum_add_padding_mem(struct jffs2_eraseblock *jeb, uint32_t size)
> +{
> +        int ret;
> +	
> +        if ((ret=jffs2_sum_care_sum_collected(jeb))) return ret;
> +        jeb->sum_collected->sum_padded += size;
> +        return 0;
> +}
> +
> +int jffs2_sum_add_inode_mem(struct jffs2_eraseblock *jeb, struct jffs2_raw_inode *ri, uint32_t ofs) 
> +{
> +	
> +	struct jffs2_sum_inode_mem *temp = (struct jffs2_sum_inode_mem *) kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
> +	
> +	if (!temp)
> +		return -ENOMEM;
> +
> +        ofs -= jeb->offset;
> +	
> +	temp->nodetype = ri->nodetype;
> +	temp->inode = ri->ino;
> +	temp->version = ri->version;
> +	temp->offset = cpu_to_je32(ofs); 
> +	temp->totlen = ri->totlen;
> +	temp->next = NULL;
> +	
> +	return jffs2_sum_add_mem(jeb, (union jffs2_sum_mem *)temp);
> +}
> +
> +int jffs2_sum_add_dirent_mem(struct jffs2_eraseblock *jeb, struct jffs2_raw_dirent *rd, uint32_t ofs) 
> +{
> +	
> +	struct jffs2_sum_dirent_mem *temp = (struct jffs2_sum_dirent_mem *) 
> +			kmalloc(sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL);
> +	
> +	if (!temp)
> +		return -ENOMEM;
> +	
> +        ofs -= jeb->offset;
> +
> +	temp->nodetype = rd->nodetype;
> +	temp->totlen = rd->totlen;
> +	temp->offset = cpu_to_je32(ofs);
> +	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(jeb, (union jffs2_sum_mem *)temp);
> +}
> +
> +/* Cleanup every collected summary information */
> +
> +void jffs2_sum_clean_collected(struct jffs2_eraseblock *jeb) 
> +{
> +	
> +	union jffs2_sum_mem *temp;
> +	
> +	if(jeb && jeb->sum_collected){
> +		
> +		while(jeb->sum_collected->sum_list){
> +			temp = jeb->sum_collected->sum_list;
> +			jeb->sum_collected->sum_list = jeb->sum_collected->sum_list->u.next;
> +			kfree(temp);
> +			jeb->sum_collected->sum_num--;
> +		}
> +		
> +		if(jeb->sum_collected->sum_num != 0){
> +			printk(KERN_WARNING "Ooops, something wrong happened! sum_num != 0, but sum_list = null ???");
> +			jeb->sum_collected->sum_num = 0;
> +		}
> +	}	
> +}
> +
> +/* 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;	
> +        int ret;
> +	
> +	node = (union jffs2_node_union *) invecs[0].iov_base;
> +	jeb = &c->blocks[ofs / c->sector_size];
> +        ofs -= jeb->offset;
> +       
> +        if ((ret=jffs2_sum_care_sum_collected(jeb))) return ret;        
> +	
> +	switch(je16_to_cpu(node->u.nodetype)){
> +		case JFFS2_NODETYPE_INODE : {
> +			struct jffs2_sum_inode_mem *temp = (struct jffs2_sum_inode_mem *) 
> +				kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
> +			
> +			if (!temp)
> +				return -ENOMEM;
> +
> +			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(jeb, (union jffs2_sum_mem *)temp);
> +			
> +			break;
> +		}
> +		
> +		case JFFS2_NODETYPE_DIRENT : {
> +			struct jffs2_sum_dirent_mem *temp = (struct jffs2_sum_dirent_mem *) 
> +				kmalloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL);
> +			
> +			if (!temp)
> +				return -ENOMEM;
> +			
> +			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;
> +			
> +			memcpy(temp->name,invecs[1].iov_base,node->d.nsize);
> +			
> +			return jffs2_sum_add_mem(jeb, (union jffs2_sum_mem *)temp);
> +			
> +			break;
> +		}
> +		
> +		case JFFS2_NODETYPE_PADDING : {
> +			D1(printk(KERN_DEBUG "jffs2_sum_add_kvec(): Node PADDING\n"));
> +                        jeb->sum_collected->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 : {
> +			printk(KERN_WARNING "jffs2_sum_add_kvec(): Node not supported\n");
> +			BUG();
> +			break;
> +		}
> +	}
> +	
> +	return 0;
> +}
> +
> +/* Process the summary information - 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 *raw;
> +	struct jffs2_raw_node_ref *cache_ref;
> +	struct jffs2_inode_cache *ic;
> +	struct jffs2_full_dirent *fd;
> +		
> +	int i, err;
> +	int bad_sum = 0;
> +	int sumsize;
> +	uint32_t ino;
> +	uint32_t crc;
> +	struct jffs2_summary_node *summary;
> +		
> +	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 = (struct jffs2_summary_node *) kmalloc(sumsize, GFP_KERNEL);
> +		
> +	if (!summary) {
> +			return -ENOMEM;
> +	}
> +	
> +	err = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize);
> +	
> +	if (err) {
> +			kfree(summary);
> +			return err;
> +	}
> +
> +	/* 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 "jffs2_scan_eraseblock(): Summary node header is corrupt (bad CRC or no summary at all)\n"));
> +			bad_sum = 1;
> +	}
> +	
> +	if ((!bad_sum) && (je32_to_cpu(summary->totlen) != sumsize)) {
> +			D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Summary node is corrupt (wrong erasesize?)\n"));
> +			bad_sum = 1;
> +	}
> +	
> +	crc = crc32(0, summary, sizeof(struct jffs2_summary_node)-8);
> +		
> +	if ((!bad_sum) && (je32_to_cpu(summary->node_crc) != crc)) {
> +			D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Summary node is corrupt (bad CRC)\n"));
> +			bad_sum = 1;
> +	}
> +	
> +	crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_summary_node));
> +
> +	if ((!bad_sum) && (je32_to_cpu(summary->sum_crc) != crc)) {
> +			D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Summary node data is corrupt (bad CRC)\n"));
> +			bad_sum = 1;
> +	}
> +	
> +	if (!bad_sum) {
> +		
> +		struct jffs2_sum_unknown_flash *sp;
> +		sp = (struct jffs2_sum_unknown_flash *) summary->sum;
> +
> +		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));
> +                }
> +		
> +		for(i = 0; i < je16_to_cpu(summary->sum_num); i++) {
> +			
> +			D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Processing summary information %d\n", i));
> +			uint8_t *temp8ptr = NULL;
> +			
> +			switch (je16_to_cpu(sp->nodetype)) {
> +				
> +				case JFFS2_NODETYPE_INODE : {
> +					struct jffs2_sum_inode_flash *spi;
> +					spi = (struct jffs2_sum_inode_flash *) sp;
> +						
> +					ino = je32_to_cpu(spi->inode);
> +					D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Inode at 0x%08x\n", jeb->offset + je32_to_cpu(spi->offset)));
> +					raw = jffs2_alloc_raw_node_ref();
> +					if (!raw) {
> +						printk(KERN_NOTICE "jffs2_scan_eraseblock(): allocation of node reference failed\n");
> +						kfree(summary);
> +						return -ENOMEM;
> +					}
> +		
> +					ic = jffs2_get_ino_cache(c, ino);
> +					if (!ic) {
> +						ic = jffs2_scan_make_ino_cache(c, ino);
> +						if (!ic) {
> +							printk(KERN_NOTICE "jffs2_scan_eraseblock(): scan_make_ino_cache failed\n");
> +							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)));
> +					
> +					temp8ptr = (uint8_t *) sp;
> +					temp8ptr += JFFS2_SUMMARY_INODE_SIZE;
> +					sp = (struct jffs2_sum_unknown_flash *) temp8ptr;
> +					
> +					break;
> +				}
> +					
> +				case JFFS2_NODETYPE_DIRENT : {
> +					struct jffs2_sum_dirent_flash *spd;
> +					spd = (struct jffs2_sum_dirent_flash *) 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 "jffs2_scan_dirent_node(): allocation of node reference failed\n");
> +						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);
> +					
> +					temp8ptr = (uint8_t *) sp;
> +					temp8ptr += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); 
> +					sp = (struct jffs2_sum_unknown_flash *) temp8ptr;
> +					
> +					break;
> +				}
> +				
> +				default : {
> +					printk(KERN_WARNING "Kernel doesn't support this type of node !!! Exiting");
> +					return -EIO;
> +					break;			
> +				}
> +			}
> +		}
> +		
> +		kfree(summary);
> +
> +		/* for ACCT_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;
> +
> +		/* somebody check this and all of space accounting in summary support */
> +
> +		if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size 
> +			&& (!jeb->first_node || !jeb->first_node->next_in_ino) ) { 
> +				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 0;
> +}
> +
> +/* Write out summary information - called from jffs2_do_reserve_space */
> +
> +int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
> +{
> +	struct jffs2_summary_node isum;
> +	union jffs2_sum_mem *temp;
> +	jint32_t offset;
> +	jint32_t *wpage;
> +	uint8_t *tempptr;
> +	int datasize;
> +	int infosize;
> +	int padsize;
> +	size_t retlen;
> +	int ret;
> +	struct jffs2_eraseblock *jeb;
> +	struct kvec vecs[2];	
> +	jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
> +		
> +	D2(printk(KERN_DEBUG "jffs2_sum_write_sumnode()\n"));
> +	
> +	jeb = c->nextblock;
> +	
> +	if (!jeb->sum_collected->sum_num || !jeb->sum_collected->sum_list) {
> +		printk(KERN_WARNING "JFFS2: jffs2_sum_write_sumnode(): empty summary info!!!\n");
> +		BUG(); 
> +	}
> +	
> +	datasize = jeb->sum_collected->sum_size + sizeof(struct jffs2_sum_marker);
> +	infosize = sizeof(struct jffs2_summary_node) + datasize;
> +	padsize = jeb->free_size - infosize;
> +	infosize += padsize; datasize += padsize;
> +	offset = cpu_to_je32(c->sector_size - jeb->free_size);
> +	
> +	if (padsize < 0) { // if jeb hasn't got enought free space for summary
> +		
> +		union jffs2_sum_mem *temp;	
> +		
> +		while(jeb->sum_collected->sum_list){ //cleanup sum_list
> +			temp = jeb->sum_collected->sum_list;
> +			jeb->sum_collected->sum_list = jeb->sum_collected->sum_list->u.next;
> +			kfree(temp);
> +			jeb->sum_collected->sum_num--;
> +		}
> +		
> +		jeb->sum_collected->sum_list = NULL;
> +		jeb->sum_collected->sum_num = 0;
> +		jeb->sum_collected->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; // don't try to write out summary for this node
> +		
> +		printk(KERN_WARNING "JFFS2: not enough space for summary, padsize = %d\n",padsize);
> +                return 0;
> +	}
> +			
> +	memset(c->summary_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(jeb->sum_collected->sum_padded);
> +		
> +	if (c->cleanmarker_size) {
> +		isum.cln_mkr = cpu_to_je32(c->cleanmarker_size);	
> +	}
> +	else{
> +		isum.cln_mkr = cpu_to_je32(0);
> +	}
> +	
> +	isum.sum_num = cpu_to_je16(jeb->sum_collected->sum_num);
> +	wpage = c->summary_buf;
> +	
> +		
> +	while (jeb->sum_collected->sum_num) { // write sum_data 
> +		
> +
> +		switch(je16_to_cpu(jeb->sum_collected->sum_list->u.nodetype)){
> +			
> +			case JFFS2_NODETYPE_INODE : {
> +				jint16_t *temp16ptr = (jint16_t *)wpage;
> +				
> +				*(temp16ptr++) = jeb->sum_collected->sum_list->i.nodetype;
> +				wpage = (jint32_t *) temp16ptr;
> +				
> +				*(wpage++) = jeb->sum_collected->sum_list->i.inode;
> +				*(wpage++) = jeb->sum_collected->sum_list->i.version;
> +				*(wpage++) = jeb->sum_collected->sum_list->i.offset;
> +				*(wpage++) = jeb->sum_collected->sum_list->i.totlen;
> +				break;
> +			}
> +			
> +			case JFFS2_NODETYPE_DIRENT : {
> +				jint16_t *temp16ptr = (jint16_t *) wpage;
> +				uint8_t *temp8ptr = NULL;
> +				
> +				*(temp16ptr++) = jeb->sum_collected->sum_list->d.nodetype;
> +				wpage = (jint32_t *) temp16ptr;
> +				
> +				*(wpage++) = jeb->sum_collected->sum_list->d.totlen;
> +				*(wpage++) = jeb->sum_collected->sum_list->d.offset;
> +				*(wpage++) = jeb->sum_collected->sum_list->d.pino;
> +				*(wpage++) = jeb->sum_collected->sum_list->d.version;
> +				*(wpage++) = jeb->sum_collected->sum_list->d.ino;
> +				
> +				temp8ptr = (uint8_t *) wpage;
> +				*(temp8ptr++) = jeb->sum_collected->sum_list->d.nsize;
> +				*(temp8ptr++) = jeb->sum_collected->sum_list->d.type;
> +								
> +				memcpy(temp8ptr,jeb->sum_collected->sum_list->d.name,jeb->sum_collected->sum_list->d.nsize);
> +				temp8ptr += jeb->sum_collected->sum_list->d.nsize;
> +				wpage = (jint32_t *) temp8ptr;
> +				
> +				break;
> +			}
> +			
> +			default : {
> +				printk(KERN_WARNING "Unknown node in summary information!!!\n");
> +				BUG();
> +			}
> +		}
> +		
> +		temp = jeb->sum_collected->sum_list;
> +		jeb->sum_collected->sum_list = jeb->sum_collected->sum_list->u.next;
> +		kfree(temp);
> +		
> +		jeb->sum_collected->sum_num--;
> +	}
> +	
> +	jeb->sum_collected->sum_size = 0;
> +	
> +	tempptr = (uint8_t *) wpage;
> +	tempptr += padsize;
> +	wpage = (jint32_t *) tempptr;
> +	
> +	*(wpage++) = offset;
> +	*(wpage++) = cpu_to_je32(c->sector_size);
> +	*(wpage++) = magic;
> +	isum.sum_crc = cpu_to_je32(crc32(0, c->summary_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_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);
> +
> +		jeb->sum_collected->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
> +				
> +		WASTED_SPACE(infosize);
> +		
> +		return 0;
> +	}	
> +	
> +	/*spin_unlock(&c->erase_completion_lock);
> +	jffs2_flush_wbuf_pad(c); // summary filled the wbuf
> +	spin_lock(&c->erase_completion_lock);*/
> +
> +	WASTED_SPACE(infosize);
> +	
> +	return 0;	
> +}
> diff --unified --new-file --recursive mtd/fs/jffs2/summary.h mtd-dec07/fs/jffs2/summary.h
> --- mtd/fs/jffs2/summary.h	1970-01-01 01:00:00.000000000 +0100
> +++ mtd-dec07/fs/jffs2/summary.h	2004-12-07 16:03:02.000000000 +0100
> @@ -0,0 +1,158 @@
> +/*
> + * 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))
> +
> +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; 
> +};
> +
> +/* list version of jffs2_sum_*flash for kernel and sumtool */
> +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_sum_info
> +{
> +	uint32_t sum_size;
> +	uint32_t sum_num;
> +        uint32_t sum_padded;
> +	union jffs2_sum_mem *sum_list;
> +};
> +
> +struct jffs2_sum_marker
> +{
> +	jint32_t offset;
> +	jint32_t erase_size;
> +	jint32_t magic;
> +};
> +
> +#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_summary_node)+sizeof(struct jffs2_sum_marker)+3)
> +	
> +#if !(defined(SUM_TOOL) || defined(JFFS2DUMP))
> +
> +int jffs2_sum_init(struct jffs2_sb_info *c);
> +void jffs2_sum_exit(struct jffs2_sb_info *c);
> +
> +int jffs2_sum_care_sum_collected(struct jffs2_eraseblock *jeb);
> +
> +void jffs2_sum_clean_collected(struct jffs2_eraseblock *jeb);
> +void jffs2_sum_clean_all_info(struct jffs2_sb_info *c); /* clean up all summary information in all jeb (umount) */
> +
> +int jffs2_sum_add_padding_mem(struct jffs2_eraseblock *jeb, uint32_t size);
> +int jffs2_sum_add_inode_mem(struct jffs2_eraseblock *jeb, struct jffs2_raw_inode *ri, uint32_t ofs);	
> +int jffs2_sum_add_dirent_mem(struct jffs2_eraseblock *jeb, struct jffs2_raw_dirent *rd, uint32_t ofs);	
> +int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count,  uint32_t to);	
> +
> +int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t ofs, uint32_t *pseudo_random);
> +int jffs2_sum_write_sumnode(struct jffs2_sb_info *c);	
> +
> +#endif
> +
> +#endif /* JFFS2_SUMMARY_H */
> diff --unified --new-file --recursive mtd/fs/jffs2/super-v24.c mtd-dec07/fs/jffs2/super-v24.c
> --- mtd/fs/jffs2/super-v24.c	2004-11-17 00:00:14.000000000 +0100
> +++ mtd-dec07/fs/jffs2/super-v24.c	2004-12-07 16:03:02.000000000 +0100
> @@ -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
> @@ -72,6 +73,9 @@
>  		put_mtd_device(c->mtd);
>  		return NULL;
>  	}
> +#ifdef CONFIG_JFFS2_SUMMARY
> +        jffs2_sum_init(c);
> +#endif
>  
>  	return sb;
>  }
> @@ -88,6 +92,10 @@
>  	down(&c->alloc_sem);
>  	jffs2_flush_wbuf_pad(c);
>  	up(&c->alloc_sem);
> +#ifdef CONFIG_JFFS2_SUMMARY
> +        jffs2_sum_clean_all_info(c);
> +        jffs2_sum_exit(c);
> +#endif
>  	jffs2_free_ino_caches(c);
>  	jffs2_free_raw_node_refs(c);
>  	kfree(c->blocks);
> @@ -110,6 +118,9 @@
>  #ifdef CONFIG_JFFS2_FS_NAND
>  	       " (NAND)"
>  #endif
> +#ifdef CONFIG_JFFS2_SUMMARY
> +	       " (SUMMARY)"
> +#endif
>  	       " (C) 2001-2003 Red Hat, Inc.\n");
>  
>  #ifdef JFFS2_OUT_OF_KERNEL
> diff --unified --new-file --recursive mtd/fs/jffs2/super.c mtd-dec07/fs/jffs2/super.c
> --- mtd/fs/jffs2/super.c	2004-11-26 15:08:31.000000000 +0100
> +++ mtd-dec07/fs/jffs2/super.c	2004-12-07 16:03:02.000000000 +0100
> @@ -152,6 +152,10 @@
>  		return ERR_PTR(ret);
>  	}
>  
> +#ifdef CONFIG_JFFS2_SUMMARY
> +        jffs2_sum_init(c);
> +#endif
> +
>  	sb->s_flags |= MS_ACTIVE;
>  	return sb;
>  
> @@ -275,6 +279,10 @@
>  	down(&c->alloc_sem);
>  	jffs2_flush_wbuf_pad(c);
>  	up(&c->alloc_sem);
> +#ifdef CONFIG_JFFS2_SUMMARY
> +        jffs2_sum_clean_all_info(c);
> +        jffs2_sum_exit(c);
> +#endif
>  	jffs2_free_ino_caches(c);
>  	jffs2_free_raw_node_refs(c);
>  	if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
> @@ -312,6 +320,9 @@
>  #ifdef CONFIG_JFFS2_FS_NAND
>  	       " (NAND)"
>  #endif
> +#ifdef CONFIG_JFFS2_SUMMARY
> +               " (SUMMARY) "
> +#endif
>  	       " (C) 2001-2003 Red Hat, Inc.\n");
>  
>  	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
> diff --unified --new-file --recursive mtd/fs/jffs2/wbuf.c mtd-dec07/fs/jffs2/wbuf.c
> --- mtd/fs/jffs2/wbuf.c	2004-11-26 15:08:31.000000000 +0100
> +++ mtd-dec07/fs/jffs2/wbuf.c	2004-12-07 16:17:11.000000000 +0100
> @@ -261,7 +261,7 @@
>  
> 
>  	/* ... 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");
>  		if (buf)
> @@ -601,8 +601,15 @@
>  	uint32_t outvec_to = to;
>  
>  	/* If not NAND flash, don't bother */
> -	if (!c->wbuf)
> + 	if (!c->wbuf){
> +#ifdef CONFIG_JFFS2_SUMMARY
> + 		D1(printk("JFFS2.summary: NOT NAND MEMORY\n"));
> + 		if(jffs2_sum_add_kvec(c,invecs,count,(uint32_t) to)){
> + 			printk("jffs2_sum_add_kvec(): MEMORY ALLOCATION ERROR!");
> + 		}	
> +#endif		
>  		return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
> +	}
>  	
>  	down_write(&c->wbuf_sem);
>  
> @@ -801,6 +808,12 @@
>  alldone:
>  	*retlen = donelen;
>  
> +#ifdef CONFIG_JFFS2_SUMMARY
> +	if(jffs2_sum_add_kvec(c,invecs,count,(uint32_t) to)){
> +		printk("jffs2_sum_add_kvec(): MEMORY ALLOCATION ERROR!");
> +	}
> +#endif
> +	
>  	if (c->wbuf_len && ino)
>  		jffs2_wbuf_dirties_inode(c, ino);
>  
> diff --unified --new-file --recursive mtd/fs/jffs2/write.c mtd-dec07/fs/jffs2/write.c
> --- mtd/fs/jffs2/write.c	2004-11-17 00:00:14.000000000 +0100
> +++ mtd-dec07/fs/jffs2/write.c	2004-12-07 16:03:02.000000000 +0100
> @@ -173,13 +173,13 @@
>  			D1(ACCT_PARANOIA_CHECK(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);
>  			}
>  
> @@ -308,13 +308,13 @@
>  			D1(ACCT_PARANOIA_CHECK(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);
>  			}
>  
> @@ -371,7 +371,7 @@
>  	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;
> @@ -458,7 +458,7 @@
>  	/* 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);
> @@ -487,7 +487,7 @@
>  
>  	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. */
> @@ -557,7 +557,7 @@
>  		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;
> @@ -663,7 +663,7 @@
>  	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 --unified --new-file --recursive mtd/include/linux/jffs2.h mtd-dec07/include/linux/jffs2.h
> --- mtd/include/linux/jffs2.h	2004-11-17 00:00:15.000000000 +0100
> +++ mtd-dec07/include/linux/jffs2.h	2004-12-07 16:03:02.000000000 +0100
> @@ -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.
>  */
> @@ -62,6 +65,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)
> @@ -148,10 +153,24 @@
>  	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;
> +	jint16_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 --unified --new-file --recursive mtd/include/linux/jffs2_fs_sb.h mtd-dec07/include/linux/jffs2_fs_sb.h
> --- mtd/include/linux/jffs2_fs_sb.h	2004-11-26 15:08:31.000000000 +0100
> +++ mtd-dec07/include/linux/jffs2_fs_sb.h	2004-12-07 16:03:02.000000000 +0100
> @@ -110,6 +110,9 @@
>  	uint32_t fsdata_pos;
>  	uint32_t fsdata_len;
>  #endif
> +#ifdef CONFIG_JFFS2_SUMMARY
> +        jint32_t *summary_buf;
> +#endif
>  
>  	/* OS-private pointer for getting back to master superblock info */
>  	void *os_priv;
> diff --unified --new-file --recursive mtd/util/Makefile mtd-dec07/util/Makefile
> --- mtd/util/Makefile	2004-07-14 00:00:18.000000000 +0200
> +++ mtd-dec07/util/Makefile	2004-12-07 16:03:02.000000000 +0100
> @@ -13,7 +13,7 @@
>  TARGETS = ftl_format flash_erase flash_eraseall nanddump doc_loadbios \
>  	mkfs.jffs ftl_check mkfs.jffs2 flash_lock flash_unlock \
>  	flash_info mtd_debug flashcp nandwrite jffs2dump \
> -	nftldump nftl_format docfdisk #jffs2reader
> +	nftldump nftl_format docfdisk sumtool #jffs2reader
>  
>  SYMLINKS = compr_lzari.c compr_lzo.c
>  
> @@ -48,6 +48,10 @@
>  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 --unified --new-file --recursive mtd/util/jffs2dump.c mtd-dec07/util/jffs2dump.c
> --- mtd/util/jffs2dump.c	2004-12-03 00:00:10.000000000 +0100
> +++ mtd-dec07/util/jffs2dump.c	2004-12-07 16:03:02.000000000 +0100
> @@ -35,6 +35,10 @@
>  #include <getopt.h>
>  #include "crc32.h"
>  
> +#define CONFIG_JFFS2_SUMMARY
> +#define JFFS2DUMP
> +#include "../fs/jffs2/summary.h"
> +
>  #define PROGRAM "jffs2dump"
>  #define VERSION "$Revision: 1.7 $"
>  
> @@ -177,7 +181,7 @@
>   */
>  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 +190,21 @@
>  	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));
> @@ -277,7 +286,110 @@
>  
>  			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),
> +					je16_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){
> +				struct jffs2_sum_unknown_flash *sp;
> +				uint8_t *temp8ptr = NULL;
> +				sp = (struct jffs2_sum_unknown_flash *) (p + sizeof (struct jffs2_summary_node));
> +					
> +				for(i = 0; i < je16_to_cpu (node->s.sum_num); i++){
> +					
> +					switch(je16_to_cpu(sp->nodetype)){
> +						case JFFS2_NODETYPE_INODE : {
> +							
> +							struct jffs2_sum_inode_flash *spi;
> +							spi = (struct jffs2_sum_inode_flash *) 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));
> +							
> +							temp8ptr = (uint8_t *) sp;
> +							temp8ptr += JFFS2_SUMMARY_INODE_SIZE;
> +							sp = (struct jffs2_sum_unknown_flash *) temp8ptr;
> +							
> +							break;	
> +						}
> +						
> +						case JFFS2_NODETYPE_DIRENT : {
> +							
> +							char name[255];
> +							struct jffs2_sum_dirent_flash *spd;
> +							spd = (struct jffs2_sum_dirent_flash *) 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);
> +							
> +							temp8ptr = (uint8_t *) sp;
> +							temp8ptr += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); 
> +							sp = (struct jffs2_sum_unknown_flash *) temp8ptr;
> +							
> +							break;
> +						}
> +						
> +						default : {
> +							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, Erase_block_size 0x%08x, Magic 0x%08x, Padded size 0x%08x\n" ,
> +					"",
> +					je32_to_cpu(sm->offset),
> +					je32_to_cpu(sm->erase_size),
> +					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", 
> diff --unified --new-file --recursive mtd/util/sumtool.c mtd-dec07/util/sumtool.c
> --- mtd/util/sumtool.c	1970-01-01 01:00:00.000000000 +0100
> +++ mtd-dec07/util/sumtool.c	2004-12-07 17:47:31.000000000 +0100
> @@ -0,0 +1,857 @@
> +/*
> + *  sumtool.c
> + *
> + *  Copyright (C) 2004 Zoltan Sogor <weth@inf.u-szeged.hu>,
> + *                     Ferenc Havasi <havasi@inf.u-szeged.hu>,
> + *                     Patrik Kluba <pajko@halom.u-szeged.hu>,
> + *                     University of Szeged, Hungary
> + *
> + * $Id: sumtool.c,v 1.2 2004/10/20 09:56:08 hafy Exp $
> + * 
> + * 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 to reorder nodes and insert inode summary information
> + *   into JFFS2 image for faster mount time - specially on NAND.
> + *
> + */
> +
> +#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"
> +
> +#define CONFIG_JFFS2_SUMMARY
> +#define SUM_TOOL
> +#include "../fs/jffs2/summary.h"
> +
> +
> +#define PAD(x) (((x)+3)&~3)
> +
> +static const char *const app_name = "sumtool";
> +
> +static struct jffs2_sum_info *sum_collected = NULL;/* summary info list */
> +
> +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"
> +	"Convert the input JFFS2 file to a SUM-ed JFFS2 file\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 erase block.\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_sum_info *) malloc (sizeof(struct jffs2_sum_info));
> +	
> +	if (!sum_collected)
> +		error_msg_and_die("Can't allocate memory for jffs2_sum_info!\n");
> +	
> +	sum_collected->sum_list = NULL;
> +	sum_collected->sum_num = 0;
> +	sum_collected->sum_size = 0; 
> +
> +}
> +
> +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){
> +			temp = sum_collected->sum_list;
> +			sum_collected->sum_list = sum_collected->sum_list->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;
> +    union jffs2_sum_mem *temp;
> +	jint32_t offset;
> +	jint32_t *wpage;
> +	uint8_t *tempptr;
> +	int datasize;
> +	int infosize;
> +	int padsize;
> +	jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
> +	
> +	if (!sum_collected->sum_num || !sum_collected->sum_list) 
> +		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_je16(sum_collected->sum_num);
> +	wpage = tpage;
> +	
> +		
> +	while (sum_collected->sum_num) {
> +		
> +
> +		switch(je16_to_cpu(sum_collected->sum_list->u.nodetype)){
> +			
> +			case JFFS2_NODETYPE_INODE : {
> +				jint16_t *temp16ptr = (jint16_t *)wpage;
> +				
> +				*(temp16ptr++) = sum_collected->sum_list->i.nodetype;
> +				wpage = (jint32_t *) temp16ptr;
> +				
> +				*(wpage++) = sum_collected->sum_list->i.inode;
> +				*(wpage++) = sum_collected->sum_list->i.version;
> +				*(wpage++) = sum_collected->sum_list->i.offset;
> +				*(wpage++) = sum_collected->sum_list->i.totlen;
> +				break;
> +			}
> +			
> +			case JFFS2_NODETYPE_DIRENT : {
> +				jint16_t *temp16ptr = (jint16_t *) wpage;
> +				uint8_t *temp8ptr = NULL;
> +				
> +				*(temp16ptr++) = sum_collected->sum_list->d.nodetype;
> +				wpage = (jint32_t *) temp16ptr;
> +				
> +				*(wpage++) = sum_collected->sum_list->d.totlen;
> +				*(wpage++) = sum_collected->sum_list->d.offset;
> +				*(wpage++) = sum_collected->sum_list->d.pino;
> +				*(wpage++) = sum_collected->sum_list->d.version;
> +				*(wpage++) = sum_collected->sum_list->d.ino;
> +				
> +				temp8ptr = (uint8_t *) wpage;
> +				*(temp8ptr++) = sum_collected->sum_list->d.nsize;
> +				*(temp8ptr++) = sum_collected->sum_list->d.type;
> +				
> +				memcpy(temp8ptr,sum_collected->sum_list->d.name,sum_collected->sum_list->d.nsize);
> +				temp8ptr += sum_collected->sum_list->d.nsize;
> +				wpage = (jint32_t *) temp8ptr;
> +				
> +				break;
> +			}
> +			
> +			default : {
> +				printf("This is not good for me!!!!\n");
> +			}
> +		}
> +		
> +		temp = sum_collected->sum_list;
> +		sum_collected->sum_list = sum_collected->sum_list->u.next;
> +		free(temp);
> +		
> +		sum_collected->sum_num--;
> +	}
> +	
> +	sum_collected->sum_size = 0;
> +	
> +	tempptr = (uint8_t *) wpage;
> +	tempptr += padsize;
> +	wpage = (jint32_t *) tempptr;
> +	
> +	*(wpage++) = offset;
> +	*(wpage++) = cpu_to_je32(erase_block_size);
> +	*(wpage++) = 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 just write out inode data */
> +			else{
> +				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 just write out inode data */
> +			else{
> +				if(padto)
> +					pad(erase_block_size - data_ofs);
> +				write_buff_to_file();
> +			}
> +		}
> +	}
> +}
> +
> +int add_sum_mem(union jffs2_sum_mem *item) {
> +	
> +	union jffs2_sum_mem *walk;
> +	
> +	if (!sum_collected->sum_list) {
> +		sum_collected->sum_list = (union jffs2_sum_mem *) item;
> +	} 
> +	else {
> +		walk = sum_collected->sum_list;
> +		
> +		while (walk->u.next) {
> +			walk = walk->u.next;
> +		}
> +		walk->u.next = (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));
> +				}
> +				
> +				//write_unknown_to_buff(node);
> +				
> +				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);
> +		
> +		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;
> +}
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-20 16:01   ` Gareth Bult (Encryptec)
@ 2004-12-20 16:09     ` Ferenc Havasi
  2004-12-20 16:39       ` Gareth Bult (Encryptec)
  2004-12-20 17:48       ` Gareth Bult (Encryptec)
  0 siblings, 2 replies; 70+ messages in thread
From: Ferenc Havasi @ 2004-12-20 16:09 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Hi Gareth,

> I'm afraid this patch seems to be quite a long way from applying cleanly
> to my source. I'm using 2.6.9 .. at least half a dozen failures or
> more ...

It works with JFFS2 in the latest MTD CVS.

JFFS3 will contains this feature soon.

Regards,
Ferenc

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-18 16:02                           ` Jörn Engel
@ 2004-12-20 16:34                             ` Josh Boyer
  2004-12-20 17:12                               ` Gareth Bult (Encryptec)
  0 siblings, 1 reply; 70+ messages in thread
From: Josh Boyer @ 2004-12-20 16:34 UTC (permalink / raw)
  To: Jörn Engel; +Cc: Linux MTD, Gareth Bult (Encryptec)

On Sat, 2004-12-18 at 10:02, Jörn Engel wrote:
> On Fri, 17 December 2004 11:35:04 -0600, Josh Boyer wrote:
> > 
> > Again, most controllers do all the wear leveling, erasing for you.  So 
> > you are left with compression, right?
> 
> If you have enough trust in your El Cheapo hardware supplier.  There
> is no standard that requires wear leveling and there are reports that
> basically tell you to do your own wear leveling on some devices.  With
> no good way to distinguish "some" devices from "others", you can read
> that as "all". ;)

Ok, that's why I said "most".  And if your El Cheapo hardware has built
in wear leveling, then doing wear leveling on top of that is always
questionable.  It might not make things worse, but it's probably not
very efficient.

Now if you have El Super Cheapo hardware that explicitly states you need
to do wear leveling, that's a different story ;).

> 
> USB keys and all the various other consumer-type flash devices are
> good enough to beat 3 1/2" floppies, that's about it.  But that's
> quite good enough for most people.  Floppies sold like crazy after
> all.

That's because it was the only removable media for PCs for a long time. 
At least to the non-geeks.  I can remember buying spare hard drives and
carrying those from machine to machine if I needed to do big transfers
;).

josh

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-20 16:09     ` Ferenc Havasi
@ 2004-12-20 16:39       ` Gareth Bult (Encryptec)
  2004-12-20 17:48       ` Gareth Bult (Encryptec)
  1 sibling, 0 replies; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-20 16:39 UTC (permalink / raw)
  To: Ferenc Havasi; +Cc: Linux MTD

[-- Attachment #1: Type: text/plain, Size: 656 bytes --]

Yup,

I've cvs'd the latest source and patched ... kernel seems to build Ok ..
Just trying a full build from clean to make sure, then I'll give it a
go ..

Is there an example of how to use sumtool anywhere ?

If I eraseall the flash then mount JFFS2 and copy files on, do I need to
use sumtool ?

Gareth.

On Mon, 2004-12-20 at 17:09 +0100, Ferenc Havasi wrote:

> Hi Gareth,
> 
> > I'm afraid this patch seems to be quite a long way from applying cleanly
> > to my source. I'm using 2.6.9 .. at least half a dozen failures or
> > more ...
> 
> It works with JFFS2 in the latest MTD CVS.
> 
> JFFS3 will contains this feature soon.
> 
> Regards,
> Ferenc

[-- Attachment #2: Type: text/html, Size: 1194 bytes --]

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-20 16:34                             ` Josh Boyer
@ 2004-12-20 17:12                               ` Gareth Bult (Encryptec)
  2004-12-21 13:09                                 ` Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-20 17:12 UTC (permalink / raw)
  To: Josh Boyer; +Cc: Linux MTD

On Mon, 2004-12-20 at 10:34 -0600, Josh Boyer wrote:
> Ok, that's why I said "most".  And if your El Cheapo hardware has built
> in wear leveling, then doing wear leveling on top of that is always
> questionable.  It might not make things worse, but it's probably not
> very efficient.

Mmm, if the USB flash micro-controllers have build-in wear levelling,
they'd be quite something .. (!) 

> Now if you have El Super Cheapo hardware that explicitly states you need
> to do wear leveling, that's a different story ;).

Here's a quote from a "Kingston" advert;

"Controllers automatically lock out bad memory cells and move the data
to avoid corruption. Controllers also automatically distribute write
cycles across the flash cells to extend the life of the flash memory
card"

What this means exactly in real terms .. [?]
(for example, do you lose some of your key to a bad block table, if so
how much ???)

Here's a bit from "Verbatim";

"For ultra-reliability, Verbatim’s new Store ‘n’ Go Pro drives feature
an on-board 32 bit ARM-7 microprocessor that manages I/O operations and
many of the drive’s technical features. An advanced wear-leveling
algorithm is used to distribute writes evenly among flash storage cells.
By evenly distributing the writing, Store ‘n’ Go Pro achieves an
unprecedented reliability rating of over one million write/erase cycles.
Advanced Error Detection Code/Error Correction Code furthers the Store
‘n’ Go Pro’s immunity to failure."

Interesting articles / links;
http://www.digitalmediadesigner.com/articles/viewarticle.jsp?id=27727
http://www.techworld.com/features/index.cfm?fuseaction=displayfeature&FeatureID=413

In summary: lots of manufacturers seem to be quoting virtual / physical
block mapping on the fly with integrated wear levelling ... (!)

So maybe wear levelling is out of date at filesystem level ?
The techworld link to the M-Systems chips looks interesting ..

Can anyone with detailed flash experience comment ?

Gareth.

> That's because it was the only removable media for PCs for a long time. 
> At least to the non-geeks.  I can remember buying spare hard drives and
> carrying those from machine to machine if I needed to do big transfers
> ;).
> 
> josh
> 

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-20 16:09     ` Ferenc Havasi
  2004-12-20 16:39       ` Gareth Bult (Encryptec)
@ 2004-12-20 17:48       ` Gareth Bult (Encryptec)
  1 sibling, 0 replies; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-20 17:48 UTC (permalink / raw)
  To: Ferenc Havasi; +Cc: Linux MTD

Hi,

Patches applied and it seems to be working ..

After dd'ing a live FS off the key, sumtool'ing it and dd'ing it back
on, it seems to have cut mount time from 31 seconds to 11 seconds ...

This is certainly much better .. any way of making it quicker .. ;-)

Gareth.


On Mon, 2004-12-20 at 17:09 +0100, Ferenc Havasi wrote:
> Hi Gareth,
> 
> > I'm afraid this patch seems to be quite a long way from applying cleanly
> > to my source. I'm using 2.6.9 .. at least half a dozen failures or
> > more ...
> 
> It works with JFFS2 in the latest MTD CVS.
> 
> JFFS3 will contains this feature soon.
> 
> Regards,
> Ferenc

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-20 17:12                               ` Gareth Bult (Encryptec)
@ 2004-12-21 13:09                                 ` Jörn Engel
  2004-12-21 13:24                                   ` Gareth Bult (Encryptec)
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:09 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

On Mon, 20 December 2004 17:12:28 +0000, Gareth Bult (Encryptec) wrote:
> On Mon, 2004-12-20 at 10:34 -0600, Josh Boyer wrote:
> > Ok, that's why I said "most".  And if your El Cheapo hardware has built
> > in wear leveling, then doing wear leveling on top of that is always
> > questionable.  It might not make things worse, but it's probably not
> > very efficient.

Imo jffs2-style wear leveling is very efficient.  So efficient, it
doesn't really matter whether the hardware does the same or not.

Difference between no wear leveling and what jffs2 does is - at most -
1% additional writes on the jffs2 side.  That's not much.  Agreed, it
can actually cost latency, but from a life-time or overall performance
point of view, it doesn't really matter.

On the other hand, it gives you absolute condidence that your El
Cheapo hardware doesn't need to have anything it may or may not
promise to have.  No nasty surprised when you really don't need them.

> > Now if you have El Super Cheapo hardware that explicitly states you need
> > to do wear leveling, that's a different story ;).

Noone will state that.  It's not exactly good marketing.  You might
remember so interesting stories about what marketing promised and what
actually got delivered, no?

> In summary: lots of manufacturers seem to be quoting virtual / physical
> block mapping on the fly with integrated wear levelling ... (!)
> 
> So maybe wear levelling is out of date at filesystem level ?
> The techworld link to the M-Systems chips looks interesting ..
> 
> Can anyone with detailed flash experience comment ?

The endorsed features sound quite nice, agreed.  But I have still to
read a spec that convinces me.

Jörn

-- 
My second remark is that our intellectual powers are rather geared to
master static relations and that our powers to visualize processes
evolving in time are relatively poorly developed.
-- Edsger W. Dijkstra

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-21 13:09                                 ` Jörn Engel
@ 2004-12-21 13:24                                   ` Gareth Bult (Encryptec)
  2004-12-21 13:34                                     ` Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-21 13:24 UTC (permalink / raw)
  To: Jörn Engel; +Cc: Linux MTD

[-- Attachment #1: Type: text/plain, Size: 1335 bytes --]

Hi,

On Tue, 2004-12-21 at 14:09 +0100, Jörn Engel wrote:
> Imo jffs2-style wear leveling is very efficient.  So efficient, it
> doesn't really matter whether the hardware does the same or not.

:) I was of the same opinion but didn't really have any evidence to back
it up .. 

> Difference between no wear leveling and what jffs2 does is - at most -
> 1% additional writes on the jffs2 side.  That's not much.  Agreed, it
> can actually cost latency, but from a life-time or overall performance
> point of view, it doesn't really matter.

Sure.

> On the other hand, it gives you absolute condidence that your El
> Cheapo hardware doesn't need to have anything it may or may not
> promise to have.  No nasty surprised when you really don't need them.

:)

> Noone will state that.  It's not exactly good marketing.  You might
> remember so interesting stories about what marketing promised and what
> actually got delivered, no?

Sure, although I have noticed that some people shout more loudly than
others with regards to the wear levelling technology in their devices ..

> The endorsed features sound quite nice, agreed.  But I have still to
> read a spec that convinces me.

Mmm .. anyone know a magazine editor who'd like to acquire a bunch of
keys and runs some tests for us .. ;-)

Gareth.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-18 20:48                     ` Gareth Bult (Encryptec)
  2004-12-19  2:44                       ` Jörn Engel
@ 2004-12-21 13:30                       ` Jörn Engel
  2004-12-21 13:39                         ` [PATCH 1/22] Add drivers/mtd/devices/blockmtd.c Jörn Engel
  2004-12-21 13:40                         ` JFFS2 mount time Gareth Bult (Encryptec)
  1 sibling, 2 replies; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:30 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

On Sat, 18 December 2004 20:48:50 +0000, Gareth Bult (Encryptec) wrote:
> 
> To be honest what's there will do me for now .. although I'd like to
> clean it up a little when I get time.

Guess you've never been patch-bombed before.  I took the liberty to do
some untested cleanups in ~20 patches.  Most likely the end result
will not work anymore, but the direction is where I'd like to go.

If you find the time, could you test the patches and see which work
and which don't?  The former will go into cvs then and I'll try to fix
the latter.

Jörn

-- 
It does not matter how slowly you go, so long as you do not stop.
-- Confucius

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-21 13:24                                   ` Gareth Bult (Encryptec)
@ 2004-12-21 13:34                                     ` Jörn Engel
  0 siblings, 0 replies; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:34 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

On Tue, 21 December 2004 13:24:35 +0000, Gareth Bult (Encryptec) wrote:
> 
> Mmm .. anyone know a magazine editor who'd like to acquire a bunch of
> keys and runs some tests for us .. ;-)

Somewhere in my lkml-mailbox was a report of some device not doing
decent wear leveling.  It should be in the archives somewhere.  Ext3
killed the devices rather quickly, jffs2 didn't.

Jörn

-- 
Data dominates. If you've chosen the right data structures and organized
things well, the algorithms will almost always be self-evident. Data
structures, not algorithms, are central to programming.
-- Rob Pike

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 1/22] Add drivers/mtd/devices/blockmtd.c
  2004-12-21 13:30                       ` Jörn Engel
@ 2004-12-21 13:39                         ` Jörn Engel
  2004-12-21 13:41                           ` [PATCH 2/22] Add copyrights Jörn Engel
  2004-12-21 13:42                           ` [PATCH 1/22] Add drivers/mtd/devices/blockmtd.c Gareth Bult (Encryptec)
  2004-12-21 13:40                         ` JFFS2 mount time Gareth Bult (Encryptec)
  1 sibling, 2 replies; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:39 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Jörn

-- 
When you close your hand, you own nothing. When you open it up, you
own the whole world.
-- Li Mu Bai in Tiger & Dragon

Add your driver under a new name.  There will be interface changes, so
it needs to be renamed anyway.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |  647 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 647 insertions(+)

--- /dev/null	2004-08-21 20:14:47.000000000 +0200
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 18:56:51.000000000 +0100
@@ -0,0 +1,647 @@
+/*
+ * $Id: blkmtd.c,v 1.23 2004/08/09 14:03:19 dwmw2 Exp $
+ *
+ * blkmtd.c - use a block device as a fake MTD
+ *
+ * Author: Simon Evans <spse@secret.org.uk>
+ *
+ * Copyright (C) 2001,2002 Simon Evans
+ *
+ * Licence: GPL
+ *
+ * How it works:
+ *	The driver uses raw/io to read/write the device and the page
+ *	cache to cache access. Writes update the page cache with the
+ *	new data and mark it dirty and add the page into a BIO which
+ *	is then written out.
+ *
+ *	It can be loaded Read-Only to prevent erases and writes to the
+ *	medium.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/pagemap.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/buffer_head.h>
+
+#define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "blkmtd: " format "\n" , ## arg)
+#define crit(format, arg...) printk(KERN_CRIT "blkmtd: " format "\n" , ## arg)
+
+
+/* Default erase size in K, always make it a multiple of PAGE_SIZE */
+#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10)	/* 128KiB */
+#define VERSION "$Revision: 1.23 $"
+
+/* Info for the block device */
+struct blkmtd_dev {
+	struct list_head list;
+	struct block_device *blkdev;
+	struct mtd_info mtd_info;
+	struct semaphore wrbuf_mutex;
+};
+
+
+/* Static info about the MTD, used in cleanup_module */
+static LIST_HEAD(blkmtd_device_list);
+
+static void blkmtd_sync(struct mtd_info *mtd);
+
+#define MAX_DEVICES 4
+
+/* Module parameters passed by insmod/modprobe */
+char *device[MAX_DEVICES];    /* the block device to use */
+int erasesz[MAX_DEVICES];     /* optional default erase size */
+int ro[MAX_DEVICES];          /* optional read only flag */
+int sync;
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
+MODULE_DESCRIPTION("Emulate an MTD using a block device");
+MODULE_PARM(device, "1-4s");
+MODULE_PARM_DESC(device, "block device to use");
+MODULE_PARM(erasesz, "1-4i");
+MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB.");
+MODULE_PARM(ro, "1-4i");
+MODULE_PARM_DESC(ro, "1=Read only, writes and erases cause errors");
+MODULE_PARM(sync, "i");
+MODULE_PARM_DESC(sync, "1=Synchronous writes");
+
+#define PAGE_READAHEAD 64
+
+void cache_readahead(struct address_space *mapping, int index)
+{
+	filler_t *filler = (filler_t*)(mapping->a_ops->readpage);
+	int i,pagei;
+	unsigned ret = 0;
+	unsigned long end_index;
+	struct page *page;
+	LIST_HEAD(page_pool);
+	struct inode *inode = mapping->host;
+	loff_t isize = i_size_read(inode);
+
+	if(!isize) {
+		printk(KERN_INFO "iSize=0 in cache_readahead\n");
+		return;
+	}
+
+	end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
+
+	spin_lock_irq(&mapping->tree_lock);
+	for(i=0;i<PAGE_READAHEAD;i++) {
+		pagei=index+i;
+		if (pagei > end_index) {
+			printk(KERN_INFO "Overrun end of disk in cache readahead\n");
+			break;
+		}
+		page = radix_tree_lookup(&mapping->page_tree, pagei);
+		if(page && (!i)) break;
+		if(page) continue;
+		spin_unlock_irq(&mapping->tree_lock);
+		page = page_cache_alloc_cold(mapping);
+		spin_lock_irq(&mapping->tree_lock);
+		if(!page) break;
+		page->index=pagei;
+		list_add(&page->lru, &page_pool);
+		ret++;
+	}
+	spin_unlock_irq(&mapping->tree_lock);
+	if(ret) {
+		read_cache_pages(mapping, &page_pool, filler, NULL);
+		//printk(KERN_INFO "Readahead [%d/%d] pages from [%d]\n",ret,PAGE_READAHEAD,index);
+	}
+}
+
+static struct page* page_readahead(struct address_space *mapping, int index)
+{
+	filler_t *filler = (filler_t*)(mapping->a_ops->readpage);
+	cache_readahead(mapping,index);
+	return read_cache_page(mapping, index, filler, NULL);
+}
+/**
+ * write_pages - write block of data to device via the page cache
+ * @dev: device to write to
+ * @buf: data source or NULL if erase (output is set to 0xff)
+ * @to: offset into output device
+ * @len: amount to data to write
+ * @retlen: amount of data written
+ *
+ * Grab pages from the page cache and fill them with the source data.
+ * Non page aligned start and end result in a readin of the page and
+ * part of the page being modified. Pages are added to the bio and then written
+ * out.
+ */
+
+static int write_pages(struct blkmtd_dev *dev, const u_char *buf, loff_t to, size_t len, size_t *retlen)
+{
+	struct	page *page;
+	struct	address_space *mapping = dev->blkdev->bd_inode->i_mapping;
+	//
+	int	err	= 0;			// return status
+	int	index	= to >> PAGE_SHIFT;	// page index
+	int	offset 	= to & ~PAGE_MASK;	// page offset
+	//
+
+	static int my_read()
+	{
+		err=0;
+		page = page_readahead(mapping,index);
+		if( unlikely(!page) ) {
+			crit("unable to read page (%d) in write_pages\n",index);
+			err=-ENOMEM;
+		}
+		//if(IS_ERR(page)) err=-EIO;
+		if(err) printk("READ ERROR\n");
+		return err;
+	}
+	//
+	static int my_erase()
+	{
+		int pages = len >> PAGE_SHIFT;
+		unsigned char *p;
+		unsigned char *max;
+		int format;
+
+		while(pages) {
+			//printk(KERN_INFO "readahead on index (%d)\n",index);
+			if(my_read()) return err;
+
+			max = ((char*)page_address(page)+PAGE_SIZE);
+			format = 0;
+
+			for(p=(unsigned char*)page_address(page); p<max; p++) 
+				if(*p != 0xff) {
+					format=1;
+					break;
+				}
+
+			if(format) {
+				//DEBUG(3, "write_pages: erasing\n");
+				lock_page(page);
+				memset(page_address(page), 0xff, PAGE_SIZE);
+				set_page_dirty(page);
+				unlock_page(page);
+			}
+			page_cache_release(page);
+			pages--;
+			index++;
+		}
+		*retlen = len;
+		return 0;
+	}
+
+	static int my_write()
+	{
+		int cpylen;
+
+		if(retlen) *retlen = 0;
+		//printk(KERN_INFO "Write req: %d\n",len);
+		while(len) {
+			if((offset+len) > PAGE_SIZE) 
+				cpylen = PAGE_SIZE - offset;	// multiple pages
+			else	cpylen = len;			// this page
+			len = len - cpylen;
+			//
+			//	Get page
+			//
+			if(my_read()) return err;
+			//
+			if(memcmp(page_address(page)+offset,buf,cpylen)) {
+				lock_page(page);
+				memcpy(page_address(page) + offset,buf, cpylen);
+				set_page_dirty(page);
+				unlock_page(page);
+			}
+			page_cache_release(page);
+
+			if(retlen) *retlen += cpylen;
+			//
+			buf+=cpylen;
+			offset = 0;
+			index++;
+			//
+		}
+		//printk(KERN_INFO "Write act: %d\n",*retlen);
+		return 0;
+	}
+
+	err=0;
+	down(&dev->wrbuf_mutex);
+	err = buf ? my_write() : my_erase();
+	up(&dev->wrbuf_mutex);
+	return err;
+}
+
+/* erase a specified part of the device */
+static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct blkmtd_dev *dev = mtd->priv;
+	struct mtd_erase_region_info *einfo = mtd->eraseregions;
+	int numregions = mtd->numeraseregions;
+	size_t from;
+	u_long len;
+	int err = -EIO;
+	size_t retlen;
+
+	instr->state = MTD_ERASING;
+	from = instr->addr;
+	len = instr->len;
+
+	/* check erase region has valid start and length */
+	//DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%zx len = 0x%lx\n", mtd->name+9, from, len);
+	while(numregions) {
+		DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
+		      einfo->offset, einfo->erasesize, einfo->numblocks);
+		if(from >= einfo->offset
+		   && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
+			if(len == einfo->erasesize
+			   && ( (from - einfo->offset) % einfo->erasesize == 0))
+				break;
+		}
+		numregions--;
+		einfo++;
+	}
+
+	if(!numregions) {
+		/* Not a valid erase block */
+		err("erase: invalid erase request 0x%lX @ 0x%08zX", len, from);
+		instr->state = MTD_ERASE_FAILED;
+		err = -EIO;
+	}
+
+	if(instr->state != MTD_ERASE_FAILED) {
+		/* do the erase */
+		DEBUG(3, "Doing erase from = %zd len = %ld\n", from, len);
+		err = write_pages(dev, NULL, from, len, &retlen);
+		if(err || retlen != len) {
+			err("erase failed err = %d", err);
+			instr->state = MTD_ERASE_FAILED;
+		} else {
+			instr->state = MTD_ERASE_DONE;
+		}
+	}
+
+	DEBUG(3, "blkmtd: erase: checking callback\n");
+	mtd_erase_callback(instr);
+	DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
+	return err;
+}
+
+static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct blkmtd_dev *dev = mtd->priv;
+	struct page *page;
+	//
+	int index	= from >> PAGE_SHIFT;
+	int offset	= from - (index << PAGE_SHIFT);
+	int cpylen;
+
+	if(from > mtd->size) return -EINVAL;
+	if(from + len > mtd->size) len = mtd->size - from;
+
+	if(retlen) *retlen = 0;
+
+	while(len) {
+		if((offset+len) > PAGE_SIZE) 
+			cpylen = PAGE_SIZE - offset;	// multiple pages
+		else	cpylen = len;			// this page
+		len = len - cpylen;
+		//
+		//	Get page
+		//
+		page = page_readahead(dev->blkdev->bd_inode->i_mapping,index);
+		if(!page) return -ENOMEM;
+		if(IS_ERR(page)) return -EIO;
+		//
+		memcpy(buf, page_address(page) + offset, cpylen);
+		page_cache_release(page);
+		//
+		if(retlen) *retlen += cpylen;
+		buf+=cpylen;
+		offset = 0;
+		index++;
+		//
+	}
+	return 0;
+}
+
+
+/* write data to the underlying device */
+static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf)
+{
+	struct blkmtd_dev *dev = mtd->priv;
+	int err;
+
+	if(!len) return 0;
+	if(to >= mtd->size) return -ENOSPC;
+	if(to + len > mtd->size) len = mtd->size - to;
+
+	err = write_pages(dev, buf, to, len, retlen);
+	if(err > 0) err = 0;
+	return err;
+}
+
+
+/* sync the device - wait until the write queue is empty */
+static void blkmtd_sync(struct mtd_info *mtd)
+{
+	sync_blockdev(((struct blkmtd_dev*)mtd->priv)->blkdev);
+	return;
+}
+
+static void free_device(struct blkmtd_dev *dev)
+{
+	DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);
+	if(dev) {
+		if(dev->mtd_info.eraseregions)
+			kfree(dev->mtd_info.eraseregions);
+		if(dev->mtd_info.name)
+			kfree(dev->mtd_info.name);
+
+		if(dev->blkdev) {
+			invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);
+			close_bdev_excl(dev->blkdev);
+		}
+		kfree(dev);
+	}
+}
+
+
+/* For a given size and initial erase size, calculate the number
+ * and size of each erase region. Goes round the loop twice,
+ * once to find out how many regions, then allocates space,
+ * then round the loop again to fill it in.
+ */
+static struct mtd_erase_region_info *calc_erase_regions(
+	size_t erase_size, size_t total_size, int *regions)
+{
+	struct mtd_erase_region_info *info = NULL;
+
+	DEBUG(2, "calc_erase_regions, es = %zd size = %zd regions = %d\n",
+	      erase_size, total_size, *regions);
+	/* Make any user specified erasesize be a power of 2
+	   and at least PAGE_SIZE */
+	if(erase_size) {
+		int es = erase_size;
+		erase_size = 1;
+		while(es != 1) {
+			es >>= 1;
+			erase_size <<= 1;
+		}
+		if(erase_size < PAGE_SIZE)
+			erase_size = PAGE_SIZE;
+	} else {
+		erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
+	}
+
+	*regions = 0;
+
+	do {
+		int tot_size = total_size;
+		int er_size = erase_size;
+		int count = 0, offset = 0, regcnt = 0;
+
+		while(tot_size) {
+			count = tot_size / er_size;
+			if(count) {
+				tot_size = tot_size % er_size;
+				if(info) {
+					DEBUG(2, "adding to erase info off=%d er=%d cnt=%d\n",
+					      offset, er_size, count);
+					(info+regcnt)->offset = offset;
+					(info+regcnt)->erasesize = er_size;
+					(info+regcnt)->numblocks = count;
+					(*regions)++;
+				}
+				regcnt++;
+				offset += (count * er_size);
+			}
+			while(er_size > tot_size)
+				er_size >>= 1;
+		}
+		if(info == NULL) {
+			info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
+			if(!info)
+				break;
+		}
+	} while(!(*regions));
+	DEBUG(2, "calc_erase_regions done, es = %zd size = %zd regions = %d\n",
+	      erase_size, total_size, *regions);
+	return info;
+}
+
+
+extern dev_t __init name_to_dev_t(const char *line);
+
+static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size)
+{
+	struct block_device *bdev;
+	int mode;
+	struct blkmtd_dev *dev;
+
+	if(!devname)
+		return NULL;
+
+	/* Get a handle on the device */
+
+
+#ifdef MODULE
+	mode = (readonly) ? O_RDONLY : O_RDWR;
+	bdev = open_bdev_excl(devname, mode, NULL);
+#else
+	mode = (readonly) ? FMODE_READ : FMODE_WRITE;
+	bdev = open_by_devnum(name_to_dev_t(devname), mode);
+#endif
+	if(IS_ERR(bdev)) {
+		err("error: cannot open device %s", devname);
+		DEBUG(2, "blkmtd: opening bdev returned %ld\n", PTR_ERR(bdev));
+		return NULL;
+	}
+
+	DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",
+	      MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
+
+	if(MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
+		err("attempting to use an MTD device as a block device");
+		blkdev_put(bdev);
+		return NULL;
+	}
+
+	dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
+	if(dev == NULL) {
+		blkdev_put(bdev);
+		return NULL;
+	}
+
+	memset(dev, 0, sizeof(struct blkmtd_dev));
+	dev->blkdev = bdev;
+	atomic_set(&(dev->blkdev->bd_inode->i_mapping->truncate_count), 0);
+	if(!readonly) {
+		init_MUTEX(&dev->wrbuf_mutex);
+	}
+
+	dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
+
+	/* Setup the MTD structure */
+	/* make the name contain the block device in */
+	dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL);
+	if(dev->mtd_info.name == NULL)
+		goto devinit_err;
+
+	sprintf(dev->mtd_info.name, "blkmtd: %s", devname);
+	dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size,
+							&dev->mtd_info.numeraseregions);
+	if(dev->mtd_info.eraseregions == NULL)
+		goto devinit_err;
+
+	dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize;
+	DEBUG(1, "blkmtd: init: found %d erase regions\n",
+	      dev->mtd_info.numeraseregions);
+
+	if(readonly) {
+		dev->mtd_info.type = MTD_ROM;
+		dev->mtd_info.flags = MTD_CAP_ROM;
+	} else {
+		dev->mtd_info.type = MTD_RAM;
+		dev->mtd_info.flags = MTD_CAP_RAM;
+		dev->mtd_info.erase = blkmtd_erase;
+		dev->mtd_info.write = blkmtd_write;
+		dev->mtd_info.writev = default_mtd_writev;
+		dev->mtd_info.sync = blkmtd_sync;
+	}
+	dev->mtd_info.read = blkmtd_read;
+	dev->mtd_info.readv = default_mtd_readv;
+	dev->mtd_info.priv = dev;
+	dev->mtd_info.owner = THIS_MODULE;
+
+	list_add(&dev->list, &blkmtd_device_list);
+	if (add_mtd_device(&dev->mtd_info)) {
+		/* Device didnt get added, so free the entry */
+		list_del(&dev->list);
+		goto devinit_err;
+	} else {
+		info("mtd%d: [%s] erase_size = %dKiB %s [%ld]",
+		     dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),
+		     dev->mtd_info.erasesize >> 10,
+		     readonly ? "(read-only)" : "", PAGE_SIZE);
+	}
+	return dev;
+
+ devinit_err:
+	free_device(dev);
+	return NULL;
+}
+
+
+/* Cleanup and exit - sync the device and kill of the kernel thread */
+static void __devexit cleanup_blkmtd(void)
+{
+	struct list_head *temp1, *temp2;
+
+	/* Remove the MTD devices */
+	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
+		struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
+						    list);
+		blkmtd_sync(&dev->mtd_info);
+		del_mtd_device(&dev->mtd_info);
+		info("mtd%d: [%s] removed", dev->mtd_info.index,
+		     dev->mtd_info.name + strlen("blkmtd: "));
+		list_del(&dev->list);
+		free_device(dev);
+	}
+}
+
+#ifndef MODULE
+
+/* Handle kernel boot params */
+
+
+static int __init param_blkmtd_device(char *str)
+{
+	int i;
+
+	for(i = 0; i < MAX_DEVICES; i++) {
+		device[i] = str;
+		DEBUG(2, "blkmtd: device setup: %d = %s\n", i, device[i]);
+		strsep(&str, ",");
+	}
+	return 1;
+}
+
+
+static int __init param_blkmtd_erasesz(char *str)
+{
+	int i;
+	for(i = 0; i < MAX_DEVICES; i++) {
+		char *val = strsep(&str, ",");
+		if(val)
+			erasesz[i] = simple_strtoul(val, NULL, 0);
+		DEBUG(2, "blkmtd: erasesz setup: %d = %d\n", i, erasesz[i]);
+	}
+
+	return 1;
+}
+
+
+static int __init param_blkmtd_ro(char *str)
+{
+	int i;
+	for(i = 0; i < MAX_DEVICES; i++) {
+		char *val = strsep(&str, ",");
+		if(val)
+			ro[i] = simple_strtoul(val, NULL, 0);
+		DEBUG(2, "blkmtd: ro setup: %d = %d\n", i, ro[i]);
+	}
+
+	return 1;
+}
+
+
+static int __init param_blkmtd_sync(char *str)
+{
+	if(str[0] == '1')
+		sync = 1;
+	return 1;
+}
+
+__setup("blkmtd_device=", param_blkmtd_device);
+__setup("blkmtd_erasesz=", param_blkmtd_erasesz);
+__setup("blkmtd_ro=", param_blkmtd_ro);
+__setup("blkmtd_sync=", param_blkmtd_sync);
+
+#endif
+
+
+/* Startup */
+static int __init init_blkmtd(void)
+{
+	int i;
+
+	info("version " VERSION);
+	/* Check args - device[0] is the bare minimum*/
+	if(!device[0]) {
+		err("error: missing `device' name\n");
+		return -EINVAL;
+	}
+
+	for(i = 0; i < MAX_DEVICES; i++)
+		add_device(device[i], ro[i], erasesz[i] << 10);
+
+	if(list_empty(&blkmtd_device_list))
+		return -EINVAL;
+
+	return 0;
+}
+
+module_init(init_blkmtd);
+module_exit(cleanup_blkmtd);

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-21 13:30                       ` Jörn Engel
  2004-12-21 13:39                         ` [PATCH 1/22] Add drivers/mtd/devices/blockmtd.c Jörn Engel
@ 2004-12-21 13:40                         ` Gareth Bult (Encryptec)
  2004-12-21 15:00                           ` David Woodhouse
  1 sibling, 1 reply; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-21 13:40 UTC (permalink / raw)
  To: Jörn Engel; +Cc: Linux MTD

[-- Attachment #1: Type: text/plain, Size: 686 bytes --]

.. and I find the patches where ?

On Tue, 2004-12-21 at 14:30 +0100, Jörn Engel wrote:
> On Sat, 18 December 2004 20:48:50 +0000, Gareth Bult (Encryptec) wrote:
> > 
> > To be honest what's there will do me for now .. although I'd like to
> > clean it up a little when I get time.
> 
> Guess you've never been patch-bombed before.  I took the liberty to do
> some untested cleanups in ~20 patches.  Most likely the end result
> will not work anymore, but the direction is where I'd like to go.
> 
> If you find the time, could you test the patches and see which work
> and which don't?  The former will go into cvs then and I'll try to fix
> the latter.
> 
> Jörn
> 

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 2/22] Add copyrights
  2004-12-21 13:39                         ` [PATCH 1/22] Add drivers/mtd/devices/blockmtd.c Jörn Engel
@ 2004-12-21 13:41                           ` Jörn Engel
  2004-12-21 13:42                             ` [PATCH 3/22] Remove read-only option Jörn Engel
  2004-12-21 13:42                           ` [PATCH 1/22] Add drivers/mtd/devices/blockmtd.c Gareth Bult (Encryptec)
  1 sibling, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:41 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Add both our copyrights.  Didn't have my mail archive at hands when
doing the patches.  Shouldn't be hard to fix.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_copyright	2004-12-20 18:33:22.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 18:34:22.000000000 +0100
@@ -1,11 +1,13 @@
 /*
  * $Id: blkmtd.c,v 1.23 2004/08/09 14:03:19 dwmw2 Exp $
  *
- * blkmtd.c - use a block device as a fake MTD
+ * blockmtd.c - use a block device as a fake MTD
  *
  * Author: Simon Evans <spse@secret.org.uk>
  *
- * Copyright (C) 2001,2002 Simon Evans
+ * Copyright (C) 2001,2002	Simon Evans
+ * Copyright (C) 2004		
+ * Copyright (C) 2004		Jörn Engel <joern@wh.fh-wedel.de>
  *
  * Licence: GPL
  *

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH 1/22] Add drivers/mtd/devices/blockmtd.c
  2004-12-21 13:39                         ` [PATCH 1/22] Add drivers/mtd/devices/blockmtd.c Jörn Engel
  2004-12-21 13:41                           ` [PATCH 2/22] Add copyrights Jörn Engel
@ 2004-12-21 13:42                           ` Gareth Bult (Encryptec)
  2004-12-21 14:15                             ` Jörn Engel
  1 sibling, 1 reply; 70+ messages in thread
From: Gareth Bult (Encryptec) @ 2004-12-21 13:42 UTC (permalink / raw)
  To: Jörn Engel; +Cc: Linux MTD

[-- Attachment #1: Type: text/plain, Size: 19514 bytes --]

Ok,

Gimmie a clue - what did you change ?

Gareth.

On Tue, 2004-12-21 at 14:39 +0100, Jörn Engel wrote:
> Jörn
> 
> -- 
> When you close your hand, you own nothing. When you open it up, you
> own the whole world.
> -- Li Mu Bai in Tiger & Dragon
> 
> Add your driver under a new name.  There will be interface changes, so
> it needs to be renamed anyway.
> 
> Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
> ---
> 
>  blockmtd.c |  647 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 647 insertions(+)
> 
> --- /dev/null	2004-08-21 20:14:47.000000000 +0200
> +++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 18:56:51.000000000 +0100
> @@ -0,0 +1,647 @@
> +/*
> + * $Id: blkmtd.c,v 1.23 2004/08/09 14:03:19 dwmw2 Exp $
> + *
> + * blkmtd.c - use a block device as a fake MTD
> + *
> + * Author: Simon Evans <spse@secret.org.uk>
> + *
> + * Copyright (C) 2001,2002 Simon Evans
> + *
> + * Licence: GPL
> + *
> + * How it works:
> + *	The driver uses raw/io to read/write the device and the page
> + *	cache to cache access. Writes update the page cache with the
> + *	new data and mark it dirty and add the page into a BIO which
> + *	is then written out.
> + *
> + *	It can be loaded Read-Only to prevent erases and writes to the
> + *	medium.
> + *
> + */
> +
> +#include <linux/config.h>
> +#include <linux/module.h>
> +#include <linux/fs.h>
> +#include <linux/blkdev.h>
> +#include <linux/bio.h>
> +#include <linux/pagemap.h>
> +#include <linux/list.h>
> +#include <linux/init.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/buffer_head.h>
> +
> +#define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
> +#define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
> +#define warn(format, arg...) printk(KERN_WARNING "blkmtd: " format "\n" , ## arg)
> +#define crit(format, arg...) printk(KERN_CRIT "blkmtd: " format "\n" , ## arg)
> +
> +
> +/* Default erase size in K, always make it a multiple of PAGE_SIZE */
> +#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10)	/* 128KiB */
> +#define VERSION "$Revision: 1.23 $"
> +
> +/* Info for the block device */
> +struct blkmtd_dev {
> +	struct list_head list;
> +	struct block_device *blkdev;
> +	struct mtd_info mtd_info;
> +	struct semaphore wrbuf_mutex;
> +};
> +
> +
> +/* Static info about the MTD, used in cleanup_module */
> +static LIST_HEAD(blkmtd_device_list);
> +
> +static void blkmtd_sync(struct mtd_info *mtd);
> +
> +#define MAX_DEVICES 4
> +
> +/* Module parameters passed by insmod/modprobe */
> +char *device[MAX_DEVICES];    /* the block device to use */
> +int erasesz[MAX_DEVICES];     /* optional default erase size */
> +int ro[MAX_DEVICES];          /* optional read only flag */
> +int sync;
> +
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
> +MODULE_DESCRIPTION("Emulate an MTD using a block device");
> +MODULE_PARM(device, "1-4s");
> +MODULE_PARM_DESC(device, "block device to use");
> +MODULE_PARM(erasesz, "1-4i");
> +MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB.");
> +MODULE_PARM(ro, "1-4i");
> +MODULE_PARM_DESC(ro, "1=Read only, writes and erases cause errors");
> +MODULE_PARM(sync, "i");
> +MODULE_PARM_DESC(sync, "1=Synchronous writes");
> +
> +#define PAGE_READAHEAD 64
> +
> +void cache_readahead(struct address_space *mapping, int index)
> +{
> +	filler_t *filler = (filler_t*)(mapping->a_ops->readpage);
> +	int i,pagei;
> +	unsigned ret = 0;
> +	unsigned long end_index;
> +	struct page *page;
> +	LIST_HEAD(page_pool);
> +	struct inode *inode = mapping->host;
> +	loff_t isize = i_size_read(inode);
> +
> +	if(!isize) {
> +		printk(KERN_INFO "iSize=0 in cache_readahead\n");
> +		return;
> +	}
> +
> +	end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
> +
> +	spin_lock_irq(&mapping->tree_lock);
> +	for(i=0;i<PAGE_READAHEAD;i++) {
> +		pagei=index+i;
> +		if (pagei > end_index) {
> +			printk(KERN_INFO "Overrun end of disk in cache readahead\n");
> +			break;
> +		}
> +		page = radix_tree_lookup(&mapping->page_tree, pagei);
> +		if(page && (!i)) break;
> +		if(page) continue;
> +		spin_unlock_irq(&mapping->tree_lock);
> +		page = page_cache_alloc_cold(mapping);
> +		spin_lock_irq(&mapping->tree_lock);
> +		if(!page) break;
> +		page->index=pagei;
> +		list_add(&page->lru, &page_pool);
> +		ret++;
> +	}
> +	spin_unlock_irq(&mapping->tree_lock);
> +	if(ret) {
> +		read_cache_pages(mapping, &page_pool, filler, NULL);
> +		//printk(KERN_INFO "Readahead [%d/%d] pages from [%d]\n",ret,PAGE_READAHEAD,index);
> +	}
> +}
> +
> +static struct page* page_readahead(struct address_space *mapping, int index)
> +{
> +	filler_t *filler = (filler_t*)(mapping->a_ops->readpage);
> +	cache_readahead(mapping,index);
> +	return read_cache_page(mapping, index, filler, NULL);
> +}
> +/**
> + * write_pages - write block of data to device via the page cache
> + * @dev: device to write to
> + * @buf: data source or NULL if erase (output is set to 0xff)
> + * @to: offset into output device
> + * @len: amount to data to write
> + * @retlen: amount of data written
> + *
> + * Grab pages from the page cache and fill them with the source data.
> + * Non page aligned start and end result in a readin of the page and
> + * part of the page being modified. Pages are added to the bio and then written
> + * out.
> + */
> +
> +static int write_pages(struct blkmtd_dev *dev, const u_char *buf, loff_t to, size_t len, size_t *retlen)
> +{
> +	struct	page *page;
> +	struct	address_space *mapping = dev->blkdev->bd_inode->i_mapping;
> +	//
> +	int	err	= 0;			// return status
> +	int	index	= to >> PAGE_SHIFT;	// page index
> +	int	offset 	= to & ~PAGE_MASK;	// page offset
> +	//
> +
> +	static int my_read()
> +	{
> +		err=0;
> +		page = page_readahead(mapping,index);
> +		if( unlikely(!page) ) {
> +			crit("unable to read page (%d) in write_pages\n",index);
> +			err=-ENOMEM;
> +		}
> +		//if(IS_ERR(page)) err=-EIO;
> +		if(err) printk("READ ERROR\n");
> +		return err;
> +	}
> +	//
> +	static int my_erase()
> +	{
> +		int pages = len >> PAGE_SHIFT;
> +		unsigned char *p;
> +		unsigned char *max;
> +		int format;
> +
> +		while(pages) {
> +			//printk(KERN_INFO "readahead on index (%d)\n",index);
> +			if(my_read()) return err;
> +
> +			max = ((char*)page_address(page)+PAGE_SIZE);
> +			format = 0;
> +
> +			for(p=(unsigned char*)page_address(page); p<max; p++) 
> +				if(*p != 0xff) {
> +					format=1;
> +					break;
> +				}
> +
> +			if(format) {
> +				//DEBUG(3, "write_pages: erasing\n");
> +				lock_page(page);
> +				memset(page_address(page), 0xff, PAGE_SIZE);
> +				set_page_dirty(page);
> +				unlock_page(page);
> +			}
> +			page_cache_release(page);
> +			pages--;
> +			index++;
> +		}
> +		*retlen = len;
> +		return 0;
> +	}
> +
> +	static int my_write()
> +	{
> +		int cpylen;
> +
> +		if(retlen) *retlen = 0;
> +		//printk(KERN_INFO "Write req: %d\n",len);
> +		while(len) {
> +			if((offset+len) > PAGE_SIZE) 
> +				cpylen = PAGE_SIZE - offset;	// multiple pages
> +			else	cpylen = len;			// this page
> +			len = len - cpylen;
> +			//
> +			//	Get page
> +			//
> +			if(my_read()) return err;
> +			//
> +			if(memcmp(page_address(page)+offset,buf,cpylen)) {
> +				lock_page(page);
> +				memcpy(page_address(page) + offset,buf, cpylen);
> +				set_page_dirty(page);
> +				unlock_page(page);
> +			}
> +			page_cache_release(page);
> +
> +			if(retlen) *retlen += cpylen;
> +			//
> +			buf+=cpylen;
> +			offset = 0;
> +			index++;
> +			//
> +		}
> +		//printk(KERN_INFO "Write act: %d\n",*retlen);
> +		return 0;
> +	}
> +
> +	err=0;
> +	down(&dev->wrbuf_mutex);
> +	err = buf ? my_write() : my_erase();
> +	up(&dev->wrbuf_mutex);
> +	return err;
> +}
> +
> +/* erase a specified part of the device */
> +static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
> +{
> +	struct blkmtd_dev *dev = mtd->priv;
> +	struct mtd_erase_region_info *einfo = mtd->eraseregions;
> +	int numregions = mtd->numeraseregions;
> +	size_t from;
> +	u_long len;
> +	int err = -EIO;
> +	size_t retlen;
> +
> +	instr->state = MTD_ERASING;
> +	from = instr->addr;
> +	len = instr->len;
> +
> +	/* check erase region has valid start and length */
> +	//DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%zx len = 0x%lx\n", mtd->name+9, from, len);
> +	while(numregions) {
> +		DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
> +		      einfo->offset, einfo->erasesize, einfo->numblocks);
> +		if(from >= einfo->offset
> +		   && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
> +			if(len == einfo->erasesize
> +			   && ( (from - einfo->offset) % einfo->erasesize == 0))
> +				break;
> +		}
> +		numregions--;
> +		einfo++;
> +	}
> +
> +	if(!numregions) {
> +		/* Not a valid erase block */
> +		err("erase: invalid erase request 0x%lX @ 0x%08zX", len, from);
> +		instr->state = MTD_ERASE_FAILED;
> +		err = -EIO;
> +	}
> +
> +	if(instr->state != MTD_ERASE_FAILED) {
> +		/* do the erase */
> +		DEBUG(3, "Doing erase from = %zd len = %ld\n", from, len);
> +		err = write_pages(dev, NULL, from, len, &retlen);
> +		if(err || retlen != len) {
> +			err("erase failed err = %d", err);
> +			instr->state = MTD_ERASE_FAILED;
> +		} else {
> +			instr->state = MTD_ERASE_DONE;
> +		}
> +	}
> +
> +	DEBUG(3, "blkmtd: erase: checking callback\n");
> +	mtd_erase_callback(instr);
> +	DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
> +	return err;
> +}
> +
> +static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
> +{
> +	struct blkmtd_dev *dev = mtd->priv;
> +	struct page *page;
> +	//
> +	int index	= from >> PAGE_SHIFT;
> +	int offset	= from - (index << PAGE_SHIFT);
> +	int cpylen;
> +
> +	if(from > mtd->size) return -EINVAL;
> +	if(from + len > mtd->size) len = mtd->size - from;
> +
> +	if(retlen) *retlen = 0;
> +
> +	while(len) {
> +		if((offset+len) > PAGE_SIZE) 
> +			cpylen = PAGE_SIZE - offset;	// multiple pages
> +		else	cpylen = len;			// this page
> +		len = len - cpylen;
> +		//
> +		//	Get page
> +		//
> +		page = page_readahead(dev->blkdev->bd_inode->i_mapping,index);
> +		if(!page) return -ENOMEM;
> +		if(IS_ERR(page)) return -EIO;
> +		//
> +		memcpy(buf, page_address(page) + offset, cpylen);
> +		page_cache_release(page);
> +		//
> +		if(retlen) *retlen += cpylen;
> +		buf+=cpylen;
> +		offset = 0;
> +		index++;
> +		//
> +	}
> +	return 0;
> +}
> +
> +
> +/* write data to the underlying device */
> +static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
> +			size_t *retlen, const u_char *buf)
> +{
> +	struct blkmtd_dev *dev = mtd->priv;
> +	int err;
> +
> +	if(!len) return 0;
> +	if(to >= mtd->size) return -ENOSPC;
> +	if(to + len > mtd->size) len = mtd->size - to;
> +
> +	err = write_pages(dev, buf, to, len, retlen);
> +	if(err > 0) err = 0;
> +	return err;
> +}
> +
> +
> +/* sync the device - wait until the write queue is empty */
> +static void blkmtd_sync(struct mtd_info *mtd)
> +{
> +	sync_blockdev(((struct blkmtd_dev*)mtd->priv)->blkdev);
> +	return;
> +}
> +
> +static void free_device(struct blkmtd_dev *dev)
> +{
> +	DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);
> +	if(dev) {
> +		if(dev->mtd_info.eraseregions)
> +			kfree(dev->mtd_info.eraseregions);
> +		if(dev->mtd_info.name)
> +			kfree(dev->mtd_info.name);
> +
> +		if(dev->blkdev) {
> +			invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);
> +			close_bdev_excl(dev->blkdev);
> +		}
> +		kfree(dev);
> +	}
> +}
> +
> +
> +/* For a given size and initial erase size, calculate the number
> + * and size of each erase region. Goes round the loop twice,
> + * once to find out how many regions, then allocates space,
> + * then round the loop again to fill it in.
> + */
> +static struct mtd_erase_region_info *calc_erase_regions(
> +	size_t erase_size, size_t total_size, int *regions)
> +{
> +	struct mtd_erase_region_info *info = NULL;
> +
> +	DEBUG(2, "calc_erase_regions, es = %zd size = %zd regions = %d\n",
> +	      erase_size, total_size, *regions);
> +	/* Make any user specified erasesize be a power of 2
> +	   and at least PAGE_SIZE */
> +	if(erase_size) {
> +		int es = erase_size;
> +		erase_size = 1;
> +		while(es != 1) {
> +			es >>= 1;
> +			erase_size <<= 1;
> +		}
> +		if(erase_size < PAGE_SIZE)
> +			erase_size = PAGE_SIZE;
> +	} else {
> +		erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
> +	}
> +
> +	*regions = 0;
> +
> +	do {
> +		int tot_size = total_size;
> +		int er_size = erase_size;
> +		int count = 0, offset = 0, regcnt = 0;
> +
> +		while(tot_size) {
> +			count = tot_size / er_size;
> +			if(count) {
> +				tot_size = tot_size % er_size;
> +				if(info) {
> +					DEBUG(2, "adding to erase info off=%d er=%d cnt=%d\n",
> +					      offset, er_size, count);
> +					(info+regcnt)->offset = offset;
> +					(info+regcnt)->erasesize = er_size;
> +					(info+regcnt)->numblocks = count;
> +					(*regions)++;
> +				}
> +				regcnt++;
> +				offset += (count * er_size);
> +			}
> +			while(er_size > tot_size)
> +				er_size >>= 1;
> +		}
> +		if(info == NULL) {
> +			info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
> +			if(!info)
> +				break;
> +		}
> +	} while(!(*regions));
> +	DEBUG(2, "calc_erase_regions done, es = %zd size = %zd regions = %d\n",
> +	      erase_size, total_size, *regions);
> +	return info;
> +}
> +
> +
> +extern dev_t __init name_to_dev_t(const char *line);
> +
> +static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size)
> +{
> +	struct block_device *bdev;
> +	int mode;
> +	struct blkmtd_dev *dev;
> +
> +	if(!devname)
> +		return NULL;
> +
> +	/* Get a handle on the device */
> +
> +
> +#ifdef MODULE
> +	mode = (readonly) ? O_RDONLY : O_RDWR;
> +	bdev = open_bdev_excl(devname, mode, NULL);
> +#else
> +	mode = (readonly) ? FMODE_READ : FMODE_WRITE;
> +	bdev = open_by_devnum(name_to_dev_t(devname), mode);
> +#endif
> +	if(IS_ERR(bdev)) {
> +		err("error: cannot open device %s", devname);
> +		DEBUG(2, "blkmtd: opening bdev returned %ld\n", PTR_ERR(bdev));
> +		return NULL;
> +	}
> +
> +	DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",
> +	      MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
> +
> +	if(MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
> +		err("attempting to use an MTD device as a block device");
> +		blkdev_put(bdev);
> +		return NULL;
> +	}
> +
> +	dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
> +	if(dev == NULL) {
> +		blkdev_put(bdev);
> +		return NULL;
> +	}
> +
> +	memset(dev, 0, sizeof(struct blkmtd_dev));
> +	dev->blkdev = bdev;
> +	atomic_set(&(dev->blkdev->bd_inode->i_mapping->truncate_count), 0);
> +	if(!readonly) {
> +		init_MUTEX(&dev->wrbuf_mutex);
> +	}
> +
> +	dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
> +
> +	/* Setup the MTD structure */
> +	/* make the name contain the block device in */
> +	dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL);
> +	if(dev->mtd_info.name == NULL)
> +		goto devinit_err;
> +
> +	sprintf(dev->mtd_info.name, "blkmtd: %s", devname);
> +	dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size,
> +							&dev->mtd_info.numeraseregions);
> +	if(dev->mtd_info.eraseregions == NULL)
> +		goto devinit_err;
> +
> +	dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize;
> +	DEBUG(1, "blkmtd: init: found %d erase regions\n",
> +	      dev->mtd_info.numeraseregions);
> +
> +	if(readonly) {
> +		dev->mtd_info.type = MTD_ROM;
> +		dev->mtd_info.flags = MTD_CAP_ROM;
> +	} else {
> +		dev->mtd_info.type = MTD_RAM;
> +		dev->mtd_info.flags = MTD_CAP_RAM;
> +		dev->mtd_info.erase = blkmtd_erase;
> +		dev->mtd_info.write = blkmtd_write;
> +		dev->mtd_info.writev = default_mtd_writev;
> +		dev->mtd_info.sync = blkmtd_sync;
> +	}
> +	dev->mtd_info.read = blkmtd_read;
> +	dev->mtd_info.readv = default_mtd_readv;
> +	dev->mtd_info.priv = dev;
> +	dev->mtd_info.owner = THIS_MODULE;
> +
> +	list_add(&dev->list, &blkmtd_device_list);
> +	if (add_mtd_device(&dev->mtd_info)) {
> +		/* Device didnt get added, so free the entry */
> +		list_del(&dev->list);
> +		goto devinit_err;
> +	} else {
> +		info("mtd%d: [%s] erase_size = %dKiB %s [%ld]",
> +		     dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),
> +		     dev->mtd_info.erasesize >> 10,
> +		     readonly ? "(read-only)" : "", PAGE_SIZE);
> +	}
> +	return dev;
> +
> + devinit_err:
> +	free_device(dev);
> +	return NULL;
> +}
> +
> +
> +/* Cleanup and exit - sync the device and kill of the kernel thread */
> +static void __devexit cleanup_blkmtd(void)
> +{
> +	struct list_head *temp1, *temp2;
> +
> +	/* Remove the MTD devices */
> +	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
> +		struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
> +						    list);
> +		blkmtd_sync(&dev->mtd_info);
> +		del_mtd_device(&dev->mtd_info);
> +		info("mtd%d: [%s] removed", dev->mtd_info.index,
> +		     dev->mtd_info.name + strlen("blkmtd: "));
> +		list_del(&dev->list);
> +		free_device(dev);
> +	}
> +}
> +
> +#ifndef MODULE
> +
> +/* Handle kernel boot params */
> +
> +
> +static int __init param_blkmtd_device(char *str)
> +{
> +	int i;
> +
> +	for(i = 0; i < MAX_DEVICES; i++) {
> +		device[i] = str;
> +		DEBUG(2, "blkmtd: device setup: %d = %s\n", i, device[i]);
> +		strsep(&str, ",");
> +	}
> +	return 1;
> +}
> +
> +
> +static int __init param_blkmtd_erasesz(char *str)
> +{
> +	int i;
> +	for(i = 0; i < MAX_DEVICES; i++) {
> +		char *val = strsep(&str, ",");
> +		if(val)
> +			erasesz[i] = simple_strtoul(val, NULL, 0);
> +		DEBUG(2, "blkmtd: erasesz setup: %d = %d\n", i, erasesz[i]);
> +	}
> +
> +	return 1;
> +}
> +
> +
> +static int __init param_blkmtd_ro(char *str)
> +{
> +	int i;
> +	for(i = 0; i < MAX_DEVICES; i++) {
> +		char *val = strsep(&str, ",");
> +		if(val)
> +			ro[i] = simple_strtoul(val, NULL, 0);
> +		DEBUG(2, "blkmtd: ro setup: %d = %d\n", i, ro[i]);
> +	}
> +
> +	return 1;
> +}
> +
> +
> +static int __init param_blkmtd_sync(char *str)
> +{
> +	if(str[0] == '1')
> +		sync = 1;
> +	return 1;
> +}
> +
> +__setup("blkmtd_device=", param_blkmtd_device);
> +__setup("blkmtd_erasesz=", param_blkmtd_erasesz);
> +__setup("blkmtd_ro=", param_blkmtd_ro);
> +__setup("blkmtd_sync=", param_blkmtd_sync);
> +
> +#endif
> +
> +
> +/* Startup */
> +static int __init init_blkmtd(void)
> +{
> +	int i;
> +
> +	info("version " VERSION);
> +	/* Check args - device[0] is the bare minimum*/
> +	if(!device[0]) {
> +		err("error: missing `device' name\n");
> +		return -EINVAL;
> +	}
> +
> +	for(i = 0; i < MAX_DEVICES; i++)
> +		add_device(device[i], ro[i], erasesz[i] << 10);
> +
> +	if(list_empty(&blkmtd_device_list))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +module_init(init_blkmtd);
> +module_exit(cleanup_blkmtd);

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 3/22] Remove read-only option
  2004-12-21 13:41                           ` [PATCH 2/22] Add copyrights Jörn Engel
@ 2004-12-21 13:42                             ` Jörn Engel
  2004-12-21 13:44                               ` [PATCH 4/22] Change init/exit functions Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:42 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Read-only devices are an inherintly stupid idea.  Get rid of them.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   51 +++++++++++++--------------------------------------
 1 files changed, 13 insertions(+), 38 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_readonly	2004-12-20 18:34:22.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 18:37:15.000000000 +0100
@@ -62,7 +62,6 @@
 /* Module parameters passed by insmod/modprobe */
 char *device[MAX_DEVICES];    /* the block device to use */
 int erasesz[MAX_DEVICES];     /* optional default erase size */
-int ro[MAX_DEVICES];          /* optional read only flag */
 int sync;
 
 
@@ -73,8 +72,6 @@
 MODULE_PARM_DESC(device, "block device to use");
 MODULE_PARM(erasesz, "1-4i");
 MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB.");
-MODULE_PARM(ro, "1-4i");
-MODULE_PARM_DESC(ro, "1=Read only, writes and erases cause errors");
 MODULE_PARM(sync, "i");
 MODULE_PARM_DESC(sync, "1=Synchronous writes");
 
@@ -445,7 +442,7 @@
 
 extern dev_t __init name_to_dev_t(const char *line);
 
-static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size)
+static struct blkmtd_dev *add_device(char *devname, int erase_size)
 {
 	struct block_device *bdev;
 	int mode;
@@ -458,10 +455,10 @@
 
 
 #ifdef MODULE
-	mode = (readonly) ? O_RDONLY : O_RDWR;
+	mode = O_RDWR;
 	bdev = open_bdev_excl(devname, mode, NULL);
 #else
-	mode = (readonly) ? FMODE_READ : FMODE_WRITE;
+	mode = FMODE_WRITE;
 	bdev = open_by_devnum(name_to_dev_t(devname), mode);
 #endif
 	if(IS_ERR(bdev)) {
@@ -488,9 +485,7 @@
 	memset(dev, 0, sizeof(struct blkmtd_dev));
 	dev->blkdev = bdev;
 	atomic_set(&(dev->blkdev->bd_inode->i_mapping->truncate_count), 0);
-	if(!readonly) {
-		init_MUTEX(&dev->wrbuf_mutex);
-	}
+	init_MUTEX(&dev->wrbuf_mutex);
 
 	dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
 
@@ -510,17 +505,12 @@
 	DEBUG(1, "blkmtd: init: found %d erase regions\n",
 	      dev->mtd_info.numeraseregions);
 
-	if(readonly) {
-		dev->mtd_info.type = MTD_ROM;
-		dev->mtd_info.flags = MTD_CAP_ROM;
-	} else {
-		dev->mtd_info.type = MTD_RAM;
-		dev->mtd_info.flags = MTD_CAP_RAM;
-		dev->mtd_info.erase = blkmtd_erase;
-		dev->mtd_info.write = blkmtd_write;
-		dev->mtd_info.writev = default_mtd_writev;
-		dev->mtd_info.sync = blkmtd_sync;
-	}
+	dev->mtd_info.type = MTD_RAM;
+	dev->mtd_info.flags = MTD_CAP_RAM;
+	dev->mtd_info.erase = blkmtd_erase;
+	dev->mtd_info.write = blkmtd_write;
+	dev->mtd_info.writev = default_mtd_writev;
+	dev->mtd_info.sync = blkmtd_sync;
 	dev->mtd_info.read = blkmtd_read;
 	dev->mtd_info.readv = default_mtd_readv;
 	dev->mtd_info.priv = dev;
@@ -532,10 +522,10 @@
 		list_del(&dev->list);
 		goto devinit_err;
 	} else {
-		info("mtd%d: [%s] erase_size = %dKiB %s [%ld]",
+		info("mtd%d: [%s] erase_size = %dKiB [%ld]",
 		     dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),
 		     dev->mtd_info.erasesize >> 10,
-		     readonly ? "(read-only)" : "", PAGE_SIZE);
+		     PAGE_SIZE);
 	}
 	return dev;
 
@@ -595,20 +585,6 @@
 }
 
 
-static int __init param_blkmtd_ro(char *str)
-{
-	int i;
-	for(i = 0; i < MAX_DEVICES; i++) {
-		char *val = strsep(&str, ",");
-		if(val)
-			ro[i] = simple_strtoul(val, NULL, 0);
-		DEBUG(2, "blkmtd: ro setup: %d = %d\n", i, ro[i]);
-	}
-
-	return 1;
-}
-
-
 static int __init param_blkmtd_sync(char *str)
 {
 	if(str[0] == '1')
@@ -618,7 +594,6 @@
 
 __setup("blkmtd_device=", param_blkmtd_device);
 __setup("blkmtd_erasesz=", param_blkmtd_erasesz);
-__setup("blkmtd_ro=", param_blkmtd_ro);
 __setup("blkmtd_sync=", param_blkmtd_sync);
 
 #endif
@@ -637,7 +612,7 @@
 	}
 
 	for(i = 0; i < MAX_DEVICES; i++)
-		add_device(device[i], ro[i], erasesz[i] << 10);
+		add_device(device[i], erasesz[i] << 10);
 
 	if(list_empty(&blkmtd_device_list))
 		return -EINVAL;

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 4/22] Change init/exit functions
  2004-12-21 13:42                             ` [PATCH 3/22] Remove read-only option Jörn Engel
@ 2004-12-21 13:44                               ` Jörn Engel
  2004-12-21 13:45                                 ` [PATCH 5/22] Remove gcc warnings Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:44 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Move/change the init and exit functions.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   53 ++++++++++++++++++++++++++---------------------------
 1 files changed, 26 insertions(+), 27 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_init_exit	2004-12-20 18:37:15.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 18:39:30.000000000 +0100
@@ -534,25 +534,6 @@
 	return NULL;
 }
 
-
-/* Cleanup and exit - sync the device and kill of the kernel thread */
-static void __devexit cleanup_blkmtd(void)
-{
-	struct list_head *temp1, *temp2;
-
-	/* Remove the MTD devices */
-	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
-		struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
-						    list);
-		blkmtd_sync(&dev->mtd_info);
-		del_mtd_device(&dev->mtd_info);
-		info("mtd%d: [%s] removed", dev->mtd_info.index,
-		     dev->mtd_info.name + strlen("blkmtd: "));
-		list_del(&dev->list);
-		free_device(dev);
-	}
-}
-
 #ifndef MODULE
 
 /* Handle kernel boot params */
@@ -599,26 +580,44 @@
 #endif
 
 
-/* Startup */
-static int __init init_blkmtd(void)
+static int __init blockmtd_init(void)
 {
 	int i;
 
 	info("version " VERSION);
-	/* Check args - device[0] is the bare minimum*/
-	if(!device[0]) {
+	/* Check args - device[0] is the bare minimum */
+	if (!device[0]) {
 		err("error: missing `device' name\n");
 		return -EINVAL;
 	}
 
-	for(i = 0; i < MAX_DEVICES; i++)
+	for (i = 0; i < MAX_DEVICES; i++)
 		add_device(device[i], erasesz[i] << 10);
 
-	if(list_empty(&blkmtd_device_list))
+	if (list_empty(&blkmtd_device_list))
 		return -EINVAL;
 
 	return 0;
 }
 
-module_init(init_blkmtd);
-module_exit(cleanup_blkmtd);
+
+static void __devexit blockmtd_exit(void)
+{
+	struct list_head *temp1, *temp2;
+
+	/* Remove the MTD devices */
+	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
+		struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
+						    list);
+		blkmtd_sync(&dev->mtd_info);
+		del_mtd_device(&dev->mtd_info);
+		info("mtd%d: [%s] removed", dev->mtd_info.index,
+				dev->mtd_info.name + strlen("blkmtd: "));
+		list_del(&dev->list);
+		free_device(dev);
+	}
+}
+
+
+module_init(blockmtd_init);
+module_exit(blockmtd_exit);

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 5/22] Remove gcc warnings
  2004-12-21 13:44                               ` [PATCH 4/22] Change init/exit functions Jörn Engel
@ 2004-12-21 13:45                                 ` Jörn Engel
  2004-12-21 13:47                                   ` [PATCH 6/22] Remove debug macros Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:45 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Name sais enough.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_prototypes	2004-12-20 18:57:18.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 19:00:27.000000000 +0100
@@ -150,7 +150,7 @@
 	int	offset 	= to & ~PAGE_MASK;	// page offset
 	//
 
-	static int my_read()
+	static int my_read(void)
 	{
 		err=0;
 		page = page_readahead(mapping,index);
@@ -163,7 +163,7 @@
 		return err;
 	}
 	//
-	static int my_erase()
+	static int my_erase(void)
 	{
 		int pages = len >> PAGE_SHIFT;
 		unsigned char *p;
@@ -198,7 +198,7 @@
 		return 0;
 	}
 
-	static int my_write()
+	static int my_write(void)
 	{
 		int cpylen;
 
@@ -240,6 +240,7 @@
 	return err;
 }
 
+
 /* erase a specified part of the device */
 static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
 {

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 6/22] Remove debug macros
  2004-12-21 13:45                                 ` [PATCH 5/22] Remove gcc warnings Jörn Engel
@ 2004-12-21 13:47                                   ` Jörn Engel
  2004-12-21 13:48                                     ` [PATCH 7/22] Lindent Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:47 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Remove debug output.  I have absolutely no love for those things.  If
you need them for debugging, add them, find the problem, fix the
problem, keep the fix and drop the debugging mess.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   24 +-----------------------
 1 files changed, 1 insertion(+), 23 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_debug	2004-12-20 19:00:27.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 19:03:50.000000000 +0100
@@ -184,7 +184,6 @@
 				}
 
 			if(format) {
-				//DEBUG(3, "write_pages: erasing\n");
 				lock_page(page);
 				memset(page_address(page), 0xff, PAGE_SIZE);
 				set_page_dirty(page);
@@ -257,10 +256,7 @@
 	len = instr->len;
 
 	/* check erase region has valid start and length */
-	//DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%zx len = 0x%lx\n", mtd->name+9, from, len);
 	while(numregions) {
-		DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
-		      einfo->offset, einfo->erasesize, einfo->numblocks);
 		if(from >= einfo->offset
 		   && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
 			if(len == einfo->erasesize
@@ -280,7 +276,6 @@
 
 	if(instr->state != MTD_ERASE_FAILED) {
 		/* do the erase */
-		DEBUG(3, "Doing erase from = %zd len = %ld\n", from, len);
 		err = write_pages(dev, NULL, from, len, &retlen);
 		if(err || retlen != len) {
 			err("erase failed err = %d", err);
@@ -290,9 +285,7 @@
 		}
 	}
 
-	DEBUG(3, "blkmtd: erase: checking callback\n");
 	mtd_erase_callback(instr);
-	DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
 	return err;
 }
 
@@ -361,7 +354,6 @@
 
 static void free_device(struct blkmtd_dev *dev)
 {
-	DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);
 	if(dev) {
 		if(dev->mtd_info.eraseregions)
 			kfree(dev->mtd_info.eraseregions);
@@ -387,8 +379,6 @@
 {
 	struct mtd_erase_region_info *info = NULL;
 
-	DEBUG(2, "calc_erase_regions, es = %zd size = %zd regions = %d\n",
-	      erase_size, total_size, *regions);
 	/* Make any user specified erasesize be a power of 2
 	   and at least PAGE_SIZE */
 	if(erase_size) {
@@ -416,8 +406,6 @@
 			if(count) {
 				tot_size = tot_size % er_size;
 				if(info) {
-					DEBUG(2, "adding to erase info off=%d er=%d cnt=%d\n",
-					      offset, er_size, count);
 					(info+regcnt)->offset = offset;
 					(info+regcnt)->erasesize = er_size;
 					(info+regcnt)->numblocks = count;
@@ -435,8 +423,7 @@
 				break;
 		}
 	} while(!(*regions));
-	DEBUG(2, "calc_erase_regions done, es = %zd size = %zd regions = %d\n",
-	      erase_size, total_size, *regions);
+
 	return info;
 }
 
@@ -464,13 +451,9 @@
 #endif
 	if(IS_ERR(bdev)) {
 		err("error: cannot open device %s", devname);
-		DEBUG(2, "blkmtd: opening bdev returned %ld\n", PTR_ERR(bdev));
 		return NULL;
 	}
 
-	DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",
-	      MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
-
 	if(MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
 		err("attempting to use an MTD device as a block device");
 		blkdev_put(bdev);
@@ -503,9 +486,6 @@
 		goto devinit_err;
 
 	dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize;
-	DEBUG(1, "blkmtd: init: found %d erase regions\n",
-	      dev->mtd_info.numeraseregions);
-
 	dev->mtd_info.type = MTD_RAM;
 	dev->mtd_info.flags = MTD_CAP_RAM;
 	dev->mtd_info.erase = blkmtd_erase;
@@ -546,7 +526,6 @@
 
 	for(i = 0; i < MAX_DEVICES; i++) {
 		device[i] = str;
-		DEBUG(2, "blkmtd: device setup: %d = %s\n", i, device[i]);
 		strsep(&str, ",");
 	}
 	return 1;
@@ -560,7 +539,6 @@
 		char *val = strsep(&str, ",");
 		if(val)
 			erasesz[i] = simple_strtoul(val, NULL, 0);
-		DEBUG(2, "blkmtd: erasesz setup: %d = %d\n", i, erasesz[i]);
 	}
 
 	return 1;

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 7/22] Lindent
  2004-12-21 13:47                                   ` [PATCH 6/22] Remove debug macros Jörn Engel
@ 2004-12-21 13:48                                     ` Jörn Engel
  2004-12-21 13:49                                       ` [PATCH 8/22] Remove sync interface Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:48 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Ran some functions through Lindent.  Mostly mindless stuff, some small
manual changes as well.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |  158 +++++++++++++++++++++++++++++++------------------------------
 1 files changed, 82 insertions(+), 76 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_lindent	2004-12-20 19:03:50.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 19:10:28.000000000 +0100
@@ -79,8 +79,8 @@
 
 void cache_readahead(struct address_space *mapping, int index)
 {
-	filler_t *filler = (filler_t*)(mapping->a_ops->readpage);
-	int i,pagei;
+	filler_t *filler = (void*)mapping->a_ops->readpage;
+	int i, pagei;
 	unsigned ret = 0;
 	unsigned long end_index;
 	struct page *page;
@@ -88,7 +88,7 @@
 	struct inode *inode = mapping->host;
 	loff_t isize = i_size_read(inode);
 
-	if(!isize) {
+	if (!isize) {
 		printk(KERN_INFO "iSize=0 in cache_readahead\n");
 		return;
 	}
@@ -96,25 +96,28 @@
 	end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
 
 	spin_lock_irq(&mapping->tree_lock);
-	for(i=0;i<PAGE_READAHEAD;i++) {
-		pagei=index+i;
+	for (i = 0; i < PAGE_READAHEAD; i++) {
+		pagei = index + i;
 		if (pagei > end_index) {
 			printk(KERN_INFO "Overrun end of disk in cache readahead\n");
 			break;
 		}
 		page = radix_tree_lookup(&mapping->page_tree, pagei);
-		if(page && (!i)) break;
-		if(page) continue;
+		if (page && (!i))
+			break;
+		if (page)
+			continue;
 		spin_unlock_irq(&mapping->tree_lock);
 		page = page_cache_alloc_cold(mapping);
 		spin_lock_irq(&mapping->tree_lock);
-		if(!page) break;
-		page->index=pagei;
+		if (!page)
+			break;
+		page->index = pagei;
 		list_add(&page->lru, &page_pool);
 		ret++;
 	}
 	spin_unlock_irq(&mapping->tree_lock);
-	if(ret) {
+	if (ret) {
 		read_cache_pages(mapping, &page_pool, filler, NULL);
 		//printk(KERN_INFO "Readahead [%d/%d] pages from [%d]\n",ret,PAGE_READAHEAD,index);
 	}
@@ -256,28 +259,26 @@
 	len = instr->len;
 
 	/* check erase region has valid start and length */
-	while(numregions) {
-		if(from >= einfo->offset
-		   && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
-			if(len == einfo->erasesize
-			   && ( (from - einfo->offset) % einfo->erasesize == 0))
+	while (numregions) {
+		if (from >= einfo->offset && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
+			if (len == einfo->erasesize && ((from - einfo->offset) % einfo->erasesize == 0))
 				break;
 		}
 		numregions--;
 		einfo++;
 	}
 
-	if(!numregions) {
+	if (!numregions) {
 		/* Not a valid erase block */
 		err("erase: invalid erase request 0x%lX @ 0x%08zX", len, from);
 		instr->state = MTD_ERASE_FAILED;
 		err = -EIO;
 	}
 
-	if(instr->state != MTD_ERASE_FAILED) {
+	if (instr->state != MTD_ERASE_FAILED) {
 		/* do the erase */
 		err = write_pages(dev, NULL, from, len, &retlen);
-		if(err || retlen != len) {
+		if (err || retlen != len) {
 			err("erase failed err = %d", err);
 			instr->state = MTD_ERASE_FAILED;
 		} else {
@@ -294,35 +295,41 @@
 	struct blkmtd_dev *dev = mtd->priv;
 	struct page *page;
 	//
-	int index	= from >> PAGE_SHIFT;
-	int offset	= from - (index << PAGE_SHIFT);
+	int index = from >> PAGE_SHIFT;
+	int offset = from - (index << PAGE_SHIFT);
 	int cpylen;
 
-	if(from > mtd->size) return -EINVAL;
-	if(from + len > mtd->size) len = mtd->size - from;
+	if (from > mtd->size)
+		return -EINVAL;
+	if (from + len > mtd->size)
+		len = mtd->size - from;
 
-	if(retlen) *retlen = 0;
+	if (retlen)
+		*retlen = 0;
 
-	while(len) {
-		if((offset+len) > PAGE_SIZE) 
+	while (len) {
+		if ((offset + len) > PAGE_SIZE)
 			cpylen = PAGE_SIZE - offset;	// multiple pages
-		else	cpylen = len;			// this page
+		else
+			cpylen = len;	// this page
 		len = len - cpylen;
-		//
-		//	Get page
-		//
-		page = page_readahead(dev->blkdev->bd_inode->i_mapping,index);
-		if(!page) return -ENOMEM;
-		if(IS_ERR(page)) return -EIO;
-		//
+
+		//      Get page
+		page = page_readahead(dev->blkdev->bd_inode->i_mapping, index);
+		if (!page)
+			return -ENOMEM;
+		if (IS_ERR(page))
+			return -EIO;
+
 		memcpy(buf, page_address(page) + offset, cpylen);
 		page_cache_release(page);
-		//
-		if(retlen) *retlen += cpylen;
-		buf+=cpylen;
+
+		if (retlen)
+			*retlen += cpylen;
+		buf += cpylen;
 		offset = 0;
 		index++;
-		//
+
 	}
 	return 0;
 }
@@ -335,12 +342,16 @@
 	struct blkmtd_dev *dev = mtd->priv;
 	int err;
 
-	if(!len) return 0;
-	if(to >= mtd->size) return -ENOSPC;
-	if(to + len > mtd->size) len = mtd->size - to;
+	if (!len)
+		return 0;
+	if (to >= mtd->size)
+		return -ENOSPC;
+	if (to + len > mtd->size)
+		len = mtd->size - to;
 
 	err = write_pages(dev, buf, to, len, retlen);
-	if(err > 0) err = 0;
+	if (err > 0)
+		err = 0;
 	return err;
 }
 
@@ -354,13 +365,13 @@
 
 static void free_device(struct blkmtd_dev *dev)
 {
-	if(dev) {
-		if(dev->mtd_info.eraseregions)
+	if (dev) {
+		if (dev->mtd_info.eraseregions)
 			kfree(dev->mtd_info.eraseregions);
-		if(dev->mtd_info.name)
+		if (dev->mtd_info.name)
 			kfree(dev->mtd_info.name);
 
-		if(dev->blkdev) {
+		if (dev->blkdev) {
 			invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);
 			close_bdev_excl(dev->blkdev);
 		}
@@ -381,14 +392,14 @@
 
 	/* Make any user specified erasesize be a power of 2
 	   and at least PAGE_SIZE */
-	if(erase_size) {
+	if (erase_size) {
 		int es = erase_size;
 		erase_size = 1;
-		while(es != 1) {
+		while (es != 1) {
 			es >>= 1;
 			erase_size <<= 1;
 		}
-		if(erase_size < PAGE_SIZE)
+		if (erase_size < PAGE_SIZE)
 			erase_size = PAGE_SIZE;
 	} else {
 		erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
@@ -401,28 +412,28 @@
 		int er_size = erase_size;
 		int count = 0, offset = 0, regcnt = 0;
 
-		while(tot_size) {
+		while (tot_size) {
 			count = tot_size / er_size;
-			if(count) {
+			if (count) {
 				tot_size = tot_size % er_size;
-				if(info) {
-					(info+regcnt)->offset = offset;
-					(info+regcnt)->erasesize = er_size;
-					(info+regcnt)->numblocks = count;
+				if (info) {
+					(info + regcnt)->offset = offset;
+					(info + regcnt)->erasesize = er_size;
+					(info + regcnt)->numblocks = count;
 					(*regions)++;
 				}
 				regcnt++;
 				offset += (count * er_size);
 			}
-			while(er_size > tot_size)
+			while (er_size > tot_size)
 				er_size >>= 1;
 		}
-		if(info == NULL) {
+		if (info == NULL) {
 			info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
-			if(!info)
+			if (!info)
 				break;
 		}
-	} while(!(*regions));
+	} while (!(*regions));
 
 	return info;
 }
@@ -436,12 +447,11 @@
 	int mode;
 	struct blkmtd_dev *dev;
 
-	if(!devname)
+	if (!devname)
 		return NULL;
 
 	/* Get a handle on the device */
 
-
 #ifdef MODULE
 	mode = O_RDWR;
 	bdev = open_bdev_excl(devname, mode, NULL);
@@ -449,19 +459,19 @@
 	mode = FMODE_WRITE;
 	bdev = open_by_devnum(name_to_dev_t(devname), mode);
 #endif
-	if(IS_ERR(bdev)) {
+	if (IS_ERR(bdev)) {
 		err("error: cannot open device %s", devname);
 		return NULL;
 	}
 
-	if(MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
+	if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
 		err("attempting to use an MTD device as a block device");
 		blkdev_put(bdev);
 		return NULL;
 	}
 
 	dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
-	if(dev == NULL) {
+	if (dev == NULL) {
 		blkdev_put(bdev);
 		return NULL;
 	}
@@ -476,13 +486,12 @@
 	/* Setup the MTD structure */
 	/* make the name contain the block device in */
 	dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL);
-	if(dev->mtd_info.name == NULL)
+	if (dev->mtd_info.name == NULL)
 		goto devinit_err;
 
 	sprintf(dev->mtd_info.name, "blkmtd: %s", devname);
-	dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size,
-							&dev->mtd_info.numeraseregions);
-	if(dev->mtd_info.eraseregions == NULL)
+	dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size, &dev->mtd_info.numeraseregions);
+	if (dev->mtd_info.eraseregions == NULL)
 		goto devinit_err;
 
 	dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize;
@@ -503,14 +512,11 @@
 		list_del(&dev->list);
 		goto devinit_err;
 	} else {
-		info("mtd%d: [%s] erase_size = %dKiB [%ld]",
-		     dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),
-		     dev->mtd_info.erasesize >> 10,
-		     PAGE_SIZE);
+		info("mtd%d: [%s] erase_size = %dKiB [%ld]", dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "), dev->mtd_info.erasesize >> 10, PAGE_SIZE);
 	}
 	return dev;
 
- devinit_err:
+devinit_err:
 	free_device(dev);
 	return NULL;
 }
@@ -524,7 +530,7 @@
 {
 	int i;
 
-	for(i = 0; i < MAX_DEVICES; i++) {
+	for (i = 0; i < MAX_DEVICES; i++) {
 		device[i] = str;
 		strsep(&str, ",");
 	}
@@ -535,9 +541,9 @@
 static int __init param_blkmtd_erasesz(char *str)
 {
 	int i;
-	for(i = 0; i < MAX_DEVICES; i++) {
+	for (i = 0; i < MAX_DEVICES; i++) {
 		char *val = strsep(&str, ",");
-		if(val)
+		if (val)
 			erasesz[i] = simple_strtoul(val, NULL, 0);
 	}
 
@@ -547,7 +553,7 @@
 
 static int __init param_blkmtd_sync(char *str)
 {
-	if(str[0] == '1')
+	if (str[0] == '1')
 		sync = 1;
 	return 1;
 }

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 8/22] Remove sync interface
  2004-12-21 13:48                                     ` [PATCH 7/22] Lindent Jörn Engel
@ 2004-12-21 13:49                                       ` Jörn Engel
  2004-12-21 13:51                                         ` [PATCH 9/22] Change parameter interface to phram-style Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:49 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

The sync interface was unused.  Not it's gone.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   13 -------------
 1 files changed, 13 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_sync	2004-12-20 19:10:28.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 21:38:46.000000000 +0100
@@ -55,14 +55,11 @@
 /* Static info about the MTD, used in cleanup_module */
 static LIST_HEAD(blkmtd_device_list);
 
-static void blkmtd_sync(struct mtd_info *mtd);
-
 #define MAX_DEVICES 4
 
 /* Module parameters passed by insmod/modprobe */
 char *device[MAX_DEVICES];    /* the block device to use */
 int erasesz[MAX_DEVICES];     /* optional default erase size */
-int sync;
 
 
 MODULE_LICENSE("GPL");
@@ -72,8 +69,6 @@
 MODULE_PARM_DESC(device, "block device to use");
 MODULE_PARM(erasesz, "1-4i");
 MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB.");
-MODULE_PARM(sync, "i");
-MODULE_PARM_DESC(sync, "1=Synchronous writes");
 
 #define PAGE_READAHEAD 64
 
@@ -551,16 +546,8 @@
 }
 
 
-static int __init param_blkmtd_sync(char *str)
-{
-	if (str[0] == '1')
-		sync = 1;
-	return 1;
-}
-
 __setup("blkmtd_device=", param_blkmtd_device);
 __setup("blkmtd_erasesz=", param_blkmtd_erasesz);
-__setup("blkmtd_sync=", param_blkmtd_sync);
 
 #endif
 

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 9/22] Change parameter interface to phram-style
  2004-12-21 13:49                                       ` [PATCH 8/22] Remove sync interface Jörn Engel
@ 2004-12-21 13:51                                         ` Jörn Engel
  2004-12-21 13:53                                           ` [PATCH 10/22] Cleanup macro usage Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:51 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Much nicer.  Same interface at boot time, module load and runtime via
/sys/.  It also groups by device, so you can add devices on the fly if
you wish to.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |  141 +++++++++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 97 insertions(+), 44 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_interface	2004-12-20 21:38:46.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 22:07:09.000000000 +0100
@@ -33,6 +33,8 @@
 #include <linux/mtd/mtd.h>
 #include <linux/buffer_head.h>
 
+#define ERROR(fmt, args...) printk(KERN_ERR "blockmtd: " fmt , ## args)
+
 #define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
 #define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
 #define warn(format, arg...) printk(KERN_WARNING "blkmtd: " format "\n" , ## arg)
@@ -57,18 +59,6 @@
 
 #define MAX_DEVICES 4
 
-/* Module parameters passed by insmod/modprobe */
-char *device[MAX_DEVICES];    /* the block device to use */
-int erasesz[MAX_DEVICES];     /* optional default erase size */
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
-MODULE_DESCRIPTION("Emulate an MTD using a block device");
-MODULE_PARM(device, "1-4s");
-MODULE_PARM_DESC(device, "block device to use");
-MODULE_PARM(erasesz, "1-4i");
-MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB.");
 
 #define PAGE_READAHEAD 64
 
@@ -516,63 +506,122 @@
 	return NULL;
 }
 
-#ifndef MODULE
 
-/* Handle kernel boot params */
+static int ustrtoul(const char *cp, char **endp, unsigned int base)
+{
+	unsigned long result = simple_strtoul(cp, endp, base);
+	switch (**endp) {
+	case 'G' :
+		result *= 1024;
+	case 'M':
+		result *= 1024;
+	case 'k':
+		result *= 1024;
+	/* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
+		if ((*endp)[1] == 'i')
+			(*endp) += 2;
+	}
+	return result;
+}
 
 
-static int __init param_blkmtd_device(char *str)
+static int parse_num32(u32 *num32, const char *token)
 {
-	int i;
+	char *endp;
+	unsigned long n;
 
-	for (i = 0; i < MAX_DEVICES; i++) {
-		device[i] = str;
-		strsep(&str, ",");
-	}
-	return 1;
+	n = ustrtoul(token, &endp, 0);
+	if (*endp)
+		return -EINVAL;
+
+	*num32 = n;
+	return 0;
 }
 
 
-static int __init param_blkmtd_erasesz(char *str)
+static int parse_name(char **pname, const char *token, size_t limit)
 {
-	int i;
-	for (i = 0; i < MAX_DEVICES; i++) {
-		char *val = strsep(&str, ",");
-		if (val)
-			erasesz[i] = simple_strtoul(val, NULL, 0);
-	}
+	size_t len;
+	char *name;
 
-	return 1;
-}
+	len = strlen(token) + 1;
+	if (len > limit)
+		return -ENOSPC;
 
+	name = kmalloc(len, GFP_KERNEL);
+	if (!name)
+		return -ENOMEM;
 
-__setup("blkmtd_device=", param_blkmtd_device);
-__setup("blkmtd_erasesz=", param_blkmtd_erasesz);
+	strcpy(name, token);
 
-#endif
+	*pname = name;
+	return 0;
+}
 
 
-static int __init blockmtd_init(void)
+#define parse_err(fmt, args...) do {		\
+	ERROR("blockmtd: " fmt "\n", ## args);	\
+	return 0;				\
+} while (0)
+
+static int blockmtd_setup(const char *val, struct kernel_param *kp)
 {
-	int i;
+	char buf[80+12], *str=buf; /* 80 for device, 12 for erase size */
+	char *token[2];
+	char *name;
+	size_t erase_size = 0;
+	int i, ret;
 
-	info("version " VERSION);
-	/* Check args - device[0] is the bare minimum */
-	if (!device[0]) {
-		err("error: missing `device' name\n");
-		return -EINVAL;
+	if (strnlen(val, sizeof(buf)) >= sizeof(buf))
+		parse_err("parameter too long");
+
+	strcpy(str, val);
+
+	for (i=0; i<2; i++)
+		token[i] = strsep(&str, ",");
+
+	{ /* people dislike typing "echo -n".  and it's simple enough */
+		char *newline = strrchr(token[1], '\n');
+		if (newline && !newline[1])
+			*newline = 0;
 	}
 
-	for (i = 0; i < MAX_DEVICES; i++)
-		add_device(device[i], erasesz[i] << 10);
+	if (str)
+		parse_err("too many arguments");
 
-	if (list_empty(&blkmtd_device_list))
-		return -EINVAL;
+	if (!token[0])
+		parse_err("no argument");
+
+	ret = parse_name(&name, token[0], 80);
+	if (ret == -ENOMEM)
+		parse_err("out of memory");
+	if (ret == -ENOSPC)
+		parse_err("name too long");
+	if (ret)
+		return 0;
+
+	if (token[1]) {
+		ret = parse_num32(&erase_size, token[1]);
+		if (ret)
+			parse_err("illegal erase size");
+	}
+
+	add_device(name, erase_size);
 
 	return 0;
 }
 
 
+module_param_call(blockmtd, blockmtd_setup, NULL, NULL, 0200);
+MODULE_PARM_DESC(blockmtd, "Device to use. \"blockmtd=<dev>[,<erasesize>]\"");
+
+static int __init blockmtd_init(void)
+{
+	info("version " VERSION);
+	return 0;
+}
+
+
 static void __devexit blockmtd_exit(void)
 {
 	struct list_head *temp1, *temp2;
@@ -593,3 +642,7 @@
 
 module_init(blockmtd_init);
 module_exit(blockmtd_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
+MODULE_DESCRIPTION("Emulate an MTD using a block device");

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 10/22] Cleanup macro usage
  2004-12-21 13:51                                         ` [PATCH 9/22] Change parameter interface to phram-style Jörn Engel
@ 2004-12-21 13:53                                           ` Jörn Engel
  2004-12-21 13:54                                             ` [PATCH 11/22] kfree simplifications Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:53 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Change some macros.  "err" and "info" were both macros and variables,
which is at best confusing to the reader.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   26 ++++++++++----------------
 1 files changed, 10 insertions(+), 16 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_macros	2004-12-20 22:07:09.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 22:12:07.000000000 +0100
@@ -33,12 +33,8 @@
 #include <linux/mtd/mtd.h>
 #include <linux/buffer_head.h>
 
-#define ERROR(fmt, args...) printk(KERN_ERR "blockmtd: " fmt , ## args)
-
-#define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "blkmtd: " format "\n" , ## arg)
-#define crit(format, arg...) printk(KERN_CRIT "blkmtd: " format "\n" , ## arg)
+#define ERROR(fmt, args...) printk(KERN_ERR "blockmtd: " fmt "\n" , ## args)
+#define INFO(fmt, args...) printk(KERN_INFO "blockmtd: " fmt "\n" , ## args)
 
 
 /* Default erase size in K, always make it a multiple of PAGE_SIZE */
@@ -57,8 +53,6 @@
 /* Static info about the MTD, used in cleanup_module */
 static LIST_HEAD(blkmtd_device_list);
 
-#define MAX_DEVICES 4
-
 
 #define PAGE_READAHEAD 64
 
@@ -143,7 +137,7 @@
 		err=0;
 		page = page_readahead(mapping,index);
 		if( unlikely(!page) ) {
-			crit("unable to read page (%d) in write_pages\n",index);
+			ERROR("unable to read page (%d) in write_pages\n", index);
 			err=-ENOMEM;
 		}
 		//if(IS_ERR(page)) err=-EIO;
@@ -255,7 +249,7 @@
 
 	if (!numregions) {
 		/* Not a valid erase block */
-		err("erase: invalid erase request 0x%lX @ 0x%08zX", len, from);
+		ERROR("erase: invalid erase request 0x%lX @ 0x%08zX", len,from);
 		instr->state = MTD_ERASE_FAILED;
 		err = -EIO;
 	}
@@ -264,7 +258,7 @@
 		/* do the erase */
 		err = write_pages(dev, NULL, from, len, &retlen);
 		if (err || retlen != len) {
-			err("erase failed err = %d", err);
+			ERROR("erase failed err = %d", err);
 			instr->state = MTD_ERASE_FAILED;
 		} else {
 			instr->state = MTD_ERASE_DONE;
@@ -445,12 +439,12 @@
 	bdev = open_by_devnum(name_to_dev_t(devname), mode);
 #endif
 	if (IS_ERR(bdev)) {
-		err("error: cannot open device %s", devname);
+		ERROR("error: cannot open device %s", devname);
 		return NULL;
 	}
 
 	if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
-		err("attempting to use an MTD device as a block device");
+		ERROR("attempting to use an MTD device as a block device");
 		blkdev_put(bdev);
 		return NULL;
 	}
@@ -497,7 +491,7 @@
 		list_del(&dev->list);
 		goto devinit_err;
 	} else {
-		info("mtd%d: [%s] erase_size = %dKiB [%ld]", dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "), dev->mtd_info.erasesize >> 10, PAGE_SIZE);
+		INFO("mtd%d: [%s] erase_size = %dKiB [%ld]", dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "), dev->mtd_info.erasesize >> 10, PAGE_SIZE);
 	}
 	return dev;
 
@@ -617,7 +611,7 @@
 
 static int __init blockmtd_init(void)
 {
-	info("version " VERSION);
+	INFO("version " VERSION);
 	return 0;
 }
 
@@ -632,7 +626,7 @@
 						    list);
 		blkmtd_sync(&dev->mtd_info);
 		del_mtd_device(&dev->mtd_info);
-		info("mtd%d: [%s] removed", dev->mtd_info.index,
+		INFO("mtd%d: [%s] removed", dev->mtd_info.index,
 				dev->mtd_info.name + strlen("blkmtd: "));
 		list_del(&dev->list);
 		free_device(dev);

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 11/22] kfree simplifications
  2004-12-21 13:53                                           ` [PATCH 10/22] Cleanup macro usage Jörn Engel
@ 2004-12-21 13:54                                             ` Jörn Engel
  2004-12-21 13:55                                               ` [PATCH 12/22] change blockmtd_sync Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:54 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

kfree(NULL) works just fine, which allows for much simpler code.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   26 +++++++++++++-------------
 1 files changed, 13 insertions(+), 13 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_kfree	2004-12-20 22:12:07.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 22:14:47.000000000 +0100
@@ -342,20 +342,20 @@
 	return;
 }
 
-static void free_device(struct blkmtd_dev *dev)
+static void blockmtd_free_device(struct blkmtd_dev *dev)
 {
-	if (dev) {
-		if (dev->mtd_info.eraseregions)
-			kfree(dev->mtd_info.eraseregions);
-		if (dev->mtd_info.name)
-			kfree(dev->mtd_info.name);
+	if (!dev)
+		return;
 
-		if (dev->blkdev) {
-			invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);
-			close_bdev_excl(dev->blkdev);
-		}
-		kfree(dev);
+	kfree(dev->mtd_info.eraseregions);
+	kfree(dev->mtd_info.name);
+
+	if (dev->blkdev) {
+		invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);
+		close_bdev_excl(dev->blkdev);
 	}
+
+	kfree(dev);
 }
 
 
@@ -496,7 +496,7 @@
 	return dev;
 
 devinit_err:
-	free_device(dev);
+	blockmtd_free_device(dev);
 	return NULL;
 }
 
@@ -629,7 +629,7 @@
 		INFO("mtd%d: [%s] removed", dev->mtd_info.index,
 				dev->mtd_info.name + strlen("blkmtd: "));
 		list_del(&dev->list);
-		free_device(dev);
+		blockmtd_free_device(dev);
 	}
 }
 

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 12/22] change blockmtd_sync
  2004-12-21 13:54                                             ` [PATCH 11/22] kfree simplifications Jörn Engel
@ 2004-12-21 13:55                                               ` Jörn Engel
  2004-12-21 13:57                                                 ` [PATCH 13/22] remove erase regions Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:55 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

I hate casts.  This adds a line, but is much simpler to read.  Also
renames the function.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_sync2	2004-12-20 22:14:47.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 22:16:31.000000000 +0100
@@ -336,12 +336,14 @@
 
 
 /* sync the device - wait until the write queue is empty */
-static void blkmtd_sync(struct mtd_info *mtd)
+static void blockmtd_sync(struct mtd_info *mtd)
 {
-	sync_blockdev(((struct blkmtd_dev*)mtd->priv)->blkdev);
+	struct blkmtd_dev *dev = mtd->priv;
+	sync_blockdev(dev->blkdev);
 	return;
 }
 
+
 static void blockmtd_free_device(struct blkmtd_dev *dev)
 {
 	if (!dev)
@@ -479,7 +481,7 @@
 	dev->mtd_info.erase = blkmtd_erase;
 	dev->mtd_info.write = blkmtd_write;
 	dev->mtd_info.writev = default_mtd_writev;
-	dev->mtd_info.sync = blkmtd_sync;
+	dev->mtd_info.sync = blockmtd_sync;
 	dev->mtd_info.read = blkmtd_read;
 	dev->mtd_info.readv = default_mtd_readv;
 	dev->mtd_info.priv = dev;
@@ -624,7 +626,7 @@
 	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
 		struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
 						    list);
-		blkmtd_sync(&dev->mtd_info);
+		blockmtd_sync(&dev->mtd_info);
 		del_mtd_device(&dev->mtd_info);
 		INFO("mtd%d: [%s] removed", dev->mtd_info.index,
 				dev->mtd_info.name + strlen("blkmtd: "));

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 13/22] remove erase regions
  2004-12-21 13:55                                               ` [PATCH 12/22] change blockmtd_sync Jörn Engel
@ 2004-12-21 13:57                                                 ` Jörn Engel
  2004-12-21 14:01                                                   ` [PATCH 14/22] Change add_device Jörn Engel
  2004-12-21 18:42                                                   ` [PATCH 13/22] remove erase regions Christopher Hoover
  0 siblings, 2 replies; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 13:57 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

I see absolutely no reason for complicated erase reagions.  On the
user side, everyone but mtdchar effectively ignores it anyway.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   64 -------------------------------------------------------------
 1 files changed, 1 insertion(+), 63 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_erase_regions	2004-12-20 22:16:31.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 22:21:50.000000000 +0100
@@ -361,65 +361,6 @@
 }
 
 
-/* For a given size and initial erase size, calculate the number
- * and size of each erase region. Goes round the loop twice,
- * once to find out how many regions, then allocates space,
- * then round the loop again to fill it in.
- */
-static struct mtd_erase_region_info *calc_erase_regions(
-	size_t erase_size, size_t total_size, int *regions)
-{
-	struct mtd_erase_region_info *info = NULL;
-
-	/* Make any user specified erasesize be a power of 2
-	   and at least PAGE_SIZE */
-	if (erase_size) {
-		int es = erase_size;
-		erase_size = 1;
-		while (es != 1) {
-			es >>= 1;
-			erase_size <<= 1;
-		}
-		if (erase_size < PAGE_SIZE)
-			erase_size = PAGE_SIZE;
-	} else {
-		erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
-	}
-
-	*regions = 0;
-
-	do {
-		int tot_size = total_size;
-		int er_size = erase_size;
-		int count = 0, offset = 0, regcnt = 0;
-
-		while (tot_size) {
-			count = tot_size / er_size;
-			if (count) {
-				tot_size = tot_size % er_size;
-				if (info) {
-					(info + regcnt)->offset = offset;
-					(info + regcnt)->erasesize = er_size;
-					(info + regcnt)->numblocks = count;
-					(*regions)++;
-				}
-				regcnt++;
-				offset += (count * er_size);
-			}
-			while (er_size > tot_size)
-				er_size >>= 1;
-		}
-		if (info == NULL) {
-			info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
-			if (!info)
-				break;
-		}
-	} while (!(*regions));
-
-	return info;
-}
-
-
 extern dev_t __init name_to_dev_t(const char *line);
 
 static struct blkmtd_dev *add_device(char *devname, int erase_size)
@@ -471,11 +412,8 @@
 		goto devinit_err;
 
 	sprintf(dev->mtd_info.name, "blkmtd: %s", devname);
-	dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size, &dev->mtd_info.numeraseregions);
-	if (dev->mtd_info.eraseregions == NULL)
-		goto devinit_err;
 
-	dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize;
+	dev->mtd_info.erasesize = erase_size;
 	dev->mtd_info.type = MTD_RAM;
 	dev->mtd_info.flags = MTD_CAP_RAM;
 	dev->mtd_info.erase = blkmtd_erase;

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 14/22] Change add_device
  2004-12-21 13:57                                                 ` [PATCH 13/22] remove erase regions Jörn Engel
@ 2004-12-21 14:01                                                   ` Jörn Engel
  2004-12-21 14:02                                                     ` [PATCH 15/22] Rename unreadable mutex Jörn Engel
  2004-12-21 18:42                                                   ` [PATCH 13/22] remove erase regions Christopher Hoover
  1 sibling, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 14:01 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

o Remove the last remaining #ifdef.
o s/mtd_info/mtd/ makes nicer reading.
o General cleanup to add_device

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   86 ++++++++++++++++++++++++++-----------------------------------
 1 files changed, 37 insertions(+), 49 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_ifdef	2004-12-20 22:21:50.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 22:38:34.000000000 +0100
@@ -45,7 +45,7 @@
 struct blkmtd_dev {
 	struct list_head list;
 	struct block_device *blkdev;
-	struct mtd_info mtd_info;
+	struct mtd_info mtd;
 	struct semaphore wrbuf_mutex;
 };
 
@@ -349,8 +349,8 @@
 	if (!dev)
 		return;
 
-	kfree(dev->mtd_info.eraseregions);
-	kfree(dev->mtd_info.name);
+	kfree(dev->mtd.eraseregions);
+	kfree(dev->mtd.name);
 
 	if (dev->blkdev) {
 		invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping);
@@ -361,78 +361,66 @@
 }
 
 
-extern dev_t __init name_to_dev_t(const char *line);
-
 static struct blkmtd_dev *add_device(char *devname, int erase_size)
 {
 	struct block_device *bdev;
-	int mode;
 	struct blkmtd_dev *dev;
 
 	if (!devname)
 		return NULL;
 
-	/* Get a handle on the device */
+	dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+	memset(dev, 0, sizeof(*dev));
 
-#ifdef MODULE
-	mode = O_RDWR;
-	bdev = open_bdev_excl(devname, mode, NULL);
-#else
-	mode = FMODE_WRITE;
-	bdev = open_by_devnum(name_to_dev_t(devname), mode);
-#endif
+	/* Get a handle on the device */
+	bdev = open_bdev_excl(devname, O_RDWR, NULL);
 	if (IS_ERR(bdev)) {
 		ERROR("error: cannot open device %s", devname);
-		return NULL;
+		goto devinit_err;
 	}
+	dev->blkdev = bdev;
 
 	if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
 		ERROR("attempting to use an MTD device as a block device");
-		blkdev_put(bdev);
-		return NULL;
-	}
-
-	dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
-	if (dev == NULL) {
-		blkdev_put(bdev);
-		return NULL;
+		goto devinit_err;
 	}
 
-	memset(dev, 0, sizeof(struct blkmtd_dev));
-	dev->blkdev = bdev;
-	atomic_set(&(dev->blkdev->bd_inode->i_mapping->truncate_count), 0);
+	atomic_set(&bdev->bd_inode->i_mapping->truncate_count, 0);
 	init_MUTEX(&dev->wrbuf_mutex);
 
-	dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
-
 	/* Setup the MTD structure */
 	/* make the name contain the block device in */
-	dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL);
-	if (dev->mtd_info.name == NULL)
+	dev->mtd.name = kmalloc(sizeof("blockmtd: ") + strlen(devname),
+			GFP_KERNEL);
+	if (!dev->mtd.name)
 		goto devinit_err;
 
-	sprintf(dev->mtd_info.name, "blkmtd: %s", devname);
+	sprintf(dev->mtd.name, "blockmtd: %s", devname);
 
-	dev->mtd_info.erasesize = erase_size;
-	dev->mtd_info.type = MTD_RAM;
-	dev->mtd_info.flags = MTD_CAP_RAM;
-	dev->mtd_info.erase = blkmtd_erase;
-	dev->mtd_info.write = blkmtd_write;
-	dev->mtd_info.writev = default_mtd_writev;
-	dev->mtd_info.sync = blockmtd_sync;
-	dev->mtd_info.read = blkmtd_read;
-	dev->mtd_info.readv = default_mtd_readv;
-	dev->mtd_info.priv = dev;
-	dev->mtd_info.owner = THIS_MODULE;
+	dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
+	dev->mtd.erasesize = erase_size;
+	dev->mtd.type = MTD_RAM;
+	dev->mtd.flags = MTD_CAP_RAM;
+	dev->mtd.erase = blkmtd_erase;
+	dev->mtd.write = blkmtd_write;
+	dev->mtd.writev = default_mtd_writev;
+	dev->mtd.sync = blockmtd_sync;
+	dev->mtd.read = blkmtd_read;
+	dev->mtd.readv = default_mtd_readv;
+	dev->mtd.priv = dev;
+	dev->mtd.owner = THIS_MODULE;
 
 	list_add(&dev->list, &blkmtd_device_list);
-	if (add_mtd_device(&dev->mtd_info)) {
+	if (add_mtd_device(&dev->mtd)) {
 		/* Device didnt get added, so free the entry */
 		list_del(&dev->list);
 		goto devinit_err;
-	} else {
-		INFO("mtd%d: [%s] erase_size = %dKiB [%ld]", dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "), dev->mtd_info.erasesize >> 10, PAGE_SIZE);
 	}
+	INFO("mtd%d: [%s] erase_size = %dKiB [%ld]", dev->mtd.index,
+			dev->mtd.name + strlen("blkmtd: "),
+			dev->mtd.erasesize >> 10, PAGE_SIZE);
 	return dev;
 
 devinit_err:
@@ -564,10 +552,10 @@
 	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
 		struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
 						    list);
-		blockmtd_sync(&dev->mtd_info);
-		del_mtd_device(&dev->mtd_info);
-		INFO("mtd%d: [%s] removed", dev->mtd_info.index,
-				dev->mtd_info.name + strlen("blkmtd: "));
+		blockmtd_sync(&dev->mtd);
+		del_mtd_device(&dev->mtd);
+		INFO("mtd%d: [%s] removed", dev->mtd.index,
+				dev->mtd.name + strlen("blkmtd: "));
 		list_del(&dev->list);
 		blockmtd_free_device(dev);
 	}

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 15/22] Rename unreadable mutex
  2004-12-21 14:01                                                   ` [PATCH 14/22] Change add_device Jörn Engel
@ 2004-12-21 14:02                                                     ` Jörn Engel
  2004-12-21 14:03                                                       ` [PATCH 16/22] list changes Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 14:02 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

If I cannot pronounce a name, my reading abilities degrade.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_mutex	2004-12-20 22:38:34.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 22:41:15.000000000 +0100
@@ -46,7 +46,7 @@
 	struct list_head list;
 	struct block_device *blkdev;
 	struct mtd_info mtd;
-	struct semaphore wrbuf_mutex;
+	struct semaphore write_mutex;
 };
 
 
@@ -215,9 +215,9 @@
 	}
 
 	err=0;
-	down(&dev->wrbuf_mutex);
+	down(&dev->write_mutex);
 	err = buf ? my_write() : my_erase();
-	up(&dev->wrbuf_mutex);
+	up(&dev->write_mutex);
 	return err;
 }
 
@@ -388,7 +388,7 @@
 	}
 
 	atomic_set(&bdev->bd_inode->i_mapping->truncate_count, 0);
-	init_MUTEX(&dev->wrbuf_mutex);
+	init_MUTEX(&dev->write_mutex);
 
 	/* Setup the MTD structure */
 	/* make the name contain the block device in */
@@ -566,5 +566,5 @@
 module_exit(blockmtd_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk> and others");
 MODULE_DESCRIPTION("Emulate an MTD using a block device");

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 16/22] list changes
  2004-12-21 14:02                                                     ` [PATCH 15/22] Rename unreadable mutex Jörn Engel
@ 2004-12-21 14:03                                                       ` Jörn Engel
  2004-12-21 14:04                                                         ` [PATCH 17/22] Rename central struct Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 14:03 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Change some list.h calls.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   10 ++++------
 1 files changed, 4 insertions(+), 6 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_list	2004-12-20 22:41:15.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-20 22:53:00.000000000 +0100
@@ -412,12 +412,11 @@
 	dev->mtd.priv = dev;
 	dev->mtd.owner = THIS_MODULE;
 
-	list_add(&dev->list, &blkmtd_device_list);
 	if (add_mtd_device(&dev->mtd)) {
 		/* Device didnt get added, so free the entry */
-		list_del(&dev->list);
 		goto devinit_err;
 	}
+	list_add(&dev->list, &blkmtd_device_list);
 	INFO("mtd%d: [%s] erase_size = %dKiB [%ld]", dev->mtd.index,
 			dev->mtd.name + strlen("blkmtd: "),
 			dev->mtd.erasesize >> 10, PAGE_SIZE);
@@ -546,12 +545,11 @@
 
 static void __devexit blockmtd_exit(void)
 {
-	struct list_head *temp1, *temp2;
+	struct list_head *pos, *next;
 
 	/* Remove the MTD devices */
-	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
-		struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
-						    list);
+	list_for_each_safe(pos, next, &blkmtd_device_list) {
+		struct blkmtd_dev *dev = list_entry(pos, typeof(*dev), list);
 		blockmtd_sync(&dev->mtd);
 		del_mtd_device(&dev->mtd);
 		INFO("mtd%d: [%s] removed", dev->mtd.index,

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 17/22] Rename central struct
  2004-12-21 14:03                                                       ` [PATCH 16/22] list changes Jörn Engel
@ 2004-12-21 14:04                                                         ` Jörn Engel
  2004-12-21 14:06                                                           ` [PATCH 18/22] Function renaming Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 14:04 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

s/blkmtd_dev/blockmtd_dev/

Maybe "struct blockmtd" without the "_dev" would be even nicer.
Later.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   22 +++++++++++-----------
 1 files changed, 11 insertions(+), 11 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_structname	2004-12-20 22:53:00.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-21 01:07:33.000000000 +0100
@@ -42,7 +42,7 @@
 #define VERSION "$Revision: 1.23 $"
 
 /* Info for the block device */
-struct blkmtd_dev {
+struct blockmtd_dev {
 	struct list_head list;
 	struct block_device *blkdev;
 	struct mtd_info mtd;
@@ -122,7 +122,7 @@
  * out.
  */
 
-static int write_pages(struct blkmtd_dev *dev, const u_char *buf, loff_t to, size_t len, size_t *retlen)
+static int write_pages(struct blockmtd_dev *dev, const u_char *buf, loff_t to, size_t len, size_t *retlen)
 {
 	struct	page *page;
 	struct	address_space *mapping = dev->blkdev->bd_inode->i_mapping;
@@ -225,7 +225,7 @@
 /* erase a specified part of the device */
 static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
-	struct blkmtd_dev *dev = mtd->priv;
+	struct blockmtd_dev *dev = mtd->priv;
 	struct mtd_erase_region_info *einfo = mtd->eraseregions;
 	int numregions = mtd->numeraseregions;
 	size_t from;
@@ -271,7 +271,7 @@
 
 static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
 {
-	struct blkmtd_dev *dev = mtd->priv;
+	struct blockmtd_dev *dev = mtd->priv;
 	struct page *page;
 	//
 	int index = from >> PAGE_SHIFT;
@@ -318,7 +318,7 @@
 static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
 			size_t *retlen, const u_char *buf)
 {
-	struct blkmtd_dev *dev = mtd->priv;
+	struct blockmtd_dev *dev = mtd->priv;
 	int err;
 
 	if (!len)
@@ -338,13 +338,13 @@
 /* sync the device - wait until the write queue is empty */
 static void blockmtd_sync(struct mtd_info *mtd)
 {
-	struct blkmtd_dev *dev = mtd->priv;
+	struct blockmtd_dev *dev = mtd->priv;
 	sync_blockdev(dev->blkdev);
 	return;
 }
 
 
-static void blockmtd_free_device(struct blkmtd_dev *dev)
+static void blockmtd_free_device(struct blockmtd_dev *dev)
 {
 	if (!dev)
 		return;
@@ -361,15 +361,15 @@
 }
 
 
-static struct blkmtd_dev *add_device(char *devname, int erase_size)
+static struct blockmtd_dev *add_device(char *devname, int erase_size)
 {
 	struct block_device *bdev;
-	struct blkmtd_dev *dev;
+	struct blockmtd_dev *dev;
 
 	if (!devname)
 		return NULL;
 
-	dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
+	dev = kmalloc(sizeof(struct blockmtd_dev), GFP_KERNEL);
 	if (!dev)
 		return NULL;
 	memset(dev, 0, sizeof(*dev));
@@ -549,7 +549,7 @@
 
 	/* Remove the MTD devices */
 	list_for_each_safe(pos, next, &blkmtd_device_list) {
-		struct blkmtd_dev *dev = list_entry(pos, typeof(*dev), list);
+		struct blockmtd_dev *dev = list_entry(pos, typeof(*dev), list);
 		blockmtd_sync(&dev->mtd);
 		del_mtd_device(&dev->mtd);
 		INFO("mtd%d: [%s] removed", dev->mtd.index,

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 18/22] Function renaming
  2004-12-21 14:04                                                         ` [PATCH 17/22] Rename central struct Jörn Engel
@ 2004-12-21 14:06                                                           ` Jörn Engel
  2004-12-21 14:09                                                             ` [PATCH 19/22] Fold various erase functions Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 14:06 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Renames _erase and _read functions and removes some leftover erase
region stuff.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   65 +++++++++++++++++++------------------------------------------
 1 files changed, 21 insertions(+), 44 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_renames	2004-12-20 22:54:59.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-21 01:05:20.000000000 +0100
@@ -223,59 +223,36 @@
 
 
 /* erase a specified part of the device */
-static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+static int blockmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
 	struct blockmtd_dev *dev = mtd->priv;
-	struct mtd_erase_region_info *einfo = mtd->eraseregions;
-	int numregions = mtd->numeraseregions;
-	size_t from;
-	u_long len;
-	int err = -EIO;
+	size_t from = instr->addr;
+	size_t len = instr->len;
 	size_t retlen;
+	int err;
 
 	instr->state = MTD_ERASING;
-	from = instr->addr;
-	len = instr->len;
-
-	/* check erase region has valid start and length */
-	while (numregions) {
-		if (from >= einfo->offset && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
-			if (len == einfo->erasesize && ((from - einfo->offset) % einfo->erasesize == 0))
-				break;
-		}
-		numregions--;
-		einfo++;
-	}
-
-	if (!numregions) {
-		/* Not a valid erase block */
-		ERROR("erase: invalid erase request 0x%lX @ 0x%08zX", len,from);
+	err = write_pages(dev, NULL, from, len, &retlen);
+	if (err || retlen != len) {
+		ERROR("erase failed err = %d", err);
 		instr->state = MTD_ERASE_FAILED;
-		err = -EIO;
-	}
-
-	if (instr->state != MTD_ERASE_FAILED) {
-		/* do the erase */
-		err = write_pages(dev, NULL, from, len, &retlen);
-		if (err || retlen != len) {
-			ERROR("erase failed err = %d", err);
-			instr->state = MTD_ERASE_FAILED;
-		} else {
-			instr->state = MTD_ERASE_DONE;
-		}
+	} else {
+		instr->state = MTD_ERASE_DONE;
 	}
 
+	instr->state = MTD_ERASE_DONE;
 	mtd_erase_callback(instr);
 	return err;
 }
 
-static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+
+static int blockmtd_read(struct mtd_info *mtd, loff_t from, size_t len,
+		size_t *retlen, u_char *buf)
 {
 	struct blockmtd_dev *dev = mtd->priv;
 	struct page *page;
-	//
 	int index = from >> PAGE_SHIFT;
-	int offset = from - (index << PAGE_SHIFT);
+	int offset = from & (PAGE_SHIFT-1);
 	int cpylen;
 
 	if (from > mtd->size)
@@ -298,7 +275,7 @@
 		if (!page)
 			return -ENOMEM;
 		if (IS_ERR(page))
-			return -EIO;
+			return PTR_ERR(page);
 
 		memcpy(buf, page_address(page) + offset, cpylen);
 		page_cache_release(page);
@@ -308,15 +285,14 @@
 		buf += cpylen;
 		offset = 0;
 		index++;
-
 	}
 	return 0;
 }
 
 
 /* write data to the underlying device */
-static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
-			size_t *retlen, const u_char *buf)
+static int blockmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
+		size_t *retlen, const u_char *buf)
 {
 	struct blockmtd_dev *dev = mtd->priv;
 	int err;
@@ -361,6 +337,7 @@
 }
 
 
+/* FIXME: ensure that mtd->size % erase_size == 0 */
 static struct blockmtd_dev *add_device(char *devname, int erase_size)
 {
 	struct block_device *bdev;
@@ -403,11 +380,11 @@
 	dev->mtd.erasesize = erase_size;
 	dev->mtd.type = MTD_RAM;
 	dev->mtd.flags = MTD_CAP_RAM;
-	dev->mtd.erase = blkmtd_erase;
-	dev->mtd.write = blkmtd_write;
+	dev->mtd.erase = blockmtd_erase;
+	dev->mtd.write = blockmtd_write;
 	dev->mtd.writev = default_mtd_writev;
 	dev->mtd.sync = blockmtd_sync;
-	dev->mtd.read = blkmtd_read;
+	dev->mtd.read = blockmtd_read;
 	dev->mtd.readv = default_mtd_readv;
 	dev->mtd.priv = dev;
 	dev->mtd.owner = THIS_MODULE;

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 19/22] Fold various erase functions
  2004-12-21 14:06                                                           ` [PATCH 18/22] Function renaming Jörn Engel
@ 2004-12-21 14:09                                                             ` Jörn Engel
  2004-12-21 14:10                                                               ` [PATCH 20/22] Fold various write functions Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 14:09 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

After the previous 18 patches and your work, it becomes obvious that
write_pages() is effectively two functions with very little overlap.
This patch moves the erase part of that function out and simplifies
it.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |  117 ++++++++++++++++++++++++++++++-------------------------------
 1 files changed, 58 insertions(+), 59 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_erase	2004-12-21 01:52:12.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-21 02:12:15.000000000 +0100
@@ -121,70 +121,35 @@
  * part of the page being modified. Pages are added to the bio and then written
  * out.
  */
-
-static int write_pages(struct blockmtd_dev *dev, const u_char *buf, loff_t to, size_t len, size_t *retlen)
+static int my_read(struct page **page, struct address_space *mapping, int index)
+{
+	int err = 0;
+	
+	*page = page_readahead(mapping, index);
+	if (unlikely(!*page)) {
+		ERROR("unable to read page (%d) in write_pages\n", index);
+		err = -ENOMEM;
+	}
+	if (IS_ERR(*page))
+		err = PTR_ERR(*page);
+	if (err)
+		printk("READ ERROR\n");
+	return err;
+}
+static int write_pages(struct blockmtd_dev *dev, const u_char *buf, loff_t to,
+		size_t len, size_t *retlen)
 {
 	struct	page *page;
 	struct	address_space *mapping = dev->blkdev->bd_inode->i_mapping;
-	//
 	int	err	= 0;			// return status
 	int	index	= to >> PAGE_SHIFT;	// page index
 	int	offset 	= to & ~PAGE_MASK;	// page offset
-	//
-
-	static int my_read(void)
-	{
-		err=0;
-		page = page_readahead(mapping,index);
-		if( unlikely(!page) ) {
-			ERROR("unable to read page (%d) in write_pages\n", index);
-			err=-ENOMEM;
-		}
-		//if(IS_ERR(page)) err=-EIO;
-		if(err) printk("READ ERROR\n");
-		return err;
-	}
-	//
-	static int my_erase(void)
-	{
-		int pages = len >> PAGE_SHIFT;
-		unsigned char *p;
-		unsigned char *max;
-		int format;
-
-		while(pages) {
-			//printk(KERN_INFO "readahead on index (%d)\n",index);
-			if(my_read()) return err;
-
-			max = ((char*)page_address(page)+PAGE_SIZE);
-			format = 0;
-
-			for(p=(unsigned char*)page_address(page); p<max; p++) 
-				if(*p != 0xff) {
-					format=1;
-					break;
-				}
-
-			if(format) {
-				lock_page(page);
-				memset(page_address(page), 0xff, PAGE_SIZE);
-				set_page_dirty(page);
-				unlock_page(page);
-			}
-			page_cache_release(page);
-			pages--;
-			index++;
-		}
-		*retlen = len;
-		return 0;
-	}
 
 	static int my_write(void)
 	{
 		int cpylen;
 
 		if(retlen) *retlen = 0;
-		//printk(KERN_INFO "Write req: %d\n",len);
 		while(len) {
 			if((offset+len) > PAGE_SIZE) 
 				cpylen = PAGE_SIZE - offset;	// multiple pages
@@ -193,7 +158,9 @@
 			//
 			//	Get page
 			//
-			if(my_read()) return err;
+			err = my_read(&page, mapping, index);
+			if (err)
+				return err;
 			//
 			if(memcmp(page_address(page)+offset,buf,cpylen)) {
 				lock_page(page);
@@ -216,29 +183,61 @@
 
 	err=0;
 	down(&dev->write_mutex);
-	err = buf ? my_write() : my_erase();
+	err = my_write();
 	up(&dev->write_mutex);
 	return err;
 }
 
 
 /* erase a specified part of the device */
+static int _blockmtd_erase(struct blockmtd_dev *dev, loff_t to, size_t len)
+{
+	struct address_space *mapping = dev->blkdev->bd_inode->i_mapping;
+	struct page *page;
+	int index = to >> PAGE_SHIFT;	// page index
+	int pages = len >> PAGE_SHIFT;
+	u_long *p;
+	u_long *max;
+
+	while (pages) {
+		page = page_readahead(mapping, index);
+		if (!page)
+			return -ENOMEM;
+		if (IS_ERR(page))
+			return PTR_ERR(page);
+
+		max = (u_long*)page_address(page) + PAGE_SIZE;
+		for (p=(u_long*)page_address(page); p<max; p++) 
+			if (*p != -1UL) {
+				lock_page(page);
+				memset(page_address(page), 0xff, PAGE_SIZE);
+				set_page_dirty(page);
+				unlock_page(page);
+				break;
+			}
+
+		page_cache_release(page);
+		pages--;
+		index++;
+	}
+	return 0;
+}
 static int blockmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
 	struct blockmtd_dev *dev = mtd->priv;
 	size_t from = instr->addr;
 	size_t len = instr->len;
-	size_t retlen;
 	int err;
 
 	instr->state = MTD_ERASING;
-	err = write_pages(dev, NULL, from, len, &retlen);
-	if (err || retlen != len) {
+	down(&dev->write_mutex);
+	err = _blockmtd_erase(dev, from, len);
+	up(&dev->write_mutex);
+	if (err) {
 		ERROR("erase failed err = %d", err);
 		instr->state = MTD_ERASE_FAILED;
-	} else {
+	} else
 		instr->state = MTD_ERASE_DONE;
-	}
 
 	instr->state = MTD_ERASE_DONE;
 	mtd_erase_callback(instr);

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 20/22] Fold various write functions
  2004-12-21 14:09                                                             ` [PATCH 19/22] Fold various erase functions Jörn Engel
@ 2004-12-21 14:10                                                               ` Jörn Engel
  2004-12-21 14:11                                                                 ` [PATCH 21/22] Default erase size Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 14:10 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

With the erase half gone, the remaining write part can be folded into
blockmtd_write as well.  Here we go.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |  126 ++++++++++++++++++++++---------------------------------------
 1 files changed, 46 insertions(+), 80 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_write	2004-12-21 02:12:15.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-21 02:19:58.000000000 +0100
@@ -102,91 +102,13 @@
 	}
 }
 
+
 static struct page* page_readahead(struct address_space *mapping, int index)
 {
 	filler_t *filler = (filler_t*)(mapping->a_ops->readpage);
 	cache_readahead(mapping,index);
 	return read_cache_page(mapping, index, filler, NULL);
 }
-/**
- * write_pages - write block of data to device via the page cache
- * @dev: device to write to
- * @buf: data source or NULL if erase (output is set to 0xff)
- * @to: offset into output device
- * @len: amount to data to write
- * @retlen: amount of data written
- *
- * Grab pages from the page cache and fill them with the source data.
- * Non page aligned start and end result in a readin of the page and
- * part of the page being modified. Pages are added to the bio and then written
- * out.
- */
-static int my_read(struct page **page, struct address_space *mapping, int index)
-{
-	int err = 0;
-	
-	*page = page_readahead(mapping, index);
-	if (unlikely(!*page)) {
-		ERROR("unable to read page (%d) in write_pages\n", index);
-		err = -ENOMEM;
-	}
-	if (IS_ERR(*page))
-		err = PTR_ERR(*page);
-	if (err)
-		printk("READ ERROR\n");
-	return err;
-}
-static int write_pages(struct blockmtd_dev *dev, const u_char *buf, loff_t to,
-		size_t len, size_t *retlen)
-{
-	struct	page *page;
-	struct	address_space *mapping = dev->blkdev->bd_inode->i_mapping;
-	int	err	= 0;			// return status
-	int	index	= to >> PAGE_SHIFT;	// page index
-	int	offset 	= to & ~PAGE_MASK;	// page offset
-
-	static int my_write(void)
-	{
-		int cpylen;
-
-		if(retlen) *retlen = 0;
-		while(len) {
-			if((offset+len) > PAGE_SIZE) 
-				cpylen = PAGE_SIZE - offset;	// multiple pages
-			else	cpylen = len;			// this page
-			len = len - cpylen;
-			//
-			//	Get page
-			//
-			err = my_read(&page, mapping, index);
-			if (err)
-				return err;
-			//
-			if(memcmp(page_address(page)+offset,buf,cpylen)) {
-				lock_page(page);
-				memcpy(page_address(page) + offset,buf, cpylen);
-				set_page_dirty(page);
-				unlock_page(page);
-			}
-			page_cache_release(page);
-
-			if(retlen) *retlen += cpylen;
-			//
-			buf+=cpylen;
-			offset = 0;
-			index++;
-			//
-		}
-		//printk(KERN_INFO "Write act: %d\n",*retlen);
-		return 0;
-	}
-
-	err=0;
-	down(&dev->write_mutex);
-	err = my_write();
-	up(&dev->write_mutex);
-	return err;
-}
 
 
 /* erase a specified part of the device */
@@ -290,6 +212,48 @@
 
 
 /* write data to the underlying device */
+static int _blockmtd_write(struct blockmtd_dev *dev, const u_char *buf,
+		loff_t to, size_t len, size_t *retlen)
+{
+	struct page *page;
+	struct address_space *mapping = dev->blkdev->bd_inode->i_mapping;
+	int index = to >> PAGE_SHIFT;	// page index
+	int offset = to & ~PAGE_MASK;	// page offset
+	int cpylen;
+
+	if (retlen)
+		*retlen = 0;
+	while (len) {
+		if ((offset+len) > PAGE_SIZE) 
+			cpylen = PAGE_SIZE - offset;	// multiple pages
+		else
+			cpylen = len;			// this page
+		len = len - cpylen;
+
+		//	Get page
+		page = page_readahead(mapping, index);
+		if (!page)
+			return -ENOMEM;
+		if (IS_ERR(page))
+			return PTR_ERR(page);
+
+		if (memcmp(page_address(page)+offset, buf, cpylen)) {
+			lock_page(page);
+			memcpy(page_address(page) + offset, buf, cpylen);
+			set_page_dirty(page);
+			unlock_page(page);
+		}
+		page_cache_release(page);
+
+		if (retlen)
+			*retlen += cpylen;
+
+		buf += cpylen;
+		offset = 0;
+		index++;
+	}
+	return 0;
+}
 static int blockmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
 		size_t *retlen, const u_char *buf)
 {
@@ -303,7 +267,9 @@
 	if (to + len > mtd->size)
 		len = mtd->size - to;
 
-	err = write_pages(dev, buf, to, len, retlen);
+	down(&dev->write_mutex);
+	err = _blockmtd_write(dev, buf, to, len, retlen);
+	up(&dev->write_mutex);
 	if (err > 0)
 		err = 0;
 	return err;

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 21/22] Default erase size
  2004-12-21 14:10                                                               ` [PATCH 20/22] Fold various write functions Jörn Engel
@ 2004-12-21 14:11                                                                 ` Jörn Engel
  2004-12-21 14:13                                                                   ` [PATCH 22/22] Readahead Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 14:11 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

For block devices, an erase size of 0 makes little sense.  PAGE_SIZE
should be a sane default.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |    4 +---
 1 files changed, 1 insertion(+), 3 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_erasesize	2004-12-21 02:19:58.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-21 02:23:25.000000000 +0100
@@ -38,7 +38,6 @@
 
 
 /* Default erase size in K, always make it a multiple of PAGE_SIZE */
-#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10)	/* 128KiB */
 #define VERSION "$Revision: 1.23 $"
 
 /* Info for the block device */
@@ -290,7 +289,6 @@
 	if (!dev)
 		return;
 
-	kfree(dev->mtd.eraseregions);
 	kfree(dev->mtd.name);
 
 	if (dev->blkdev) {
@@ -432,7 +430,7 @@
 	char buf[80+12], *str=buf; /* 80 for device, 12 for erase size */
 	char *token[2];
 	char *name;
-	size_t erase_size = 0;
+	size_t erase_size = PAGE_SIZE;
 	int i, ret;
 
 	if (strnlen(val, sizeof(buf)) >= sizeof(buf))

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH 22/22] Readahead
  2004-12-21 14:11                                                                 ` [PATCH 21/22] Default erase size Jörn Engel
@ 2004-12-21 14:13                                                                   ` Jörn Engel
  0 siblings, 0 replies; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 14:13 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

Small changes to readahead functions.  I guess they can use some more,
but it was getting late and things looked too complicated.

Signed-off-by: Jörn Engel <joern@wohnheim.fh-wedel.de>
---

 blockmtd.c |   11 ++++-------
 1 files changed, 4 insertions(+), 7 deletions(-)

--- linux-2.6.9cow/drivers/mtd/devices/blockmtd.c~blockmtd_readahead	2004-12-21 02:24:35.000000000 +0100
+++ linux-2.6.9cow/drivers/mtd/devices/blockmtd.c	2004-12-21 02:30:03.000000000 +0100
@@ -54,10 +54,9 @@
 
 
 #define PAGE_READAHEAD 64
-
 void cache_readahead(struct address_space *mapping, int index)
 {
-	filler_t *filler = (void*)mapping->a_ops->readpage;
+	filler_t *filler = (filler_t*)mapping->a_ops->readpage;
 	int i, pagei;
 	unsigned ret = 0;
 	unsigned long end_index;
@@ -95,17 +94,15 @@
 		ret++;
 	}
 	spin_unlock_irq(&mapping->tree_lock);
-	if (ret) {
+	if (ret)
 		read_cache_pages(mapping, &page_pool, filler, NULL);
-		//printk(KERN_INFO "Readahead [%d/%d] pages from [%d]\n",ret,PAGE_READAHEAD,index);
-	}
 }
 
 
 static struct page* page_readahead(struct address_space *mapping, int index)
 {
-	filler_t *filler = (filler_t*)(mapping->a_ops->readpage);
-	cache_readahead(mapping,index);
+	filler_t *filler = (filler_t*)mapping->a_ops->readpage;
+	cache_readahead(mapping, index);
 	return read_cache_page(mapping, index, filler, NULL);
 }
 

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH 1/22] Add drivers/mtd/devices/blockmtd.c
  2004-12-21 13:42                           ` [PATCH 1/22] Add drivers/mtd/devices/blockmtd.c Gareth Bult (Encryptec)
@ 2004-12-21 14:15                             ` Jörn Engel
  0 siblings, 0 replies; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 14:15 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

On Tue, 21 December 2004 13:42:41 +0000, Gareth Bult (Encryptec) wrote:
> 
> Gimmie a clue - what did you change ?

Nothing yet.  But you should have the other 21 patches by now.  In
case you never dealt with inline patches, you can simply save the mail
(with all headers etc.) as a file and patch your preferred kernel with
that file.  Patch is smart enough to ignore private chitchat.

Jörn

-- 
All art is but imitation of nature.
-- Lucius Annaeus Seneca

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
  2004-12-21 13:40                         ` JFFS2 mount time Gareth Bult (Encryptec)
@ 2004-12-21 15:00                           ` David Woodhouse
       [not found]                             ` <1103644945.10792.175.camel@squizzey.bult.co.uk>
  0 siblings, 1 reply; 70+ messages in thread
From: David Woodhouse @ 2004-12-21 15:00 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD

On Tue, 2004-12-21 at 13:40 +0000, Gareth Bult (Encryptec) wrote:
> .. and I find the patches where ?

On the list after I approved all 22 of them; they were trapped for
moderation because they had attachments. After looking at one or two of
yours which were also trapped, I approved them all because I thought
they were all due to the GPG signature. Unfortunately I let through an
HTML mail. Please don't send those -- and please don't top-post either.

-- 
dwmw2

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: JFFS2 mount time
       [not found]                             ` <1103644945.10792.175.camel@squizzey.bult.co.uk>
@ 2004-12-21 16:04                               ` Jörn Engel
  0 siblings, 0 replies; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 16:04 UTC (permalink / raw)
  To: Gareth Bult (Encryptec); +Cc: Linux MTD, David Woodhouse

On Tue, 21 December 2004 16:02:25 +0000, Gareth Bult (Encryptec) wrote:
> 
> Ahhhhhh!

I get that a lot. ;)

Jörn

-- 
Fantasy is more important than knowledge. Knowledge is limited,
while fantasy embraces the whole world.
-- Albert Einstein

^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH 13/22] remove erase regions
  2004-12-21 13:57                                                 ` [PATCH 13/22] remove erase regions Jörn Engel
  2004-12-21 14:01                                                   ` [PATCH 14/22] Change add_device Jörn Engel
@ 2004-12-21 18:42                                                   ` Christopher Hoover
  2004-12-21 18:49                                                     ` Jörn Engel
  1 sibling, 1 reply; 70+ messages in thread
From: Christopher Hoover @ 2004-12-21 18:42 UTC (permalink / raw)
  To: 'Jörn Engel'; +Cc: 'Linux MTD'

 
>From Jörn Engel -
> I see absolutely no reason for complicated erase reagions.  On the
> user side, everyone but mtdchar effectively ignores it anyway.

I don't grok this.   What about flash with variable-sized blocks?  (I have a
board with such flash and code that uses eraseregions.)

-ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH 13/22] remove erase regions
  2004-12-21 18:42                                                   ` [PATCH 13/22] remove erase regions Christopher Hoover
@ 2004-12-21 18:49                                                     ` Jörn Engel
  2004-12-21 21:09                                                       ` Christopher Hoover
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-21 18:49 UTC (permalink / raw)
  To: Christopher Hoover; +Cc: 'Linux MTD'

On Tue, 21 December 2004 10:42:07 -0800, Christopher Hoover wrote:
> >From Jörn Engel -
> > I see absolutely no reason for complicated erase reagions.  On the
> > user side, everyone but mtdchar effectively ignores it anyway.
> 
> I don't grok this.   What about flash with variable-sized blocks?  (I have a
> board with such flash and code that uses eraseregions.)

Sure, from AMD or some other compatible manufacturer.  The
variable-sized blocks were nice until there were better solutions to
the problem, like jffs2.  Jffs2 exists, so they are largely useless.

Last time I looked, there were five users of mtd devices:
1. jffs
2. jffs2
3. yaffs
4. mtdblock
5. mtdchar

1 and 2 don't use the smaller blocks.  3 doesn't work with NOR-flash
anyway.  4 doesn't use the smaller blocks.  5 does, but is horribly
ugly and noone cares enough to clean it up.  You do the math.

1, 2 and 4 effectively use the smaller blocks as if they were a single
larger block.  So the space is not wasted, but that's about it.

Jörn

-- 
With a PC, I always felt limited by the software available. On Unix, 
I am limited only by my knowledge.
-- Peter J. Schoenster

^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH 13/22] remove erase regions
  2004-12-21 18:49                                                     ` Jörn Engel
@ 2004-12-21 21:09                                                       ` Christopher Hoover
  2004-12-22  2:47                                                         ` Eric W. Biederman
  0 siblings, 1 reply; 70+ messages in thread
From: Christopher Hoover @ 2004-12-21 21:09 UTC (permalink / raw)
  To: 'Jörn Engel'; +Cc: 'Linux MTD'



>From Jörn Engel [mailto:joern@wohnheim.fh-wedel.de] - 
> On Tue, 21 December 2004 10:42:07 -0800, Christopher Hoover wrote:
> > >From Jörn Engel -
> > > I see absolutely no reason for complicated erase reagions.  On the
> > > user side, everyone but mtdchar effectively ignores it anyway.
> > 
> > I don't grok this.   What about flash with variable-sized 
> blocks?  (I have a
> > board with such flash and code that uses eraseregions.)
> 
> Sure, from AMD or some other compatible manufacturer.  The
> variable-sized blocks were nice until there were better solutions to
> the problem, like jffs2.  Jffs2 exists, so they are largely useless.

Intel C3 flash, too.

> 5. mtdchar

This is an important case.  

The reason embedded systems use flash with variable sized blocks is for (in
the small blocks) parameter stores for bootloaders and applications.

I've got several deployed systems that use this technique.  I've seen at
least one other.


> 5 does, but is horribly ugly and noone cares enough to clean it up. 

This is not a reason to toss it.  We don't capriciously break user space
interfaces in Linux.

Also this:

6. The hook that unlocks locked-on-power-up flash, such as (*surprise*) C3
flash.  It needs to call unlock with the start address of each block.  It
needs eraseergions to do that.

-ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH 13/22] remove erase regions
  2004-12-21 21:09                                                       ` Christopher Hoover
@ 2004-12-22  2:47                                                         ` Eric W. Biederman
  2004-12-22  8:59                                                           ` Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Eric W. Biederman @ 2004-12-22  2:47 UTC (permalink / raw)
  To: Christopher Hoover; +Cc: 'Linux, MTD'

"Christopher Hoover" <ch@murgatroid.com> writes:

> >From Jörn Engel [mailto:joern@wohnheim.fh-wedel.de] - 
> > On Tue, 21 December 2004 10:42:07 -0800, Christopher Hoover wrote:
> > > >From Jörn Engel -
> > > > I see absolutely no reason for complicated erase reagions.  On the
> > > > user side, everyone but mtdchar effectively ignores it anyway.
> > > 
> > > I don't grok this.   What about flash with variable-sized 
> > blocks?  (I have a
> > > board with such flash and code that uses eraseregions.)
> > 
> > Sure, from AMD or some other compatible manufacturer.  The
> > variable-sized blocks were nice until there were better solutions to
> > the problem, like jffs2.  Jffs2 exists, so they are largely useless.

jffs2 is only a solution on large NOR flash parts.

However I find this conversation confusing.  The patches appear to affect
just mtdblock.c.  Which sounds like it is exclusively the mtd block device.
At which point I don't see a problem with simply removing variable erase
size for the silly block device emulation code.

Now if someone wants to remove something silly the block device emulation
sounds like a fine place to start.  Just to place the silliness on the
other foot.
 
> Intel C3 flash, too.
> 
> > 5. mtdchar
> 
> This is an important case.  
> 
> The reason embedded systems use flash with variable sized blocks is for (in
> the small blocks) parameter stores for bootloaders and applications.
> 
> I've got several deployed systems that use this technique.  I've seen at
> least one other.

> > 5 does, but is horribly ugly and noone cares enough to clean it up. 

If it ain't broke don't fix it.  Besides I have trouble seeing how 500 lines
of code can be horribly ugly.  
 
> This is not a reason to toss it.  We don't capriciously break user space
> interfaces in Linux.
> 
> Also this:
> 
> 6. The hook that unlocks locked-on-power-up flash, such as (*surprise*) C3
> flash.  It needs to call unlock with the start address of each block.  It
> needs eraseergions to do that.

If Christopher is reading this right I agree that killing variable
erase sizes across the board is a very bad idea.

Eric

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH 13/22] remove erase regions
  2004-12-22  2:47                                                         ` Eric W. Biederman
@ 2004-12-22  8:59                                                           ` Jörn Engel
  2004-12-22 10:05                                                             ` Eric W. Biederman
  0 siblings, 1 reply; 70+ messages in thread
From: Jörn Engel @ 2004-12-22  8:59 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Christopher Hoover, 'Linux MTD'

On Tue, 21 December 2004 19:47:00 -0700, Eric W. Biederman wrote:
> "Christopher Hoover" <ch@murgatroid.com> writes:
> > >From Jörn Engel [mailto:joern@wohnheim.fh-wedel.de] - 
> > > On Tue, 21 December 2004 10:42:07 -0800, Christopher Hoover wrote:
> > > > >From Jörn Engel -
> > > > > I see absolutely no reason for complicated erase reagions.  On the
> > > > > user side, everyone but mtdchar effectively ignores it anyway.
> > > > 
> > > > I don't grok this.   What about flash with variable-sized 
> > > blocks?  (I have a
> > > > board with such flash and code that uses eraseregions.)
> > > 
> > > Sure, from AMD or some other compatible manufacturer.  The
> > > variable-sized blocks were nice until there were better solutions to
> > > the problem, like jffs2.  Jffs2 exists, so they are largely useless.
> 
> jffs2 is only a solution on large NOR flash parts.

True.  I've been meaning to scale jffs2 down, but never found the
time.

> However I find this conversation confusing.  The patches appear to affect
> just mtdblock.c.

The other way around, blockmtd.c.  Which is a cleaned up version of
blkmtd.c.  It turns a block device into an mtd device, not vice versa.
Name is confusing, so if you have a better one...

> Which sounds like it is exclusively the mtd block device.
> At which point I don't see a problem with simply removing variable erase
> size for the silly block device emulation code.
> 
> Now if someone wants to remove something silly the block device emulation
> sounds like a fine place to start.  Just to place the silliness on the
> other foot.

Both emulations have valid uses:
mtd -> block device:
Very simple block devices.  It is much simpler to write an mtd device
than a block device.  Right now, all known-to-me users of phram use it
as a block device.

block device -> mtd:
Cheap flash media.  Jffs2 helps on usb sticks as well, so turn those
puppies into mtds and be done.

> > > 5 does, but is horribly ugly and noone cares enough to clean it up. 
> 
> If it ain't broke don't fix it.  Besides I have trouble seeing how 500 lines
> of code can be horribly ugly.  

o read-only devices that confuse every single new user
o #define MAX_KMALLOC_SIZE 0x20000
o FIXME: This _really_ needs to die. In 2.5, we should ...

> > This is not a reason to toss it.  We don't capriciously break user space
> > interfaces in Linux.

I don't.  Instead I take a driver I'm unhappy with, copy it, and
change the parts I don't like in the copy.  Nothing breaks on your
side.

> > Also this:
> > 
> > 6. The hook that unlocks locked-on-power-up flash, such as (*surprise*) C3
> > flash.  It needs to call unlock with the start address of each block.  It
> > needs eraseergions to do that.
> 
> If Christopher is reading this right I agree that killing variable
> erase sizes across the board is a very bad idea.

He isn't.

To finally lift all the confusion:
This is about the blockmtd driver, nothing else.  Said driver takes a
block device and turns it into an mtd.  And for an bd-based mtd, there
is _no_ point in having complicated erase regions.

For regular flash, I consider them to be silly as well, but there are
so many silly things that people like.  Let them have fun, as long as
noone gets hurt.

Jörn

-- 
The only real mistake is the one from which we learn nothing.
-- John Powell

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH 13/22] remove erase regions
  2004-12-22  8:59                                                           ` Jörn Engel
@ 2004-12-22 10:05                                                             ` Eric W. Biederman
  2004-12-22 10:41                                                               ` Jörn Engel
  0 siblings, 1 reply; 70+ messages in thread
From: Eric W. Biederman @ 2004-12-22 10:05 UTC (permalink / raw)
  To: Jörn Engel; +Cc: Christopher Hoover, 'Linux MTD'

Jörn Engel <joern@wohnheim.fh-wedel.de> writes:

> On Tue, 21 December 2004 19:47:00 -0700, Eric W. Biederman wrote:
> > jffs2 is only a solution on large NOR flash parts.
> 
> True.  I've been meaning to scale jffs2 down, but never found the
> time.

I keep trying to scale my flash chips up but that is non-trivial
on commodity motherboards :)

Until jffs2 is an effective solution on the very small flash
parts there will be a use for variable size flash blocks.

The flash parts I typically work with are 256KiB to 1MiB.
Usually with most blocks at 64KiB, although some variants have 4KiB
blocks.

On a 4KiB flash I could probably afford to not use a spare flash block
or two.   For the common case of 64KiB I don't see how I could leave
an entire flash block unused.  Which is the very hard part of scaling
jffs2 down to the tiniest systems.

> The other way around, blockmtd.c.  Which is a cleaned up version of
> blkmtd.c.  It turns a block device into an mtd device, not vice versa.
> Name is confusing, so if you have a better one...

block2mtd ?

> Both emulations have valid uses:

Agreed.

> > > > 5 does, but is horribly ugly and noone cares enough to clean it up. 
> > 
> > If it ain't broke don't fix it.  Besides I have trouble seeing how 500 lines
> > of code can be horribly ugly.  
> 
> o read-only devices that confuse every single new user

Agreed.  The read-only devices are silly.

> o #define MAX_KMALLOC_SIZE 0x20000
> o FIXME: This _really_ needs to die. In 2.5, we should ...

I see more problems with where the code wanted to go, as indicated
by those comments than with where the code is now.  Probably
allocating a single buffer page and calling down into the mtd device
layer multiple times.  I have trouble seeing the benefit
of making it a zero copy interface.

But none of this counts as horribly ugly in my book.  Just
warts that may benefit from being cleaned up.

Some of the current IB stacks count get a lot closer to horribly ugly.
Several hundred lines of global variables in one file I count horribly
ugly.  At 500 lines I can see ugly code, but it is hard to write
something that is a disaster that is that small.  The obfuscated C
contest shows you can do it but we certainly don't have that.

> > 
> > If Christopher is reading this right I agree that killing variable
> > erase sizes across the board is a very bad idea.
> 
> He isn't.
> 
> To finally lift all the confusion:
> This is about the blockmtd driver, nothing else.  Said driver takes a
> block device and turns it into an mtd.  And for an bd-based mtd, there
> is _no_ point in having complicated erase regions.
> 
> For regular flash, I consider them to be silly as well, but there are
> so many silly things that people like.  Let them have fun, as long as
> noone gets hurt.

Agreed.

So have your fun with block2mtd and I won't worry about it.

Eric

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH 13/22] remove erase regions
  2004-12-22 10:05                                                             ` Eric W. Biederman
@ 2004-12-22 10:41                                                               ` Jörn Engel
  0 siblings, 0 replies; 70+ messages in thread
From: Jörn Engel @ 2004-12-22 10:41 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Christopher Hoover, 'Linux MTD'

On Wed, 22 December 2004 03:05:06 -0700, Eric W. Biederman wrote:
> 
> On a 4KiB flash I could probably afford to not use a spare flash block
> or two.   For the common case of 64KiB I don't see how I could leave
> an entire flash block unused.  Which is the very hard part of scaling
> jffs2 down to the tiniest systems.

Yup.  One block (plus a few bytes) is the lower bound.  Below that,
you can read-modify-erase-update and hope the power won't fail before
you're done.  Not fun.

> block2mtd ?

Deal.

> I see more problems with where the code wanted to go, as indicated
> by those comments than with where the code is now.  Probably
> allocating a single buffer page and calling down into the mtd device
> layer multiple times.  I have trouble seeing the benefit
> of making it a zero copy interface.
> 
> But none of this counts as horribly ugly in my book.  Just
> warts that may benefit from being cleaned up.
> 
> Some of the current IB stacks count get a lot closer to horribly ugly.
> Several hundred lines of global variables in one file I count horribly
> ugly.  At 500 lines I can see ugly code, but it is hard to write
> something that is a disaster that is that small.  The obfuscated C
> contest shows you can do it but we certainly don't have that.

Agreed.  Just ugly then.

> So have your fun with block2mtd and I won't worry about it.

;)

Jörn

-- 
Those who come seeking peace without a treaty are plotting.
-- Sun Tzu

^ permalink raw reply	[flat|nested] 70+ messages in thread

end of thread, other threads:[~2004-12-22 10:41 UTC | newest]

Thread overview: 70+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-12-15 23:19 JFFS2 mount time Gareth Bult (Encryptec)
2004-12-16  0:15 ` Josh Boyer
2004-12-16  1:02   ` Gareth Bult (Encryptec)
2004-12-16 12:53     ` Josh Boyer
2004-12-16 21:22       ` Gareth Bult (Encryptec)
2004-12-16 21:28         ` Josh Boyer
2004-12-16 21:47           ` Gareth Bult (Encryptec)
2004-12-17 12:54             ` Josh Boyer
2004-12-17 15:33               ` Gareth Bult (Encryptec)
2004-12-17 16:02                 ` Josh Boyer
2004-12-17 16:46                   ` Gareth Bult (Encryptec)
2004-12-17 17:08                     ` Artem B. Bityuckiy
2004-12-17 17:10                     ` Josh Boyer
2004-12-17 17:26                       ` Gareth Bult (Encryptec)
2004-12-17 17:35                         ` Josh Boyer
2004-12-17 18:09                           ` Gareth Bult (Encryptec)
2004-12-17 19:14                             ` jasmine
2004-12-17 20:55                               ` Gareth Bult (Encryptec)
2004-12-18 16:02                           ` Jörn Engel
2004-12-20 16:34                             ` Josh Boyer
2004-12-20 17:12                               ` Gareth Bult (Encryptec)
2004-12-21 13:09                                 ` Jörn Engel
2004-12-21 13:24                                   ` Gareth Bult (Encryptec)
2004-12-21 13:34                                     ` Jörn Engel
2004-12-18 16:19             ` Jörn Engel
2004-12-18 17:32               ` Gareth Bult (Encryptec)
2004-12-18 17:52                 ` Jörn Engel
2004-12-18 18:11                   ` Jörn Engel
2004-12-18 20:48                     ` Gareth Bult (Encryptec)
2004-12-19  2:44                       ` Jörn Engel
2004-12-21 13:30                       ` Jörn Engel
2004-12-21 13:39                         ` [PATCH 1/22] Add drivers/mtd/devices/blockmtd.c Jörn Engel
2004-12-21 13:41                           ` [PATCH 2/22] Add copyrights Jörn Engel
2004-12-21 13:42                             ` [PATCH 3/22] Remove read-only option Jörn Engel
2004-12-21 13:44                               ` [PATCH 4/22] Change init/exit functions Jörn Engel
2004-12-21 13:45                                 ` [PATCH 5/22] Remove gcc warnings Jörn Engel
2004-12-21 13:47                                   ` [PATCH 6/22] Remove debug macros Jörn Engel
2004-12-21 13:48                                     ` [PATCH 7/22] Lindent Jörn Engel
2004-12-21 13:49                                       ` [PATCH 8/22] Remove sync interface Jörn Engel
2004-12-21 13:51                                         ` [PATCH 9/22] Change parameter interface to phram-style Jörn Engel
2004-12-21 13:53                                           ` [PATCH 10/22] Cleanup macro usage Jörn Engel
2004-12-21 13:54                                             ` [PATCH 11/22] kfree simplifications Jörn Engel
2004-12-21 13:55                                               ` [PATCH 12/22] change blockmtd_sync Jörn Engel
2004-12-21 13:57                                                 ` [PATCH 13/22] remove erase regions Jörn Engel
2004-12-21 14:01                                                   ` [PATCH 14/22] Change add_device Jörn Engel
2004-12-21 14:02                                                     ` [PATCH 15/22] Rename unreadable mutex Jörn Engel
2004-12-21 14:03                                                       ` [PATCH 16/22] list changes Jörn Engel
2004-12-21 14:04                                                         ` [PATCH 17/22] Rename central struct Jörn Engel
2004-12-21 14:06                                                           ` [PATCH 18/22] Function renaming Jörn Engel
2004-12-21 14:09                                                             ` [PATCH 19/22] Fold various erase functions Jörn Engel
2004-12-21 14:10                                                               ` [PATCH 20/22] Fold various write functions Jörn Engel
2004-12-21 14:11                                                                 ` [PATCH 21/22] Default erase size Jörn Engel
2004-12-21 14:13                                                                   ` [PATCH 22/22] Readahead Jörn Engel
2004-12-21 18:42                                                   ` [PATCH 13/22] remove erase regions Christopher Hoover
2004-12-21 18:49                                                     ` Jörn Engel
2004-12-21 21:09                                                       ` Christopher Hoover
2004-12-22  2:47                                                         ` Eric W. Biederman
2004-12-22  8:59                                                           ` Jörn Engel
2004-12-22 10:05                                                             ` Eric W. Biederman
2004-12-22 10:41                                                               ` Jörn Engel
2004-12-21 13:42                           ` [PATCH 1/22] Add drivers/mtd/devices/blockmtd.c Gareth Bult (Encryptec)
2004-12-21 14:15                             ` Jörn Engel
2004-12-21 13:40                         ` JFFS2 mount time Gareth Bult (Encryptec)
2004-12-21 15:00                           ` David Woodhouse
     [not found]                             ` <1103644945.10792.175.camel@squizzey.bult.co.uk>
2004-12-21 16:04                               ` Jörn Engel
2004-12-16 13:43 ` Ferenc Havasi
2004-12-20 16:01   ` Gareth Bult (Encryptec)
2004-12-20 16:09     ` Ferenc Havasi
2004-12-20 16:39       ` Gareth Bult (Encryptec)
2004-12-20 17:48       ` Gareth Bult (Encryptec)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.