From: Maneesh Soni <maneesh@in.ibm.com>

- Following patch uses synchronize_kernel in detach_mnt() and facilitates
  lockless lookup_mnt.



 25-akpm/fs/namespace.c |   22 ++++++++++++++++++----
 1 files changed, 18 insertions(+), 4 deletions(-)

diff -puN fs/namespace.c~lockfree-lookup_mnt fs/namespace.c
--- 25/fs/namespace.c~lockfree-lookup_mnt	Wed May 21 15:04:05 2003
+++ 25-akpm/fs/namespace.c	Wed May 21 15:04:05 2003
@@ -73,6 +73,11 @@ void free_vfsmnt(struct vfsmount *mnt)
 /*
  * Now, lookup_mnt increments the ref count before returning
  * the vfsmount struct.
+ *
+ * lookup_mnt can be done without taking any lock, as now we 
+ * do synchronize_kernel() while removing vfsmount struct
+ * from mnt_hash list. rcu_read_(un)lock is required for 
+ * pre-emptive kernels.
  */
 struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
 {
@@ -80,7 +85,7 @@ struct vfsmount *lookup_mnt(struct vfsmo
 	struct list_head * tmp = head;
 	struct vfsmount *p, *found = NULL;
 
-	spin_lock(&vfsmount_lock);
+	rcu_read_lock();
 	for (;;) {
 		tmp = tmp->next;
 		p = NULL;
@@ -92,7 +97,7 @@ struct vfsmount *lookup_mnt(struct vfsmo
 			break;
 		}
 	}
-	spin_unlock(&vfsmount_lock);
+	rcu_read_unlock();
 	return found;
 }
 
@@ -109,10 +114,19 @@ static void detach_mnt(struct vfsmount *
 {
 	old_nd->dentry = mnt->mnt_mountpoint;
 	old_nd->mnt = mnt->mnt_parent;
+
+	/* remove from the hash_list, before other things */
+	list_del_rcu(&mnt->mnt_hash);
+	spin_unlock(&vfsmount_lock);
+
+	/* There could be existing users doing lookup_mnt, let
+	 * them finish their work.
+	 */
+	synchronize_kernel();
+	spin_lock(&vfsmount_lock);
 	mnt->mnt_parent = mnt;
 	mnt->mnt_mountpoint = mnt->mnt_root;
 	list_del_init(&mnt->mnt_child);
-	list_del_init(&mnt->mnt_hash);
 	old_nd->dentry->d_mounted--;
 }
 
@@ -120,7 +134,7 @@ static void attach_mnt(struct vfsmount *
 {
 	mnt->mnt_parent = mntget(nd->mnt);
 	mnt->mnt_mountpoint = dget(nd->dentry);
-	list_add(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry));
+	list_add_rcu(&mnt->mnt_hash, mount_hashtable+hash(nd->mnt, nd->dentry));
 	list_add_tail(&mnt->mnt_child, &nd->mnt->mnt_mounts);
 	nd->dentry->d_mounted++;
 }

_