From: KaiGai Kohei Date: Sat, 24 Jun 2006 00:14:13 +0000 (+0900) Subject: [JFFS2][XATTR] rid unnecessary writing of delete marker. X-Git-Tag: v2.6.18-rc1~458^2~7 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a13695cbe4e8311b363f9bd25162904b984ca74;p=linux-2.6 [JFFS2][XATTR] rid unnecessary writing of delete marker. In the followinf situation, an explicit delete marker is not necessary, because we can certainlly detect those obsolete xattr_datum or xattr_ref on next mounting. - When to delete xattr_datum node. - When to delete xattr_ref node on removing inode. - When to delete xattr_ref node on updating xattr. This patch rids writing delete marker in those situations. Signed-off-by: KaiGai Kohei Signed-off-by: David Woodhouse --- diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 79638f56c5..2bfdc33752 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -332,10 +332,8 @@ static int jffs2_scan_xattr_node(struct jffs2_sb_info *c, struct jffs2_erasebloc xid = je32_to_cpu(rx->xid); version = je32_to_cpu(rx->version); - totlen = sizeof(struct jffs2_raw_xattr); - if (version != XDATUM_DELETE_MARKER) - totlen += rx->name_len + 1 + je16_to_cpu(rx->value_len); - totlen = PAD(totlen); + totlen = PAD(sizeof(struct jffs2_raw_xattr) + + 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); diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 03871ab7c2..7622f79cb5 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c @@ -50,12 +50,9 @@ * is used to write xdatum to medium. xd->version will be incremented. * create_xattr_datum(c, xprefix, xname, xvalue, xsize) * is used to create new xdatum and write to medium. - * delete_xattr_datum_delay(c, xd) - * is used to delete a xdatum without 'delete marker'. It has a possibility to detect - * orphan xdatum on next mounting. * delete_xattr_datum(c, xd) - * is used to delete a xdatum with 'delete marker'. Calling jffs2_reserve_space() is - * necessary before this function. + * is used to delete a xdatum. It marks xd JFFS2_XFLAGS_DEAD, and allows + * GC to reclaim those physical nodes. * -------------------------------------------------- */ static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize) { @@ -154,10 +151,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat xd->flags |= JFFS2_XFLAGS_INVALID; return EIO; } - totlen = sizeof(rx); - if (xd->version != XDATUM_DELETE_MARKER) - totlen += rx.name_len + 1 + je16_to_cpu(rx.value_len); - totlen = PAD(totlen); + totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len)); if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK || je16_to_cpu(rx.nodetype) != JFFS2_NODETYPE_XATTR || je32_to_cpu(rx.totlen) != totlen @@ -268,6 +262,7 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x */ int rc = 0; + BUG_ON(xd->flags & JFFS2_XFLAGS_DEAD); if (xd->xname) return 0; if (xd->flags & JFFS2_XFLAGS_INVALID) @@ -285,20 +280,18 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x struct jffs2_raw_xattr rx; struct kvec vecs[2]; size_t length; - int rc, totlen, nvecs = 1; + int rc, totlen; uint32_t phys_ofs = write_ofs(c); - BUG_ON(is_xattr_datum_dead(xd) || (xd->flags & JFFS2_XFLAGS_INVALID) - ? !!xd->xname : !xd->xname); + BUG_ON(!xd->xname); + BUG_ON(xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID)); vecs[0].iov_base = ℞ - vecs[0].iov_len = totlen = sizeof(rx); - if (!is_xattr_datum_dead(xd) && !(xd->flags & JFFS2_XFLAGS_INVALID)) { - nvecs++; - vecs[1].iov_base = xd->xname; - vecs[1].iov_len = xd->name_len + 1 + xd->value_len; - totlen += vecs[1].iov_len; - } + vecs[0].iov_len = sizeof(rx); + vecs[1].iov_base = xd->xname; + vecs[1].iov_len = xd->name_len + 1 + xd->value_len; + totlen = vecs[0].iov_len + vecs[1].iov_len; + /* Setup raw-xattr */ memset(&rx, 0, sizeof(rx)); rx.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); @@ -307,18 +300,14 @@ static int save_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x rx.hdr_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_unknown_node) - 4)); rx.xid = cpu_to_je32(xd->xid); - if (!is_xattr_datum_dead(xd) && !(xd->flags & JFFS2_XFLAGS_INVALID)) { - rx.version = cpu_to_je32(++xd->version); - rx.xprefix = xd->xprefix; - rx.name_len = xd->name_len; - rx.value_len = cpu_to_je16(xd->value_len); - rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len)); - } else { - rx.version = cpu_to_je32(XDATUM_DELETE_MARKER); - } + rx.version = cpu_to_je32(++xd->version); + rx.xprefix = xd->xprefix; + rx.name_len = xd->name_len; + rx.value_len = cpu_to_je16(xd->value_len); + rx.data_crc = cpu_to_je32(crc32(0, vecs[1].iov_base, vecs[1].iov_len)); rx.node_crc = cpu_to_je32(crc32(0, &rx, sizeof(struct jffs2_raw_xattr) - 4)); - rc = jffs2_flash_writev(c, vecs, nvecs, phys_ofs, &length, 0); + rc = jffs2_flash_writev(c, vecs, 2, phys_ofs, &length, 0); if (rc || totlen != length) { JFFS2_WARNING("jffs2_flash_writev()=%d, req=%u, wrote=%zu, at %#08x\n", rc, totlen, length, phys_ofs); @@ -405,53 +394,36 @@ static struct jffs2_xattr_datum *create_xattr_datum(struct jffs2_sb_info *c, return xd; } -static void delete_xattr_datum_delay(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) +static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) { /* must be called under down_write(xattr_sem) */ BUG_ON(xd->refcnt); unload_xattr_datum(c, xd); - set_xattr_datum_dead(xd); + xd->flags |= JFFS2_XFLAGS_DEAD; spin_lock(&c->erase_completion_lock); - list_add(&xd->xindex, &c->xattr_dead_list); - spin_unlock(&c->erase_completion_lock); - JFFS2_NOTICE("xdatum(xid=%u) was removed without delete marker. " - "An orphan xdatum may be detected on next mounting.\n", xd->xid); -} - -static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) -{ - /* must be called under jffs2_reserve_space() and down_write(xattr_sem) */ - int rc; - BUG_ON(xd->refcnt); - - unload_xattr_datum(c, xd); - set_xattr_datum_dead(xd); - rc = save_xattr_datum(c, xd); - if (rc) { - JFFS2_NOTICE("xdatum(xid=%u) was removed without delete marker. " - "An orphan xdatum may be detected on next mounting.\n", - xd->xid); + if (xd->node == (void *)xd) { + BUG_ON(!(xd->flags & JFFS2_XFLAGS_INVALID)); + jffs2_free_xattr_datum(xd); + } else { + list_add(&xd->xindex, &c->xattr_dead_list); } - spin_lock(&c->erase_completion_lock); - list_add(&xd->xindex, &c->xattr_dead_list); spin_unlock(&c->erase_completion_lock); + dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", xd->xid, xd->version); } /* -------- xref related functions ------------------ * verify_xattr_ref(c, ref) * is used to load xref information from medium. Because summary data does not * contain xid/ino, it's necessary to verify once while mounting process. - * delete_xattr_ref_node(c, ref) - * is used to delete a jffs2 node is dominated by xref. When EBS is enabled, - * it overwrites the obsolete node by myself. - * delete_xattr_ref(c, ref) - * is used to delete jffs2_xattr_ref object. If the reference counter of xdatum - * is refered by this xref become 0, delete_xattr_datum() is called later. * save_xattr_ref(c, ref) - * is used to write xref to medium. + * is used to write xref to medium. If delete marker is marked, it write + * a delete marker of xref into medium. * create_xattr_ref(c, ic, xd) * is used to create a new xref and write to medium. + * delete_xattr_ref(c, ref) + * is used to delete jffs2_xattr_ref. It marks xref XREF_DELETE_MARKER, + * and allows GC to reclaim those physical nodes. * jffs2_xattr_delete_inode(c, ic) * is called to remove xrefs related to obsolete inode when inode is unlinked. * jffs2_xattr_free_inode(c, ic) @@ -591,13 +563,13 @@ static struct jffs2_xattr_ref *create_xattr_ref(struct jffs2_sb_info *c, struct return ref; /* success */ } -static void delete_xattr_ref_delay(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) +static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref) { /* must be called under down_write(xattr_sem) */ struct jffs2_xattr_datum *xd; - set_xattr_ref_dead(ref); xd = ref->xd; + ref->xseqno |= XREF_DELETE_MARKER; ref->ino = ref->ic->ino; ref->xid = ref->xd->xid; spin_lock(&c->erase_completion_lock); @@ -605,102 +577,29 @@ static void delete_xattr_ref_delay(struct jffs2_sb_info *c, struct jffs2_xattr_r c->xref_dead_list = ref; spin_unlock(&c->erase_completion_lock); - JFFS2_NOTICE("xref(ino=%u, xid=%u) was removed without delete marker. " - "An orphan xref may be detected on next mounting.\n", - ref->ino, ref->xid); + dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) was removed.\n", + ref->ino, ref->xid, ref->xseqno); if (!--xd->refcnt) - delete_xattr_datum_delay(c, xd); -} - -static int delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, int enforce) -{ - /* must be called under jffs2_reserve_space() and down_write(xattr_sem) */ - struct jffs2_inode_cache *ic; - struct jffs2_xattr_datum *xd; - uint32_t length; - int rc; - - set_xattr_ref_dead(ref); - ic = ref->ic; - xd = ref->xd; - ref->ino = ic->ino; - ref->xid = xd->xid; - rc = save_xattr_ref(c, ref); - if (rc) { - if (!enforce) { - clr_xattr_ref_dead(ref); - ref->ic = ic; - ref->xd = xd; - return rc; - } - JFFS2_WARNING("could not write delete marker of xref(ino=%u, xid=%u). " - "An orphan xref may be detected on next mounting.\n", - ref->ic->ino, ref->xd->xid); - } - spin_lock(&c->erase_completion_lock); - ref->next = c->xref_dead_list; - c->xref_dead_list = ref; - spin_unlock(&c->erase_completion_lock); - - xd->refcnt--; - if (xd->refcnt) - return 0; - - /* delete xdatum */ - unload_xattr_datum(c, xd); - up_write(&c->xattr_sem); - jffs2_complete_reservation(c); - - rc = jffs2_reserve_space(c, PAD(sizeof(struct jffs2_raw_xattr)), &length, - ALLOC_DELETION, JFFS2_SUMMARY_XATTR_SIZE); - if (rc) { - down(&c->alloc_sem); - down_write(&c->xattr_sem); - delete_xattr_datum_delay(c, xd); - } else { - down_write(&c->xattr_sem); delete_xattr_datum(c, xd); - } - return 0; } void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) { /* It's called from jffs2_clear_inode() on inode removing. When an inode with XATTR is removed, those XATTRs must be removed. */ - struct jffs2_xattr_ref *ref; - uint32_t length; - int rc, retry; + struct jffs2_xattr_ref *ref, *_ref; if (!ic || ic->nlink > 0) return; - down_read(&c->xattr_sem); - if (!ic->xref) { - up_read(&c->xattr_sem); - return; - } - up_read(&c->xattr_sem); - retry: - rc = jffs2_reserve_space(c, PAD(sizeof(struct jffs2_raw_xref)), &length, - ALLOC_DELETION, JFFS2_SUMMARY_XREF_SIZE); down_write(&c->xattr_sem); - if (ic->xref) { - ref = ic->xref; - ic->xref = ref->next; - if (rc) { - delete_xattr_ref_delay(c, ref); - } else { - delete_xattr_ref(c, ref, 1); - } + for (ref = ic->xref; ref; ref = _ref) { + _ref = ref->next; + delete_xattr_ref(c, ref); } - retry = ic->xref ? 1 : 0; + ic->xref = NULL; up_write(&c->xattr_sem); - if (!rc) - jffs2_complete_reservation(c); - if (retry) - goto retry; } void jffs2_xattr_free_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) @@ -743,7 +642,7 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac rc = load_xattr_datum(c, ref->xd); if (unlikely(rc > 0)) { *pref = ref->next; - delete_xattr_ref_delay(c, ref); + delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) goto out; @@ -755,7 +654,7 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac ref->xd->flags &= ~JFFS2_XFLAGS_BIND; if (unlikely(rc > 0)) { *pcmp = cmp->next; - delete_xattr_ref_delay(c, cmp); + delete_xattr_ref(c, cmp); goto retry; } else if (unlikely(rc < 0)) goto out; @@ -764,10 +663,10 @@ static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cac && !strcmp(ref->xd->xname, cmp->xd->xname)) { if (ref->xseqno > cmp->xseqno) { *pcmp = cmp->next; - delete_xattr_ref_delay(c, cmp); + delete_xattr_ref(c, cmp); } else { *pref = ref->next; - delete_xattr_ref_delay(c, ref); + delete_xattr_ref(c, ref); } goto retry; } @@ -865,20 +764,11 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) struct jffs2_inode_cache *ic; struct jffs2_raw_node_ref *raw; int i, xdatum_count = 0, xdatum_unchecked_count = 0, xref_count = 0; + int xdatum_orphan_count = 0, xref_orphan_count = 0, xref_dead_count = 0; BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING)); - /* Phase.1 : Drop dead xdatum */ - for (i=0; i < XATTRINDEX_HASHSIZE; i++) { - list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { - BUG_ON(xd->node == (void *)xd); - if (is_xattr_datum_dead(xd)) { - list_del_init(&xd->xindex); - list_add(&xd->xindex, &c->xattr_unchecked); - } - } - } - /* Phase.2 : Merge same xref */ + /* Phase.1 : Merge same xref */ for (i=0; i < XREF_TMPHASH_SIZE; i++) xref_tmphash[i] = NULL; for (ref=c->xref_temp; ref; ref=_ref) { @@ -919,13 +809,15 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) } c->xref_temp = NULL; - /* Phase.3 : Bind xref with inode_cache and xattr_datum */ + /* Phase.2 : Bind xref with inode_cache and xattr_datum */ for (i=0; i < XREF_TMPHASH_SIZE; i++) { for (ref=xref_tmphash[i]; ref; ref=_ref) { + xref_count++; _ref = ref->next; if (is_xattr_ref_dead(ref)) { ref->next = c->xref_dead_list; c->xref_dead_list = ref; + xref_dead_count++; continue; } /* At this point, ref->xid and ref->ino contain XID and inode number. @@ -933,11 +825,12 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) xd = jffs2_find_xattr_datum(c, ref->xid); ic = jffs2_get_ino_cache(c, ref->ino); if (!xd || !ic) { - JFFS2_WARNING("xref(ino=%u, xid=%u, xseqno=%u) is orphan. \n", - ref->ino, ref->xid, ref->xseqno); - set_xattr_ref_dead(ref); + dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n", + ref->ino, ref->xid, ref->xseqno); + ref->xseqno |= XREF_DELETE_MARKER; ref->next = c->xref_dead_list; c->xref_dead_list = ref; + xref_orphan_count++; continue; } ref->xd = xd; @@ -945,19 +838,20 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) xd->refcnt++; ref->next = ic->xref; ic->xref = ref; - xref_count++; } } - /* Phase.4 : Link unchecked xdatum to xattr_unchecked list */ + /* Phase.3 : Link unchecked xdatum to xattr_unchecked list */ for (i=0; i < XATTRINDEX_HASHSIZE; i++) { list_for_each_entry_safe(xd, _xd, &c->xattrindex[i], xindex) { + xdatum_count++; list_del_init(&xd->xindex); if (!xd->refcnt) { - JFFS2_WARNING("orphan xdatum(xid=%u, version=%u)\n", - xd->xid, xd->version); - set_xattr_datum_dead(xd); + dbg_xattr("xdatum(xid=%u, version=%u) is orphan.\n", + xd->xid, xd->version); + xd->flags |= JFFS2_XFLAGS_DEAD; list_add(&xd->xindex, &c->xattr_unchecked); + xdatum_orphan_count++; continue; } if (is_xattr_datum_unchecked(c, xd)) { @@ -966,12 +860,14 @@ void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) list_add(&xd->xindex, &c->xattr_unchecked); xdatum_unchecked_count++; } - xdatum_count++; } } /* build complete */ - JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum (%u unchecked) and " - "%u of xref found.\n", xdatum_count, xdatum_unchecked_count, xref_count); + JFFS2_NOTICE("complete building xattr subsystem, %u of xdatum" + " (%u unchecked, %u orphan) and " + "%u of xref (%u dead, %u orphan) found.\n", + xdatum_count, xdatum_unchecked_count, xdatum_orphan_count, + xref_count, xref_dead_count, xref_orphan_count); } struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, @@ -1079,7 +975,7 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size) rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { *pref = ref->next; - delete_xattr_ref_delay(c, ref); + delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) goto out; @@ -1140,7 +1036,7 @@ int do_jffs2_getxattr(struct inode *inode, int xprefix, const char *xname, rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { *pref = ref->next; - delete_xattr_ref_delay(c, ref); + delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) { goto out; @@ -1203,7 +1099,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, rc = load_xattr_datum(c, xd); if (unlikely(rc > 0)) { *pref = ref->next; - delete_xattr_ref_delay(c, ref); + delete_xattr_ref(c, ref); goto retry; } else if (unlikely(rc < 0)) goto out; @@ -1214,8 +1110,23 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, goto out; } if (!buffer) { - *pref = ref->next; - rc = delete_xattr_ref(c, ref, 0); + ref->ino = ic->ino; + ref->xid = xd->xid; + ref->xseqno |= XREF_DELETE_MARKER; + rc = save_xattr_ref(c, ref); + if (!rc) { + *pref = ref->next; + spin_lock(&c->erase_completion_lock); + ref->next = c->xref_dead_list; + c->xref_dead_list = ref; + spin_unlock(&c->erase_completion_lock); + if (!--xd->refcnt) + delete_xattr_datum(c, xd); + } else { + ref->ic = ic; + ref->xd = xd; + ref->xseqno &= ~XREF_DELETE_MARKER; + } goto out; } goto found; @@ -1248,7 +1159,7 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request); xd->refcnt--; if (!xd->refcnt) - delete_xattr_datum_delay(c, xd); + delete_xattr_datum(c, xd); up_write(&c->xattr_sem); return rc; } @@ -1263,21 +1174,9 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, rc = PTR_ERR(newref); xd->refcnt--; if (!xd->refcnt) - delete_xattr_datum_delay(c, xd); + delete_xattr_datum(c, xd); } else if (ref) { - up_write(&c->xattr_sem); - jffs2_complete_reservation(c); - - rc = jffs2_reserve_space(c, request, &length, - ALLOC_DELETION, JFFS2_SUMMARY_XREF_SIZE); - down_write(&c->xattr_sem); - if (rc) { - JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request); - delete_xattr_ref_delay(c, ref); - up_write(&c->xattr_sem); - return 0; - } - delete_xattr_ref(c, ref, 1); + delete_xattr_ref(c, ref); } out: up_write(&c->xattr_sem); @@ -1292,6 +1191,10 @@ int do_jffs2_setxattr(struct inode *inode, int xprefix, const char *xname, * is used to move xref into new node. * jffs2_verify_xattr(c) * is used to call do_verify_xattr_datum() before garbage collecting. + * jffs2_release_xattr_datum(c, xd) + * is used to release an in-memory object of xdatum. + * jffs2_release_xattr_ref(c, ref) + * is used to release an in-memory object of xref. * -------------------------------------------------- */ int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd, struct jffs2_raw_node_ref *raw) @@ -1302,18 +1205,17 @@ int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xatt down_write(&c->xattr_sem); if (xd->node != raw) goto out; - if (is_xattr_datum_dead(xd) && (raw->next_in_ino == (void *)xd)) + if (xd->flags & (JFFS2_XFLAGS_DEAD|JFFS2_XFLAGS_INVALID)) goto out; - old_ofs = ref_offset(xd->node); - totlen = ref_totlen(c, c->gcblock, xd->node); - - if (!is_xattr_datum_dead(xd)) { - rc = load_xattr_datum(c, xd); - if (unlikely(rc < 0)) - goto out; + rc = load_xattr_datum(c, xd); + if (unlikely(rc)) { + rc = (rc > 0) ? 0 : rc; + goto out; } - + old_ofs = ref_offset(xd->node); + totlen = PAD(sizeof(struct jffs2_raw_xattr) + + xd->name_len + 1 + xd->value_len); rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XATTR_SIZE); if (rc) { JFFS2_WARNING("jffs2_reserve_space_gc()=%d, request=%u\n", rc, totlen); @@ -1331,7 +1233,6 @@ int jffs2_garbage_collect_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xatt return rc; } - int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref, struct jffs2_raw_node_ref *raw) { @@ -1392,7 +1293,7 @@ int jffs2_verify_xattr(struct jffs2_sb_info *c) raw->flash_offset = ref_offset(raw) | ((xd->node == (void *)raw) ? REF_PRISTINE : REF_NORMAL); } - if (is_xattr_datum_dead(xd)) + if (xd->flags & JFFS2_XFLAGS_DEAD) list_add(&xd->xindex, &c->xattr_dead_list); spin_unlock(&c->erase_completion_lock); } @@ -1403,7 +1304,7 @@ int jffs2_verify_xattr(struct jffs2_sb_info *c) void jffs2_release_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd) { /* must be called under spin_lock(&c->erase_completion_lock) */ - if (xd->node != (void *)xd) + if (xd->refcnt > 0 || xd->node != (void *)xd) return; list_del(&xd->xindex); @@ -1421,8 +1322,8 @@ void jffs2_release_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *re for (tmp=c->xref_dead_list, ptmp=&c->xref_dead_list; tmp; ptmp=&tmp->next, tmp=tmp->next) { if (ref == tmp) { *ptmp = tmp->next; - jffs2_free_xattr_ref(ref); break; } } + jffs2_free_xattr_ref(ref); } diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h index 06ab7b8802..4a10abc6d9 100644 --- a/fs/jffs2/xattr.h +++ b/fs/jffs2/xattr.h @@ -16,6 +16,7 @@ #define JFFS2_XFLAGS_HOT (0x01) /* This datum is HOT */ #define JFFS2_XFLAGS_BIND (0x02) /* This datum is not reclaimed */ +#define JFFS2_XFLAGS_DEAD (0x40) /* This datum is already dead */ #define JFFS2_XFLAGS_INVALID (0x80) /* This datum contains crc error */ struct jffs2_xattr_datum @@ -60,34 +61,12 @@ struct jffs2_xattr_ref struct jffs2_xattr_ref *next; /* chained from ic->xref_list */ }; -#define XDATUM_DELETE_MARKER (0xffffffff) #define XREF_DELETE_MARKER (0x00000001) -static inline int is_xattr_datum_dead(struct jffs2_xattr_datum *xd) -{ - return (xd->version == XDATUM_DELETE_MARKER); -} - -static inline void set_xattr_datum_dead(struct jffs2_xattr_datum *xd) -{ - xd->version = XDATUM_DELETE_MARKER; -} - static inline int is_xattr_ref_dead(struct jffs2_xattr_ref *ref) { return ((ref->xseqno & XREF_DELETE_MARKER) != 0); } -static inline void set_xattr_ref_dead(struct jffs2_xattr_ref *ref) -{ - ref->xseqno |= XREF_DELETE_MARKER; -} - -static inline void clr_xattr_ref_dead(struct jffs2_xattr_ref *ref) -{ - ref->xseqno &= ~XREF_DELETE_MARKER; -} - - #ifdef CONFIG_JFFS2_FS_XATTR extern void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c);