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/summary.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 7b0ed77a4c35..5d9ec8e36528 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -5,6 +5,7 @@ * Zoltan Sogor , * Patrik Kluba , * University of Szeged, Hungary + * 2005 KaiGai Kohei * * For licensing information, see the file 'LICENCE' in this directory. * @@ -81,6 +82,19 @@ static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item) dbg_summary("dirent (%u) added to summary\n", je32_to_cpu(item->d.ino)); break; +#ifdef CONFIG_JFFS2_FS_XATTR + case JFFS2_NODETYPE_XATTR: + s->sum_size += JFFS2_SUMMARY_XATTR_SIZE; + s->sum_num++; + dbg_summary("xattr (xid=%u, version=%u) added to summary\n", + je32_to_cpu(item->x.xid), je32_to_cpu(item->x.version)); + break; + case JFFS2_NODETYPE_XREF: + s->sum_size += JFFS2_SUMMARY_XREF_SIZE; + s->sum_num++; + dbg_summary("xref added to summary\n"); + break; +#endif default: JFFS2_WARNING("UNKNOWN node type %u\n", je16_to_cpu(item->u.nodetype)); @@ -141,6 +155,40 @@ int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *r return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); } +#ifdef CONFIG_JFFS2_FS_XATTR +int jffs2_sum_add_xattr_mem(struct jffs2_summary *s, struct jffs2_raw_xattr *rx, uint32_t ofs) +{ + struct jffs2_sum_xattr_mem *temp; + + temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL); + if (!temp) + return -ENOMEM; + + temp->nodetype = rx->nodetype; + temp->xid = rx->xid; + temp->version = rx->version; + temp->offset = cpu_to_je32(ofs); + temp->totlen = rx->totlen; + temp->next = NULL; + + return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); +} + +int jffs2_sum_add_xref_mem(struct jffs2_summary *s, struct jffs2_raw_xref *rr, uint32_t ofs) +{ + struct jffs2_sum_xref_mem *temp; + + temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL); + if (!temp) + return -ENOMEM; + + temp->nodetype = rr->nodetype; + temp->offset = cpu_to_je32(ofs); + temp->next = NULL; + + return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); +} +#endif /* Cleanup every collected summary information */ static void jffs2_sum_clean_collected(struct jffs2_summary *s) @@ -259,7 +307,40 @@ int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); } +#ifdef CONFIG_JFFS2_FS_XATTR + case JFFS2_NODETYPE_XATTR: { + struct jffs2_sum_xattr_mem *temp; + if (je32_to_cpu(node->x.version) == 0xffffffff) + return 0; + temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL); + if (!temp) + goto no_mem; + temp->nodetype = node->x.nodetype; + temp->xid = node->x.xid; + temp->version = node->x.version; + temp->totlen = node->x.totlen; + temp->offset = cpu_to_je32(ofs); + temp->next = NULL; + + return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); + } + case JFFS2_NODETYPE_XREF: { + struct jffs2_sum_xref_mem *temp; + + if (je32_to_cpu(node->r.ino) == 0xffffffff + && je32_to_cpu(node->r.xid) == 0xffffffff) + return 0; + temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL); + if (!temp) + goto no_mem; + temp->nodetype = node->r.nodetype; + temp->offset = cpu_to_je32(ofs); + temp->next = NULL; + + return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); + } +#endif case JFFS2_NODETYPE_PADDING: dbg_summary("node PADDING\n"); c->summary->sum_padded += je32_to_cpu(node->u.totlen); @@ -408,8 +489,94 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras break; } +#ifdef CONFIG_JFFS2_FS_XATTR + case JFFS2_NODETYPE_XATTR: { + struct jffs2_xattr_datum *xd; + struct jffs2_sum_xattr_flash *spx; + uint32_t ofs; + + spx = (struct jffs2_sum_xattr_flash *)sp; + ofs = jeb->offset + je32_to_cpu(spx->offset); + dbg_summary("xattr at %#08x (xid=%u, version=%u)\n", ofs, + je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); + raw = jffs2_alloc_raw_node_ref(); + if (!raw) { + JFFS2_NOTICE("allocation of node reference failed\n"); + kfree(summary); + return -ENOMEM; + } + xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid), + je32_to_cpu(spx->version)); + if (IS_ERR(xd)) { + JFFS2_NOTICE("allocation of xattr_datum failed\n"); + jffs2_free_raw_node_ref(raw); + kfree(summary); + return PTR_ERR(xd); + } + 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; + + *pseudo_random += je32_to_cpu(spx->xid); + UNCHECKED_SPACE(je32_to_cpu(spx->totlen)); + sp += JFFS2_SUMMARY_XATTR_SIZE; + + break; + } + case JFFS2_NODETYPE_XREF: { + struct jffs2_xattr_ref *ref; + struct jffs2_sum_xref_flash *spr; + uint32_t ofs; + + spr = (struct jffs2_sum_xref_flash *)sp; + ofs = jeb->offset + je32_to_cpu(spr->offset); + dbg_summary("xref at %#08x (xid=%u, ino=%u)\n", ofs, + je32_to_cpu(spr->xid), je32_to_cpu(spr->ino)); + raw = jffs2_alloc_raw_node_ref(); + if (!raw) { + JFFS2_NOTICE("allocation of node reference failed\n"); + kfree(summary); + return -ENOMEM; + } + ref = jffs2_alloc_xattr_ref(); + if (!ref) { + JFFS2_NOTICE("allocation of xattr_datum failed\n"); + jffs2_free_raw_node_ref(raw); + kfree(summary); + return -ENOMEM; + } + ref->ino = 0xfffffffe; + ref->xid = 0xfffffffd; + ref->node = raw; + list_add_tail(&ref->ilist, &c->xattr_temp); + + 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))); + *pseudo_random += ofs; + sp += JFFS2_SUMMARY_XREF_SIZE; + + break; + } +#endif default : { +printk("nodetype = %#04x\n",je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)); JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); kfree(summary); return -EIO; @@ -617,7 +784,31 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock break; } +#ifdef CONFIG_JFFS2_FS_XATTR + case JFFS2_NODETYPE_XATTR: { + struct jffs2_sum_xattr_flash *sxattr_ptr = wpage; + + temp = c->summary->sum_list_head; + sxattr_ptr->nodetype = temp->x.nodetype; + sxattr_ptr->xid = temp->x.xid; + sxattr_ptr->version = temp->x.version; + sxattr_ptr->offset = temp->x.offset; + sxattr_ptr->totlen = temp->x.totlen; + + wpage += JFFS2_SUMMARY_XATTR_SIZE; + break; + } + case JFFS2_NODETYPE_XREF: { + struct jffs2_sum_xref_flash *sxref_ptr = wpage; + + temp = c->summary->sum_list_head; + sxref_ptr->nodetype = temp->r.nodetype; + sxref_ptr->offset = temp->r.offset; + wpage += JFFS2_SUMMARY_XREF_SIZE; + break; + } +#endif default : { BUG(); /* unknown node in summary information */ } -- cgit v1.2.3 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/summary.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 From c8708a9275928cc8e77bd443cd12565dda0a3ded Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Sat, 13 May 2006 15:21:38 +0900 Subject: [JFFS2][XATTR] Handling the duplicate JFFS2_NODETYPE_XATTR node cases. When jffs2_sum_process_sum_data() found a JFFS2_NODETYPE_XATTR which has duplicate xid and older version, an error was returned without appropriate process. In the result, mounting filesystem is failed. This patch fix this problem. If jffs2_setup_xattr_datum() returned -EEXIST, the caller marks this node as DIRTY_SPACE(). [1/2] jffs2-xattr-v5.2-01-fix-duplicate-xdatum.patch Signed-off-by: KaiGai Kohei --- fs/jffs2/summary.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'fs/jffs2/summary.c') diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 831a42c13059..9763d73c0da1 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c @@ -508,8 +508,14 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); if (IS_ERR(xd)) { - JFFS2_NOTICE("allocation of xattr_datum failed\n"); jffs2_free_raw_node_ref(raw); + if (PTR_ERR(xd) == -EEXIST) { + /* a newer version of xd exists */ + DIRTY_SPACE(je32_to_cpu(spx->totlen)); + sp += JFFS2_SUMMARY_XATTR_SIZE; + break; + } + JFFS2_NOTICE("allocation of xattr_datum failed\n"); kfree(summary); return PTR_ERR(xd); } -- cgit v1.2.3