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/malloc.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) (limited to 'fs/jffs2/malloc.c') diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 036cbd11c00..3d5b7ecfbf8 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -26,6 +26,10 @@ static kmem_cache_t *tmp_dnode_info_slab; static kmem_cache_t *raw_node_ref_slab; static kmem_cache_t *node_frag_slab; static kmem_cache_t *inode_cache_slab; +#ifdef CONFIG_JFFS2_FS_XATTR +static kmem_cache_t *xattr_datum_cache; +static kmem_cache_t *xattr_ref_cache; +#endif int __init jffs2_create_slab_caches(void) { @@ -68,8 +72,24 @@ int __init jffs2_create_slab_caches(void) inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), 0, 0, NULL, NULL); - if (inode_cache_slab) - return 0; + if (!inode_cache_slab) + goto err; + +#ifdef CONFIG_JFFS2_FS_XATTR + xattr_datum_cache = kmem_cache_create("jffs2_xattr_datum", + sizeof(struct jffs2_xattr_datum), + 0, 0, NULL, NULL); + if (!xattr_datum_cache) + goto err; + + xattr_ref_cache = kmem_cache_create("jffs2_xattr_ref", + sizeof(struct jffs2_xattr_ref), + 0, 0, NULL, NULL); + if (!xattr_ref_cache) + goto err; +#endif + + return 0; err: jffs2_destroy_slab_caches(); return -ENOMEM; @@ -91,6 +111,12 @@ void jffs2_destroy_slab_caches(void) kmem_cache_destroy(node_frag_slab); if(inode_cache_slab) kmem_cache_destroy(inode_cache_slab); +#ifdef CONFIG_JFFS2_FS_XATTR + if (xattr_datum_cache) + kmem_cache_destroy(xattr_datum_cache); + if (xattr_ref_cache) + kmem_cache_destroy(xattr_ref_cache); +#endif } struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) @@ -205,3 +231,41 @@ void jffs2_free_inode_cache(struct jffs2_inode_cache *x) dbg_memalloc("%p\n", x); kmem_cache_free(inode_cache_slab, x); } + +#ifdef CONFIG_JFFS2_FS_XATTR +struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void) +{ + struct jffs2_xattr_datum *xd; + xd = kmem_cache_alloc(xattr_datum_cache, GFP_KERNEL); + dbg_memalloc("%p\n", xd); + + memset(xd, 0, sizeof(struct jffs2_xattr_datum)); + xd->class = RAWNODE_CLASS_XATTR_DATUM; + INIT_LIST_HEAD(&xd->xindex); + return xd; +} + +void jffs2_free_xattr_datum(struct jffs2_xattr_datum *xd) +{ + dbg_memalloc("%p\n", xd); + kmem_cache_free(xattr_datum_cache, xd); +} + +struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void) +{ + struct jffs2_xattr_ref *ref; + ref = kmem_cache_alloc(xattr_ref_cache, GFP_KERNEL); + dbg_memalloc("%p\n", ref); + + memset(ref, 0, sizeof(struct jffs2_xattr_ref)); + ref->class = RAWNODE_CLASS_XATTR_REF; + INIT_LIST_HEAD(&ref->ilist); + return ref; +} + +void jffs2_free_xattr_ref(struct jffs2_xattr_ref *ref) +{ + dbg_memalloc("%p\n", ref); + kmem_cache_free(xattr_ref_cache, ref); +} +#endif -- 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/malloc.c') diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 3b4e0edd6db..272fbea5519 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 3d5b7ecfbf8..f2473fa2fd1 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 6f6279cf490..351d947c937 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 61ccdf4f104..e1acce8fb2b 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 f09689e320f..0a79fc921e9 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 5d9ec8e3652..831a42c1305 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 d5c78195f3b..ff2b00b604e 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 c9a185c54ce..b16bc71c9cd 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 d157ad641ed..0360097e593 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