From: Maneesh Soni - Following patch uses synchronize_kernel in detach_mnt() and facilitates lockless lookup_mnt. 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 2003-05-22 01:52:26.000000000 -0700 +++ 25-akpm/fs/namespace.c 2003-05-22 01:52:26.000000000 -0700 @@ -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++; } _