[PATCH] 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>

authored by Trond Myklebust and committed by Linus Torvalds 6d09bb62 c7d2d28b

+10 -9
+10 -9
fs/namei.c
··· 1080 nd->flags = flags; 1081 nd->depth = 0; 1082 1083 - read_lock(&current->fs->lock); 1084 if (*name=='/') { 1085 if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) { 1086 nd->mnt = mntget(current->fs->altrootmnt); 1087 nd->dentry = dget(current->fs->altroot); ··· 1092 } 1093 nd->mnt = mntget(current->fs->rootmnt); 1094 nd->dentry = dget(current->fs->root); 1095 } else if (dfd == AT_FDCWD) { 1096 nd->mnt = mntget(current->fs->pwdmnt); 1097 nd->dentry = dget(current->fs->pwd); 1098 } else { 1099 struct dentry *dentry; 1100 1101 file = fget_light(dfd, &fput_needed); 1102 retval = -EBADF; 1103 if (!file) 1104 - goto unlock_fail; 1105 1106 dentry = file->f_dentry; 1107 1108 retval = -ENOTDIR; 1109 if (!S_ISDIR(dentry->d_inode->i_mode)) 1110 - goto fput_unlock_fail; 1111 1112 retval = file_permission(file, MAY_EXEC); 1113 if (retval) 1114 - goto fput_unlock_fail; 1115 1116 nd->mnt = mntget(file->f_vfsmnt); 1117 nd->dentry = dget(dentry); 1118 1119 fput_light(file, fput_needed); 1120 } 1121 - read_unlock(&current->fs->lock); 1122 current->total_link_count = 0; 1123 retval = link_path_walk(name, nd); 1124 out: ··· 1129 nd->dentry->d_inode)) 1130 audit_inode(name, nd->dentry->d_inode, flags); 1131 } 1132 return retval; 1133 1134 - fput_unlock_fail: 1135 fput_light(file, fput_needed); 1136 - unlock_fail: 1137 - read_unlock(&current->fs->lock); 1138 - return retval; 1139 } 1140 1141 int fastcall path_lookup(const char *name, unsigned int flags,
··· 1080 nd->flags = flags; 1081 nd->depth = 0; 1082 1083 if (*name=='/') { 1084 + read_lock(&current->fs->lock); 1085 if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) { 1086 nd->mnt = mntget(current->fs->altrootmnt); 1087 nd->dentry = dget(current->fs->altroot); ··· 1092 } 1093 nd->mnt = mntget(current->fs->rootmnt); 1094 nd->dentry = dget(current->fs->root); 1095 + read_unlock(&current->fs->lock); 1096 } else if (dfd == AT_FDCWD) { 1097 + read_lock(&current->fs->lock); 1098 nd->mnt = mntget(current->fs->pwdmnt); 1099 nd->dentry = dget(current->fs->pwd); 1100 + read_unlock(&current->fs->lock); 1101 } else { 1102 struct dentry *dentry; 1103 1104 file = fget_light(dfd, &fput_needed); 1105 retval = -EBADF; 1106 if (!file) 1107 + goto out_fail; 1108 1109 dentry = file->f_dentry; 1110 1111 retval = -ENOTDIR; 1112 if (!S_ISDIR(dentry->d_inode->i_mode)) 1113 + goto fput_fail; 1114 1115 retval = file_permission(file, MAY_EXEC); 1116 if (retval) 1117 + goto fput_fail; 1118 1119 nd->mnt = mntget(file->f_vfsmnt); 1120 nd->dentry = dget(dentry); 1121 1122 fput_light(file, fput_needed); 1123 } 1124 current->total_link_count = 0; 1125 retval = link_path_walk(name, nd); 1126 out: ··· 1127 nd->dentry->d_inode)) 1128 audit_inode(name, nd->dentry->d_inode, flags); 1129 } 1130 + out_fail: 1131 return retval; 1132 1133 + fput_fail: 1134 fput_light(file, fput_needed); 1135 + goto out_fail; 1136 } 1137 1138 int fastcall path_lookup(const char *name, unsigned int flags,