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/gc.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'fs/jffs2/gc.c') diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 967fb2c..4ea1b7f 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -125,6 +125,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) struct jffs2_eraseblock *jeb; struct jffs2_raw_node_ref *raw; int ret = 0, inum, nlink; + int xattr = 0; if (down_interruptible(&c->alloc_sem)) return -EINTR; @@ -138,7 +139,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) the node CRCs etc. Do it now. */ /* checked_ino is protected by the alloc_sem */ - if (c->checked_ino > c->highest_ino) { + if (c->checked_ino > c->highest_ino && xattr) { printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n", c->unchecked_size); jffs2_dbg_dump_block_lists_nolock(c); @@ -148,6 +149,9 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) spin_unlock(&c->erase_completion_lock); + if (!xattr) + xattr = jffs2_verify_xattr(c); + spin_lock(&c->inocache_lock); ic = jffs2_get_ino_cache(c, c->checked_ino++); @@ -262,6 +266,16 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ic = jffs2_raw_ref_to_ic(raw); + /* When 'ic' refers xattr_datum/xattr_ref, this node is GCed as xattr. + We can decide whether this node is inode or xattr by ic->class. + ret = 0 : ic is xattr_datum/xattr_ref, and GC was SUCCESSED. + ret < 0 : ic is xattr_datum/xattr_ref, but GC was FAILED. + ret > 0 : ic is NOT xattr_datum/xattr_ref. + */ + ret = jffs2_garbage_collect_xattr(c, ic); + if (ret <= 0) + goto release_sem; + /* We need to hold the inocache. Either the erase_completion_lock or the inocache_lock are sufficient; we trade down since the inocache_lock causes less contention. */ -- cgit v1.1 From 084702e00111eb9ffb6d8a5c1938b8e5423e40a8 Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Sat, 13 May 2006 15:16:13 +0900 Subject: [JFFS2][XATTR] Remove jffs2_garbage_collect_xattr(c, ic) Remove jffs2_garbage_collect_xattr(c, ic). jffs2_garbage_collect_xattr_datum/ref() are called from gc.c directly. In original implementation, jffs2_garbage_collect_xattr(c, ic) returns with holding a spinlock if 'ic' is inode_cache. But it returns after releasing a spinlock if 'ic' is xattr_datum/ref. It looks so confusable behavior. Thus, this patch makes caller manage locking/unlocking. [5/10] jffs2-xattr-v5.1-05-update_xattr_gc.patch Signed-off-by: KaiGai Kohei --- fs/jffs2/gc.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'fs/jffs2/gc.c') diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 4ea1b7f..a5ef9814 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -266,15 +266,22 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ic = jffs2_raw_ref_to_ic(raw); +#ifdef CONFIG_JFFS2_FS_XATTR /* When 'ic' refers xattr_datum/xattr_ref, this node is GCed as xattr. - We can decide whether this node is inode or xattr by ic->class. - ret = 0 : ic is xattr_datum/xattr_ref, and GC was SUCCESSED. - ret < 0 : ic is xattr_datum/xattr_ref, but GC was FAILED. - ret > 0 : ic is NOT xattr_datum/xattr_ref. - */ - ret = jffs2_garbage_collect_xattr(c, ic); - if (ret <= 0) + * We can decide whether this node is inode or xattr by ic->class. */ + if (ic->class == RAWNODE_CLASS_XATTR_DATUM + || ic->class == RAWNODE_CLASS_XATTR_REF) { + BUG_ON(raw->next_in_ino != (void *)ic); + spin_unlock(&c->erase_completion_lock); + + if (ic->class == RAWNODE_CLASS_XATTR_DATUM) { + ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic); + } else { + ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic); + } goto release_sem; + } +#endif /* We need to hold the inocache. Either the erase_completion_lock or the inocache_lock are sufficient; we trade down since the inocache_lock -- cgit v1.1 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 +++++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 20 deletions(-) (limited to 'fs/jffs2/gc.c') diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 23587f8..b0a5c40 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))); -- cgit v1.1 From b64335f2b740d6f5dbf5d3b04af30d407bf599f5 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 21 May 2006 04:36:45 +0100 Subject: [JFFS2] Add length argument to jffs2_add_physical_node_ref() If __totlen is going away, we need to pass the length in separately. Also stop callers from needlessly setting ref->next_phys to NULL, since that's done for them... and since that'll also be going away soon. Signed-off-by: David Woodhouse --- fs/jffs2/gc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'fs/jffs2/gc.c') diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index b0a5c40..4773ba2 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -627,8 +627,6 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, /* OK, all the CRCs are good; this node can just be copied as-is. */ retry: nraw->flash_offset = phys_ofs; - nraw->__totlen = rawlen; - nraw->next_phys = NULL; ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node); @@ -640,7 +638,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, nraw->next_in_ino = NULL; nraw->flash_offset |= REF_OBSOLETE; - jffs2_add_physical_node_ref(c, nraw); + jffs2_add_physical_node_ref(c, nraw, rawlen); 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); @@ -680,7 +678,7 @@ 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); + jffs2_add_physical_node_ref(c, nraw, rawlen); if (ic) { /* Link into per-inode list. This is safe because of the ic -- cgit v1.1