From 3d518fd7d7533c35735e4ce1f01476dcb58d99b3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 May 2006 15:58:23 +0200 Subject: [PATCH] --- yaml --- r: 27862 b: refs/heads/master c: 9a57d470fd4a77b9732fee97bed29c565c730af0 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/fs/jffs2/debug.c | 14 +-- trunk/fs/jffs2/erase.c | 16 +++- trunk/fs/jffs2/gc.c | 27 ++++-- trunk/fs/jffs2/jffs2_fs_sb.h | 3 - trunk/fs/jffs2/malloc.c | 26 +----- trunk/fs/jffs2/nodelist.c | 64 +++++-------- trunk/fs/jffs2/nodelist.h | 25 +++-- trunk/fs/jffs2/nodemgmt.c | 59 ++++++------ trunk/fs/jffs2/scan.c | 81 +++++++++++++---- trunk/fs/jffs2/summary.c | 162 +++++++++++++++++++++++---------- trunk/fs/jffs2/wbuf.c | 26 ++++-- trunk/fs/jffs2/write.c | 71 ++++++++++----- trunk/fs/jffs2/xattr.c | 38 ++++++-- trunk/include/linux/mtd/nand.h | 2 +- 15 files changed, 380 insertions(+), 236 deletions(-) diff --git a/[refs] b/[refs] index f0637f917e2b..ed46c2295b86 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 99988f7bbd16b861590dda4631c4db6cb17b5091 +refs/heads/master: 9a57d470fd4a77b9732fee97bed29c565c730af0 diff --git a/trunk/fs/jffs2/debug.c b/trunk/fs/jffs2/debug.c index 72b4fc13a106..1fe17de713e8 100644 --- a/trunk/fs/jffs2/debug.c +++ b/trunk/fs/jffs2/debug.c @@ -192,13 +192,13 @@ __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c, else my_dirty_size += totlen; - if ((!ref_next(ref2)) != (ref2 == jeb->last_node)) { - JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next at %#08x (mem %p), last_node is at %#08x (mem %p).\n", - ref_offset(ref2), ref2, ref_offset(ref_next(ref2)), ref_next(ref2), - ref_offset(jeb->last_node), jeb->last_node); + if ((!ref2->next_phys) != (ref2 == jeb->last_node)) { + JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next_phys at %#08x (mem %p), last_node is at %#08x (mem %p).\n", + ref_offset(ref2), ref2, ref_offset(ref2->next_phys), ref2->next_phys, + ref_offset(jeb->last_node), jeb->last_node); goto error; } - ref2 = ref_next(ref2); + ref2 = ref2->next_phys; } if (my_used_size != jeb->used_size) { @@ -268,9 +268,9 @@ __jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c, } printk(JFFS2_DBG); - for (ref = jeb->first_node; ; ref = ref_next(ref)) { + for (ref = jeb->first_node; ; ref = ref->next_phys) { printk("%#08x(%#x)", ref_offset(ref), ref->__totlen); - if (ref_next(ref)) + if (ref->next_phys) printk("->"); else break; diff --git a/trunk/fs/jffs2/erase.c b/trunk/fs/jffs2/erase.c index f939f908b948..4616fed75730 100644 --- a/trunk/fs/jffs2/erase.c +++ b/trunk/fs/jffs2/erase.c @@ -296,7 +296,7 @@ void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock * jffs2_remove_node_refs_from_ino_list(c, ref, jeb); /* else it was a non-inode node or already removed, so don't bother */ - __jffs2_free_raw_node_ref(ref); + jffs2_free_raw_node_ref(ref); } jeb->last_node = NULL; } @@ -351,6 +351,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { + struct jffs2_raw_node_ref *marker_ref = NULL; size_t retlen; int ret; uint32_t bad_offset; @@ -383,7 +384,11 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb .totlen = cpu_to_je32(c->cleanmarker_size) }; - jffs2_prealloc_raw_node_refs(c, 1); + marker_ref = jffs2_alloc_raw_node_ref(); + if (!marker_ref) { + printk(KERN_WARNING "Failed to allocate raw node ref for clean marker. Refiling\n"); + goto refile; + } marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4)); @@ -399,13 +404,16 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n", jeb->offset, sizeof(marker), retlen); + jffs2_free_raw_node_ref(marker_ref); goto filebad; } /* Everything else got zeroed before the erase */ jeb->free_size = c->sector_size; - /* FIXME Special case for cleanmarker in empty block */ - jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); + + marker_ref->flash_offset = jeb->offset | REF_NORMAL; + + jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size, NULL); } spin_lock(&c->erase_completion_lock); diff --git a/trunk/fs/jffs2/gc.c b/trunk/fs/jffs2/gc.c index 477c526d638b..f9e982a65ac2 100644 --- a/trunk/fs/jffs2/gc.c +++ b/trunk/fs/jffs2/gc.c @@ -239,7 +239,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) while(ref_obsolete(raw)) { D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw))); - raw = ref_next(raw); + raw = raw->next_phys; if (unlikely(!raw)) { printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n"); printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", @@ -528,6 +528,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw) { union jffs2_node_union *node; + struct jffs2_raw_node_ref *nraw; size_t retlen; int ret; uint32_t phys_ofs, alloclen; @@ -617,21 +618,30 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, } } + nraw = jffs2_alloc_raw_node_ref(); + if (!nraw) { + ret = -ENOMEM; + goto out_node; + } + /* OK, all the CRCs are good; this node can just be copied as-is. */ retry: - phys_ofs = write_ofs(c); + nraw->flash_offset = phys_ofs = write_ofs(c); ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node); if (ret || (retlen != rawlen)) { printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", - rawlen, phys_ofs, ret, retlen); + rawlen, nraw->flash_offset, ret, retlen); if (retlen) { - jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL); + nraw->flash_offset |= REF_OBSOLETE; + jffs2_add_physical_node_ref(c, nraw, rawlen, NULL); + jffs2_mark_node_obsolete(c, nraw); } else { - printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", phys_ofs); + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset); + jffs2_free_raw_node_ref(nraw); } - if (!retried) { + if (!retried && (nraw = jffs2_alloc_raw_node_ref())) { /* Try to reallocate space and retry */ uint32_t dummy; struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size]; @@ -656,13 +666,16 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, goto retry; } D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); + jffs2_free_raw_node_ref(nraw); } + jffs2_free_raw_node_ref(nraw); if (!ret) ret = -EIO; goto out_node; } - jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, rawlen, ic); + nraw->flash_offset |= REF_PRISTINE; + jffs2_add_physical_node_ref(c, nraw, rawlen, ic); jffs2_mark_node_obsolete(c, raw); D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw))); diff --git a/trunk/fs/jffs2/jffs2_fs_sb.h b/trunk/fs/jffs2/jffs2_fs_sb.h index 67529f0a44dd..272fbea55192 100644 --- a/trunk/fs/jffs2/jffs2_fs_sb.h +++ b/trunk/fs/jffs2/jffs2_fs_sb.h @@ -26,9 +26,6 @@ struct jffs2_inodirty; struct jffs2_sb_info { struct mtd_info *mtd; - struct jffs2_raw_node_ref *refs; - int reserved_refs; - uint32_t highest_ino; uint32_t checked_ino; diff --git a/trunk/fs/jffs2/malloc.c b/trunk/fs/jffs2/malloc.c index 3df3250314a2..f2473fa2fd16 100644 --- a/trunk/fs/jffs2/malloc.c +++ b/trunk/fs/jffs2/malloc.c @@ -190,29 +190,7 @@ void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) kmem_cache_free(tmp_dnode_info_slab, x); } -int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, int nr) -{ - struct jffs2_raw_node_ref *p = c->refs; - - dbg_memalloc("%d\n", nr); - - while (nr && p) { - p = p->next_in_ino; - nr--; - } - while (nr) { - p = __jffs2_alloc_raw_node_ref(); - if (!p) - return -ENOMEM; - p->next_in_ino = c->refs; - c->refs = p; - nr--; - } - c->reserved_refs = nr; - return 0; -} - -struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void) +struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void) { struct jffs2_raw_node_ref *ret; ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); @@ -220,7 +198,7 @@ struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void) return ret; } -void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) +void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) { dbg_memalloc("%p\n", x); kmem_cache_free(raw_node_ref_slab, x); diff --git a/trunk/fs/jffs2/nodelist.c b/trunk/fs/jffs2/nodelist.c index 0e82979c741c..d25d4919ca97 100644 --- a/trunk/fs/jffs2/nodelist.c +++ b/trunk/fs/jffs2/nodelist.c @@ -953,19 +953,13 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c) for (i=0; inr_blocks; i++) { this = c->blocks[i].first_node; - while (this) { + while(this) { next = this->next_phys; - __jffs2_free_raw_node_ref(this); + jffs2_free_raw_node_ref(this); this = next; } c->blocks[i].first_node = c->blocks[i].last_node = NULL; } - this = c->refs; - while (this) { - next = this->next_in_ino; - __jffs2_free_raw_node_ref(this); - this = next; - } } struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset) @@ -1053,27 +1047,10 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) } } -struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, - struct jffs2_eraseblock *jeb, - uint32_t ofs, uint32_t len, - struct jffs2_inode_cache *ic) +void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *ref, uint32_t len, + struct jffs2_inode_cache *ic) { - struct jffs2_raw_node_ref *ref; - - /* These will be preallocated _very_ shortly. */ - ref = c->refs; - if (!c->refs) { - JFFS2_WARNING("Using non-preallocated refs!\n"); - ref = __jffs2_alloc_raw_node_ref(); - BUG_ON(!ref); - WARN_ON(1); - } else { - c->refs = ref->next_in_ino; - } - - ref->next_phys = NULL; - ref->flash_offset = ofs; - if (!jeb->first_node) jeb->first_node = ref; if (jeb->last_node) { @@ -1116,15 +1093,15 @@ struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, c->free_size -= len; jeb->free_size -= len; + ref->next_phys = NULL; #ifdef TEST_TOTLEN /* Set (and test) __totlen field... for now */ ref->__totlen = len; ref_totlen(c, jeb, ref); #endif - return ref; } -/* No locking, no reservation of 'ref'. Do not use on a live file system */ +/* 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) { @@ -1144,10 +1121,18 @@ int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb jeb->dirty_size += size; jeb->free_size -= size; } else { - uint32_t ofs = jeb->offset + c->sector_size - jeb->free_size; - ofs |= REF_OBSOLETE; + 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; +#ifdef TEST_TOTLEN + ref->__totlen = size; +#endif - jffs2_link_node_ref(c, jeb, ofs, size, NULL); + jffs2_link_node_ref(c, jeb, ref, size, NULL); } return 0; @@ -1159,10 +1144,9 @@ static inline uint32_t __ref_totlen(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref) { uint32_t ref_end; - struct jffs2_raw_node_ref *next_ref = ref_next(ref); - if (next_ref) - ref_end = ref_offset(next_ref); + if (ref->next_phys) + ref_end = ref_offset(ref->next_phys); else { if (!jeb) jeb = &c->blocks[ref->flash_offset / c->sector_size]; @@ -1197,11 +1181,11 @@ uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *je 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(ref)) { - printk(KERN_CRIT "next %p (0x%08x-0x%08x)\n", ref_next(ref), ref_offset(ref_next(ref)), - ref_offset(ref_next(ref))+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 ref. jeb->last_node is %p\n", jeb->last_node); + 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; diff --git a/trunk/fs/jffs2/nodelist.h b/trunk/fs/jffs2/nodelist.h index 94d152de95eb..76f1b9419eea 100644 --- a/trunk/fs/jffs2/nodelist.h +++ b/trunk/fs/jffs2/nodelist.h @@ -88,18 +88,18 @@ struct jffs2_raw_node_ref #endif }; -#define ref_next(r) ((r)->next_phys) - static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_node_ref *raw) { - while(raw->next_in_ino) + while(raw->next_in_ino) { raw = raw->next_in_ino; + } /* NB. This can be a jffs2_xattr_datum or jffs2_xattr_ref and not actually a jffs2_inode_cache. Check ->class */ return ((struct jffs2_inode_cache *)raw); } + /* flash_offset & 3 always has to be zero, because nodes are always aligned at 4 bytes. So we have a couple of extra bits to play with, which indicate the node's status; see below: */ @@ -318,10 +318,9 @@ void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *t int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn); -struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, - struct jffs2_eraseblock *jeb, - uint32_t ofs, uint32_t len, - struct jffs2_inode_cache *ic); +void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *ref, uint32_t len, + struct jffs2_inode_cache *ic); extern uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_node_ref *ref); @@ -332,9 +331,10 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *len, int prio, uint32_t sumsize); int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *len, uint32_t sumsize); -struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, - uint32_t ofs, uint32_t len, - struct jffs2_inode_cache *ic); +int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, + struct jffs2_raw_node_ref *new, + uint32_t len, + struct jffs2_inode_cache *ic); 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); @@ -378,9 +378,8 @@ struct jffs2_raw_inode *jffs2_alloc_raw_inode(void); void jffs2_free_raw_inode(struct jffs2_raw_inode *); struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void); void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *); -int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, int nr); -struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void); -void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *); +struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void); +void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *); struct jffs2_node_frag *jffs2_alloc_node_frag(void); void jffs2_free_node_frag(struct jffs2_node_frag *); struct jffs2_inode_cache *jffs2_alloc_inode_cache(void); diff --git a/trunk/fs/jffs2/nodemgmt.c b/trunk/fs/jffs2/nodemgmt.c index f4649c275fbe..8feb8749bc75 100644 --- a/trunk/fs/jffs2/nodemgmt.c +++ b/trunk/fs/jffs2/nodemgmt.c @@ -137,8 +137,6 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, } } spin_unlock(&c->erase_completion_lock); - if (!ret) - ret = jffs2_prealloc_raw_node_refs(c, 1); if (ret) up(&c->alloc_sem); return ret; @@ -160,9 +158,6 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, } } spin_unlock(&c->erase_completion_lock); - if (!ret) - ret = jffs2_prealloc_raw_node_refs(c, 1); - return ret; } @@ -386,30 +381,30 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, * Must be called with the alloc_sem held. */ -struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, - uint32_t ofs, uint32_t len, - struct jffs2_inode_cache *ic) +int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, + uint32_t len, struct jffs2_inode_cache *ic) { struct jffs2_eraseblock *jeb; - struct jffs2_raw_node_ref *new; - jeb = &c->blocks[ofs / c->sector_size]; + 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", - ofs & ~3, ofs & 3, len)); + 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 - /* Allow non-obsolete nodes only to be added at the end of c->nextblock, - if c->nextblock is set. Note that wbuf.c will file obsolete nodes - even after refiling c->nextblock */ - if ((c->nextblock || ((ofs & 3) != REF_OBSOLETE)) - && (jeb != c->nextblock || (ofs & ~3) != jeb->offset + (c->sector_size - jeb->free_size))) { + /* we could get some obsolete nodes after nextblock was refiled + in wbuf.c */ + if ((c->nextblock || !ref_obsolete(new)) + &&(jeb != c->nextblock || ref_offset(new) != jeb->offset + (c->sector_size - jeb->free_size))) { printk(KERN_WARNING "argh. node added in wrong place\n"); - return ERR_PTR(-EINVAL); + jffs2_free_raw_node_ref(new); + return -EINVAL; } #endif spin_lock(&c->erase_completion_lock); - new = jffs2_link_node_ref(c, jeb, ofs, len, ic); + jffs2_link_node_ref(c, jeb, new, len, ic); if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) { /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ @@ -430,7 +425,7 @@ struct jffs2_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, spin_unlock(&c->erase_completion_lock); - return new; + return 0; } @@ -458,7 +453,6 @@ static inline int on_list(struct list_head *obj, struct list_head *head) void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref) { struct jffs2_eraseblock *jeb; - struct jffs2_raw_node_ref *next_ref; int blocknr; struct jffs2_unknown_node n; int ret, addedsize; @@ -686,23 +680,24 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref /* Merge with the next node in the physical list, if there is one and if it's also obsolete and if it doesn't belong to any inode */ - next_ref = ref_next(ref); + if (ref->next_phys && ref_obsolete(ref->next_phys) && + !ref->next_phys->next_in_ino) { + struct jffs2_raw_node_ref *n = ref->next_phys; - if (next_ref && ref_obsolete(next_ref) && !next_ref->next_in_ino) { spin_lock(&c->erase_completion_lock); #ifdef TEST_TOTLEN - ref->__totlen += next_ref->__totlen; + ref->__totlen += n->__totlen; #endif - ref->next_phys = ref_next(next_ref); - if (jeb->last_node == next_ref) jeb->last_node = ref; - if (jeb->gc_node == next_ref) { + ref->next_phys = n->next_phys; + if (jeb->last_node == n) jeb->last_node = ref; + if (jeb->gc_node == n) { /* gc will be happy continuing gc on this node */ jeb->gc_node=ref; } spin_unlock(&c->erase_completion_lock); - __jffs2_free_raw_node_ref(next_ref); + jffs2_free_raw_node_ref(n); } /* Also merge with the previous node in the list, if there is one @@ -712,8 +707,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref spin_lock(&c->erase_completion_lock); - while ((next_ref = ref_next(ref)) != ref) - p = next_ref; + while (p->next_phys != ref) + p = p->next_phys; if (ref_obsolete(p) && !ref->next_in_ino) { #ifdef TEST_TOTLEN @@ -726,8 +721,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref /* gc will be happy continuing gc on this node */ jeb->gc_node=p; } - p->next_phys = ref_next(ref); - __jffs2_free_raw_node_ref(ref); + p->next_phys = ref->next_phys; + jffs2_free_raw_node_ref(ref); } spin_unlock(&c->erase_completion_lock); } diff --git a/trunk/fs/jffs2/scan.c b/trunk/fs/jffs2/scan.c index 3551c39d7472..6fce703c0543 100644 --- a/trunk/fs/jffs2/scan.c +++ b/trunk/fs/jffs2/scan.c @@ -295,7 +295,7 @@ int jffs2_fill_scan_buf (struct jffs2_sb_info *c, void *buf, int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size - && (!jeb->first_node || !ref_next(jeb->first_node)) ) + && (!jeb->first_node || !jeb->first_node->next_phys) ) return BLK_STATE_CLEANMARKER; /* move blocks with max 4 byte dirty space to cleanlist */ @@ -317,6 +317,7 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc struct jffs2_summary *s) { struct jffs2_xattr_datum *xd; + struct jffs2_raw_node_ref *raw; uint32_t totlen, crc; int err; @@ -339,8 +340,13 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc return 0; } + raw = jffs2_alloc_raw_node_ref(); + if (!raw) + return -ENOMEM; + xd = jffs2_setup_xattr_datum(c, je32_to_cpu(rx->xid), je32_to_cpu(rx->version)); if (IS_ERR(xd)) { + jffs2_free_raw_node_ref(raw); if (PTR_ERR(xd) == -EEXIST) { if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rx->totlen))))) return err; @@ -352,9 +358,12 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc xd->name_len = rx->name_len; xd->value_len = je16_to_cpu(rx->value_len); xd->data_crc = je32_to_cpu(rx->data_crc); + xd->node = raw; + + raw->flash_offset = ofs | REF_PRISTINE; - xd->node = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, NULL); - /* FIXME */ xd->node->next_in_ino = (void *)xd; + jffs2_link_node_ref(c, jeb, raw, totlen, NULL); + /* FIXME */ raw->next_in_ino = (void *)xd; if (jffs2_sum_active()) jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset); @@ -368,6 +377,7 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock struct jffs2_summary *s) { struct jffs2_xattr_ref *ref; + struct jffs2_raw_node_ref *raw; uint32_t crc; int err; @@ -394,6 +404,12 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock if (!ref) return -ENOMEM; + raw = jffs2_alloc_raw_node_ref(); + if (!raw) { + jffs2_free_xattr_ref(ref); + return -ENOMEM; + } + /* BEFORE jffs2_build_xattr_subsystem() called, * ref->xid is used to store 32bit xid, xd is not used * ref->ino is used to store 32bit inode-number, ic is not used @@ -402,13 +418,16 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock * used to chain all xattr_ref object. It's re-chained to * jffs2_inode_cache in jffs2_build_xattr_subsystem() correctly. */ + ref->node = raw; ref->ino = je32_to_cpu(rr->ino); ref->xid = je32_to_cpu(rr->xid); ref->next = c->xref_temp; c->xref_temp = ref; - ref->node = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rr->totlen)), NULL); - /* FIXME */ ref->node->next_in_ino = (void *)ref; + raw->flash_offset = ofs | REF_PRISTINE; + + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rr->totlen)), NULL); + /* FIXME */ raw->next_in_ino = (void *)ref; if (jffs2_sum_active()) jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset); @@ -578,11 +597,6 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo jffs2_dbg_acct_paranoia_check_nolock(c, jeb); - /* Make sure there are node refs available for use */ - err = jffs2_prealloc_raw_node_refs(c, 2); - if (err) - return err; - cond_resched(); if (ofs & 3) { @@ -647,7 +661,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo /* If we're only checking the beginning of a block with a cleanmarker, bail now */ if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && - c->cleanmarker_size && !jeb->dirty_size && !ref_next(jeb->first_node)) { + c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_phys) { D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size))); return BLK_STATE_CLEANMARKER; } @@ -825,7 +839,14 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo return err; ofs += PAD(sizeof(struct jffs2_unknown_node)); } else { - jffs2_link_node_ref(c, jeb, ofs | REF_NORMAL, c->cleanmarker_size, NULL); + struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); + if (!marker_ref) { + printk(KERN_NOTICE "Failed to allocate node ref for clean marker\n"); + return -ENOMEM; + } + marker_ref->flash_offset = ofs | REF_NORMAL; + + jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size, NULL); ofs += PAD(c->cleanmarker_size); } @@ -863,9 +884,14 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo break; case JFFS2_FEATURE_RWCOMPAT_COPY: { + struct jffs2_raw_node_ref *ref; D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs)); - jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(node->totlen)), NULL); + ref = jffs2_alloc_raw_node_ref(); + if (!ref) + return -ENOMEM; + ref->flash_offset = ofs | REF_PRISTINE; + jffs2_link_node_ref(c, jeb, ref, PAD(je32_to_cpu(node->totlen)), NULL); /* We can't summarise nodes we don't grok */ jffs2_sum_disable_collecting(s); @@ -927,6 +953,7 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s) { + struct jffs2_raw_node_ref *raw; struct jffs2_inode_cache *ic; uint32_t ino = je32_to_cpu(ri->ino); int err; @@ -942,6 +969,12 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc Which means that the _full_ amount of time to get to proper write mode with GC operational may actually be _longer_ than before. Sucks to be me. */ + raw = jffs2_alloc_raw_node_ref(); + if (!raw) { + printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of node reference failed\n"); + return -ENOMEM; + } + ic = jffs2_get_ino_cache(c, ino); if (!ic) { /* Inocache get failed. Either we read a bogus ino# or it's just genuinely the @@ -955,15 +988,21 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */ if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(ri->totlen))))) return err; + jffs2_free_raw_node_ref(raw); return 0; } ic = jffs2_scan_make_ino_cache(c, ino); - if (!ic) + if (!ic) { + jffs2_free_raw_node_ref(raw); return -ENOMEM; + } } /* Wheee. It worked */ - jffs2_link_node_ref(c, jeb, ofs | REF_UNCHECKED, PAD(je32_to_cpu(ri->totlen)), ic); + + raw->flash_offset = ofs | REF_UNCHECKED; + + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(ri->totlen)), ic); D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n", je32_to_cpu(ri->ino), je32_to_cpu(ri->version), @@ -982,6 +1021,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s) { + struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *fd; struct jffs2_inode_cache *ic; uint32_t crc; @@ -1023,14 +1063,23 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo return err; return 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"); + return -ENOMEM; + } ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino)); if (!ic) { jffs2_free_full_dirent(fd); + jffs2_free_raw_node_ref(raw); return -ENOMEM; } - fd->raw = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(rd->totlen)), ic); + raw->flash_offset = ofs | REF_PRISTINE; + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rd->totlen)), ic); + fd->raw = raw; fd->next = NULL; fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); diff --git a/trunk/fs/jffs2/summary.c b/trunk/fs/jffs2/summary.c index ccb6803a6e41..351ba9f8185e 100644 --- a/trunk/fs/jffs2/summary.c +++ b/trunk/fs/jffs2/summary.c @@ -369,18 +369,22 @@ int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, return -ENOMEM; } -static struct jffs2_raw_node_ref *sum_link_node_ref(struct jffs2_sb_info *c, - struct jffs2_eraseblock *jeb, - uint32_t ofs, uint32_t len, - struct jffs2_inode_cache *ic) +static struct jffs2_raw_node_ref *alloc_ref_at(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + uint32_t offset) { + struct jffs2_raw_node_ref *ref; /* If there was a gap, mark it dirty */ - if ((ofs & ~3) > c->sector_size - jeb->free_size) { - /* Ew. Summary doesn't actually tell us explicitly about dirty space */ - jffs2_scan_dirty_space(c, jeb, (ofs & ~3) - (c->sector_size - jeb->free_size)); + if (offset > c->sector_size - jeb->free_size) { + int ret = jffs2_scan_dirty_space(c, jeb, offset - (c->sector_size - jeb->free_size)); + if (ret) + return NULL; } + ref = jffs2_alloc_raw_node_ref(); + if (!ref) + return NULL; - return jffs2_link_node_ref(c, jeb, jeb->offset + ofs, len, ic); + ref->flash_offset = jeb->offset + offset; + return ref; } /* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */ @@ -388,6 +392,7 @@ static struct jffs2_raw_node_ref *sum_link_node_ref(struct jffs2_sb_info *c, static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_raw_summary *summary, uint32_t *pseudo_random) { + struct jffs2_raw_node_ref *raw; struct jffs2_inode_cache *ic; struct jffs2_full_dirent *fd; void *sp; @@ -399,11 +404,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras for (i=0; isum_num); i++) { dbg_summary("processing summary index %d\n", i); - /* Make sure there's a spare ref for dirty space */ - err = jffs2_prealloc_raw_node_refs(c, 2); - if (err) - return err; - switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { case JFFS2_NODETYPE_INODE: { struct jffs2_sum_inode_flash *spi; @@ -415,14 +415,22 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras jeb->offset + je32_to_cpu(spi->offset), jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spu->totlen)); + raw = alloc_ref_at(c, jeb, je32_to_cpu(spi->offset)); + if (!raw) { + JFFS2_NOTICE("allocation of node reference failed\n"); + return -ENOMEM; + } + ic = jffs2_scan_make_ino_cache(c, ino); if (!ic) { JFFS2_NOTICE("scan_make_ino_cache failed\n"); + jffs2_free_raw_node_ref(raw); return -ENOMEM; } - sum_link_node_ref(c, jeb, je32_to_cpu(spi->offset) | REF_UNCHECKED, - PAD(je32_to_cpu(spi->totlen)), ic); + raw->flash_offset |= REF_UNCHECKED; + + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spi->totlen)), ic); *pseudo_random += je32_to_cpu(spi->version); @@ -447,15 +455,24 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras memcpy(&fd->name, spd->name, spd->nsize); fd->name[spd->nsize] = 0; + raw = alloc_ref_at(c, jeb, je32_to_cpu(spd->offset)); + if (!raw) { + jffs2_free_full_dirent(fd); + JFFS2_NOTICE("allocation of node reference failed\n"); + 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); return -ENOMEM; } - fd->raw = sum_link_node_ref(c, jeb, je32_to_cpu(spd->offset) | REF_PRISTINE, - PAD(je32_to_cpu(spd->totlen)), ic); + raw->flash_offset |= REF_PRISTINE; + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spd->totlen)), ic); + fd->raw = raw; fd->next = NULL; fd->version = je32_to_cpu(spd->version); fd->ino = je32_to_cpu(spd->ino); @@ -480,10 +497,15 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras jeb->offset + je32_to_cpu(spx->offset), jeb->offset + je32_to_cpu(spx->offset) + je32_to_cpu(spx->totlen), je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); - + raw = alloc_ref_at(c, jeb, je32_to_cpu(spx->offset)); + if (!raw) { + JFFS2_NOTICE("allocation of node reference failed\n"); + return -ENOMEM; + } xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); if (IS_ERR(xd)) { + jffs2_free_raw_node_ref(raw); if (PTR_ERR(xd) == -EEXIST) { /* a newer version of xd exists */ if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(spx->totlen)))) @@ -494,10 +516,12 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras JFFS2_NOTICE("allocation of xattr_datum failed\n"); return PTR_ERR(xd); } + xd->node = raw; - xd->node = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED, - PAD(je32_to_cpu(spx->totlen)), NULL); - /* FIXME */ xd->node->next_in_ino = (void *)xd; + raw->flash_offset |= REF_UNCHECKED; + + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spx->totlen)), NULL); + /* FIXME */ raw->next_in_ino = (void *)xd; *pseudo_random += je32_to_cpu(spx->xid); sp += JFFS2_SUMMARY_XATTR_SIZE; @@ -513,21 +537,29 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras jeb->offset + je32_to_cpu(spr->offset), jeb->offset + je32_to_cpu(spr->offset) + PAD(sizeof(struct jffs2_raw_xref))); + raw = alloc_ref_at(c, jeb, je32_to_cpu(spr->offset)); + if (!raw) { + JFFS2_NOTICE("allocation of node reference failed\n"); + return -ENOMEM; + } ref = jffs2_alloc_xattr_ref(); if (!ref) { JFFS2_NOTICE("allocation of xattr_datum failed\n"); + jffs2_free_raw_node_ref(raw); return -ENOMEM; } ref->ino = 0xfffffffe; ref->xid = 0xfffffffd; + ref->node = raw; ref->next = c->xref_temp; c->xref_temp = ref; - ref->node = sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED, - PAD(sizeof(struct jffs2_raw_xref)), NULL); - /* FIXME */ ref->node->next_in_ino = (void *)ref; + raw->flash_offset |= REF_UNCHECKED; - *pseudo_random += ref->node->flash_offset; + jffs2_link_node_ref(c, jeb, raw, PAD(sizeof(struct jffs2_raw_xref)), NULL); + /* FIXME */ raw->next_in_ino = (void *)ref; + + *pseudo_random += raw->flash_offset; sp += JFFS2_SUMMARY_XREF_SIZE; break; @@ -552,6 +584,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras } } } + return 0; } @@ -561,6 +594,7 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb uint32_t *pseudo_random) { struct jffs2_unknown_node crcnode; + struct jffs2_raw_node_ref *cache_ref; int ret, ofs; uint32_t crc; int err; @@ -616,8 +650,16 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) return err; } else { - jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, - je32_to_cpu(summary->cln_mkr), NULL); + struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); + + if (!marker_ref) { + JFFS2_NOTICE("Failed to allocate node ref for clean marker\n"); + return -ENOMEM; + } + + marker_ref->flash_offset = jeb->offset | REF_NORMAL; + + jffs2_link_node_ref(c, jeb, marker_ref, je32_to_cpu(summary->cln_mkr), NULL); } } @@ -630,11 +672,16 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb return ret; /* real error */ /* for PARANOIA_CHECK */ - ret = jffs2_prealloc_raw_node_refs(c, 1); - if (ret) - return ret; + cache_ref = alloc_ref_at(c, jeb, ofs); + + if (!cache_ref) { + JFFS2_NOTICE("Failed to allocate node ref for cache\n"); + return -ENOMEM; + } + + cache_ref->flash_offset |= REF_NORMAL; - jffs2_link_node_ref(c, jeb, (jeb->offset + ofs) | REF_NORMAL, sumsize, NULL); + jffs2_link_node_ref(c, jeb, cache_ref, sumsize, NULL); if (unlikely(jeb->free_size)) { JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n", @@ -662,7 +709,6 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock union jffs2_sum_mem *temp; struct jffs2_sum_marker *sm; struct kvec vecs[2]; - uint32_t sum_ofs; void *wpage; int ret; size_t retlen; @@ -775,31 +821,36 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock vecs[1].iov_base = c->summary->sum_buf; vecs[1].iov_len = datasize; - sum_ofs = jeb->offset + c->sector_size - jeb->free_size; - dbg_summary("JFFS2: writing out data to flash to pos : 0x%08x\n", - sum_ofs); + jeb->offset + c->sector_size - jeb->free_size); - ret = jffs2_flash_writev(c, vecs, 2, sum_ofs, &retlen, 0); + spin_unlock(&c->erase_completion_lock); + ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size - + jeb->free_size, &retlen, 0); if (ret || (retlen != infosize)) { + struct jffs2_raw_node_ref *ref; JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n", - infosize, sum_ofs, ret, retlen); + infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen); /* Waste remaining space */ - spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL); - spin_unlock(&c->erase_completion_lock); + ref = jffs2_alloc_raw_node_ref(); + if (ref) { + spin_lock(&c->erase_completion_lock); + + ref->flash_offset = jeb->offset + c->sector_size - jeb->free_size; + ref->flash_offset |= REF_OBSOLETE; + + jffs2_link_node_ref(c, jeb, ref, c->sector_size - jeb->free_size, NULL); + } c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; - return 0; + return 1; } spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, sum_ofs | REF_NORMAL, infosize, NULL); - spin_unlock(&c->erase_completion_lock); return 0; } @@ -808,15 +859,12 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) { - int datasize, infosize, padsize; + struct jffs2_raw_node_ref *summary_ref; + int datasize, infosize, padsize, ret; struct jffs2_eraseblock *jeb; - int ret; dbg_summary("called\n"); - spin_unlock(&c->erase_completion_lock); - jffs2_prealloc_raw_node_refs(c, 1); - jeb = c->nextblock; if (!c->summary->sum_num || !c->summary->sum_list_head) { @@ -840,6 +888,22 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) } ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize); + if (ret) + return 0; /* can't write out summary, block is marked as NOSUM_SIZE */ + + /* for ACCT_PARANOIA_CHECK */ + spin_unlock(&c->erase_completion_lock); + summary_ref = jffs2_alloc_raw_node_ref(); + + if (!summary_ref) { + JFFS2_NOTICE("Failed to allocate node ref for summary\n"); + return -ENOMEM; + } + + summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL; + spin_lock(&c->erase_completion_lock); - return ret; + jffs2_link_node_ref(c, jeb, summary_ref, infosize, NULL); + + return 0; } diff --git a/trunk/fs/jffs2/wbuf.c b/trunk/fs/jffs2/wbuf.c index 0d7abb260489..916c87d3393b 100644 --- a/trunk/fs/jffs2/wbuf.c +++ b/trunk/fs/jffs2/wbuf.c @@ -179,9 +179,6 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) unsigned char *buf; uint32_t start, end, ofs, len; - if (jffs2_prealloc_raw_node_refs(c, c->reserved_refs + 1)) - return; - spin_lock(&c->erase_completion_lock); jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; @@ -309,9 +306,17 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); kfree(buf); - if (retlen) - jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, *first_raw), NULL); + if (retlen) { + struct jffs2_raw_node_ref *raw2; + + raw2 = jffs2_alloc_raw_node_ref(); + if (!raw2) + return; + + raw2->flash_offset = ofs | REF_OBSOLETE; + jffs2_add_physical_node_ref(c, raw2, ref_totlen(c, jeb, *first_raw), NULL); + } return; } printk(KERN_NOTICE "Recovery of wbuf succeeded to %08x\n", ofs); @@ -423,9 +428,6 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) if (!c->wbuf_len) /* already checked c->wbuf above */ return 0; - if (jffs2_prealloc_raw_node_refs(c, c->reserved_refs + 1)) - return -ENOMEM; - /* claim remaining space on the page this happens, if we have a change to a new block, or if fsync forces us to flush the writebuffer. @@ -483,6 +485,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) /* Adjust free size of the block if we padded. */ if (pad) { struct jffs2_eraseblock *jeb; + struct jffs2_raw_node_ref *ref; uint32_t waste = c->wbuf_pagesize - c->wbuf_len; jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; @@ -500,10 +503,15 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) jeb->offset, jeb->free_size); BUG(); } + ref = jffs2_alloc_raw_node_ref(); + if (!ref) + return -ENOMEM; + ref->flash_offset = c->wbuf_ofs + c->wbuf_len; + ref->flash_offset |= REF_OBSOLETE; spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL); + jffs2_link_node_ref(c, jeb, ref, waste, NULL); /* FIXME: that made it count as dirty. Convert to wasted */ jeb->dirty_size -= waste; c->dirty_size -= waste; diff --git a/trunk/fs/jffs2/write.c b/trunk/fs/jffs2/write.c index 67176792e138..0e12b7561b71 100644 --- a/trunk/fs/jffs2/write.c +++ b/trunk/fs/jffs2/write.c @@ -61,6 +61,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 uint32_t datalen, int alloc_mode) { + struct jffs2_raw_node_ref *raw; struct jffs2_full_dnode *fn; size_t retlen; uint32_t flash_ofs; @@ -82,16 +83,27 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) { printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen); } + raw = jffs2_alloc_raw_node_ref(); + if (!raw) + return ERR_PTR(-ENOMEM); fn = jffs2_alloc_full_dnode(); - if (!fn) + if (!fn) { + jffs2_free_raw_node_ref(raw); return ERR_PTR(-ENOMEM); + } + + fn->ofs = je32_to_cpu(ri->offset); + fn->size = je32_to_cpu(ri->dsize); + fn->frags = 0; /* check number of valid vecs */ if (!datalen || !data) cnt = 1; retry: - flash_ofs = write_ofs(c); + fn->raw = raw; + + raw->flash_offset = flash_ofs = write_ofs(c); jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len); @@ -118,11 +130,14 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 seem corrupted, in which case the scan would skip over any node we write before the original intended end of this node */ - jffs2_add_physical_node_ref(c, flash_ofs | REF_OBSOLETE, PAD(sizeof(*ri)+datalen), NULL); + raw->flash_offset |= REF_OBSOLETE; + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen), NULL); + jffs2_mark_node_obsolete(c, raw); } else { - printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", flash_ofs); + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); + jffs2_free_raw_node_ref(raw); } - if (!retried && alloc_mode != ALLOC_NORETRY) { + if (!retried && alloc_mode != ALLOC_NORETRY && (raw = jffs2_alloc_raw_node_ref())) { /* Try to reallocate space and retry */ uint32_t dummy; struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size]; @@ -157,6 +172,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 goto retry; } D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); + jffs2_free_raw_node_ref(raw); } /* Release the full_dnode which is now useless, and return */ jffs2_free_full_dnode(fn); @@ -170,17 +186,14 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) || ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) && (je32_to_cpu(ri->dsize)+je32_to_cpu(ri->offset) == je32_to_cpu(ri->isize)))) { - flash_ofs |= REF_PRISTINE; + raw->flash_offset |= REF_PRISTINE; } else { - flash_ofs |= REF_NORMAL; + raw->flash_offset |= REF_NORMAL; } - fn->raw = jffs2_add_physical_node_ref(c, flash_ofs, PAD(sizeof(*ri)+datalen), f->inocache); - fn->ofs = je32_to_cpu(ri->offset); - fn->size = je32_to_cpu(ri->dsize); - fn->frags = 0; + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen), f->inocache); D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", - flash_ofs & ~3, flash_ofs & 3, je32_to_cpu(ri->dsize), + flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc), je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen))); @@ -195,10 +208,11 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, int alloc_mode) { + struct jffs2_raw_node_ref *raw; struct jffs2_full_dirent *fd; size_t retlen; struct kvec vecs[2]; - uint32_t flash_ofs; + uint32_t flash_ofs = write_ofs(c); int retried = 0; int ret; @@ -209,16 +223,26 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n"); BUG(); - }); + } + ); vecs[0].iov_base = rd; vecs[0].iov_len = sizeof(*rd); vecs[1].iov_base = (unsigned char *)name; vecs[1].iov_len = namelen; + jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len); + + raw = jffs2_alloc_raw_node_ref(); + + if (!raw) + return ERR_PTR(-ENOMEM); + fd = jffs2_alloc_full_dirent(namelen+1); - if (!fd) + if (!fd) { + jffs2_free_raw_node_ref(raw); return ERR_PTR(-ENOMEM); + } fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); @@ -228,9 +252,9 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff fd->name[namelen]=0; retry: - flash_ofs = write_ofs(c); + fd->raw = raw; - jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len); + raw->flash_offset = flash_ofs; if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) { BUG_ON(!retried); @@ -249,11 +273,14 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff sizeof(*rd)+namelen, flash_ofs, ret, retlen); /* Mark the space as dirtied */ if (retlen) { - jffs2_add_physical_node_ref(c, flash_ofs | REF_OBSOLETE, PAD(sizeof(*rd)+namelen), NULL); + raw->flash_offset |= REF_OBSOLETE; + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen), NULL); + jffs2_mark_node_obsolete(c, raw); } else { - printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", flash_ofs); + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); + jffs2_free_raw_node_ref(raw); } - if (!retried) { + if (!retried && (raw = jffs2_alloc_raw_node_ref())) { /* Try to reallocate space and retry */ uint32_t dummy; struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size]; @@ -286,13 +313,15 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff goto retry; } D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); + jffs2_free_raw_node_ref(raw); } /* Release the full_dnode which is now useless, and return */ jffs2_free_full_dirent(fd); return ERR_PTR(ret?ret:-EIO); } /* Mark the space used */ - fd->raw = jffs2_add_physical_node_ref(c, flash_ofs | REF_PRISTINE, PAD(sizeof(*rd)+namelen), f->inocache); + raw->flash_offset |= REF_PRISTINE; + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen), f->inocache); if (retried) { jffs2_dbg_acct_sanity_check(c,NULL); diff --git a/trunk/fs/jffs2/xattr.c b/trunk/fs/jffs2/xattr.c index 2255f1367bd5..008f91b1c171 100644 --- a/trunk/fs/jffs2/xattr.c +++ b/trunk/fs/jffs2/xattr.c @@ -304,8 +304,8 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) { /* must be called under down_write(xattr_sem) */ - struct jffs2_raw_node_ref *raw; struct jffs2_raw_xattr rx; + struct jffs2_raw_node_ref *raw; struct kvec vecs[2]; uint32_t length; int rc, totlen; @@ -319,6 +319,11 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x vecs[1].iov_len = xd->name_len + 1 + xd->value_len; totlen = vecs[0].iov_len + vecs[1].iov_len; + raw = jffs2_alloc_raw_node_ref(); + if (!raw) + return -ENOMEM; + raw->flash_offset = phys_ofs; + /* Setup raw-xattr */ rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rx.nodetype = cpu_to_je16(JFFS2_NODETYPE_XATTR); @@ -338,14 +343,19 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%u, at %#08x\n", rc, totlen, length, phys_ofs); rc = rc ? rc : -EIO; - if (length) - jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, PAD(totlen), NULL); - + if (length) { + raw->flash_offset |= REF_OBSOLETE; + jffs2_add_physical_node_ref(c, raw, PAD(totlen), NULL); + jffs2_mark_node_obsolete(c, raw); + } else { + jffs2_free_raw_node_ref(raw); + } return rc; } /* success */ - raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), NULL); + raw->flash_offset |= REF_PRISTINE; + jffs2_add_physical_node_ref(c, raw, PAD(totlen), NULL); /* FIXME */ raw->next_in_ino = (void *)xd; if (xd->node) @@ -553,6 +563,11 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) uint32_t phys_ofs = write_ofs(c); int ret; + raw = jffs2_alloc_raw_node_ref(); + if (!raw) + return -ENOMEM; + raw->flash_offset = phys_ofs; + rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rr.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF); rr.totlen = cpu_to_je32(PAD(sizeof(rr))); @@ -567,13 +582,18 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) JFFS2_WARNING("jffs2_flash_write() returned %d, request=%u, retlen=%u, at %#08x\n", ret, sizeof(rr), length, phys_ofs); ret = ret ? ret : -EIO; - if (length) - jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, PAD(sizeof(rr)), NULL); - + if (length) { + raw->flash_offset |= REF_OBSOLETE; + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr)), NULL); + jffs2_mark_node_obsolete(c, raw); + } else { + jffs2_free_raw_node_ref(raw); + } return ret; } + raw->flash_offset |= REF_PRISTINE; - raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), NULL); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr)), NULL); /* FIXME */ raw->next_in_ino = (void *)ref; if (ref->node) delete_xattr_ref_node(c, ref); diff --git a/trunk/include/linux/mtd/nand.h b/trunk/include/linux/mtd/nand.h index 460525841a27..6931376ed68d 100644 --- a/trunk/include/linux/mtd/nand.h +++ b/trunk/include/linux/mtd/nand.h @@ -237,7 +237,7 @@ struct nand_ecc_ctrl { int steps; int size; int bytes; - int (*hwctl)(struct mtd_info *mtd, int mode); + void (*hwctl)(struct mtd_info *mtd, int mode); int (*calculate)(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code);