JFFS2 mount time
Gareth Bult (Encryptec)
Gareth at Encryptec.net
Mon Dec 20 11:01:04 EST 2004
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 at inf.u-szeged.hu>,
> + * Zoltan Sogor <weth at inf.u-szeged.hu>,
> + * Patrik Kluba <pajko at 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 at inf.u-szeged.hu>,
> + * Zoltan Sogor <weth at inf.u-szeged.hu>,
> + * Patrik Kluba <pajko at 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 at inf.u-szeged.hu>,
> + * Ferenc Havasi <havasi at inf.u-szeged.hu>,
> + * Patrik Kluba <pajko at 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/
More information about the linux-mtd
mailing list