Mercurial > flash_v2
changeset 1118:18f99a0f0059
Merge with latest CVS from infradead.org
line wrap: on
line diff
--- a/packages/fs/jffs2/current/cdl/jffs2.cdl +++ b/packages/fs/jffs2/current/cdl/jffs2.cdl @@ -4,6 +4,8 @@ # # JFFS2 Filesystem configuration data # +# $Id: jffs2.cdl,v 1.5 2003/07/15 20:42:32 gthomas Exp $ +# # ==================================================================== #####ECOSGPLCOPYRIGHTBEGIN#### ## -------------------------------------------
--- a/packages/fs/jffs2/current/include/linux/jffs2.h +++ b/packages/fs/jffs2/current/include/linux/jffs2.h @@ -8,7 +8,7 @@ * For licensing information, see the file 'LICENCE' in the * jffs2 directory. * - * $Id: jffs2.h,v 1.29 2003/01/22 11:59:23 dwmw2 Exp $ + * $Id: jffs2.h,v 1.30 2003/02/15 00:15:22 dwmw2 Exp $ * */ @@ -24,7 +24,7 @@ /* Values we may expect to find in the 'magic' field */ #define JFFS2_OLD_MAGIC_BITMASK 0x1984 #define JFFS2_MAGIC_BITMASK 0x1985 -#define KSAMTIB_CIGAM_2SFFJ 0x5981 /* For detecting wrong-endian fs */ +#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */ #define JFFS2_EMPTY_BITMASK 0xffff #define JFFS2_DIRTY_BITMASK 0x0000
--- a/packages/fs/jffs2/current/include/linux/jffs2_fs_sb.h +++ b/packages/fs/jffs2/current/include/linux/jffs2_fs_sb.h @@ -1,4 +1,4 @@ -/* $Id: jffs2_fs_sb.h,v 1.37 2003/01/17 16:04:44 dwmw2 Exp $ */ +/* $Id: jffs2_fs_sb.h,v 1.39 2003/06/30 14:36:47 dwmw2 Exp $ */ #ifndef _JFFS2_FS_SB #define _JFFS2_FS_SB @@ -84,6 +84,7 @@ struct jffs2_sb_info { to an obsoleted node. I don't like this. Alternatives welcomed. */ struct semaphore erase_free_sem; +#ifdef CONFIG_JFFS2_FS_NAND /* Write-behind buffer for NAND flash */ unsigned char *wbuf; uint32_t wbuf_ofs; @@ -92,6 +93,13 @@ struct jffs2_sb_info { struct work_struct wbuf_task; /* task for timed wbuf flush */ struct timer_list wbuf_timer; /* timer for flushing wbuf */ + /* Information about out-of-band area usage... */ + struct nand_oobinfo *oobinfo; + uint32_t badblock_pos; + uint32_t fsdata_pos; + uint32_t fsdata_len; +#endif + /* OS-private pointer for getting back to master superblock info */ void *os_priv; };
--- a/packages/fs/jffs2/current/src/build.c +++ b/packages/fs/jffs2/current/src/build.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: build.c,v 1.44 2003/01/17 16:04:16 dwmw2 Exp $ + * $Id: build.c,v 1.46 2003/04/29 17:12:26 gleixner Exp $ * */ @@ -19,8 +19,30 @@ int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *); int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *); +static inline struct jffs2_inode_cache * +first_inode_chain(int *i, struct jffs2_sb_info *c) +{ + for (; *i < INOCACHE_HASHSIZE; (*i)++) { + if (c->inocache_list[*i]) + return c->inocache_list[*i]; + } + return NULL; +} -#define for_each_inode(i, c, ic) for (i=0; i<INOCACHE_HASHSIZE; i++) for (ic=c->inocache_list[i]; ic; ic=ic->next) +static inline struct jffs2_inode_cache * +next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c) +{ + /* More in this chain? */ + if (ic->next) + return ic->next; + (*i)++; + return first_inode_chain(i, c); +} + +#define for_each_inode(i, c, ic) \ + for (i = 0, ic = first_inode_chain(&i, (c)); \ + ic; \ + ic = next_inode(&i, ic, (c))) /* Scan plan: - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go
--- a/packages/fs/jffs2/current/src/compr_rtime.c +++ b/packages/fs/jffs2/current/src/compr_rtime.c @@ -7,13 +7,13 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr_rtime.c,v 1.9 2002/05/20 14:56:37 dwmw2 Exp $ + * $Id: compr_rtime.c,v 1.10 2003/05/11 10:47:13 dwmw2 Exp $ * * * Very simple lz77-ish encoder. * * Theory of operation: Both encoder and decoder have a list of "last - * occurances" for every possible source-value; after sending the + * occurrences" for every possible source-value; after sending the * first source-byte, the second byte indicated the "run" length of * matches * @@ -30,7 +30,7 @@ int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen) { - int positions[256]; + short positions[256]; int outpos = 0; int pos=0; @@ -70,7 +70,7 @@ int jffs2_rtime_compress(unsigned char * void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen) { - int positions[256]; + short positions[256]; int outpos = 0; int pos=0;
--- a/packages/fs/jffs2/current/src/compr_zlib.c +++ b/packages/fs/jffs2/current/src/compr_zlib.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr_zlib.c,v 1.22 2003/01/12 13:21:28 dwmw2 Exp $ + * $Id: compr_zlib.c,v 1.23 2003/05/26 09:15:19 dwmw2 Exp $ * */ @@ -17,7 +17,8 @@ #include <linux/config.h> #include <linux/kernel.h> -#include <linux/mtd/compatmac.h> /* for min() */ +#include <linux/vmalloc.h> +#include <linux/init.h> #include <linux/slab.h> #include <linux/zlib.h> #include <linux/zutil.h>
--- a/packages/fs/jffs2/current/src/erase.c +++ b/packages/fs/jffs2/current/src/erase.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: erase.c,v 1.49 2003/01/21 18:11:28 dwmw2 Exp $ + * $Id: erase.c,v 1.51 2003/05/11 22:47:36 dwmw2 Exp $ * */ @@ -52,6 +52,8 @@ void jffs2_erase_block(struct jffs2_sb_i list_del(&jeb->list); list_add(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; + c->dirty_size += c->sector_size; + jeb->dirty_size = c->sector_size; spin_unlock(&c->erase_completion_lock); return; } @@ -85,6 +87,8 @@ void jffs2_erase_block(struct jffs2_sb_i list_del(&jeb->list); list_add(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; + c->dirty_size += c->sector_size; + jeb->dirty_size = c->sector_size; spin_unlock(&c->erase_completion_lock); return; } @@ -94,12 +98,6 @@ void jffs2_erase_block(struct jffs2_sb_i else printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret); - /* Note: This is almost identical to jffs2_erase_failed() except - for the fact that we used spin_lock() not spin_lock(). If - we could use spin_lock() from a BH, we could merge them. - Or if we abandon the idea that MTD drivers may call the erase - callback from a BH, I suppose :) - */ jffs2_erase_failed(c, jeb); }
--- a/packages/fs/jffs2/current/src/fs-ecos.c +++ b/packages/fs/jffs2/current/src/fs-ecos.c @@ -8,7 +8,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: fs-ecos.c,v 1.8 2003/01/21 18:13:01 dwmw2 Exp $ + * $Id: fs-ecos.c,v 1.9 2003/07/15 20:42:33 gthomas Exp $ * */
--- a/packages/fs/jffs2/current/src/gc.c +++ b/packages/fs/jffs2/current/src/gc.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: gc.c,v 1.100 2003/01/22 14:43:51 dwmw2 Exp $ + * $Id: gc.c,v 1.103 2003/05/22 18:01:02 dwmw2 Exp $ * */ @@ -122,8 +122,6 @@ int jffs2_garbage_collect_pass(struct jf return -EINTR; for (;;) { - struct jffs2_inode_cache *ic; - spin_lock(&c->erase_completion_lock); if (!c->unchecked_size) break; @@ -191,8 +189,10 @@ int jffs2_garbage_collect_pass(struct jf D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%d\n", ic->ino)); ret = jffs2_do_crccheck_inode(c, ic); - if (!ret) - jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); + if (ret) + printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino); + + jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); up(&c->alloc_sem); return ret; } @@ -624,7 +624,7 @@ static int jffs2_garbage_collect_metadat { struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; - unsigned short dev; + jint16_t dev; char *mdata = NULL, mdatalen = 0; uint32_t alloclen, phys_ofs; int ret; @@ -633,8 +633,8 @@ static int jffs2_garbage_collect_metadat S_ISCHR(JFFS2_F_I_MODE(f)) ) { /* For these, we don't actually need to read the old node */ /* FIXME: for minor or major > 255. */ - dev = ((JFFS2_F_I_RDEV_MAJ(f) << 8) | - JFFS2_F_I_RDEV_MIN(f)); + dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | + JFFS2_F_I_RDEV_MIN(f))); mdata = (char *)&dev; mdatalen = sizeof(dev); D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen));
--- a/packages/fs/jffs2/current/src/nodelist.c +++ b/packages/fs/jffs2/current/src/nodelist.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.c,v 1.75 2003/01/21 18:11:28 dwmw2 Exp $ + * $Id: nodelist.c,v 1.79 2003/04/08 08:20:01 dwmw2 Exp $ * */ @@ -159,6 +159,14 @@ int jffs2_get_inode_nodes(struct jffs2_s err = -EIO; goto free_out; } + /* sanity check */ + if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) { + printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n", + ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen)); + jffs2_mark_node_obsolete(c, ref); + spin_lock(&c->erase_completion_lock); + continue; + } if (je32_to_cpu(node.d.version) > *highest_version) *highest_version = je32_to_cpu(node.d.version); if (ref_obsolete(ref)) { @@ -167,6 +175,7 @@ int jffs2_get_inode_nodes(struct jffs2_s ref_offset(ref)); BUG(); } + fd = jffs2_alloc_full_dirent(node.d.nsize+1); if (!fd) { err = -ENOMEM; @@ -248,6 +257,18 @@ int jffs2_get_inode_nodes(struct jffs2_s spin_lock(&c->erase_completion_lock); continue; } + + /* sanity checks */ + if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) || + PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) { + printk(KERN_NOTICE "jffs2_get_inode_nodes(): Inode corrupted at 0x%08x, totlen %d, #ino %d, version %d, isize %d, csize %d, dsize %d \n", + ref_offset(ref), 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)); + jffs2_mark_node_obsolete(c, ref); + spin_lock(&c->erase_completion_lock); + continue; + } if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) { unsigned char *buf=NULL; @@ -429,7 +450,7 @@ void jffs2_set_inocache_state(struct jff Rather than introducing special case get_ino_cache functions or callbacks, we just let the caller do the locking itself. */ -struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, int ino) +struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino) { struct jffs2_inode_cache *ret;
--- a/packages/fs/jffs2/current/src/nodelist.h +++ b/packages/fs/jffs2/current/src/nodelist.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.h,v 1.92 2003/01/22 14:43:29 dwmw2 Exp $ + * $Id: nodelist.h,v 1.94 2003/07/03 10:35:45 dwmw2 Exp $ * */ @@ -29,7 +29,7 @@ #endif #ifndef CONFIG_JFFS2_FS_DEBUG -#define CONFIG_JFFS2_FS_DEBUG 2 +#define CONFIG_JFFS2_FS_DEBUG 1 #endif #if CONFIG_JFFS2_FS_DEBUG > 0 @@ -292,7 +292,7 @@ int jffs2_get_inode_nodes(struct jffs2_s uint32_t *highest_version, uint32_t *latest_mctime, uint32_t *mctime_ver); void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); -struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, int ino); +struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino); void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new); void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old); void jffs2_free_ino_caches(struct jffs2_sb_info *c);
--- a/packages/fs/jffs2/current/src/nodemgmt.c +++ b/packages/fs/jffs2/current/src/nodemgmt.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodemgmt.c,v 1.92 2003/01/22 14:40:26 dwmw2 Exp $ + * $Id: nodemgmt.c,v 1.95 2003/06/30 10:58:57 dwmw2 Exp $ * */ @@ -57,16 +57,47 @@ int jffs2_reserve_space(struct jffs2_sb_ spin_lock(&c->erase_completion_lock); - /* this needs a little more thought */ + /* this needs a little more thought (true <tglx> :)) */ while(ret == -EAGAIN) { while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { int ret; + uint32_t dirty, avail; up(&c->alloc_sem); - if (c->dirty_size + c->unchecked_size < c->sector_size) { + /* calculate real dirty size + * dirty_size contains blocks on erase_pending_list + * those blocks are counted in c->nr_erasing_blocks. + * If one block is actually erased, it is not longer counted as dirty_space + * but it is counted in c->nr_erasing_blocks, so we add it and subtract it + * with c->nr_erasing_blocks * c->sector_size again. + * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks + * This helps us to force gc and pick eventually a clean block to spread the load. + * We add unchecked_size here, as we hopefully will find some space to use. + * This will affect the sum only once, as gc first finishes checking + * of nodes. + */ + dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size; + if (dirty < c->sector_size) { D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < sector size 0x%08x, returning -ENOSPC\n", - c->dirty_size, c->unchecked_size, c->sector_size)); + dirty, c->unchecked_size, c->sector_size)); + spin_unlock(&c->erase_completion_lock); + return -ENOSPC; + } + + /* Calc possibly available space. Possibly available means that we + * don't know, if unchecked size contains obsoleted nodes, which could give us some + * more usable space. This will affect the sum only once, as gc first finishes checking + * of nodes. + + Return -ENOSPC, if the maximum possibly available space is less or equal than + * blocksneeded * sector_size. + * This blocks endless gc looping on a filesystem, which is nearly full, even if + * the check above passes. + */ + avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size; + if ( (avail / c->sector_size) <= blocksneeded) { + D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n", + avail, blocksneeded * c->sector_size)); spin_unlock(&c->erase_completion_lock); return -ENOSPC; } @@ -127,7 +158,7 @@ static int jffs2_do_reserve_space(struct 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 (c->wbuf_len) { + 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(c, 1); @@ -313,7 +344,7 @@ int jffs2_add_physical_node_ref(struct j /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ 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)); - if (c->wbuf_len) { + if (jffs2_wbuf_dirty(c)) { /* Flush the last write in the block if it's outstanding */ spin_unlock(&c->erase_completion_lock); jffs2_flush_wbuf(c, 1); @@ -344,7 +375,7 @@ void jffs2_mark_node_obsolete(struct jff struct jffs2_eraseblock *jeb; int blocknr; struct jffs2_unknown_node n; - int ret; + int ret, addedsize; size_t retlen; if(!ref) { @@ -384,14 +415,17 @@ void jffs2_mark_node_obsolete(struct jff c->used_size -= ref->totlen; } + // Take care, that wasted size is taken into concern if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref->totlen)) && jeb != c->nextblock) { D1(printk("Dirtying\n")); - jeb->dirty_size += ref->totlen + jeb->wasted_size; - c->dirty_size += ref->totlen + jeb->wasted_size; + addedsize = ref->totlen + jeb->wasted_size; + jeb->dirty_size += addedsize; + c->dirty_size += addedsize; c->wasted_size -= jeb->wasted_size; jeb->wasted_size = 0; } else { D1(printk("Wasting\n")); + addedsize = 0; jeb->wasted_size += ref->totlen; c->wasted_size += ref->totlen; } @@ -421,7 +455,7 @@ void jffs2_mark_node_obsolete(struct jff D1(printk(KERN_DEBUG "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", jeb->offset)); list_del(&jeb->list); } - if (c->wbuf_len) { + if (jffs2_wbuf_dirty(c)) { D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n")); list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list); #if 0 /* This check was added to allow us to find places where we added nodes to the lists @@ -466,7 +500,7 @@ void jffs2_mark_node_obsolete(struct jff D1(printk(KERN_DEBUG "Done OK\n")); } else if (jeb == c->gcblock) { D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty_list\n", jeb->offset)); - } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - ref->totlen)) { + } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - addedsize)) { D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset)); list_del(&jeb->list); D1(printk(KERN_DEBUG "...and adding to dirty_list\n"));
--- a/packages/fs/jffs2/current/src/read.c +++ b/packages/fs/jffs2/current/src/read.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: read.c,v 1.31 2003/01/14 14:06:22 dwmw2 Exp $ + * $Id: read.c,v 1.32 2003/07/15 10:11:37 dwmw2 Exp $ * */ @@ -165,7 +165,7 @@ int jffs2_read_inode_range(struct jffs2_ /* Now we're pointing at the first frag which overlaps our page */ while(offset < end) { D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end)); - if (!frag || frag->ofs > offset) { + if (unlikely(!frag || frag->ofs > offset)) { uint32_t holesize = end - offset; if (frag) { D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset)); @@ -177,13 +177,7 @@ int jffs2_read_inode_range(struct jffs2_ buf += holesize; offset += holesize; continue; - } else if (frag->ofs < offset && (offset & (PAGE_CACHE_SIZE-1)) != 0) { - D1(printk(KERN_NOTICE "Eep. Overlap in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", - f->inocache->ino, frag->ofs, offset)); - D1(jffs2_print_frag_list(f)); - memset(buf, 0, end - offset); - return -EIO; - } else if (!frag->node) { + } else if (unlikely(!frag->node)) { uint32_t holeend = min(end, frag->ofs + frag->size); D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size)); memset(buf, 0, holeend - offset);
--- a/packages/fs/jffs2/current/src/readinode.c +++ b/packages/fs/jffs2/current/src/readinode.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: readinode.c,v 1.103 2003/01/22 14:43:29 dwmw2 Exp $ + * $Id: readinode.c,v 1.106 2003/05/14 06:53:26 dwmw2 Exp $ * */ @@ -169,8 +169,10 @@ static int jffs2_add_frag_to_fragtree(st if (lastend < newfrag->node->ofs) { /* ... and we need to put a hole in before the new node */ struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag(); - if (!holefrag) + if (!holefrag) { + jffs2_free_node_frag(newfrag); return -ENOMEM; + } holefrag->ofs = lastend; holefrag->size = newfrag->node->ofs - lastend; holefrag->node = NULL; @@ -408,6 +410,7 @@ int jffs2_do_crccheck_inode(struct jffs2 { struct jffs2_raw_inode n; struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL); + int ret; if (!f) return -ENOMEM; @@ -416,7 +419,13 @@ int jffs2_do_crccheck_inode(struct jffs2 init_MUTEX_LOCKED(&f->sem); f->inocache = ic; - return jffs2_do_read_inode_internal(c, f, &n); + ret = jffs2_do_read_inode_internal(c, f, &n); + if (!ret) { + up(&f->sem); + jffs2_do_clear_inode(c, f); + } + kfree (f); + return ret; } static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, @@ -450,13 +459,21 @@ static int jffs2_do_read_inode_internal( fn = tn->fn; - if (f->metadata && tn->version > mdata_ver) { - D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw))); - jffs2_mark_node_obsolete(c, f->metadata->raw); - jffs2_free_full_dnode(f->metadata); - f->metadata = NULL; - - mdata_ver = 0; + if (f->metadata) { + if (tn->version > mdata_ver) { + D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw))); + jffs2_mark_node_obsolete(c, f->metadata->raw); + jffs2_free_full_dnode(f->metadata); + f->metadata = NULL; + + mdata_ver = 0; + } else { + D1(printk(KERN_DEBUG "Er. New metadata at 0x%08x with ver %d is actually older than previous %d\n", + ref_offset(f->metadata->raw), tn->version, mdata_ver)); + jffs2_mark_node_obsolete(c, fn->raw); + jffs2_free_full_dnode(fn); + goto next_tn; + } } if (fn->size) { @@ -467,6 +484,7 @@ static int jffs2_do_read_inode_internal( f->metadata = fn; mdata_ver = tn->version; } + next_tn: tn_list = tn->next; jffs2_free_tmp_dnode_info(tn); }
--- a/packages/fs/jffs2/current/src/scan.c +++ b/packages/fs/jffs2/current/src/scan.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: scan.c,v 1.98 2003/01/22 16:33:39 dwmw2 Exp $ + * $Id: scan.c,v 1.101 2003/06/30 10:58:57 dwmw2 Exp $ * */ #include <linux/kernel.h> @@ -65,6 +65,16 @@ static int jffs2_scan_dirent_node(struct #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); +#ifdef CONFIG_JFFS2_FS_NAND + if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize) + return c->wbuf_pagesize; +#endif + return min; + +} int jffs2_scan_medium(struct jffs2_sb_info *c) { int i, ret; @@ -151,8 +161,7 @@ int jffs2_scan_medium(struct jffs2_sb_in Later when we do snapshots, this must be the most recent block, not the one with most free space. */ - if (jeb->free_size > 2*sizeof(struct jffs2_raw_inode) && - (jffs2_can_mark_obsolete(c) || jeb->free_size > c->wbuf_pagesize) && + if (jeb->free_size > min_free(c) && (!c->nextblock || c->nextblock->free_size < jeb->free_size)) { /* Better candidate for the next writes to go to */ if (c->nextblock) { @@ -210,7 +219,7 @@ int jffs2_scan_medium(struct jffs2_sb_in c->dirty_size -= c->nextblock->dirty_size; c->nextblock->dirty_size = 0; } - +#ifdef CONFIG_JFFS2_FS_NAND if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) { /* If we're going to start writing into a block which already contains data, and the end of the data isn't page-aligned, @@ -226,6 +235,7 @@ int jffs2_scan_medium(struct jffs2_sb_in c->nextblock->free_size -= skip; c->free_size -= skip; } +#endif if (c->nr_erasing_blocks) { if ( !c->used_size && ((empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) { printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n"); @@ -354,7 +364,7 @@ static int jffs2_scan_eraseblock (struct if (ofs & 3) { printk(KERN_WARNING "Eep. ofs 0x%08x not word-aligned!\n", ofs); - ofs = (ofs+3)&~3; + ofs = PAD(ofs); continue; } if (ofs == prevofs) { @@ -410,8 +420,8 @@ static int jffs2_scan_eraseblock (struct /* Ran off end. */ D1(printk(KERN_DEBUG "Empty flash ends normally at 0x%08x\n", ofs)); - if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && - !jeb->first_node->next_in_ino && !jeb->dirty_size) + if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && + c->cleanmarker_size && !jeb->first_node->next_in_ino && !jeb->dirty_size) return BLK_STATE_CLEANMARKER; wasempty = 1; continue; @@ -430,7 +440,7 @@ static int jffs2_scan_eraseblock (struct continue; } if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) { - D1(printk(KERN_DEBUG "Empty bitmask at 0x%08x\n", ofs)); + D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs)); DIRTY_SPACE(4); ofs += 4; continue;
