All of lore.kernel.org
 help / color / mirror / Atom feed
From: KaiGai Kohei <kaigai@ak.jp.nec.com>
To: David Woodhouse <dwmw2@infradead.org>
Cc: KaiGai Kohei <kaigai@kaigai.gr.jp>,
	linux-mtd@lists.infradead.org,
	KaiGai Kohei <kaigai@ak.jp.nec.com>
Subject: Re: JFFS2/xattr problems.
Date: Thu, 29 Jun 2006 15:02:30 +0900	[thread overview]
Message-ID: <44A36CF6.6010204@ak.jp.nec.com> (raw)
In-Reply-To: <44A09B53.80908@ak.jp.nec.com>

[-- Attachment #1: Type: text/plain, Size: 1345 bytes --]

> But I noticed this patch has another problem last night.
> In delete_xattr_ref(), we don't hold c->erase_completion_lock before
> atomic_dec_and_test(), so there is a possibility to release
> a xattr_datum twice.
> I think atomic_dec_and_lock() should be used in delete_xattr_datum().
> If so, we can release it safely with minimum locking pain.
> This behavior may be correct. Please wait a fix.

* jffs2-xattr-v6.2-01-fix-xd_refcnt-race-condition.patch

   Signed-off-by: KaiGai Kohei <kaigai@ak.jp.nec.com>

The attached patch resolves this problem.
When xd->refcnt is checked whether this xdatum should be released
or not, atomic_dec_and_lock() is used to ensure holding the
c->erase_completion_lock.

This fix change a specification of delete_xattr_datum().
Previously, it's only called when xd->refcnt equals zero.
(calling it with positive xd->refcnt cause a BUG())
If you applied this patch, the function checks whether
xd->refcnt is zero or not under the spinlock if necessary.
Then, it marks xd DEAD flahs and links with xattr_dead_list
or releases it immediately when xd->refcnt become zero.

I think it's not appropriate to call this behavior 'delete'.
Thus, I changed the function name 'unrefer_xattr_datum'.
Isn't it superfluous modify?

Thanks,
-- 
Open Source Software Promotion Center, NEC
KaiGai Kohei <kaigai@ak.jp.nec.com>

[-- Attachment #2: jffs2-xattr-v6.2-01-fix-xd_refcnt-race-condition.patch --]
[-- Type: text/plain, Size: 3503 bytes --]

diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index 18e66db..25bc1ae 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -50,9 +50,10 @@ #include "nodelist.h"
  *   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(c, xd)
- *   is used to delete a xdatum. It marks xd JFFS2_XFLAGS_DEAD, and allows
- *   GC to reclaim those physical nodes.
+ * unrefer_xattr_datum(c, xd)
+ *   is used to delete a xdatum. When nobody refers this xdatum, JFFS2_XFLAGS_DEAD
+ *   is set on xd->flags and chained xattr_dead_list or release it immediately.
+ *   In the first case, the garbage collector release it later.
  * -------------------------------------------------- */
 static uint32_t xattr_datum_hashkey(int xprefix, const char *xname, const char *xvalue, int xsize)
 {
@@ -394,22 +395,24 @@ static struct jffs2_xattr_datum *create_
 	return xd;
 }
 
-static void delete_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
+static void unrefer_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
 {
 	/* must be called under down_write(xattr_sem) */
-	BUG_ON(atomic_read(&xd->refcnt));
+	if (atomic_dec_and_lock(&xd->refcnt, &c->erase_completion_lock)) {
+		uint32_t xid = xd->xid, version = xd->version;
 
-	unload_xattr_datum(c, xd);
-	xd->flags |= JFFS2_XFLAGS_DEAD;
-	spin_lock(&c->erase_completion_lock);
-	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);
+		unload_xattr_datum(c, xd);
+		xd->flags |= JFFS2_XFLAGS_DEAD;
+		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_unlock(&c->erase_completion_lock);
+
+		dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", xid, version);
 	}
-	spin_unlock(&c->erase_completion_lock);
-	dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", xd->xid, xd->version);
 }
 
 /* -------- xref related functions ------------------
@@ -580,8 +583,7 @@ static void delete_xattr_ref(struct jffs
 	dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) was removed.\n",
 		  ref->ino, ref->xid, ref->xseqno);
 
-	if (atomic_dec_and_test(&xd->refcnt))
-		delete_xattr_datum(c, xd);
+	unrefer_xattr_datum(c, xd);
 }
 
 void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
@@ -1119,8 +1121,7 @@ int do_jffs2_setxattr(struct inode *inod
 					ref->next = c->xref_dead_list;
 					c->xref_dead_list = ref;
 					spin_unlock(&c->erase_completion_lock);
-					if (atomic_dec_and_test(&xd->refcnt))
-						delete_xattr_datum(c, xd);
+					unrefer_xattr_datum(c, xd);
 				} else {
 					ref->ic = ic;
 					ref->xd = xd;
@@ -1156,8 +1157,7 @@ int do_jffs2_setxattr(struct inode *inod
 	down_write(&c->xattr_sem);
 	if (rc) {
 		JFFS2_WARNING("jffs2_reserve_space()=%d, request=%u\n", rc, request);
-		if (atomic_dec_and_test(&xd->refcnt))
-			delete_xattr_datum(c, xd);
+		unrefer_xattr_datum(c, xd);
 		up_write(&c->xattr_sem);
 		return rc;
 	}
@@ -1170,8 +1170,7 @@ int do_jffs2_setxattr(struct inode *inod
 			ic->xref = ref;
 		}
 		rc = PTR_ERR(newref);
-		if (atomic_dec_and_test(&xd->refcnt))
-			delete_xattr_datum(c, xd);
+		unrefer_xattr_datum(c, xd);
 	} else if (ref) {
 		delete_xattr_ref(c, ref);
 	}

      reply	other threads:[~2006-06-29  6:02 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-05-20 18:41 JFFS2/xattr problems David Woodhouse
2006-05-21  3:22 ` David Woodhouse
2006-05-21 11:24   ` KaiGai Kohei
2006-05-21 11:19 ` KaiGai Kohei
2006-05-21 12:41   ` David Woodhouse
2006-06-12  2:17   ` KaiGai Kohei
2006-06-12  8:03     ` David Woodhouse
2006-06-12  9:43       ` KaiGai Kohei
2006-06-12  9:53         ` David Woodhouse
2006-06-12 18:06           ` Jörn Engel
2006-06-13 13:36             ` KaiGai Kohei
2006-06-13 14:13               ` Jörn Engel
2006-06-14 21:58                 ` Theodore Tso
2006-06-15 11:47                   ` Jörn Engel
2006-06-15 15:24                     ` Theodore Tso
2006-06-13 13:30           ` KaiGai Kohei
2006-06-24  5:58             ` KaiGai Kohei
2006-06-24 12:44               ` David Woodhouse
2006-06-26 15:45               ` David Woodhouse
2006-06-27  2:43                 ` KaiGai Kohei
2006-06-29  6:02                   ` KaiGai Kohei [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=44A36CF6.6010204@ak.jp.nec.com \
    --to=kaigai@ak.jp.nec.com \
    --cc=dwmw2@infradead.org \
    --cc=kaigai@kaigai.gr.jp \
    --cc=linux-mtd@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.