--- /dev/null
+From stable-bounces@linux.kernel.org Tue Jun 6 08:23:00 2006
+Date: Tue, 6 Jun 2006 11:19:35 -0400
+From: Joe Korty <joe.korty@ccur.com>
+To: stable@kernel.org
+Cc:
+Subject: fs/namei.c: Call to file_permission() under a spinlock in do_lookup_path()
+
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+
+We're presently running lock_kernel() under fs_lock via nfs's ->permission
+handler. That's a ranking bug and sometimes a sleep-in-spinlock bug. This
+problem was introduced in the openat() patchset.
+
+We should not need to hold the current->fs->lock for a codepath that doesn't
+use current->fs.
+
+[vsu@altlinux.ru: fix error path]
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+Cc: Al Viro <viro@ftp.linux.org.uk>
+Signed-off-by: Sergey Vlasov <vsu@altlinux.ru>
+Signed-off-by: Andrew Morton <akpm@osdl.org>
+Signed-off-by: Linus Torvalds <torvalds@osdl.org>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+---
+
+ fs/namei.c | 19 ++++++++++---------
+ 1 file changed, 10 insertions(+), 9 deletions(-)
+
+--- linux-2.6.16.20.orig/fs/namei.c
++++ linux-2.6.16.20/fs/namei.c
+@@ -1077,8 +1077,8 @@ static int fastcall do_path_lookup(int d
+ nd->flags = flags;
+ nd->depth = 0;
+
+- read_lock(¤t->fs->lock);
+ if (*name=='/') {
++ read_lock(¤t->fs->lock);
+ if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
+ nd->mnt = mntget(current->fs->altrootmnt);
+ nd->dentry = dget(current->fs->altroot);
+@@ -1089,33 +1089,35 @@ static int fastcall do_path_lookup(int d
+ }
+ nd->mnt = mntget(current->fs->rootmnt);
+ nd->dentry = dget(current->fs->root);
++ read_unlock(¤t->fs->lock);
+ } else if (dfd == AT_FDCWD) {
++ read_lock(¤t->fs->lock);
+ nd->mnt = mntget(current->fs->pwdmnt);
+ nd->dentry = dget(current->fs->pwd);
++ read_unlock(¤t->fs->lock);
+ } else {
+ struct dentry *dentry;
+
+ file = fget_light(dfd, &fput_needed);
+ retval = -EBADF;
+ if (!file)
+- goto unlock_fail;
++ goto out_fail;
+
+ dentry = file->f_dentry;
+
+ retval = -ENOTDIR;
+ if (!S_ISDIR(dentry->d_inode->i_mode))
+- goto fput_unlock_fail;
++ goto fput_fail;
+
+ retval = file_permission(file, MAY_EXEC);
+ if (retval)
+- goto fput_unlock_fail;
++ goto fput_fail;
+
+ nd->mnt = mntget(file->f_vfsmnt);
+ nd->dentry = dget(dentry);
+
+ fput_light(file, fput_needed);
+ }
+- read_unlock(¤t->fs->lock);
+ current->total_link_count = 0;
+ retval = link_path_walk(name, nd);
+ out:
+@@ -1124,13 +1126,12 @@ out:
+ nd->dentry->d_inode))
+ audit_inode(name, nd->dentry->d_inode, flags);
+ }
++out_fail:
+ return retval;
+
+-fput_unlock_fail:
++fput_fail:
+ fput_light(file, fput_needed);
+-unlock_fail:
+- read_unlock(¤t->fs->lock);
+- return retval;
++ goto out_fail;
+ }
+
+ int fastcall path_lookup(const char *name, unsigned int flags,