From aa98d7cf59b5b0764d3502662053489585faf2fe Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Sat, 13 May 2006 15:09:47 +0900 Subject: [JFFS2][XATTR] XATTR support on JFFS2 (version. 5) This attached patches provide xattr support including POSIX-ACL and SELinux support on JFFS2 (version.5). There are some significant differences from previous version posted at last December. The biggest change is addition of EBS(Erase Block Summary) support. Currently, both kernel and usermode utility (sumtool) can recognize xattr nodes which have JFFS2_NODETYPE_XATTR/_XREF nodetype. In addition, some bugs are fixed. - A potential race condition was fixed. - Unexpected fail when updating a xattr by same name/value pair was fixed. - A bug when removing xattr name/value pair was fixed. The fundamental structures (such as using two new nodetypes and exclusion mechanism by rwsem) are unchanged. But most of implementation were reviewed and updated if necessary. Espacially, we had to change several internal implementations related to load_xattr_datum() to avoid a potential race condition. [1/2] xattr_on_jffs2.kernel.version-5.patch [2/2] xattr_on_jffs2.utils.version-5.patch Signed-off-by: KaiGai Kohei Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index cf55b221fc2b..f09689e320fe 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -306,6 +306,136 @@ int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *je return BLK_STATE_ALLDIRTY; } +#ifdef CONFIG_JFFS2_FS_XATTR +static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_xattr *rx, uint32_t ofs, + struct jffs2_summary *s) +{ + struct jffs2_xattr_datum *xd; + struct jffs2_raw_node_ref *raw; + uint32_t totlen, crc; + + crc = crc32(0, rx, sizeof(struct jffs2_raw_xattr) - 4); + if (crc != je32_to_cpu(rx->node_crc)) { + if (je32_to_cpu(rx->node_crc) != 0xffffffff) + JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", + ofs, je32_to_cpu(rx->node_crc), crc); + DIRTY_SPACE(je32_to_cpu(rx->totlen)); + return 0; + } + + totlen = PAD(sizeof(*rx) + rx->name_len + 1 + je16_to_cpu(rx->value_len)); + if (totlen != je32_to_cpu(rx->totlen)) { + JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n", + ofs, je32_to_cpu(rx->totlen), totlen); + DIRTY_SPACE(je32_to_cpu(rx->totlen)); + 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) { + DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen))); + return 0; + } + return PTR_ERR(xd); + } + xd->xprefix = rx->xprefix; + 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->__totlen = totlen; + raw->flash_offset = ofs | REF_PRISTINE; + raw->next_phys = NULL; + raw->next_in_ino = (void *)xd; + if (!jeb->first_node) + jeb->first_node = raw; + if (jeb->last_node) + jeb->last_node->next_phys = raw; + jeb->last_node = raw; + + USED_SPACE(PAD(je32_to_cpu(rx->totlen))); + if (jffs2_sum_active()) + jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset); + dbg_xattr("scaning xdatum at %#08x (xid=%u, version=%u)\n", + ofs, xd->xid, xd->version); + return 0; +} + +static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_xref *rr, uint32_t ofs, + struct jffs2_summary *s) +{ + struct jffs2_xattr_ref *ref; + struct jffs2_raw_node_ref *raw; + uint32_t crc; + + crc = crc32(0, rr, sizeof(*rr) - 4); + if (crc != je32_to_cpu(rr->node_crc)) { + if (je32_to_cpu(rr->node_crc) != 0xffffffff) + JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", + ofs, je32_to_cpu(rr->node_crc), crc); + DIRTY_SPACE(PAD(je32_to_cpu(rr->totlen))); + return 0; + } + + if (PAD(sizeof(struct jffs2_raw_xref)) != je32_to_cpu(rr->totlen)) { + JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n", + ofs, je32_to_cpu(rr->totlen), + PAD(sizeof(struct jffs2_raw_xref))); + DIRTY_SPACE(je32_to_cpu(rr->totlen)); + return 0; + } + + ref = jffs2_alloc_xattr_ref(); + 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 + * Thoes variables are declared as union, thus using those + * are exclusive. In a similar way, ref->ilist is temporarily + * 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); + list_add_tail(&ref->ilist, &c->xattr_temp); + + raw->__totlen = PAD(je32_to_cpu(rr->totlen)); + raw->flash_offset = ofs | REF_PRISTINE; + raw->next_phys = NULL; + raw->next_in_ino = (void *)ref; + if (!jeb->first_node) + jeb->first_node = raw; + if (jeb->last_node) + jeb->last_node->next_phys = raw; + jeb->last_node = raw; + + USED_SPACE(PAD(je32_to_cpu(rr->totlen))); + if (jffs2_sum_active()) + jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset); + dbg_xattr("scan xref at %#08x (xid=%u, ino=%u)\n", + ofs, ref->xid, ref->ino); + return 0; +} +#endif + static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { struct jffs2_unknown_node *node; @@ -614,6 +744,43 @@ scan_more: ofs += PAD(je32_to_cpu(node->totlen)); break; +#ifdef CONFIG_JFFS2_FS_XATTR + case JFFS2_NODETYPE_XATTR: + if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) { + buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); + D1(printk(KERN_DEBUG "Fewer than %d bytes (xattr node)" + " left to end of buf. Reading 0x%x at 0x%08x\n", + je32_to_cpu(node->totlen), buf_len, ofs)); + err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); + if (err) + return err; + buf_ofs = ofs; + node = (void *)buf; + } + err = jffs2_scan_xattr_node(c, jeb, (void *)node, ofs, s); + if (err) + return err; + ofs += PAD(je32_to_cpu(node->totlen)); + break; + case JFFS2_NODETYPE_XREF: + if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) { + buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); + D1(printk(KERN_DEBUG "Fewer than %d bytes (xref node)" + " left to end of buf. Reading 0x%x at 0x%08x\n", + je32_to_cpu(node->totlen), buf_len, ofs)); + err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); + if (err) + return err; + buf_ofs = ofs; + node = (void *)buf; + } + err = jffs2_scan_xref_node(c, jeb, (void *)node, ofs, s); + if (err) + return err; + ofs += PAD(je32_to_cpu(node->totlen)); + break; +#endif /* CONFIG_JFFS2_FS_XATTR */ + case JFFS2_NODETYPE_CLEANMARKER: D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs)); if (je32_to_cpu(node->totlen) != c->cleanmarker_size) { @@ -721,6 +888,7 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin ic->ino = ino; ic->nodes = (void *)ic; + init_xattr_inode_cache(ic); jffs2_add_ino_cache(c, ic); if (ino == 1) ic->nlink = 1; -- cgit v1.2.3-70-g09d2 From 8f2b6f49c656dd4597904f8c20661d6b73cdbbeb Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Sat, 13 May 2006 15:15:07 +0900 Subject: [JFFS2][XATTR] Remove 'struct list_head ilist' from jffs2_inode_cache. This patch can reduce 4-byte of memory usage per inode_cache. [4/10] jffs2-xattr-v5.1-04-remove_ilist_from_ic.patch Signed-off-by: KaiGai Kohei --- fs/jffs2/jffs2_fs_sb.h | 2 +- fs/jffs2/malloc.c | 1 - fs/jffs2/nodelist.h | 2 +- fs/jffs2/readinode.c | 1 - fs/jffs2/scan.c | 6 ++-- fs/jffs2/summary.c | 3 +- fs/jffs2/write.c | 1 - fs/jffs2/xattr.c | 75 +++++++++++++++++++++++++++++++------------------- fs/jffs2/xattr.h | 7 +---- 9 files changed, 55 insertions(+), 43 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 3b4e0edd6dbb..272fbea55192 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -119,8 +119,8 @@ struct jffs2_sb_info { #define XATTRINDEX_HASHSIZE (57) uint32_t highest_xid; struct list_head xattrindex[XATTRINDEX_HASHSIZE]; - struct list_head xattr_temp; struct list_head xattr_unchecked; + struct jffs2_xattr_ref *xref_temp; struct rw_semaphore xattr_sem; uint32_t xdatum_mem_usage; uint32_t xdatum_mem_threshold; diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 3d5b7ecfbf8d..f2473fa2fd16 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -259,7 +259,6 @@ struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void) memset(ref, 0, sizeof(struct jffs2_xattr_ref)); ref->class = RAWNODE_CLASS_XATTR_REF; - INIT_LIST_HEAD(&ref->ilist); return ref; } diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 6f6279cf4909..351d947c9375 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -117,7 +117,7 @@ struct jffs2_inode_cache { uint32_t ino; int nlink; #ifdef CONFIG_JFFS2_FS_XATTR - struct list_head ilist; + struct jffs2_xattr_ref *xref; #endif }; diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 61ccdf4f1042..e1acce8fb2bf 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -902,7 +902,6 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, f->inocache->ino = f->inocache->nlink = 1; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; f->inocache->state = INO_STATE_READING; - init_xattr_inode_cache(f->inocache); jffs2_add_ino_cache(c, f->inocache); } if (!f->inocache) { diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index f09689e320fe..0a79fc921e9f 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -408,14 +408,15 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock * 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 * Thoes variables are declared as union, thus using those - * are exclusive. In a similar way, ref->ilist is temporarily + * are exclusive. In a similar way, ref->next is temporarily * 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); - list_add_tail(&ref->ilist, &c->xattr_temp); + ref->next = c->xref_temp; + c->xref_temp = ref; raw->__totlen = PAD(je32_to_cpu(rr->totlen)); raw->flash_offset = ofs | REF_PRISTINE; @@ -888,7 +889,6 @@ struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uin ic->ino = ino; ic->nodes = (void *)ic; - init_xattr_inode_cache(ic); jffs2_add_ino_cache(c, ic); if (ino == 1) ic->nlink = 1; diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 5d9ec8e36528..831a42c13059 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -556,7 +556,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras ref->ino = 0xfffffffe; ref->xid = 0xfffffffd; ref->node = raw; - list_add_tail(&ref->ilist, &c->xattr_temp); + ref->next = c->xref_temp; + c->xref_temp = ref; raw->__totlen = PAD(sizeof(struct jffs2_raw_xref)); raw->flash_offset = ofs | REF_UNCHECKED; diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index d5c78195f3b8..ff2b00b604ec 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -36,7 +36,6 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint f->inocache->nlink = 1; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; f->inocache->state = INO_STATE_PRESENT; - init_xattr_inode_cache(f->inocache); jffs2_add_ino_cache(c, f->inocache); D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino)); diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index c9a185c54ce7..b16bc71c9cd2 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -456,7 +456,7 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c, * is called to remove xrefs related to obsolete inode when inode is unlinked. * jffs2_xattr_free_inode(c, ic) * is called to release xattr related objects when unmounting. - * check_xattr_ref_ilist(c, ic) + * check_xattr_ref_inode(c, ic) * is used to confirm inode does not have duplicate xattr name/value pair. * -------------------------------------------------- */ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) @@ -549,7 +549,6 @@ static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *re BUG_ON(!ref->node); delete_xattr_ref_node(c, ref); - list_del(&ref->ilist); xd = ref->xd; xd->refcnt--; if (!xd->refcnt) @@ -629,7 +628,8 @@ static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct } /* Chain to inode */ - list_add(&ref->ilist, &ic->ilist); + ref->next = ic->xref; + ic->xref = ref; return ref; /* success */ } @@ -644,8 +644,11 @@ void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache return; down_write(&c->xattr_sem); - list_for_each_entry_safe(ref, _ref, &ic->ilist, ilist) + for (ref = ic->xref; ref; ref = _ref) { + _ref = ref->next; delete_xattr_ref(c, ref); + } + ic->xref = NULL; up_write(&c->xattr_sem); } @@ -656,8 +659,8 @@ void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i struct jffs2_xattr_ref *ref, *_ref; down_write(&c->xattr_sem); - list_for_each_entry_safe(ref, _ref, &ic->ilist, ilist) { - list_del(&ref->ilist); + for (ref = ic->xref; ref; ref = _ref) { + _ref = ref->next; xd = ref->xd; xd->refcnt--; if (!xd->refcnt) { @@ -666,16 +669,17 @@ void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *i } jffs2_free_xattr_ref(ref); } + ic->xref = NULL; up_write(&c->xattr_sem); } -static int check_xattr_ref_ilist(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) { - /* success of check_xattr_ref_ilist() means taht inode (ic) dose not have + /* success of check_xattr_ref_inode() means taht inode (ic) dose not have * duplicate name/value pairs. If duplicate name/value pair would be found, * one will be removed. */ - struct jffs2_xattr_ref *ref, *cmp; + struct jffs2_xattr_ref *ref, *cmp, **pref; int rc = 0; if (likely(ic->flags & INO_FLAGS_XATTR_CHECKED)) @@ -683,22 +687,23 @@ static int check_xattr_ref_ilist(struct jffs2_sb_info *c, struct jffs2_inode_cac down_write(&c->xattr_sem); retry: rc = 0; - list_for_each_entry(ref, &ic->ilist, ilist) { + for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { if (!ref->xd->xname) { rc = load_xattr_datum(c, ref->xd); if (unlikely(rc > 0)) { + *pref = ref->next; delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) goto out; } - cmp = ref; - list_for_each_entry_continue(cmp, &ic->ilist, ilist) { + for (cmp=ref->next, pref=&ref->next; cmp; pref=&cmp->next, cmp=cmp->next) { if (!cmp->xd->xname) { ref->xd->flags |= JFFS2_XFLAGS_BIND; rc = load_xattr_datum(c, cmp->xd); ref->xd->flags &= ~JFFS2_XFLAGS_BIND; if (unlikely(rc > 0)) { + *pref = cmp->next; delete_xattr_ref(c, cmp); goto retry; } else if (unlikely(rc < 0)) @@ -706,6 +711,7 @@ static int check_xattr_ref_ilist(struct jffs2_sb_info *c, struct jffs2_inode_cac } if (ref->xd->xprefix == cmp->xd->xprefix && !strcmp(ref->xd->xname, cmp->xd->xname)) { + *pref = cmp->next; delete_xattr_ref(c, cmp); goto retry; } @@ -736,8 +742,8 @@ void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c) for (i=0; i < XATTRINDEX_HASHSIZE; i++) INIT_LIST_HEAD(&c->xattrindex[i]); - INIT_LIST_HEAD(&c->xattr_temp); INIT_LIST_HEAD(&c->xattr_unchecked); + c->xref_temp = NULL; init_rwsem(&c->xattr_sem); c->xdatum_mem_usage = 0; @@ -765,8 +771,11 @@ void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c) struct jffs2_xattr_ref *ref, *_ref; int i; - list_for_each_entry_safe(ref, _ref, &c->xattr_temp, ilist) + for (ref=c->xref_temp; ref; ref = _ref) { + _ref = ref->next; jffs2_free_xattr_ref(ref); + } + c->xref_temp = NULL; for (i=0; i < XATTRINDEX_HASHSIZE; i++) { list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { @@ -788,8 +797,8 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING)); /* Phase.1 */ - list_for_each_entry_safe(ref, _ref, &c->xattr_temp, ilist) { - list_del_init(&ref->ilist); + for (ref=c->xref_temp; ref; ref=_ref) { + _ref = ref->next; /* checking REF_UNCHECKED nodes */ if (ref_flags(ref->node) != REF_PRISTINE) { if (verify_xattr_ref(c, ref)) { @@ -813,9 +822,11 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) ref->xd = xd; ref->ic = ic; xd->refcnt++; - list_add_tail(&ref->ilist, &ic->ilist); + ref->next = ic->xref; + ic->xref = ref; xref_count++; } + c->xref_temp = NULL; /* After this, ref->xid/ino are NEVER used. */ /* Phase.2 */ @@ -931,20 +942,20 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size) struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_inode_cache *ic = f->inocache; - struct jffs2_xattr_ref *ref; + struct jffs2_xattr_ref *ref, **pref; struct jffs2_xattr_datum *xd; struct xattr_handler *xhandle; ssize_t len, rc; int retry = 0; - rc = check_xattr_ref_ilist(c, ic); + rc = check_xattr_ref_inode(c, ic); if (unlikely(rc)) return rc; down_read(&c->xattr_sem); retry: len = 0; - list_for_each_entry(ref, &ic->ilist, ilist) { + for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { BUG_ON(ref->ic != ic); xd = ref->xd; if (!xd->xname) { @@ -957,6 +968,7 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size) } else { rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { + *pref = ref->next; delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) @@ -992,16 +1004,16 @@ int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_inode_cache *ic = f->inocache; struct jffs2_xattr_datum *xd; - struct jffs2_xattr_ref *ref; + struct jffs2_xattr_ref *ref, **pref; int rc, retry = 0; - rc = check_xattr_ref_ilist(c, ic); + rc = check_xattr_ref_inode(c, ic); if (unlikely(rc)) return rc; down_read(&c->xattr_sem); retry: - list_for_each_entry(ref, &ic->ilist, ilist) { + for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { BUG_ON(ref->ic!=ic); xd = ref->xd; @@ -1017,6 +1029,7 @@ int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, } else { rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { + *pref = ref->next; delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) { @@ -1053,11 +1066,11 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); struct jffs2_inode_cache *ic = f->inocache; struct jffs2_xattr_datum *xd; - struct jffs2_xattr_ref *ref, *newref; + struct jffs2_xattr_ref *ref, *newref, **pref; uint32_t phys_ofs, length, request; int rc; - rc = check_xattr_ref_ilist(c, ic); + rc = check_xattr_ref_inode(c, ic); if (unlikely(rc)) return rc; @@ -1072,13 +1085,14 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, /* Find existing xattr */ down_write(&c->xattr_sem); retry: - list_for_each_entry(ref, &ic->ilist, ilist) { + for (ref=ic->xref, pref=&ic->xref; ref; pref=&ref->next, ref=ref->next) { xd = ref->xd; if (xd->xprefix != xprefix) continue; if (!xd->xname) { rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { + *pref = ref->next; delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) @@ -1090,6 +1104,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, goto out; } if (!buffer) { + *pref = ref->next; delete_xattr_ref(c, ref); rc = 0; goto out; @@ -1098,7 +1113,6 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, } } /* not found */ - ref = NULL; if (flags & XATTR_REPLACE) { rc = -ENODATA; goto out; @@ -1130,14 +1144,19 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, return rc; } down_write(&c->xattr_sem); + if (ref) + *pref = ref->next; newref = create_xattr_ref(c, ic, xd, phys_ofs); if (IS_ERR(newref)) { + if (ref) { + ref->next = ic->xref; + ic->xref = ref; + } rc = PTR_ERR(newref); xd->refcnt--; if (!xd->refcnt) delete_xattr_datum(c, xd); } else if (ref) { - /* If replaced xattr_ref exists */ delete_xattr_ref(c, ref); } out: diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h index d157ad641ed4..0360097e5933 100644 --- a/fs/jffs2/xattr.h +++ b/fs/jffs2/xattr.h @@ -54,7 +54,7 @@ struct jffs2_xattr_ref struct jffs2_xattr_datum *xd; /* reference to jffs2_xattr_datum */ uint32_t xid; /* only used in sccanning/building */ }; - struct list_head ilist; /* chained from ic->ilist */ + struct jffs2_xattr_ref *next; /* chained from ic->xref_list */ }; #ifdef CONFIG_JFFS2_FS_XATTR @@ -86,9 +86,6 @@ extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t); #define jffs2_setxattr generic_setxattr #define jffs2_removexattr generic_removexattr -/*---- Any inline initialize functions ----*/ -#define init_xattr_inode_cache(x) INIT_LIST_HEAD(&((x)->ilist)) - #else #define jffs2_init_xattr_subsystem(c) @@ -106,8 +103,6 @@ extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t); #define jffs2_setxattr NULL #define jffs2_removexattr NULL -#define init_xattr_inode_cache(x) - #endif /* CONFIG_JFFS2_FS_XATTR */ #ifdef CONFIG_JFFS2_FS_SECURITY -- cgit v1.2.3-70-g09d2 From 5b5ffbc1e6d62d89747f3f59c09b2e488a7d7fce Mon Sep 17 00:00:00 2001 From: Florin Malita Date: Mon, 15 May 2006 23:42:31 +0100 Subject: [PATCH] jffs2: memory leak in jffs2_scan_medium() If jffs2_scan_eraseblock() fails and the exit path is taken, 's' is not being deallocated. Reported by Coverity, CID: 1258. Signed-off-by: Florin Malita Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index cf55b221fc2b..eca0996def60 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -222,9 +222,6 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) } } - if (jffs2_sum_active() && s) - kfree(s); - /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */ if (c->nextblock && (c->nextblock->dirty_size)) { c->nextblock->wasted_size += c->nextblock->dirty_size; @@ -266,6 +263,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) else c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); #endif + if (s) + kfree(s); + return ret; } -- cgit v1.2.3-70-g09d2 From 8e4482fba21d15da99f39a13396d3361e810d199 Mon Sep 17 00:00:00 2001 From: Ferenc Havasi Date: Fri, 19 May 2006 21:00:36 +0100 Subject: [JFFS2] Remove forgotten summary code Remove forgotten lines from jffs2_scan_eraseblock() which were unnecessary and may cause problem in some environments. Thanks to Alexander Belyakov . Signed-off-by: Ferenc Havasi Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index eca0996def60..352ada892f3e 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -365,23 +365,12 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo } kfree(sm); - - ofs = jeb->offset; - prevofs = jeb->offset - 1; } buf_ofs = jeb->offset; if (!buf_size) { buf_len = c->sector_size; - - if (jffs2_sum_active()) { - /* must reread because of summary test */ - err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); - if (err) - return err; - } - } else { buf_len = EMPTY_SCAN_SIZE(c->sector_size); err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); -- cgit v1.2.3-70-g09d2 From 9641b784ff82cf0a48a6c70ef9867f5fd728de67 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 20 May 2006 16:13:34 +0100 Subject: [JFFS2] Optimise reading of eraseblock summary nodes This improves the time to mount 512MiB of NAND flash on my OLPC prototype by about 4%. We used to read the last page of the eraseblock twice -- once to find the offset of the summary node, and again to actually _read_ the summary node. Now we read the last page only once, and read more only if we need to. We also don't allocate a new buffer just for the summary code -- we use the buffer which was already allocated for the scan. Better still, if the 'buffer' for the scan is actually just a pointer directly into NOR flash, we use that too, avoiding the memcpy() which we used to do. Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 74 +++++++++++++++++++++++++++++++++++++++++------------- fs/jffs2/summary.c | 36 +++++--------------------- fs/jffs2/summary.h | 3 ++- 3 files changed, 64 insertions(+), 49 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 352ada892f3e..2a24b44662bb 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -306,11 +306,12 @@ int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *je return BLK_STATE_ALLDIRTY; } +/* Called with 'buf_size == 0' if buf is in fact a pointer _directly_ into + the flash, XIP-style */ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { + unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { struct jffs2_unknown_node *node; struct jffs2_unknown_node crcnode; - struct jffs2_sum_marker *sm; uint32_t ofs, prevofs; uint32_t hdr_crc, buf_ofs, buf_len; int err; @@ -344,32 +345,69 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo #endif if (jffs2_sum_active()) { - sm = kmalloc(sizeof(struct jffs2_sum_marker), GFP_KERNEL); - if (!sm) { - return -ENOMEM; - } + struct jffs2_sum_marker *sm; + void *sumptr = NULL; + uint32_t sumlen; + + if (!buf_size) { + /* XIP case. Just look, point at the summary if it's there */ + sm = (void *)buf + jeb->offset - sizeof(*sm); + if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) { + sumptr = buf + je32_to_cpu(sm->offset); + sumlen = c->sector_size - je32_to_cpu(sm->offset); + } + } else { + /* If NAND flash, read a whole page of it. Else just the end */ + if (c->wbuf_pagesize) + buf_len = c->wbuf_pagesize; + else + buf_len = sizeof(*sm); + + /* Read as much as we want into the _end_ of the preallocated buffer */ + err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len, + jeb->offset + c->sector_size - buf_len, + buf_len); + if (err) + return err; + + sm = (void *)buf + buf_size - sizeof(*sm); + if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) { + sumlen = c->sector_size - je32_to_cpu(sm->offset); + sumptr = buf + buf_size - sumlen; + + /* Now, make sure the summary itself is available */ + if (sumlen > buf_size) { + /* Need to kmalloc for this. */ + sumptr = kmalloc(sumlen, GFP_KERNEL); + if (!sumptr) + return -ENOMEM; + memcpy(sumptr + sumlen - buf_len, buf + buf_size - buf_len, buf_len); + } + if (buf_len < sumlen) { + /* Need to read more so that the entire summary node is present */ + err = jffs2_fill_scan_buf(c, sumptr, + jeb->offset + c->sector_size - sumlen, + sumlen - buf_len); + if (err) + return err; + } + } - 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 ) { - err = jffs2_sum_scan_sumnode(c, jeb, je32_to_cpu(sm->offset), &pseudo_random); - if (err) { - kfree(sm); + if (sumptr) { + err = jffs2_sum_scan_sumnode(c, jeb, sumptr, sumlen, &pseudo_random); + if (err) return err; - } + if (buf_size && sumlen > buf_size) + kfree(sumptr); } - - kfree(sm); } buf_ofs = jeb->offset; if (!buf_size) { + /* This is the XIP case -- we're reading _directly_ from the flash chip */ buf_len = c->sector_size; } else { buf_len = EMPTY_SCAN_SIZE(c->sector_size); diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 48293c197f13..82a3706c54d8 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -318,7 +318,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras raw = jffs2_alloc_raw_node_ref(); if (!raw) { JFFS2_NOTICE("allocation of node reference failed\n"); - kfree(summary); return -ENOMEM; } @@ -326,7 +325,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras if (!ic) { JFFS2_NOTICE("scan_make_ino_cache failed\n"); jffs2_free_raw_node_ref(raw); - kfree(summary); return -ENOMEM; } @@ -358,10 +356,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras jeb->offset + je32_to_cpu(spd->offset)); fd = jffs2_alloc_full_dirent(spd->nsize+1); - if (!fd) { - kfree(summary); + if (!fd) return -ENOMEM; - } memcpy(&fd->name, spd->name, spd->nsize); fd->name[spd->nsize] = 0; @@ -370,7 +366,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras if (!raw) { jffs2_free_full_dirent(fd); JFFS2_NOTICE("allocation of node reference failed\n"); - kfree(summary); return -ENOMEM; } @@ -378,7 +373,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras if (!ic) { jffs2_free_full_dirent(fd); jffs2_free_raw_node_ref(raw); - kfree(summary); return -ENOMEM; } @@ -411,45 +405,28 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras default : { JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); - kfree(summary); return -EIO; } } } - kfree(summary); return 0; } /* Process the summary node - 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_raw_summary *summary, uint32_t sumsize, + uint32_t *pseudo_random) { struct jffs2_unknown_node crcnode; struct jffs2_raw_node_ref *cache_ref; - struct jffs2_raw_summary *summary; - int ret, sumsize; + int ret, ofs; uint32_t crc; - sumsize = c->sector_size - ofs; - ofs += jeb->offset; + ofs = jeb->offset + c->sector_size - sumsize; dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", - jeb->offset, ofs, sumsize); - - summary = kmalloc(sumsize, GFP_KERNEL); - - if (!summary) { - return -ENOMEM; - } - - ret = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize); - - if (ret) { - kfree(summary); - return ret; - } + jeb->offset, ofs, sumsize); /* OK, now check for node validity and CRC */ crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -499,7 +476,6 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb if (!marker_ref) { JFFS2_NOTICE("Failed to allocate node ref for clean marker\n"); - kfree(summary); return -ENOMEM; } diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index b7a678be1709..afff4bd551a1 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h @@ -160,7 +160,8 @@ int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size); int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs); int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs); int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - uint32_t ofs, uint32_t *pseudo_random); + struct jffs2_raw_summary *summary, uint32_t sumlen, + uint32_t *pseudo_random); #else /* SUMMARY DISABLED */ -- cgit v1.2.3-70-g09d2 From f1f9671bd8f7d2ac6a918bad806ab5bdc0daaf4e Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 20 May 2006 19:45:26 +0100 Subject: [JFFS2] Introduce jffs2_link_node_ref() function to reduce code duplication The same sequence of code was repeated in many places, to add a new struct jffs2_raw_node_ref to an eraseblock and adjust the space accounting accordingly. Move it out-of-line. Signed-off-by: David Woodhouse --- fs/jffs2/erase.c | 18 ++++---------- fs/jffs2/nodelist.c | 34 +++++++++++++++++++++++++ fs/jffs2/nodelist.h | 2 ++ fs/jffs2/nodemgmt.c | 16 +----------- fs/jffs2/scan.c | 49 +++++++++--------------------------- fs/jffs2/summary.c | 71 +++++++++++------------------------------------------ 6 files changed, 68 insertions(+), 122 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index dad68fdffe9e..fecf5584f830 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -373,12 +373,8 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb goto filebad; } - jeb->first_node = jeb->last_node = NULL; + /* Everything else got zeroed before the erase */ jeb->free_size = c->sector_size; - jeb->used_size = 0; - jeb->dirty_size = 0; - jeb->wasted_size = 0; - } else { struct kvec vecs[1]; @@ -412,17 +408,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb goto filebad; } + /* Everything else got zeroed before the erase */ + jeb->free_size = c->sector_size; + marker_ref->next_in_ino = NULL; - marker_ref->next_phys = NULL; marker_ref->flash_offset = jeb->offset | REF_NORMAL; - marker_ref->__totlen = c->cleanmarker_size; - - jeb->first_node = jeb->last_node = marker_ref; - jeb->free_size = c->sector_size - c->cleanmarker_size; - jeb->used_size = c->cleanmarker_size; - jeb->dirty_size = 0; - jeb->wasted_size = 0; + jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size); } spin_lock(&c->erase_completion_lock); diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 4973cd648ba8..1fc8aedb56fb 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -1046,3 +1046,37 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) cond_resched(); } } + +void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *ref, uint32_t len) +{ + if (!jeb->first_node) + jeb->first_node = ref; + if (jeb->last_node) + jeb->last_node->next_phys = ref; + jeb->last_node = ref; + + switch(ref_flags(ref)) { + case REF_UNCHECKED: + c->unchecked_size += len; + jeb->unchecked_size += len; + break; + + case REF_NORMAL: + case REF_PRISTINE: + c->used_size += len; + jeb->used_size += len; + break; + + case REF_OBSOLETE: + c->dirty_size += len; + jeb->used_size += len; + break; + } + c->free_size -= len; + jeb->free_size -= len; + + /* Set __totlen field... for now */ + ref->__totlen = len; + ref->next_phys = NULL; +} diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 8dda98ff5561..bac4ec35bbd0 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -348,6 +348,8 @@ 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); +void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *ref, uint32_t len); /* 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 0e1f58aa606c..d6eab1b7ad53 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -403,21 +403,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r #endif spin_lock(&c->erase_completion_lock); - if (!jeb->first_node) - jeb->first_node = new; - if (jeb->last_node) - jeb->last_node->next_phys = new; - jeb->last_node = new; - - jeb->free_size -= len; - c->free_size -= len; - if (ref_obsolete(new)) { - jeb->dirty_size += len; - c->dirty_size += len; - } else { - jeb->used_size += len; - c->used_size += len; - } + jffs2_link_node_ref(c, jeb, new, len); 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 */ diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 40d62d057aa4..3cbe9f029e01 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -351,17 +351,11 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc xd->data_crc = je32_to_cpu(rx->data_crc); xd->node = raw; - raw->__totlen = totlen; raw->flash_offset = ofs | REF_PRISTINE; - raw->next_phys = NULL; raw->next_in_ino = (void *)xd; - if (!jeb->first_node) - jeb->first_node = raw; - if (jeb->last_node) - jeb->last_node->next_phys = raw; - jeb->last_node = raw; - USED_SPACE(PAD(je32_to_cpu(rx->totlen))); + jffs2_link_node_ref(c, jeb, raw, totlen); + if (jffs2_sum_active()) jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset); dbg_xattr("scaning xdatum at %#08x (xid=%u, version=%u)\n", @@ -418,17 +412,11 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock ref->next = c->xref_temp; c->xref_temp = ref; - raw->__totlen = PAD(je32_to_cpu(rr->totlen)); raw->flash_offset = ofs | REF_PRISTINE; - raw->next_phys = NULL; raw->next_in_ino = (void *)ref; - if (!jeb->first_node) - jeb->first_node = raw; - if (jeb->last_node) - jeb->last_node->next_phys = raw; - jeb->last_node = raw; - USED_SPACE(PAD(je32_to_cpu(rr->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rr->totlen))); + if (jffs2_sum_active()) jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset); dbg_xattr("scan xref at %#08x (xid=%u, ino=%u)\n", @@ -827,12 +815,10 @@ scan_more: return -ENOMEM; } marker_ref->next_in_ino = NULL; - marker_ref->next_phys = NULL; marker_ref->flash_offset = ofs | REF_NORMAL; - marker_ref->__totlen = c->cleanmarker_size; - jeb->first_node = jeb->last_node = marker_ref; - USED_SPACE(PAD(c->cleanmarker_size)); + jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size); + ofs += PAD(c->cleanmarker_size); } break; @@ -971,16 +957,11 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc /* Wheee. It worked */ raw->flash_offset = ofs | REF_UNCHECKED; - raw->__totlen = PAD(je32_to_cpu(ri->totlen)); - raw->next_phys = NULL; - raw->next_in_ino = ic->nodes; + 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; + + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(ri->totlen))); 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), @@ -989,8 +970,6 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc pseudo_random += je32_to_cpu(ri->version); - UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen))); - if (jffs2_sum_active()) { jffs2_sum_add_inode_mem(s, ri, ofs - jeb->offset); } @@ -1053,16 +1032,11 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo return -ENOMEM; } - raw->__totlen = PAD(je32_to_cpu(rd->totlen)); raw->flash_offset = ofs | 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; + + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rd->totlen))); fd->raw = raw; fd->next = NULL; @@ -1070,7 +1044,6 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo fd->ino = je32_to_cpu(rd->ino); fd->nhash = full_name_hash(fd->name, rd->nsize); fd->type = rd->type; - USED_SPACE(PAD(je32_to_cpu(rd->totlen))); jffs2_add_fd_to_list(c, fd, &ic->scan_dents); if (jffs2_sum_active()) { diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 5dbe87b67ab6..912189762323 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -410,19 +410,13 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras } 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; + 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))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spi->totlen))); + + *pseudo_random += je32_to_cpu(spi->version); sp += JFFS2_SUMMARY_INODE_SIZE; @@ -457,16 +451,11 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras 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; + + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spd->totlen))); fd->raw = raw; fd->next = NULL; @@ -474,7 +463,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras 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); @@ -516,17 +505,11 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras xd->node = raw; raw->flash_offset = ofs | REF_UNCHECKED; - raw->__totlen = PAD(je32_to_cpu(spx->totlen)); - raw->next_phys = NULL; raw->next_in_ino = (void *)xd; - if (!jeb->first_node) - jeb->first_node = raw; - if (jeb->last_node) - jeb->last_node->next_phys = raw; - jeb->last_node = raw; + + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spx->totlen))); *pseudo_random += je32_to_cpu(spx->xid); - UNCHECKED_SPACE(je32_to_cpu(spx->totlen)); sp += JFFS2_SUMMARY_XATTR_SIZE; break; @@ -559,17 +542,11 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras ref->next = c->xref_temp; c->xref_temp = ref; - raw->__totlen = PAD(sizeof(struct jffs2_raw_xref)); raw->flash_offset = ofs | REF_UNCHECKED; - raw->next_phys = NULL; raw->next_in_ino = (void *)ref; - if (!jeb->first_node) - jeb->first_node = raw; - if (jeb->last_node) - jeb->last_node->next_phys = raw; - jeb->last_node = raw; - UNCHECKED_SPACE(PAD(sizeof(struct jffs2_raw_xref))); + jffs2_link_node_ref(c, jeb, raw, PAD(sizeof(struct jffs2_raw_xref))); + *pseudo_random += ofs; sp += JFFS2_SUMMARY_XREF_SIZE; @@ -653,13 +630,10 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb 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; + marker_ref->next_in_ino = NULL; - USED_SPACE( PAD(je32_to_cpu(summary->cln_mkr)) ); + jffs2_link_node_ref(c, jeb, marker_ref, je32_to_cpu(summary->cln_mkr)); } } @@ -682,15 +656,8 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb 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); + jffs2_link_node_ref(c, jeb, cache_ref, sumsize); jeb->wasted_size += jeb->free_size; c->wasted_size += jeb->free_size; @@ -888,17 +855,9 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) } summary_ref->next_in_ino = NULL; - summary_ref->next_phys = NULL; summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL; - summary_ref->__totlen = infosize; - - if (!jeb->first_node) - jeb->first_node = summary_ref; - if (jeb->last_node) - jeb->last_node->next_phys = summary_ref; - jeb->last_node = summary_ref; - USED_SPACE(infosize); + jffs2_link_node_ref(c, jeb, summary_ref, infosize); return 0; } -- cgit v1.2.3-70-g09d2 From 6171586a7ae5198988774e8480631e8d15f65dfe Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 21 May 2006 00:02:06 +0100 Subject: [JFFS2] Correct handling of JFFS2_FEATURE_RWCOMPAT_COPY nodes. We should preserve these when we come to garbage collect them, not let them get erased. Use jffs2_garbage_collect_pristine() for this, and make sure the summary code copes -- just refrain from writing a summary for any block which contains a node we don't understand. Signed-off-by: David Woodhouse --- fs/jffs2/gc.c | 49 +++++++++++++++++++++++++++++-------------------- fs/jffs2/nodelist.h | 5 +++++ fs/jffs2/scan.c | 15 +++++++++++++-- fs/jffs2/summary.c | 9 ++++++++- 4 files changed, 55 insertions(+), 23 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 23587f8a221f..b0a5c407b476 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -256,10 +256,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) if (!raw->next_in_ino) { /* Inode-less node. Clean marker, snapshot or something like that */ - /* FIXME: If it's something that needs to be copied, including something - we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */ spin_unlock(&c->erase_completion_lock); - jffs2_mark_node_obsolete(c, raw); + if (ref_flags(raw) == REF_PRISTINE) { + /* It's an unknown node with JFFS2_FEATURE_RWCOMPAT_COPY */ + jffs2_garbage_collect_pristine(c, NULL, raw); + } else { + /* Just mark it obsolete */ + jffs2_mark_node_obsolete(c, raw); + } up(&c->alloc_sem); goto eraseit_lock; } @@ -533,15 +537,16 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw))); - rawlen = ref_totlen(c, c->gcblock, raw); + alloclen = rawlen = ref_totlen(c, c->gcblock, raw); /* Ask for a small amount of space (or the totlen if smaller) because we 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); - /* this is not the exact summary size of it, - it is only an upper estimation */ + if (ic && alloclen > sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN) + alloclen = sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN; + + ret = jffs2_reserve_space_gc(c, alloclen, &phys_ofs, &alloclen, rawlen); + /* 'rawlen' is not the exact summary size; it is only an upper estimation */ if (ret) return ret; @@ -605,9 +610,12 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, } break; default: - printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", - ref_offset(raw), je16_to_cpu(node->u.nodetype)); - goto bail; + /* If it's inode-less, we don't _know_ what it is. Just copy it intact */ + if (ic) { + printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", + ref_offset(raw), je16_to_cpu(node->u.nodetype)); + goto bail; + } } nraw = jffs2_alloc_raw_node_ref(); @@ -674,15 +682,16 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, nraw->flash_offset |= REF_PRISTINE; jffs2_add_physical_node_ref(c, nraw); - /* Link into per-inode list. This is safe because of the ic - state being INO_STATE_GC. Note that if we're doing this - for an inode which is in-core, the 'nraw' pointer is then - going to be fetched from ic->nodes by our caller. */ - spin_lock(&c->erase_completion_lock); - nraw->next_in_ino = ic->nodes; - ic->nodes = nraw; - spin_unlock(&c->erase_completion_lock); - + if (ic) { + /* Link into per-inode list. This is safe because of the ic + state being INO_STATE_GC. Note that if we're doing this + for an inode which is in-core, the 'nraw' pointer is then + going to be fetched from ic->nodes by our caller. */ + spin_lock(&c->erase_completion_lock); + nraw->next_in_ino = ic->nodes; + ic->nodes = nraw; + spin_unlock(&c->erase_completion_lock); + } 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/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index bac4ec35bbd0..1f5d5b0100aa 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -97,6 +97,11 @@ struct jffs2_raw_node_ref #define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE) #define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0) +/* NB: REF_PRISTINE for an inode-less node (ref->next_in_ino == NULL) indicates + it is an unknown node of type JFFS2_NODETYPE_RWCOMPAT_COPY, so it'll get + copied. If you need to do anything different to GC inode-less nodes, then + you need to modify gc.c accordingly. */ + /* For each inode in the filesystem, we need to keep a record of nlink, because it would be a PITA to scan the whole directory tree at read_inode() time to calculate it, and to keep sufficient information diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 3cbe9f029e01..06637050749d 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -851,11 +851,22 @@ scan_more: ofs += PAD(je32_to_cpu(node->totlen)); break; - case JFFS2_FEATURE_RWCOMPAT_COPY: + 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)); - USED_SPACE(PAD(je32_to_cpu(node->totlen))); + + ref = jffs2_alloc_raw_node_ref(); + if (!ref) + return -ENOMEM; + ref->flash_offset = ofs | REF_PRISTINE; + ref->next_in_ino = 0; + jffs2_link_node_ref(c, jeb, ref, PAD(je32_to_cpu(node->totlen))); + + /* We can't summarise nodes we don't grok */ + jffs2_sum_disable_collecting(s); ofs += PAD(je32_to_cpu(node->totlen)); break; + } } } } diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 95b5bf8f4a99..53a84b468cfe 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -760,7 +760,14 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock } #endif default : { - BUG(); /* unknown node in summary information */ + if ((je16_to_cpu(temp->u.nodetype) & JFFS2_COMPAT_MASK) + == JFFS2_FEATURE_RWCOMPAT_COPY) { + dbg_summary("Writing unknown RWCOMPAT_COPY node type %x\n", + je16_to_cpu(temp->u.nodetype)); + jffs2_sum_disable_collecting(c->summary); + } else { + BUG(); /* unknown node in summary information */ + } } } -- cgit v1.2.3-70-g09d2 From 3560160aa26ebced1944aaa2e7e436d2a1b1bf70 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 21 May 2006 01:28:05 +0100 Subject: [JFFS2] Fix memory leak in scan code; improve comments. If we had to allocate extra space for the summary node, we weren't correctly freeing it when jffs2_sum_scan_sumnode() returned nonzero -- which is both the success and the failure case. Only when it returned zero, which means fall through to the full scan, were we correctly freeing the buffer. Document the meaning of those return codes while we're at it. Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 06637050749d..192b0bd21180 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -516,10 +516,15 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo if (sumptr) { err = jffs2_sum_scan_sumnode(c, jeb, sumptr, sumlen, &pseudo_random); - if (err) - return err; + if (buf_size && sumlen > buf_size) kfree(sumptr); + /* If it returns with a real error, bail. + If it returns positive, that's a block classification + (i.e. BLK_STATE_xxx) so return that too. + If it returns zero, fall through to full scan. */ + if (err) + return err; } } -- cgit v1.2.3-70-g09d2 From 68270995f29f1a82b3eaab01df63ea7e721e2fa6 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 21 May 2006 03:46:05 +0100 Subject: [JFFS2] Introduce jffs2_scan_dirty_space() function. To eliminate the __totlen field from struct jffs2_raw_node_ref, we need to allocate nodes for dirty space instead of just tweaking the accounting data. Introduce jffs2_scan_dirty_space() in preparation for that. Signed-off-by: David Woodhouse --- fs/jffs2/nodelist.c | 11 ++++++++ fs/jffs2/nodelist.h | 1 + fs/jffs2/scan.c | 76 ++++++++++++++++++++++++++++++++++++----------------- fs/jffs2/summary.c | 16 +++++++---- fs/jffs2/summary.h | 17 ------------ 5 files changed, 75 insertions(+), 46 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 1fc8aedb56fb..00506857eabc 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -1080,3 +1080,14 @@ void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, ref->__totlen = len; ref->next_phys = NULL; } + +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; + + return 0; +} diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 194cff7c4853..ca15b3c731cf 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -430,6 +430,7 @@ int jffs2_fill_scan_buf(struct jffs2_sb_info *c, void *buf, uint32_t ofs, uint32_t len); struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino); int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); +int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t size); /* build.c */ int jffs2_do_mount_fs(struct jffs2_sb_info *c); diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 192b0bd21180..b3fc9fd5b03d 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -314,13 +314,15 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc struct jffs2_xattr_datum *xd; struct jffs2_raw_node_ref *raw; uint32_t totlen, crc; + int err; crc = crc32(0, rx, sizeof(struct jffs2_raw_xattr) - 4); if (crc != je32_to_cpu(rx->node_crc)) { if (je32_to_cpu(rx->node_crc) != 0xffffffff) JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", ofs, je32_to_cpu(rx->node_crc), crc); - DIRTY_SPACE(je32_to_cpu(rx->totlen)); + if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rx->totlen)))) + return err; return 0; } @@ -328,7 +330,8 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc if (totlen != je32_to_cpu(rx->totlen)) { JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n", ofs, je32_to_cpu(rx->totlen), totlen); - DIRTY_SPACE(je32_to_cpu(rx->totlen)); + if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rx->totlen)))) + return err; return 0; } @@ -340,7 +343,8 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc if (IS_ERR(xd)) { jffs2_free_raw_node_ref(raw); if (PTR_ERR(xd) == -EEXIST) { - DIRTY_SPACE(PAD(je32_to_cpu(rx->totlen))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rx->totlen))))) + return err; return 0; } return PTR_ERR(xd); @@ -370,13 +374,15 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock struct jffs2_xattr_ref *ref; struct jffs2_raw_node_ref *raw; uint32_t crc; + int err; crc = crc32(0, rr, sizeof(*rr) - 4); if (crc != je32_to_cpu(rr->node_crc)) { if (je32_to_cpu(rr->node_crc) != 0xffffffff) JFFS2_WARNING("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", ofs, je32_to_cpu(rr->node_crc), crc); - DIRTY_SPACE(PAD(je32_to_cpu(rr->totlen))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rr->totlen))))) + return err; return 0; } @@ -384,7 +390,8 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n", ofs, je32_to_cpu(rr->totlen), PAD(sizeof(struct jffs2_raw_xref))); - DIRTY_SPACE(je32_to_cpu(rr->totlen)); + if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rr->totlen)))) + return err; return 0; } @@ -569,7 +576,8 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo if (ofs) { D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset, jeb->offset + ofs)); - DIRTY_SPACE(ofs); + if ((err = jffs2_scan_dirty_space(c, jeb, ofs))) + return err; } /* Now ofs is a complete physical flash offset as it always was... */ @@ -593,7 +601,8 @@ scan_more: } if (ofs == prevofs) { printk(KERN_WARNING "ofs 0x%08x has already been seen. Skipping\n", ofs); - DIRTY_SPACE(4); + if ((err = jffs2_scan_dirty_space(c, jeb, 4))) + return err; ofs += 4; continue; } @@ -602,7 +611,8 @@ scan_more: if (jeb->offset + c->sector_size < ofs + sizeof(*node)) { D1(printk(KERN_DEBUG "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n", sizeof(struct jffs2_unknown_node), jeb->offset, c->sector_size, ofs, sizeof(*node))); - DIRTY_SPACE((jeb->offset + c->sector_size)-ofs); + if ((err = jffs2_scan_dirty_space(c, jeb, (jeb->offset + c->sector_size)-ofs))) + return err; break; } @@ -632,7 +642,8 @@ scan_more: if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff) { printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n", empty_start, ofs); - DIRTY_SPACE(ofs-empty_start); + if ((err = jffs2_scan_dirty_space(c, jeb, ofs-empty_start))) + return err; goto scan_more; } @@ -669,20 +680,23 @@ scan_more: if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) { printk(KERN_WARNING "Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n", ofs); - DIRTY_SPACE(4); + if ((err = jffs2_scan_dirty_space(c, jeb, 4))) + return err; ofs += 4; continue; } if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) { D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs)); - DIRTY_SPACE(4); + if ((err = jffs2_scan_dirty_space(c, jeb, 4))) + return err; ofs += 4; continue; } if (je16_to_cpu(node->magic) == JFFS2_OLD_MAGIC_BITMASK) { printk(KERN_WARNING "Old JFFS2 bitmask found at 0x%08x\n", ofs); printk(KERN_WARNING "You cannot use older JFFS2 filesystems with newer kernels\n"); - DIRTY_SPACE(4); + if ((err = jffs2_scan_dirty_space(c, jeb, 4))) + return err; ofs += 4; continue; } @@ -691,7 +705,8 @@ scan_more: noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", JFFS2_MAGIC_BITMASK, ofs, je16_to_cpu(node->magic)); - DIRTY_SPACE(4); + if ((err = jffs2_scan_dirty_space(c, jeb, 4))) + return err; ofs += 4; continue; } @@ -708,7 +723,8 @@ scan_more: je32_to_cpu(node->totlen), je32_to_cpu(node->hdr_crc), hdr_crc); - DIRTY_SPACE(4); + if ((err = jffs2_scan_dirty_space(c, jeb, 4))) + return err; ofs += 4; continue; } @@ -719,7 +735,8 @@ scan_more: printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n", ofs, je32_to_cpu(node->totlen)); printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n"); - DIRTY_SPACE(4); + if ((err = jffs2_scan_dirty_space(c, jeb, 4))) + return err; ofs += 4; continue; } @@ -727,7 +744,8 @@ scan_more: if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) { /* Wheee. This is an obsoleted node */ D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs)); - DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen))))) + return err; ofs += PAD(je32_to_cpu(node->totlen)); continue; } @@ -807,11 +825,13 @@ scan_more: if (je32_to_cpu(node->totlen) != c->cleanmarker_size) { printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n", ofs, je32_to_cpu(node->totlen), c->cleanmarker_size); - DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(sizeof(struct jffs2_unknown_node))))) + return err; ofs += PAD(sizeof(struct jffs2_unknown_node)); } else if (jeb->first_node) { printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n", ofs, jeb->offset); - DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(sizeof(struct jffs2_unknown_node))))) + return err; ofs += PAD(sizeof(struct jffs2_unknown_node)); } else { struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); @@ -831,7 +851,8 @@ scan_more: case JFFS2_NODETYPE_PADDING: if (jffs2_sum_active()) jffs2_sum_add_padding_mem(s, je32_to_cpu(node->totlen)); - DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen))))) + return err; ofs += PAD(je32_to_cpu(node->totlen)); break; @@ -842,7 +863,8 @@ scan_more: c->flags |= JFFS2_SB_FLAG_RO; if (!(jffs2_is_readonly(c))) return -EROFS; - DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen))))) + return err; ofs += PAD(je32_to_cpu(node->totlen)); break; @@ -852,7 +874,8 @@ scan_more: case JFFS2_FEATURE_RWCOMPAT_DELETE: D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs)); - DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen))))) + return err; ofs += PAD(je32_to_cpu(node->totlen)); break; @@ -930,6 +953,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc struct jffs2_raw_node_ref *raw; struct jffs2_inode_cache *ic; uint32_t ino = je32_to_cpu(ri->ino); + int err; D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs)); @@ -959,7 +983,8 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ofs, je32_to_cpu(ri->node_crc), crc); /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */ - DIRTY_SPACE(PAD(je32_to_cpu(ri->totlen))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(ri->totlen))))) + return err; jffs2_free_raw_node_ref(raw); return 0; } @@ -1000,6 +1025,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo struct jffs2_full_dirent *fd; struct jffs2_inode_cache *ic; uint32_t crc; + int err; D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", ofs)); @@ -1011,7 +1037,8 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ofs, je32_to_cpu(rd->node_crc), crc); /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */ - DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rd->totlen))))) + return err; return 0; } @@ -1032,7 +1059,8 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo jffs2_free_full_dirent(fd); /* FIXME: Why do we believe totlen? */ /* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */ - DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rd->totlen))))) + return err; return 0; } raw = jffs2_alloc_raw_node_ref(); diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 9ced3aa95818..11ea54c90f44 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -380,6 +380,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras struct jffs2_full_dirent *fd; void *sp; int i, ino; + int err; sp = summary->sum; @@ -494,7 +495,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras jffs2_free_raw_node_ref(raw); if (PTR_ERR(xd) == -EEXIST) { /* a newer version of xd exists */ - DIRTY_SPACE(je32_to_cpu(spx->totlen)); + if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(spx->totlen)))) + return err; sp += JFFS2_SUMMARY_XATTR_SIZE; break; } @@ -585,6 +587,7 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb struct jffs2_raw_node_ref *cache_ref; int ret, ofs; uint32_t crc; + int err; ofs = jeb->offset + c->sector_size - sumsize; @@ -629,11 +632,13 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) { dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n", je32_to_cpu(summary->cln_mkr), c->cleanmarker_size); - DIRTY_SPACE(PAD(je32_to_cpu(summary->cln_mkr))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) + return err; } else if (jeb->first_node) { dbg_summary("CLEANMARKER node not first node in block " "(0x%08x)\n", jeb->offset); - DIRTY_SPACE(PAD(je32_to_cpu(summary->cln_mkr))); + if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) + return err; } else { struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); @@ -650,7 +655,8 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb } if (je32_to_cpu(summary->padded)) { - DIRTY_SPACE(je32_to_cpu(summary->padded)); + if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(summary->padded)))) + return err; } ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random); @@ -823,7 +829,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen); c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; - DIRTY_SPACE(infosize); + jffs2_scan_dirty_space(c, jeb, infosize); return 1; } diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index ce892d57ad59..e7eb0c5814f6 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h @@ -18,23 +18,6 @@ #include #include -#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 -- cgit v1.2.3-70-g09d2 From 25090a6b23906552cf3d204aa421f811327e1b15 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 21 May 2006 03:57:56 +0100 Subject: [JFFS2] Discard remaining free space when filing a dirty block in scan. The incoming ref_totlen() calculation is going to rely on the existence of nodes which cover all dirty space. We can't just tweak the accounting data any more; we have to call jffs2_scan_dirty_space() to do it. Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index b3fc9fd5b03d..cffafec01e48 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -65,6 +65,25 @@ static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) { return DEFAULT_EMPTY_SCAN_SIZE; } +static int file_dirty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) +{ + int ret = jffs2_scan_dirty_space(c, jeb, jeb->free_size); + if (ret) + return ret; + /* Turned wasted size into dirty, since we apparently + think it's recoverable now. */ + jeb->dirty_size += jeb->wasted_size; + c->dirty_size += jeb->wasted_size; + c->wasted_size -= jeb->wasted_size; + jeb->wasted_size = 0; + if (VERYDIRTY(c, jeb->dirty_size)) { + list_add(&jeb->list, &c->very_dirty_list); + } else { + list_add(&jeb->list, &c->dirty_list); + } + return 0; +} + int jffs2_scan_medium(struct jffs2_sb_info *c) { int i, ret; @@ -170,34 +189,20 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) (!c->nextblock || c->nextblock->free_size < jeb->free_size)) { /* Better candidate for the next writes to go to */ if (c->nextblock) { - c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; - c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; - c->free_size -= c->nextblock->free_size; - c->wasted_size -= c->nextblock->wasted_size; - c->nextblock->free_size = c->nextblock->wasted_size = 0; - if (VERYDIRTY(c, c->nextblock->dirty_size)) { - list_add(&c->nextblock->list, &c->very_dirty_list); - } else { - list_add(&c->nextblock->list, &c->dirty_list); - } + ret = file_dirty(c, c->nextblock); + if (ret) + return ret; /* deleting summary information of the old nextblock */ jffs2_sum_reset_collected(c->summary); } - /* update collected summary infromation for the current nextblock */ + /* update collected summary information for the current nextblock */ jffs2_sum_move_collected(c, s); D1(printk(KERN_DEBUG "jffs2_scan_medium(): new nextblock = 0x%08x\n", jeb->offset)); c->nextblock = jeb; } else { - jeb->dirty_size += jeb->free_size + jeb->wasted_size; - c->dirty_size += jeb->free_size + jeb->wasted_size; - c->free_size -= jeb->free_size; - c->wasted_size -= jeb->wasted_size; - jeb->free_size = jeb->wasted_size = 0; - if (VERYDIRTY(c, jeb->dirty_size)) { - list_add(&jeb->list, &c->very_dirty_list); - } else { - list_add(&jeb->list, &c->dirty_list); - } + ret = file_dirty(c, jeb); + if (ret) + return ret; } break; -- cgit v1.2.3-70-g09d2 From fcb7578719529898aef9edce8e409e457a1c2d15 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 22 May 2006 15:23:10 +0100 Subject: [JFFS2] Extend jffs2_link_node_ref() to link into per-inode list too. Let's avoid the potential for forgetting to set ref->next_in_ino, by doing it within jffs2_link_node_ref() instead. This highlights the ugliness of what we're currently doing with xattr_datum and xattr_ref structures -- we should find a nicer way of dealing with that. Signed-off-by: David Woodhouse --- fs/jffs2/erase.c | 3 +-- fs/jffs2/gc.c | 17 ++--------------- fs/jffs2/nodelist.c | 13 ++++++++++--- fs/jffs2/nodelist.h | 8 ++++++-- fs/jffs2/nodemgmt.c | 5 +++-- fs/jffs2/scan.c | 24 ++++++++---------------- fs/jffs2/summary.c | 30 ++++++++++-------------------- fs/jffs2/wbuf.c | 6 ++---- fs/jffs2/write.c | 23 ++++------------------- fs/jffs2/xattr.c | 15 +++++++-------- 10 files changed, 53 insertions(+), 91 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index f677d6950fd4..0fc19a2fb5d9 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -410,10 +410,9 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb /* Everything else got zeroed before the erase */ jeb->free_size = c->sector_size; - marker_ref->next_in_ino = NULL; marker_ref->flash_offset = jeb->offset | REF_NORMAL; - jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size); + jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size, NULL); } spin_lock(&c->erase_completion_lock); diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 4773ba24304f..153755bc1d53 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -634,11 +634,8 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", rawlen, phys_ofs, ret, retlen); if (retlen) { - /* Doesn't belong to any inode */ - nraw->next_in_ino = NULL; - nraw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, nraw, rawlen); + 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", nraw->flash_offset); @@ -678,18 +675,8 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, goto out_node; } nraw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, nraw, rawlen); + jffs2_add_physical_node_ref(c, nraw, rawlen, ic); - if (ic) { - /* Link into per-inode list. This is safe because of the ic - state being INO_STATE_GC. Note that if we're doing this - for an inode which is in-core, the 'nraw' pointer is then - going to be fetched from ic->nodes by our caller. */ - spin_lock(&c->erase_completion_lock); - nraw->next_in_ino = ic->nodes; - ic->nodes = nraw; - spin_unlock(&c->erase_completion_lock); - } 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/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 7d563f938b1c..d25d4919ca97 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -1048,7 +1048,8 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) } 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_raw_node_ref *ref, uint32_t len, + struct jffs2_inode_cache *ic) { if (!jeb->first_node) jeb->first_node = ref; @@ -1065,6 +1066,13 @@ void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, } jeb->last_node = ref; + if (ic) { + ref->next_in_ino = ic->nodes; + ic->nodes = ref; + } else { + ref->next_in_ino = NULL; + } + switch(ref_flags(ref)) { case REF_UNCHECKED: c->unchecked_size += len; @@ -1120,12 +1128,11 @@ int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb 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); + jffs2_link_node_ref(c, jeb, ref, size, NULL); } return 0; diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 80d1fda2212b..ee5aedcffc12 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -307,7 +307,8 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in 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); 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_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); @@ -318,7 +319,10 @@ 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, uint32_t len); +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); diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 9a0f312cfcda..e10e58eab8e5 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -381,7 +381,8 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uin * Must be called with the alloc_sem held. */ -int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, uint32_t len) +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; @@ -403,7 +404,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r #endif spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, new, len); + 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 */ diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index cffafec01e48..6fce703c0543 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -361,9 +361,9 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc xd->node = raw; raw->flash_offset = ofs | REF_PRISTINE; - raw->next_in_ino = (void *)xd; - jffs2_link_node_ref(c, jeb, raw, totlen); + 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); @@ -425,9 +425,9 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock c->xref_temp = ref; raw->flash_offset = ofs | REF_PRISTINE; - raw->next_in_ino = (void *)ref; - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rr->totlen))); + 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); @@ -844,10 +844,9 @@ scan_more: printk(KERN_NOTICE "Failed to allocate node ref for clean marker\n"); return -ENOMEM; } - marker_ref->next_in_ino = NULL; marker_ref->flash_offset = ofs | REF_NORMAL; - jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size); + jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size, NULL); ofs += PAD(c->cleanmarker_size); } @@ -892,8 +891,7 @@ scan_more: if (!ref) return -ENOMEM; ref->flash_offset = ofs | REF_PRISTINE; - ref->next_in_ino = 0; - jffs2_link_node_ref(c, jeb, ref, PAD(je32_to_cpu(node->totlen))); + 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); @@ -1004,10 +1002,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc raw->flash_offset = ofs | REF_UNCHECKED; - raw->next_in_ino = ic->nodes; - ic->nodes = raw; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(ri->totlen))); + 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), @@ -1082,10 +1077,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo } raw->flash_offset = ofs | REF_PRISTINE; - raw->next_in_ino = ic->nodes; - ic->nodes = raw; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rd->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rd->totlen)), ic); fd->raw = raw; fd->next = NULL; diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 1451732e1fa7..351ba9f8185e 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -430,10 +430,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras raw->flash_offset |= REF_UNCHECKED; - raw->next_in_ino = ic->nodes; - ic->nodes = raw; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spi->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spi->totlen)), ic); *pseudo_random += je32_to_cpu(spi->version); @@ -473,10 +470,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras } raw->flash_offset |= REF_PRISTINE; - raw->next_in_ino = ic->nodes; - ic->nodes = raw; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spd->totlen))); + jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spd->totlen)), ic); fd->raw = raw; fd->next = NULL; @@ -525,9 +519,9 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras xd->node = raw; raw->flash_offset |= REF_UNCHECKED; - raw->next_in_ino = (void *)xd; - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spx->totlen))); + 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; @@ -561,9 +555,9 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras c->xref_temp = ref; raw->flash_offset |= REF_UNCHECKED; - raw->next_in_ino = (void *)ref; - jffs2_link_node_ref(c, jeb, raw, PAD(sizeof(struct jffs2_raw_xref))); + 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; @@ -664,9 +658,8 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb } marker_ref->flash_offset = jeb->offset | REF_NORMAL; - marker_ref->next_in_ino = NULL; - jffs2_link_node_ref(c, jeb, marker_ref, je32_to_cpu(summary->cln_mkr)); + jffs2_link_node_ref(c, jeb, marker_ref, je32_to_cpu(summary->cln_mkr), NULL); } } @@ -686,10 +679,9 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb return -ENOMEM; } - cache_ref->next_in_ino = NULL; cache_ref->flash_offset |= REF_NORMAL; - jffs2_link_node_ref(c, jeb, cache_ref, sumsize); + 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", @@ -849,9 +841,8 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock ref->flash_offset = jeb->offset + c->sector_size - jeb->free_size; ref->flash_offset |= REF_OBSOLETE; - ref->next_in_ino = 0; - jffs2_link_node_ref(c, jeb, ref, c->sector_size - jeb->free_size); + jffs2_link_node_ref(c, jeb, ref, c->sector_size - jeb->free_size, NULL); } c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; @@ -909,11 +900,10 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) return -ENOMEM; } - summary_ref->next_in_ino = NULL; summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL; spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, summary_ref, infosize); + jffs2_link_node_ref(c, jeb, summary_ref, infosize, NULL); return 0; } diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 45e3573cf107..62f685faeba8 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -312,9 +312,8 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) return; raw2->flash_offset = ofs | REF_OBSOLETE; - raw2->next_in_ino = NULL; - jffs2_add_physical_node_ref(c, raw2, ref_totlen(c, jeb, *first_raw)); + jffs2_add_physical_node_ref(c, raw2, ref_totlen(c, jeb, *first_raw), NULL); } return; } @@ -507,11 +506,10 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) return -ENOMEM; ref->flash_offset = c->wbuf_ofs + c->wbuf_len; ref->flash_offset |= REF_OBSOLETE; - ref->next_in_ino = NULL; spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, ref, waste); + 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/fs/jffs2/write.c b/fs/jffs2/write.c index 4462541d11f8..319a70f531f8 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -122,16 +122,13 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 /* Mark the space as dirtied */ if (retlen) { - /* Doesn't belong to any inode */ - raw->next_in_ino = NULL; - /* Don't change raw->size to match retlen. We may have written the node header already, and only the data will seem corrupted, in which case the scan would skip over any node we write before the original intended end of this node */ raw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen)); + 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", raw->flash_offset); @@ -189,13 +186,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 } else { raw->flash_offset |= REF_NORMAL; } - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen)); - - /* Link into per-inode list */ - spin_lock(&c->erase_completion_lock); - raw->next_in_ino = f->inocache->nodes; - f->inocache->nodes = raw; - spin_unlock(&c->erase_completion_lock); + 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, ref_flags(raw), je32_to_cpu(ri->dsize), @@ -275,9 +266,8 @@ 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) { - raw->next_in_ino = NULL; raw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen)); + 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", raw->flash_offset); @@ -323,12 +313,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff } /* Mark the space used */ raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen)); - - spin_lock(&c->erase_completion_lock); - raw->next_in_ino = f->inocache->nodes; - f->inocache->nodes = raw; - spin_unlock(&c->erase_completion_lock); + 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/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index e16f8460ff04..76d166140381 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -322,7 +322,6 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x if (!raw) return -ENOMEM; raw->flash_offset = phys_ofs; - raw->next_in_ino = (void *)xd; /* Setup raw-xattr */ rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -345,8 +344,7 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x rc = rc ? rc : -EIO; if (length) { raw->flash_offset |= REF_OBSOLETE; - raw->next_in_ino = NULL; - jffs2_add_physical_node_ref(c, raw, PAD(totlen)); + jffs2_add_physical_node_ref(c, raw, PAD(totlen), NULL); jffs2_mark_node_obsolete(c, raw); } else { jffs2_free_raw_node_ref(raw); @@ -356,7 +354,9 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x /* success */ raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(totlen)); + jffs2_add_physical_node_ref(c, raw, PAD(totlen), NULL); + /* FIXME */ raw->next_in_ino = (void *)xd; + if (xd->node) delete_xattr_datum_node(c, xd); xd->node = raw; @@ -566,7 +566,6 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, if (!raw) return -ENOMEM; raw->flash_offset = phys_ofs; - raw->next_in_ino = (void *)ref; rr.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); rr.nodetype = cpu_to_je16(JFFS2_NODETYPE_XREF); @@ -584,8 +583,7 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, ret = ret ? ret : -EIO; if (length) { raw->flash_offset |= REF_OBSOLETE; - raw->next_in_ino = NULL; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr))); + jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr)), NULL); jffs2_mark_node_obsolete(c, raw); } else { jffs2_free_raw_node_ref(raw); @@ -594,7 +592,8 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, } raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr))); + 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); ref->node = raw; -- cgit v1.2.3-70-g09d2 From 2f785402f39b96a077b6e62bf26164bfb8e0c980 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 24 May 2006 02:04:45 +0100 Subject: [JFFS2] Reduce visibility of raw_node_ref to upper layers of JFFS2 code. As the first step towards eliminating the ref->next_phys member and saving memory by using an _array_ of struct jffs2_raw_node_ref per eraseblock, stop the write functions from allocating their own refs; have them just _reserve_ the appropriate number instead. Then jffs2_link_node_ref() can just fill them in. Use a linked list of pre-allocated refs in the superblock, for now. Once we switch to an array, it'll just be a case of extending that array. Signed-off-by: David Woodhouse --- fs/jffs2/erase.c | 16 ++--- fs/jffs2/gc.c | 25 ++------ fs/jffs2/jffs2_fs_sb.h | 3 + fs/jffs2/malloc.c | 26 +++++++- fs/jffs2/nodelist.c | 51 ++++++++++------ fs/jffs2/nodelist.h | 19 +++--- fs/jffs2/nodemgmt.c | 39 ++++++------ fs/jffs2/scan.c | 77 +++++------------------ fs/jffs2/summary.c | 162 +++++++++++++++---------------------------------- fs/jffs2/wbuf.c | 26 +++----- fs/jffs2/write.c | 71 +++++++--------------- fs/jffs2/xattr.c | 38 +++--------- 12 files changed, 204 insertions(+), 349 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 4616fed75730..f939f908b948 100644 --- a/fs/jffs2/erase.c +++ b/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,7 +351,6 @@ fail: 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; @@ -384,11 +383,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb .totlen = cpu_to_je32(c->cleanmarker_size) }; - 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; - } + jffs2_prealloc_raw_node_refs(c, 1); marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4)); @@ -404,16 +399,13 @@ 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; - - marker_ref->flash_offset = jeb->offset | REF_NORMAL; - - jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size, NULL); + /* FIXME Special case for cleanmarker in empty block */ + jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL); } spin_lock(&c->erase_completion_lock); diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index f9e982a65ac2..a22ff5df7fcc 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -528,7 +528,6 @@ 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; @@ -618,30 +617,21 @@ 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: - nraw->flash_offset = phys_ofs = write_ofs(c); + 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, nraw->flash_offset, ret, retlen); + rawlen, phys_ofs, ret, retlen); if (retlen) { - nraw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, nraw, rawlen, NULL); - jffs2_mark_node_obsolete(c, nraw); + jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL); } else { - 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); + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", phys_ofs); } - if (!retried && (nraw = jffs2_alloc_raw_node_ref())) { + if (!retried) { /* Try to reallocate space and retry */ uint32_t dummy; struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size]; @@ -666,16 +656,13 @@ 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; } - nraw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, nraw, rawlen, ic); + jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, 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/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 272fbea55192..67529f0a44dd 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -26,6 +26,9 @@ 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/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index f2473fa2fd16..3df3250314a2 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -190,7 +190,29 @@ void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) kmem_cache_free(tmp_dnode_info_slab, x); } -struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void) +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 *ret; ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); @@ -198,7 +220,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/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index d25d4919ca97..1e6eabd730f2 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -953,13 +953,19 @@ 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) @@ -1047,10 +1053,27 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) } } -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 *jffs2_link_node_ref(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb, + uint32_t ofs, 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) { @@ -1093,15 +1116,15 @@ void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 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. Do not use on a live file system */ +/* No locking, no reservation of 'ref'. 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) { @@ -1121,18 +1144,10 @@ int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb 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; -#ifdef TEST_TOTLEN - ref->__totlen = size; -#endif + uint32_t ofs = jeb->offset + c->sector_size - jeb->free_size; + ofs |= REF_OBSOLETE; - jffs2_link_node_ref(c, jeb, ref, size, NULL); + jffs2_link_node_ref(c, jeb, ofs, size, NULL); } return 0; diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 76f1b9419eea..7cc74d2ab4dc 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -318,9 +318,10 @@ 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); -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 *jffs2_link_node_ref(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb, + uint32_t ofs, 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); @@ -331,10 +332,9 @@ 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); -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_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, + uint32_t ofs, 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,8 +378,9 @@ 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 *); -struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void); -void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *); +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_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/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 8feb8749bc75..01bf2773fe4d 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -137,6 +137,8 @@ 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; @@ -158,6 +160,9 @@ 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; } @@ -381,30 +386,30 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, * Must be called with the alloc_sem held. */ -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_raw_node_ref *jffs2_add_physical_node_ref(struct jffs2_sb_info *c, + uint32_t ofs, uint32_t len, + struct jffs2_inode_cache *ic) { struct jffs2_eraseblock *jeb; + struct jffs2_raw_node_ref *new; - jeb = &c->blocks[new->flash_offset / c->sector_size]; -#ifdef TEST_TOTLEN - new->__totlen = len; -#endif + jeb = &c->blocks[ofs / c->sector_size]; - 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)); + D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", + ofs & ~3, ofs & 3, len)); #if 1 - /* 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))) { + /* 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))) { printk(KERN_WARNING "argh. node added in wrong place\n"); - jffs2_free_raw_node_ref(new); - return -EINVAL; + return ERR_PTR(-EINVAL); } #endif spin_lock(&c->erase_completion_lock); - jffs2_link_node_ref(c, jeb, new, len, ic); + new = jffs2_link_node_ref(c, jeb, ofs, 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 */ @@ -425,7 +430,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r spin_unlock(&c->erase_completion_lock); - return 0; + return new; } @@ -697,7 +702,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref } spin_unlock(&c->erase_completion_lock); - jffs2_free_raw_node_ref(n); + __jffs2_free_raw_node_ref(n); } /* Also merge with the previous node in the list, if there is one @@ -722,7 +727,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref jeb->gc_node=p; } p->next_phys = ref->next_phys; - jffs2_free_raw_node_ref(ref); + __jffs2_free_raw_node_ref(ref); } spin_unlock(&c->erase_completion_lock); } diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 6fce703c0543..87b0a416b6a0 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -317,7 +317,6 @@ 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; @@ -340,13 +339,8 @@ 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; @@ -358,12 +352,9 @@ 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; - jffs2_link_node_ref(c, jeb, raw, totlen, NULL); - /* FIXME */ raw->next_in_ino = (void *)xd; + xd->node = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, totlen, NULL); + /* FIXME */ xd->node->next_in_ino = (void *)xd; if (jffs2_sum_active()) jffs2_sum_add_xattr_mem(s, rx, ofs - jeb->offset); @@ -377,7 +368,6 @@ 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; @@ -404,12 +394,6 @@ 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 @@ -418,16 +402,13 @@ 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; - 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; + 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; if (jffs2_sum_active()) jffs2_sum_add_xref_mem(s, rr, ofs - jeb->offset); @@ -597,6 +578,11 @@ scan_more: 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) { @@ -839,14 +825,7 @@ scan_more: return err; ofs += PAD(sizeof(struct jffs2_unknown_node)); } else { - 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); + jffs2_link_node_ref(c, jeb, ofs | REF_NORMAL, c->cleanmarker_size, NULL); ofs += PAD(c->cleanmarker_size); } @@ -884,14 +863,9 @@ scan_more: 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)); - 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); + jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(node->totlen)), NULL); /* We can't summarise nodes we don't grok */ jffs2_sum_disable_collecting(s); @@ -953,7 +927,6 @@ 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; @@ -969,12 +942,6 @@ 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 @@ -988,21 +955,15 @@ 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) { - jffs2_free_raw_node_ref(raw); + if (!ic) return -ENOMEM; - } } /* Wheee. It worked */ - - raw->flash_offset = ofs | REF_UNCHECKED; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(ri->totlen)), ic); + jffs2_link_node_ref(c, jeb, ofs | REF_UNCHECKED, 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), @@ -1021,7 +982,6 @@ 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; @@ -1063,23 +1023,14 @@ 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; } - raw->flash_offset = ofs | REF_PRISTINE; - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(rd->totlen)), ic); + fd->raw = jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, 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/fs/jffs2/summary.c b/fs/jffs2/summary.c index 351ba9f8185e..ccb6803a6e41 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -369,22 +369,18 @@ no_mem: return -ENOMEM; } -static struct jffs2_raw_node_ref *alloc_ref_at(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - uint32_t offset) +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) { - struct jffs2_raw_node_ref *ref; /* If there was a gap, mark it dirty */ - 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; + 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)); } - ref = jffs2_alloc_raw_node_ref(); - if (!ref) - return NULL; - ref->flash_offset = jeb->offset + offset; - return ref; + return jffs2_link_node_ref(c, jeb, jeb->offset + ofs, len, ic); } /* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */ @@ -392,7 +388,6 @@ static struct jffs2_raw_node_ref *alloc_ref_at(struct jffs2_sb_info *c, struct j 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; @@ -404,6 +399,11 @@ 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,22 +415,14 @@ 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; } - raw->flash_offset |= REF_UNCHECKED; - - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spi->totlen)), ic); + sum_link_node_ref(c, jeb, je32_to_cpu(spi->offset) | REF_UNCHECKED, + PAD(je32_to_cpu(spi->totlen)), ic); *pseudo_random += je32_to_cpu(spi->version); @@ -455,24 +447,15 @@ 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; } - raw->flash_offset |= REF_PRISTINE; - jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spd->totlen)), ic); + fd->raw = sum_link_node_ref(c, jeb, je32_to_cpu(spd->offset) | REF_PRISTINE, + 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); @@ -497,15 +480,10 @@ 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)))) @@ -516,12 +494,10 @@ 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; - 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; + 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; *pseudo_random += je32_to_cpu(spx->xid); sp += JFFS2_SUMMARY_XATTR_SIZE; @@ -537,29 +513,21 @@ 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; - raw->flash_offset |= REF_UNCHECKED; + 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; - 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; + *pseudo_random += ref->node->flash_offset; sp += JFFS2_SUMMARY_XREF_SIZE; break; @@ -584,7 +552,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras } } } - return 0; } @@ -594,7 +561,6 @@ 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; @@ -650,16 +616,8 @@ 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 { - 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); + jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, + je32_to_cpu(summary->cln_mkr), NULL); } } @@ -672,16 +630,11 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb return ret; /* real error */ /* for PARANOIA_CHECK */ - 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; + ret = jffs2_prealloc_raw_node_refs(c, 1); + if (ret) + return ret; - jffs2_link_node_ref(c, jeb, cache_ref, sumsize, NULL); + jffs2_link_node_ref(c, jeb, (jeb->offset + ofs) | REF_NORMAL, sumsize, NULL); if (unlikely(jeb->free_size)) { JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n", @@ -709,6 +662,7 @@ 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; @@ -821,36 +775,31 @@ 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", - jeb->offset + c->sector_size - jeb->free_size); + sum_ofs); - spin_unlock(&c->erase_completion_lock); - ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size - - jeb->free_size, &retlen, 0); + ret = jffs2_flash_writev(c, vecs, 2, sum_ofs, &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, jeb->offset + c->sector_size - jeb->free_size, ret, retlen); + infosize, sum_ofs, ret, retlen); /* Waste remaining space */ - 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); - } + spin_lock(&c->erase_completion_lock); + jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL); + spin_unlock(&c->erase_completion_lock); c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; - return 1; + return 0; } 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; } @@ -859,12 +808,15 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) { - struct jffs2_raw_node_ref *summary_ref; - int datasize, infosize, padsize, ret; + int datasize, infosize, padsize; 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) { @@ -888,22 +840,6 @@ 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); - jffs2_link_node_ref(c, jeb, summary_ref, infosize, NULL); - - return 0; + return ret; } diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 916c87d3393b..0d7abb260489 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -179,6 +179,9 @@ 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]; @@ -306,17 +309,9 @@ 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) { - struct jffs2_raw_node_ref *raw2; - - raw2 = jffs2_alloc_raw_node_ref(); - if (!raw2) - return; - - raw2->flash_offset = ofs | REF_OBSOLETE; + if (retlen) + jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, *first_raw), NULL); - 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); @@ -428,6 +423,9 @@ 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. @@ -485,7 +483,6 @@ 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]; @@ -503,15 +500,10 @@ 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, ref, waste, NULL); + jffs2_link_node_ref(c, jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL); /* FIXME: that made it count as dirty. Convert to wasted */ jeb->dirty_size -= waste; c->dirty_size -= waste; diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 0e12b7561b71..67176792e138 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -61,7 +61,6 @@ 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; @@ -83,27 +82,16 @@ 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) { - jffs2_free_raw_node_ref(raw); + if (!fn) 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: - fn->raw = raw; - - raw->flash_offset = flash_ofs = write_ofs(c); + flash_ofs = write_ofs(c); jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len); @@ -130,14 +118,11 @@ 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 */ - raw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen), NULL); - jffs2_mark_node_obsolete(c, raw); + jffs2_add_physical_node_ref(c, flash_ofs | REF_OBSOLETE, PAD(sizeof(*ri)+datalen), NULL); } else { - 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); + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", flash_ofs); } - if (!retried && alloc_mode != ALLOC_NORETRY && (raw = jffs2_alloc_raw_node_ref())) { + if (!retried && alloc_mode != ALLOC_NORETRY) { /* Try to reallocate space and retry */ uint32_t dummy; struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size]; @@ -172,7 +157,6 @@ 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); @@ -186,14 +170,17 @@ 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)))) { - raw->flash_offset |= REF_PRISTINE; + flash_ofs |= REF_PRISTINE; } else { - raw->flash_offset |= REF_NORMAL; + flash_ofs |= REF_NORMAL; } - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*ri)+datalen), f->inocache); + 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; 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, ref_flags(raw), je32_to_cpu(ri->dsize), + flash_ofs & ~3, flash_ofs & 3, 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))); @@ -208,11 +195,10 @@ 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 = write_ofs(c); + uint32_t flash_ofs; int retried = 0; int ret; @@ -223,26 +209,16 @@ 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) { - jffs2_free_raw_node_ref(raw); + if (!fd) return ERR_PTR(-ENOMEM); - } fd->version = je32_to_cpu(rd->version); fd->ino = je32_to_cpu(rd->ino); @@ -252,9 +228,9 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff fd->name[namelen]=0; retry: - fd->raw = raw; + flash_ofs = write_ofs(c); - raw->flash_offset = flash_ofs; + jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len); if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) { BUG_ON(!retried); @@ -273,14 +249,11 @@ 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) { - raw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen), NULL); - jffs2_mark_node_obsolete(c, raw); + jffs2_add_physical_node_ref(c, flash_ofs | REF_OBSOLETE, PAD(sizeof(*rd)+namelen), NULL); } else { - 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); + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", flash_ofs); } - if (!retried && (raw = jffs2_alloc_raw_node_ref())) { + if (!retried) { /* Try to reallocate space and retry */ uint32_t dummy; struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size]; @@ -313,15 +286,13 @@ 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 */ - raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(*rd)+namelen), f->inocache); + fd->raw = jffs2_add_physical_node_ref(c, flash_ofs | REF_PRISTINE, PAD(sizeof(*rd)+namelen), f->inocache); if (retried) { jffs2_dbg_acct_sanity_check(c,NULL); diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 008f91b1c171..2255f1367bd5 100644 --- a/fs/jffs2/xattr.c +++ b/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_xattr rx; struct jffs2_raw_node_ref *raw; + struct jffs2_raw_xattr rx; struct kvec vecs[2]; uint32_t length; int rc, totlen; @@ -319,11 +319,6 @@ 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); @@ -343,19 +338,14 @@ 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) { - 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); - } + if (length) + jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, PAD(totlen), NULL); + return rc; } /* success */ - raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(totlen), NULL); + raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(totlen), NULL); /* FIXME */ raw->next_in_ino = (void *)xd; if (xd->node) @@ -563,11 +553,6 @@ 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))); @@ -582,18 +567,13 @@ 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) { - 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); - } + if (length) + jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, PAD(sizeof(rr)), NULL); + return ret; } - raw->flash_offset |= REF_PRISTINE; - jffs2_add_physical_node_ref(c, raw, PAD(sizeof(rr)), NULL); + raw = jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, PAD(sizeof(rr)), NULL); /* FIXME */ raw->next_in_ino = (void *)ref; if (ref->node) delete_xattr_ref_node(c, ref); -- cgit v1.2.3-70-g09d2 From 99988f7bbd16b861590dda4631c4db6cb17b5091 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 24 May 2006 09:04:17 +0100 Subject: [JFFS2] Introduce ref_next() macro for finding next physical node Another part of the preparation for switching to an array... Signed-off-by: David Woodhouse --- fs/jffs2/debug.c | 14 +++++++------- fs/jffs2/gc.c | 2 +- fs/jffs2/nodelist.c | 13 +++++++------ fs/jffs2/nodelist.h | 6 +++--- fs/jffs2/nodemgmt.c | 22 +++++++++++----------- fs/jffs2/scan.c | 4 ++-- 6 files changed, 31 insertions(+), 30 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c index 1fe17de713e8..72b4fc13a106 100644 --- a/fs/jffs2/debug.c +++ b/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 ((!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); + 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); goto error; } - ref2 = ref2->next_phys; + ref2 = ref_next(ref2); } 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_phys) { + for (ref = jeb->first_node; ; ref = ref_next(ref)) { printk("%#08x(%#x)", ref_offset(ref), ref->__totlen); - if (ref->next_phys) + if (ref_next(ref)) printk("->"); else break; diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index a22ff5df7fcc..477c526d638b 100644 --- a/fs/jffs2/gc.c +++ b/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 = raw->next_phys; + raw = ref_next(raw); 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", diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 1e6eabd730f2..0e82979c741c 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -1159,9 +1159,10 @@ 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 (ref->next_phys) - ref_end = ref_offset(ref->next_phys); + if (next_ref) + ref_end = ref_offset(next_ref); else { if (!jeb) jeb = &c->blocks[ref->flash_offset / c->sector_size]; @@ -1196,11 +1197,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_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); + 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); } else - printk(KERN_CRIT "No next_phys. jeb->last_node is %p\n", jeb->last_node); + printk(KERN_CRIT "No next ref. 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/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 7cc74d2ab4dc..94d152de95eb 100644 --- a/fs/jffs2/nodelist.h +++ b/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: */ diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 01bf2773fe4d..f4649c275fbe 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -458,6 +458,7 @@ 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; @@ -685,24 +686,23 @@ 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 */ - if (ref->next_phys && ref_obsolete(ref->next_phys) && - !ref->next_phys->next_in_ino) { - struct jffs2_raw_node_ref *n = ref->next_phys; + next_ref = ref_next(ref); + if (next_ref && ref_obsolete(next_ref) && !next_ref->next_in_ino) { spin_lock(&c->erase_completion_lock); #ifdef TEST_TOTLEN - ref->__totlen += n->__totlen; + ref->__totlen += next_ref->__totlen; #endif - ref->next_phys = n->next_phys; - if (jeb->last_node == n) jeb->last_node = ref; - if (jeb->gc_node == n) { + ref->next_phys = ref_next(next_ref); + if (jeb->last_node == next_ref) jeb->last_node = ref; + if (jeb->gc_node == next_ref) { /* gc will be happy continuing gc on this node */ jeb->gc_node=ref; } spin_unlock(&c->erase_completion_lock); - __jffs2_free_raw_node_ref(n); + __jffs2_free_raw_node_ref(next_ref); } /* Also merge with the previous node in the list, if there is one @@ -712,8 +712,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref spin_lock(&c->erase_completion_lock); - while (p->next_phys != ref) - p = p->next_phys; + while ((next_ref = ref_next(ref)) != ref) + p = next_ref; if (ref_obsolete(p) && !ref->next_in_ino) { #ifdef TEST_TOTLEN @@ -726,7 +726,7 @@ 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_phys; + p->next_phys = ref_next(ref); __jffs2_free_raw_node_ref(ref); } spin_unlock(&c->erase_completion_lock); diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 87b0a416b6a0..3551c39d7472 100644 --- a/fs/jffs2/scan.c +++ b/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 || !jeb->first_node->next_phys) ) + && (!jeb->first_node || !ref_next(jeb->first_node)) ) return BLK_STATE_CLEANMARKER; /* move blocks with max 4 byte dirty space to cleanlist */ @@ -647,7 +647,7 @@ scan_more: /* 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 && !jeb->first_node->next_phys) { + c->cleanmarker_size && !jeb->dirty_size && !ref_next(jeb->first_node)) { 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; } -- cgit v1.2.3-70-g09d2 From f560928baa605e8faaa3de6cc1b11ebb645e97db Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 25 May 2006 01:37:28 +0100 Subject: [JFFS2] Allocate node_ref for wasted space when skipping to page boundary One more place where we were changing the accounting info without actually allocating a ref for the lost space... Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 3551c39d7472..c25750aa85e3 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -244,11 +244,8 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n", skip)); - c->nextblock->wasted_size += skip; - c->wasted_size += skip; - - c->nextblock->free_size -= skip; - c->free_size -= skip; + jffs2_prealloc_raw_node_refs(c, 1); + jffs2_scan_dirty_space(c, c->nextblock, skip); } #endif if (c->nr_erasing_blocks) { -- cgit v1.2.3-70-g09d2 From 046b8b9808127d63326a33bc6298c90eaee90eeb Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 25 May 2006 01:50:35 +0100 Subject: [JFFS2] Add 'jeb' argument to jffs2_prealloc_raw_node_refs() Preallocation of refs is shortly going to be a per-eraseblock thing, rather than per-filesystem. Add the required argument to the function. Signed-off-by: David Woodhouse --- fs/jffs2/erase.c | 2 +- fs/jffs2/malloc.c | 3 ++- fs/jffs2/nodelist.h | 3 ++- fs/jffs2/nodemgmt.c | 4 ++-- fs/jffs2/scan.c | 4 ++-- fs/jffs2/summary.c | 6 +++--- fs/jffs2/wbuf.c | 8 ++++---- 7 files changed, 16 insertions(+), 14 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index aea58ee64d23..c8386b256831 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -383,7 +383,7 @@ 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); + jffs2_prealloc_raw_node_refs(c, jeb, 1); marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4)); diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 3df3250314a2..171483ef0e4d 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -190,7 +190,8 @@ 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) +int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb, int nr) { struct jffs2_raw_node_ref *p = c->refs; diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 21b0b7b6c75f..6c92dc46fe9e 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -378,7 +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); +int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb, 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_node_frag *jffs2_alloc_node_frag(void); diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index bbc873e20807..73a06d01db48 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -138,7 +138,7 @@ 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); + ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); if (ret) up(&c->alloc_sem); return ret; @@ -161,7 +161,7 @@ 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); + ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); return ret; } diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index c25750aa85e3..5bbd4a36c75e 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -244,7 +244,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n", skip)); - jffs2_prealloc_raw_node_refs(c, 1); + jffs2_prealloc_raw_node_refs(c, c->nextblock, 1); jffs2_scan_dirty_space(c, c->nextblock, skip); } #endif @@ -576,7 +576,7 @@ scan_more: 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); + err = jffs2_prealloc_raw_node_refs(c, jeb, 2); if (err) return err; diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 0c66d16eaa22..a60bbcea5b7f 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -400,7 +400,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras 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); + err = jffs2_prealloc_raw_node_refs(c, jeb, 2); if (err) return err; @@ -630,7 +630,7 @@ 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, 2); + ret = jffs2_prealloc_raw_node_refs(c, jeb, 2); if (ret) return ret; @@ -815,9 +815,9 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) dbg_summary("called\n"); spin_unlock(&c->erase_completion_lock); - jffs2_prealloc_raw_node_refs(c, 1); jeb = c->nextblock; + jffs2_prealloc_raw_node_refs(c, jeb, 1); if (!c->summary->sum_num || !c->summary->sum_list_head) { JFFS2_WARNING("Empty summary info!!!\n"); diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 1871140e1e78..e16e45ea0474 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -179,13 +179,13 @@ 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)) + jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; + + if (jffs2_prealloc_raw_node_refs(c, jeb, c->reserved_refs + 1)) return; spin_lock(&c->erase_completion_lock); - jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; - jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); /* Find the first node to be recovered, by skipping over every @@ -417,7 +417,7 @@ 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)) + if (jffs2_prealloc_raw_node_refs(c, c->nextblock, c->reserved_refs + 1)) return -ENOMEM; /* claim remaining space on the page -- cgit v1.2.3-70-g09d2 From 8b9e9fe8c6ee354aa75dc5a33e1575b21aa52084 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 25 May 2006 01:53:09 +0100 Subject: [JFFS2] Fix and improve debugging output during scan. Print wasted_size in scanned eraseblocks, print range correctly for summary dirent and inode entries. Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 6 +++--- fs/jffs2/summary.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 5bbd4a36c75e..404ba6e48581 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -881,9 +881,9 @@ scan_more: } } - D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, - jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size)); - + D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x, wasted 0x%08x\n", + jeb->offset,jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size, jeb->wasted_size)); + /* mark_node_obsolete can add to wasted !! */ if (jeb->wasted_size) { jeb->dirty_size += jeb->wasted_size; diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index a60bbcea5b7f..523a8f330ef5 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -413,7 +413,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras dbg_summary("Inode at 0x%08x-0x%08x\n", jeb->offset + je32_to_cpu(spi->offset), - jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spu->totlen)); + jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spi->totlen)); ic = jffs2_scan_make_ino_cache(c, ino); if (!ic) { @@ -435,7 +435,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras struct jffs2_sum_dirent_flash *spd; spd = sp; - dbg_summary("Dirent at 0x%08x\n", + dbg_summary("Dirent at 0x%08x-0x%08x\n", jeb->offset + je32_to_cpu(spd->offset), jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen)); -- cgit v1.2.3-70-g09d2 From 89291a9d5b70778e49e2563247c6c7e3efac9b14 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 25 May 2006 13:30:24 +0100 Subject: [JFFS2] Fix 64-bit size_t problems in XATTR code. Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 2 +- fs/jffs2/xattr.c | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 404ba6e48581..3fb0e7e82cf2 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -379,7 +379,7 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock } if (PAD(sizeof(struct jffs2_raw_xref)) != je32_to_cpu(rr->totlen)) { - JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%u\n", + JFFS2_WARNING("node length mismatch at %#08x, read=%u, calc=%zd\n", ofs, je32_to_cpu(rr->totlen), PAD(sizeof(struct jffs2_raw_xref))); if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(rr->totlen)))) diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 2255f1367bd5..2d82e250be34 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -111,7 +111,7 @@ static void delete_xattr_datum_node(struct jffs2_sb_info *c, struct jffs2_xattr_ { /* must be called under down_write(xattr_sem) */ struct jffs2_raw_xattr rx; - uint32_t length; + size_t length; int rc; if (!xd->node) { @@ -124,14 +124,14 @@ static void delete_xattr_datum_node(struct jffs2_sb_info *c, struct jffs2_xattr_ sizeof(struct jffs2_unknown_node), &length, (char *)&rx); if (rc || length != sizeof(struct jffs2_unknown_node)) { - JFFS2_ERROR("jffs2_flash_read()=%d, req=%u, read=%u at %#08x\n", + JFFS2_ERROR("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n", rc, sizeof(struct jffs2_unknown_node), length, ref_offset(xd->node)); } rc = jffs2_flash_write(c, ref_offset(xd->node), sizeof(rx), &length, (char *)&rx); if (rc || length != sizeof(struct jffs2_raw_xattr)) { - JFFS2_ERROR("jffs2_flash_write()=%d, req=%u, wrote=%u ar %#08x\n", + JFFS2_ERROR("jffs2_flash_write()=%d, req=%zu, wrote=%zu ar %#08x\n", rc, sizeof(rx), length, ref_offset(xd->node)); } } @@ -169,7 +169,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat rc = jffs2_flash_read(c, ref_offset(xd->node), sizeof(rx), &readlen, (char *)&rx); if (rc || readlen != sizeof(rx)) { - JFFS2_WARNING("jffs2_flash_read()=%d, req=%u, read=%u at %#08x\n", + JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n", rc, sizeof(rx), readlen, ref_offset(xd->node)); return rc ? rc : -EIO; } @@ -240,7 +240,7 @@ static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum length, &readlen, data); if (ret || length!=readlen) { - JFFS2_WARNING("jffs2_flash_read() returned %d, request=%d, readlen=%d, at %#08x\n", + JFFS2_WARNING("jffs2_flash_read() returned %d, request=%d, readlen=%zu, at %#08x\n", ret, length, readlen, ref_offset(xd->node)); kfree(data); return ret ? ret : -EIO; @@ -307,7 +307,7 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x struct jffs2_raw_node_ref *raw; struct jffs2_raw_xattr rx; struct kvec vecs[2]; - uint32_t length; + size_t length; int rc, totlen; uint32_t phys_ofs = write_ofs(c); @@ -335,7 +335,7 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x rc = jffs2_flash_writev(c, vecs, 2, phys_ofs, &length, 0); if (rc || totlen != length) { - JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%u, at %#08x\n", + JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%zu, at %#08x\n", rc, totlen, length, phys_ofs); rc = rc ? rc : -EIO; if (length) @@ -459,7 +459,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref rc = jffs2_flash_read(c, ref_offset(ref->node), sizeof(rr), &readlen, (char *)&rr); if (rc || sizeof(rr) != readlen) { - JFFS2_WARNING("jffs2_flash_read()=%d, req=%u, read=%u, at %#08x\n", + JFFS2_WARNING("jffs2_flash_read()=%d, req=%zu, read=%zu, at %#08x\n", rc, sizeof(rr), readlen, ref_offset(ref->node)); return rc ? rc : -EIO; } @@ -475,7 +475,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref || je16_to_cpu(rr.nodetype) != JFFS2_NODETYPE_XREF || je32_to_cpu(rr.totlen) != PAD(sizeof(rr))) { JFFS2_ERROR("inconsistent xref at %#08x, magic=%#04x/%#04x, " - "nodetype=%#04x/%#04x, totlen=%u/%u\n", + "nodetype=%#04x/%#04x, totlen=%u/%zu\n", ref_offset(ref->node), je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK, je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF, je32_to_cpu(rr.totlen), PAD(sizeof(rr))); @@ -502,7 +502,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref static void delete_xattr_ref_node(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) { struct jffs2_raw_xref rr; - uint32_t length; + size_t length; int rc; if (jffs2_sum_active()) { @@ -511,14 +511,14 @@ static void delete_xattr_ref_node(struct jffs2_sb_info *c, struct jffs2_xattr_re sizeof(struct jffs2_unknown_node), &length, (char *)&rr); if (rc || length != sizeof(struct jffs2_unknown_node)) { - JFFS2_ERROR("jffs2_flash_read()=%d, req=%u, read=%u at %#08x\n", + JFFS2_ERROR("jffs2_flash_read()=%d, req=%zu, read=%zu at %#08x\n", rc, sizeof(struct jffs2_unknown_node), length, ref_offset(ref->node)); } rc = jffs2_flash_write(c, ref_offset(ref->node), sizeof(rr), &length, (char *)&rr); if (rc || length != sizeof(struct jffs2_raw_xref)) { - JFFS2_ERROR("jffs2_flash_write()=%d, req=%u, wrote=%u at %#08x\n", + JFFS2_ERROR("jffs2_flash_write()=%d, req=%zu, wrote=%zu at %#08x\n", rc, sizeof(rr), length, ref_offset(ref->node)); } } @@ -549,7 +549,7 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) /* must be called under down_write(xattr_sem) */ struct jffs2_raw_node_ref *raw; struct jffs2_raw_xref rr; - uint32_t length; + size_t length; uint32_t phys_ofs = write_ofs(c); int ret; @@ -564,7 +564,7 @@ static int save_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) ret = jffs2_flash_write(c, phys_ofs, sizeof(rr), &length, (char *)&rr); if (ret || sizeof(rr) != length) { - JFFS2_WARNING("jffs2_flash_write() returned %d, request=%u, retlen=%u, at %#08x\n", + JFFS2_WARNING("jffs2_flash_write() returned %d, request=%zu, retlen=%zu, at %#08x\n", ret, sizeof(rr), length, phys_ofs); ret = ret ? ret : -EIO; if (length) -- cgit v1.2.3-70-g09d2 From a6a8bef722875a95bb73e6de7da924a8d417b52c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 29 May 2006 00:41:11 +0100 Subject: [JFFS2] Preallocate raw_node_refs in a couple of missing places in scan Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 3fb0e7e82cf2..42c1ff21d352 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -67,8 +67,11 @@ static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) { static int file_dirty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { - int ret = jffs2_scan_dirty_space(c, jeb, jeb->free_size); - if (ret) + int ret; + + if ((ret = jffs2_prealloc_raw_node_refs(c, jeb, 1))) + return ret; + if ((ret = jffs2_scan_dirty_space(c, jeb, jeb->free_size))) return ret; /* Turned wasted size into dirty, since we apparently think it's recoverable now. */ @@ -559,6 +562,8 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo if (ofs) { D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset, jeb->offset + ofs)); + if ((err = jffs2_prealloc_raw_node_refs(c, jeb, 1))) + return err; if ((err = jffs2_scan_dirty_space(c, jeb, ofs))) return err; } -- cgit v1.2.3-70-g09d2 From 13ba42df4a385d7b77d7aac32b93bdcd73e6d6e1 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 30 May 2006 08:59:34 +0100 Subject: [JFFS2] Fix calculation of potential summary marker offset on NOR flash. Helps if we look _inside_ the buffer, rather than adding jeb->offset to it. Doh. Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/jffs2/scan.c') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 42c1ff21d352..61618080b86f 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -463,7 +463,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo if (!buf_size) { /* XIP case. Just look, point at the summary if it's there */ - sm = (void *)buf + jeb->offset - sizeof(*sm); + sm = (void *)buf + c->sector_size - sizeof(*sm); if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) { sumptr = buf + je32_to_cpu(sm->offset); sumlen = c->sector_size - je32_to_cpu(sm->offset); -- cgit v1.2.3-70-g09d2