aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-06-04 05:51:37 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-05 15:29:16 -0400
commit6d09bb627d2470299dfb1af0e6d27fb4aece9196 (patch)
treece62b91f11c5df5fbee41aa053b33add79c2c37a
parentc7d2d28b9851d0ffc9924b0e36bac806d18ebf25 (diff)
[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>
-rw-r--r--fs/namei.c19
1 files changed, 10 insertions, 9 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 96723ae83c89..d6e2ee251736 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1080,8 +1080,8 @@ static int fastcall do_path_lookup(int dfd, const char *name,
1080 nd->flags = flags; 1080 nd->flags = flags;
1081 nd->depth = 0; 1081 nd->depth = 0;
1082 1082
1083 read_lock(&current->fs->lock);
1084 if (*name=='/') { 1083 if (*name=='/') {
1084 read_lock(&current->fs->lock);
1085 if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) { 1085 if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
1086 nd->mnt = mntget(current->fs->altrootmnt); 1086 nd->mnt = mntget(current->fs->altrootmnt);
1087 nd->dentry = dget(current->fs->altroot); 1087 nd->dentry = dget(current->fs->altroot);
@@ -1092,33 +1092,35 @@ static int fastcall do_path_lookup(int dfd, const char *name,
1092 } 1092 }
1093 nd->mnt = mntget(current->fs->rootmnt); 1093 nd->mnt = mntget(current->fs->rootmnt);
1094 nd->dentry = dget(current->fs->root); 1094 nd->dentry = dget(current->fs->root);
1095 read_unlock(&current->fs->lock);
1095 } else if (dfd == AT_FDCWD) { 1096 } else if (dfd == AT_FDCWD) {
1097 read_lock(&current->fs->lock);
1096 nd->mnt = mntget(current->fs->pwdmnt); 1098 nd->mnt = mntget(current->fs->pwdmnt);
1097 nd->dentry = dget(current->fs->pwd); 1099 nd->dentry = dget(current->fs->pwd);
1100 read_unlock(&current->fs->lock);
1098 } else { 1101 } else {
1099 struct dentry *dentry; 1102 struct dentry *dentry;
1100 1103
1101 file = fget_light(dfd, &fput_needed); 1104 file = fget_light(dfd, &fput_needed);
1102 retval = -EBADF; 1105 retval = -EBADF;
1103 if (!file) 1106 if (!file)
1104 goto unlock_fail; 1107 goto out_fail;
1105 1108
1106 dentry = file->f_dentry; 1109 dentry = file->f_dentry;
1107 1110
1108 retval = -ENOTDIR; 1111 retval = -ENOTDIR;
1109 if (!S_ISDIR(dentry->d_inode->i_mode)) 1112 if (!S_ISDIR(dentry->d_inode->i_mode))
1110 goto fput_unlock_fail; 1113 goto fput_fail;
1111 1114
1112 retval = file_permission(file, MAY_EXEC); 1115 retval = file_permission(file, MAY_EXEC);
1113 if (retval) 1116 if (retval)
1114 goto fput_unlock_fail; 1117 goto fput_fail;
1115 1118
1116 nd->mnt = mntget(file->f_vfsmnt); 1119 nd->mnt = mntget(file->f_vfsmnt);
1117 nd->dentry = dget(dentry); 1120 nd->dentry = dget(dentry);
1118 1121
1119 fput_light(file, fput_needed); 1122 fput_light(file, fput_needed);
1120 } 1123 }
1121 read_unlock(&current->fs->lock);
1122 current->total_link_count = 0; 1124 current->total_link_count = 0;
1123 retval = link_path_walk(name, nd); 1125 retval = link_path_walk(name, nd);
1124out: 1126out:
@@ -1127,13 +1129,12 @@ out:
1127 nd->dentry->d_inode)) 1129 nd->dentry->d_inode))
1128 audit_inode(name, nd->dentry->d_inode, flags); 1130 audit_inode(name, nd->dentry->d_inode, flags);
1129 } 1131 }
1132out_fail:
1130 return retval; 1133 return retval;
1131 1134
1132fput_unlock_fail: 1135fput_fail:
1133 fput_light(file, fput_needed); 1136 fput_light(file, fput_needed);
1134unlock_fail: 1137 goto out_fail;
1135 read_unlock(&current->fs->lock);
1136 return retval;
1137} 1138}
1138 1139
1139int fastcall path_lookup(const char *name, unsigned int flags, 1140int fastcall path_lookup(const char *name, unsigned int flags,