diff options
author | David Woodhouse <dwmw2@infradead.org> | 2006-05-21 14:29:11 +0200 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2006-05-21 14:29:11 +0200 |
commit | ca89a517fa577e6f26621463d3aa4f3c3d530b1e (patch) | |
tree | e277f31d6629c5dcc358adfa80190fc247d43f65 /fs/jffs2 | |
parent | [JFFS2] Locking issues in summary write code. (diff) | |
download | linux-ca89a517fa577e6f26621463d3aa4f3c3d530b1e.tar.xz linux-ca89a517fa577e6f26621463d3aa4f3c3d530b1e.zip |
[JFFS2] Finally eliminate __totlen field from struct jffs2_raw_node_ref
Well, almost. We'll actually keep a 'TEST_TOTLEN' macro set for now, and keep
doing some paranoia checks to make sure it's all working correctly. But if
TEST_TOTLEN is unset, the size of struct jffs2_raw_node_ref drops from 16
bytes to 12 on 32-bit machines. That's a saving of about half a megabyte of
memory on the OLPC prototype board, with 125K or so nodes in its 512MiB of
flash.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'fs/jffs2')
-rw-r--r-- | fs/jffs2/nodelist.c | 115 | ||||
-rw-r--r-- | fs/jffs2/nodelist.h | 58 | ||||
-rw-r--r-- | fs/jffs2/nodemgmt.c | 6 |
3 files changed, 121 insertions, 58 deletions
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 00506857eabc..9a6ced05f894 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -1052,8 +1052,17 @@ void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, { if (!jeb->first_node) jeb->first_node = ref; - if (jeb->last_node) + if (jeb->last_node) { jeb->last_node->next_phys = ref; +#ifdef TEST_TOTLEN + if (ref_offset(jeb->last_node) + jeb->last_node->__totlen != ref_offset(ref)) { + printk(KERN_CRIT "Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x)\n", + ref, ref_offset(ref), ref_offset(ref)+ref->__totlen, + ref_offset(jeb->last_node), ref_offset(jeb->last_node)+jeb->last_node->__totlen); + WARN_ON(1); + } +#endif + } jeb->last_node = ref; switch(ref_flags(ref)) { @@ -1076,18 +1085,110 @@ void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, c->free_size -= len; jeb->free_size -= len; - /* Set __totlen field... for now */ - ref->__totlen = len; ref->next_phys = NULL; +#ifdef TEST_TOTLEN + /* Set (and test) __totlen field... for now */ + ref->__totlen = len; + ref_totlen(c, jeb, ref); +#endif } +/* No locking. Do not use on a live file system */ int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t size) { - c->dirty_size += size; - c->free_size -= size; - jeb->dirty_size += size; - jeb->free_size -= size; + if (!size) + return 0; + if (size > c->sector_size - jeb->used_size) { + printk(KERN_CRIT "Dirty space 0x%x larger then used_size 0x%x (wasted 0x%x)\n", + size, jeb->used_size, jeb->wasted_size); + BUG(); + } + if (jeb->last_node && ref_obsolete(jeb->last_node)) { +#ifdef TEST_TOTLEN + jeb->last_node->__totlen += size; +#endif + c->dirty_size += size; + c->free_size -= size; + jeb->dirty_size += size; + jeb->free_size -= size; + } else { + struct jffs2_raw_node_ref *ref; + ref = jffs2_alloc_raw_node_ref(); + if (!ref) + return -ENOMEM; + + ref->flash_offset = jeb->offset + c->sector_size - jeb->free_size; + ref->flash_offset |= REF_OBSOLETE; + ref->next_in_ino = 0; +#ifdef TEST_TOTLEN + ref->__totlen = size; +#endif + + jffs2_link_node_ref(c, jeb, ref, size); + } return 0; } + +/* Calculate totlen from surrounding nodes or eraseblock */ +static inline uint32_t __ref_totlen(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *ref) +{ + uint32_t ref_end; + + if (ref->next_phys) + ref_end = ref_offset(ref->next_phys); + else { + if (!jeb) + jeb = &c->blocks[ref->flash_offset / c->sector_size]; + + /* Last node in block. Use free_space */ + if (ref != jeb->last_node) { + printk(KERN_CRIT "ref %p @0x%08x is not jeb->last_node (%p @0x%08x)\n", + ref, ref_offset(ref), jeb->last_node, jeb->last_node?ref_offset(jeb->last_node):0); + BUG(); + } + ref_end = jeb->offset + c->sector_size - jeb->free_size; + } + return ref_end - ref_offset(ref); +} + +uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *ref) +{ + uint32_t ret; + +#if CONFIG_JFFS2_FS_DEBUG > 0 + if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) { + printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n", + jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref)); + BUG(); + } +#endif + + ret = __ref_totlen(c, jeb, ref); +#ifdef TEST_TOTLEN + if (ret != ref->__totlen) { + printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n", + ref, ref_offset(ref), ref_offset(ref)+ref->__totlen, + ret, ref->__totlen); + if (ref->next_phys) { + printk(KERN_CRIT "next_phys %p (0x%08x-0x%08x)\n", ref->next_phys, ref_offset(ref->next_phys), + ref_offset(ref->next_phys)+ref->__totlen); + } else + printk(KERN_CRIT "No next_phys. jeb->last_node is %p\n", jeb->last_node); + + printk(KERN_CRIT "jeb->wasted_size %x, dirty_size %x, used_size %x, free_size %x\n", jeb->wasted_size, jeb->dirty_size, jeb->used_size, jeb->free_size); + ret = ref->__totlen; + if (!jeb) + jeb = &c->blocks[ref->flash_offset / c->sector_size]; +#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS) + __jffs2_dbg_dump_node_refs_nolock(c, jeb); +#endif + WARN_ON(1); + } +#endif /* TEST_TOTLEN */ + return ret; +} diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 94ef88787347..80d1fda2212b 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -82,7 +82,10 @@ struct jffs2_raw_node_ref word so you know when you've got there :) */ struct jffs2_raw_node_ref *next_phys; uint32_t flash_offset; +#define TEST_TOTLEN +#ifdef TEST_TOTLEN uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */ +#endif }; /* flash_offset & 3 always has to be zero, because nodes are @@ -221,57 +224,7 @@ static inline int jffs2_blocks_use_vmalloc(struct jffs2_sb_info *c) return ((c->flash_size / c->sector_size) * sizeof (struct jffs2_eraseblock)) > (128 * 1024); } -/* Calculate totlen from surrounding nodes or eraseblock */ -static inline uint32_t __ref_totlen(struct jffs2_sb_info *c, - struct jffs2_eraseblock *jeb, - struct jffs2_raw_node_ref *ref) -{ - uint32_t ref_end; - - if (ref->next_phys) - ref_end = ref_offset(ref->next_phys); - else { - if (!jeb) - jeb = &c->blocks[ref->flash_offset / c->sector_size]; - - /* Last node in block. Use free_space */ - BUG_ON(ref != jeb->last_node); - ref_end = jeb->offset + c->sector_size - jeb->free_size; - } - return ref_end - ref_offset(ref); -} - -static inline uint32_t ref_totlen(struct jffs2_sb_info *c, - struct jffs2_eraseblock *jeb, - struct jffs2_raw_node_ref *ref) -{ - uint32_t ret; - -#if CONFIG_JFFS2_FS_DEBUG > 0 - if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) { - printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n", - jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref)); - BUG(); - } -#endif - -#if 1 - ret = ref->__totlen; -#else - /* This doesn't actually work yet */ - ret = __ref_totlen(c, jeb, ref); - if (ret != ref->__totlen) { - printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n", - ref, ref_offset(ref), ref_offset(ref)+ref->__totlen, - ret, ref->__totlen); - if (!jeb) - jeb = &c->blocks[ref->flash_offset / c->sector_size]; - jffs2_dbg_dump_node_refs_nolock(c, jeb); - BUG(); - } -#endif - return ret; -} +#define ref_totlen(a, b, c) __jffs2_ref_totlen((a), (b), (c)) #define ALLOC_NORMAL 0 /* Normal allocation */ #define ALLOC_DELETION 1 /* Deletion node. Best to allow it */ @@ -355,6 +308,9 @@ void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uin int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn); void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_node_ref *ref, uint32_t len); +extern uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *ref); /* nodemgmt.c */ int jffs2_thread_should_wake(struct jffs2_sb_info *c); diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 4701556be49d..9a0f312cfcda 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -386,7 +386,9 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r struct jffs2_eraseblock *jeb; jeb = &c->blocks[new->flash_offset / c->sector_size]; +#ifdef TEST_TOTLEN new->__totlen = len; +#endif D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len)); #if 1 @@ -679,7 +681,9 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref spin_lock(&c->erase_completion_lock); +#ifdef TEST_TOTLEN ref->__totlen += n->__totlen; +#endif ref->next_phys = n->next_phys; if (jeb->last_node == n) jeb->last_node = ref; if (jeb->gc_node == n) { @@ -702,7 +706,9 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref p = p->next_phys; if (ref_obsolete(p) && !ref->next_in_ino) { +#ifdef TEST_TOTLEN p->__totlen += ref->__totlen; +#endif if (jeb->last_node == ref) { jeb->last_node = p; } |