All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dipankar Sarma <dipankar@in.ibm.com>
To: Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk>
Cc: Andrew Morton <akpm@osdl.org>, linux-kernel@vger.kernel.org
Subject: Re: [patch 2/3] Remove d_bucket
Date: Mon, 20 Sep 2004 22:39:30 +0530	[thread overview]
Message-ID: <20040920170930.GB5181@in.ibm.com> (raw)
In-Reply-To: <20040920170439.GA5181@in.ibm.com>

Tested using dcachebench and hevy rename test.
http://lse.sourceforge.net/locking/dcache/rename_test/

Thanks
Dipankar

While going over dcache code, I realized that d_bucket which
was introduced to prevent hash chain traversals from going into
an infinite loop earlier, is no longer necessary. Originally,
when RCU based lock-free lookup was first introduced, dcache
hash chains used list_head. Hash chain traversal was terminated
when dentry->next reaches the list_head in the hash bucket.
However, if renames happen during a lock-free lookup, a dentry
may move to different bucket and subsequent hash chain traversal from
there onwards may not see the list_head in the original bucket
at all. In fact, this would result in the list_head in the bucket
interpreted as a list_head in dentry and bad things will happen
after that. Once hlist based hash chains were introduced in dcache,
the termination condition changed and lock-free traversal would
be safe with NULL pointer based termination of hlists. This means
that d_bucket check is no longer required.

There still exist some theoritical livelocks like a dentry getting
continuously moving and lock-free look-up never terminating.
But that isn't really any worse that what we have. In return
for these changes, we reduce the dentry size by the size of
a pointer. That should make akpm and mpm happy.

Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com>


 fs/dcache.c            |   39 +++++++++++++++------------------------
 include/linux/dcache.h |    3 +--
 2 files changed, 16 insertions(+), 26 deletions(-)

diff -puN fs/dcache.c~dcache-remove-bucket-test fs/dcache.c
--- linux-2.6.9-rc2-dcache/fs/dcache.c~dcache-remove-bucket-test	2004-09-18 20:22:47.000000000 +0530
+++ linux-2.6.9-rc2-dcache-dipankar/fs/dcache.c	2004-09-20 02:55:12.000000000 +0530
@@ -715,7 +715,6 @@ struct dentry *d_alloc(struct dentry * p
 	dentry->d_fsdata = NULL;
 	dentry->d_mounted = 0;
 	dentry->d_cookie = NULL;
-	dentry->d_bucket = NULL;
 	INIT_HLIST_NODE(&dentry->d_hash);
 	INIT_LIST_HEAD(&dentry->d_lru);
 	INIT_LIST_HEAD(&dentry->d_subdirs);
@@ -850,12 +849,6 @@ struct dentry * d_alloc_anon(struct inod
 			res->d_sb = inode->i_sb;
 			res->d_parent = res;
 			res->d_inode = inode;
-
-			/*
-			 * Set d_bucket to an "impossible" bucket address so
-			 * that d_move() doesn't get a false positive
-			 */
-			res->d_bucket = NULL;
 			res->d_flags |= DCACHE_DISCONNECTED;
 			res->d_flags &= ~DCACHE_UNHASHED;
 			list_add(&res->d_alias, &inode->i_dentry);
@@ -986,13 +979,6 @@ struct dentry * __d_lookup(struct dentry
 		spin_lock(&dentry->d_lock);
 
 		/*
-		 * If lookup ends up in a different bucket due to concurrent
-		 * rename, fail it
-		 */
-		if (unlikely(dentry->d_bucket != head))
-			goto terminate;
-
-		/*
 		 * Recheck the dentry after taking the lock - d_move may have
 		 * changed things.  Don't bother checking the hash because we're
 		 * about to compare the whole name anyway.
@@ -1111,6 +1097,13 @@ void d_delete(struct dentry * dentry)
 	spin_unlock(&dcache_lock);
 }
 
+static void __d_rehash(struct dentry * entry, struct hlist_head *list)
+{
+
+ 	entry->d_flags &= ~DCACHE_UNHASHED;
+ 	hlist_add_head_rcu(&entry->d_hash, list);
+}
+
 /**
  * d_rehash	- add an entry back to the hash
  * @entry: dentry to add to the hash
@@ -1124,10 +1117,8 @@ void d_rehash(struct dentry * entry)
 
 	spin_lock(&dcache_lock);
 	spin_lock(&entry->d_lock);
- 	entry->d_flags &= ~DCACHE_UNHASHED;
+	__d_rehash(entry, list);
 	spin_unlock(&entry->d_lock);
-	entry->d_bucket = list;
- 	hlist_add_head_rcu(&entry->d_hash, list);
 	spin_unlock(&dcache_lock);
 }
 
@@ -1205,6 +1196,8 @@ static void switch_names(struct dentry *
 
 void d_move(struct dentry * dentry, struct dentry * target)
 {
+	struct hlist_head *list;
+
 	if (!dentry->d_inode)
 		printk(KERN_WARNING "VFS: moving negative dcache entry\n");
 
@@ -1224,13 +1217,12 @@ void d_move(struct dentry * dentry, stru
 	/* Move the dentry to the target hash queue, if on different bucket */
 	if (dentry->d_flags & DCACHE_UNHASHED)
 		goto already_unhashed;
-	if (dentry->d_bucket != target->d_bucket) {
-		hlist_del_rcu(&dentry->d_hash);
+
+	hlist_del_rcu(&dentry->d_hash);
+
 already_unhashed:
-		dentry->d_bucket = target->d_bucket;
-		hlist_add_head_rcu(&dentry->d_hash, target->d_bucket);
-		dentry->d_flags &= ~DCACHE_UNHASHED;
-	}
+	list = d_hash(target->d_parent, target->d_name.hash);
+	__d_rehash(dentry, list);
 
 	/* Unhash the target: dput() will then get rid of it */
 	__d_drop(target);
@@ -1240,7 +1232,6 @@ already_unhashed:
 
 	/* Switch the names.. */
 	switch_names(dentry, target);
-	smp_wmb();
 	do_switch(dentry->d_name.len, target->d_name.len);
 	do_switch(dentry->d_name.hash, target->d_name.hash);
 
diff -puN include/linux/dcache.h~dcache-remove-bucket-test include/linux/dcache.h
--- linux-2.6.9-rc2-dcache/include/linux/dcache.h~dcache-remove-bucket-test	2004-09-18 21:03:43.000000000 +0530
+++ linux-2.6.9-rc2-dcache-dipankar/include/linux/dcache.h	2004-09-18 21:04:22.000000000 +0530
@@ -28,7 +28,7 @@ struct vfsmount;
  * "quick string" -- eases parameter passing, but more importantly
  * saves "metadata" about the string (ie length and the hash).
  *
- * hash comes first so it snuggles against d_parent and d_bucket in the
+ * hash comes first so it snuggles against d_parent in the
  * dentry.
  */
 struct qstr {
@@ -91,7 +91,6 @@ struct dentry {
 	 * so they all fit in a 16-byte range, with 16-byte alignment.
 	 */
 	struct dentry *d_parent;	/* parent directory */
-	struct hlist_head *d_bucket;	/* lookup hash bucket */
 	struct qstr d_name;
 
 	struct list_head d_lru;		/* LRU list */

_

  reply	other threads:[~2004-09-20 17:05 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-09-20 17:04 [patch 1/3] Fix dcache lookup Dipankar Sarma
2004-09-20 17:09 ` Dipankar Sarma [this message]
2004-09-20 17:11   ` [patch 3/3] Document RCU based " Dipankar Sarma
     [not found]   ` <20040920170225.GB5112@logos.cnet>
2004-09-20 18:49     ` [patch 2/3] Remove d_bucket Dipankar Sarma

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=20040920170930.GB5181@in.ibm.com \
    --to=dipankar@in.ibm.com \
    --cc=akpm@osdl.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=viro@parcelfarce.linux.theplanet.co.uk \
    /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.