aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorCatalin Marinas <catalin.marinas@arm.com>2009-07-07 05:32:58 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2009-07-08 09:25:13 -0400
commitb87324d082d9d898e3c06b2a07a2b94b2430b8ba (patch)
tree23183d749d3267e3c3636fdc78e10ceb0cd10b1a /mm
parent288c857d66a400ca4846dd700eb1c4820d738bb9 (diff)
kmemleak: Do not acquire scan_mutex in kmemleak_open()
Initially, the scan_mutex was acquired in kmemleak_open() and released in kmemleak_release() (corresponding to /sys/kernel/debug/kmemleak operations). This was causing some lockdep reports when the file was closed from a different task than the one opening it. This patch moves the scan_mutex acquiring in kmemleak_write() or kmemleak_seq_start() with releasing in kmemleak_seq_stop(). Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'mm')
-rw-r--r--mm/kmemleak.c63
1 files changed, 30 insertions, 33 deletions
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 3c2b24c49a84..7cfb7d014a20 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -1101,6 +1101,11 @@ static void *kmemleak_seq_start(struct seq_file *seq, loff_t *pos)
1101{ 1101{
1102 struct kmemleak_object *object; 1102 struct kmemleak_object *object;
1103 loff_t n = *pos; 1103 loff_t n = *pos;
1104 int err;
1105
1106 err = mutex_lock_interruptible(&scan_mutex);
1107 if (err < 0)
1108 return ERR_PTR(err);
1104 1109
1105 rcu_read_lock(); 1110 rcu_read_lock();
1106 list_for_each_entry_rcu(object, &object_list, object_list) { 1111 list_for_each_entry_rcu(object, &object_list, object_list) {
@@ -1144,8 +1149,15 @@ static void *kmemleak_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1144 */ 1149 */
1145static void kmemleak_seq_stop(struct seq_file *seq, void *v) 1150static void kmemleak_seq_stop(struct seq_file *seq, void *v)
1146{ 1151{
1147 if (v) 1152 if (!IS_ERR(v)) {
1148 put_object(v); 1153 /*
1154 * kmemleak_seq_start may return ERR_PTR if the scan_mutex
1155 * waiting was interrupted, so only release it if !IS_ERR.
1156 */
1157 mutex_unlock(&scan_mutex);
1158 if (v)
1159 put_object(v);
1160 }
1149} 1161}
1150 1162
1151/* 1163/*
@@ -1172,36 +1184,15 @@ static const struct seq_operations kmemleak_seq_ops = {
1172 1184
1173static int kmemleak_open(struct inode *inode, struct file *file) 1185static int kmemleak_open(struct inode *inode, struct file *file)
1174{ 1186{
1175 int ret = 0;
1176
1177 if (!atomic_read(&kmemleak_enabled)) 1187 if (!atomic_read(&kmemleak_enabled))
1178 return -EBUSY; 1188 return -EBUSY;
1179 1189
1180 ret = mutex_lock_interruptible(&scan_mutex); 1190 return seq_open(file, &kmemleak_seq_ops);
1181 if (ret < 0)
1182 goto out;
1183 if (file->f_mode & FMODE_READ) {
1184 ret = seq_open(file, &kmemleak_seq_ops);
1185 if (ret < 0)
1186 goto scan_unlock;
1187 }
1188 return ret;
1189
1190scan_unlock:
1191 mutex_unlock(&scan_mutex);
1192out:
1193 return ret;
1194} 1191}
1195 1192
1196static int kmemleak_release(struct inode *inode, struct file *file) 1193static int kmemleak_release(struct inode *inode, struct file *file)
1197{ 1194{
1198 int ret = 0; 1195 return seq_release(inode, file);
1199
1200 if (file->f_mode & FMODE_READ)
1201 seq_release(inode, file);
1202 mutex_unlock(&scan_mutex);
1203
1204 return ret;
1205} 1196}
1206 1197
1207/* 1198/*
@@ -1221,15 +1212,17 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
1221{ 1212{
1222 char buf[64]; 1213 char buf[64];
1223 int buf_size; 1214 int buf_size;
1224 1215 int ret;
1225 if (!atomic_read(&kmemleak_enabled))
1226 return -EBUSY;
1227 1216
1228 buf_size = min(size, (sizeof(buf) - 1)); 1217 buf_size = min(size, (sizeof(buf) - 1));
1229 if (strncpy_from_user(buf, user_buf, buf_size) < 0) 1218 if (strncpy_from_user(buf, user_buf, buf_size) < 0)
1230 return -EFAULT; 1219 return -EFAULT;
1231 buf[buf_size] = 0; 1220 buf[buf_size] = 0;
1232 1221
1222 ret = mutex_lock_interruptible(&scan_mutex);
1223 if (ret < 0)
1224 return ret;
1225
1233 if (strncmp(buf, "off", 3) == 0) 1226 if (strncmp(buf, "off", 3) == 0)
1234 kmemleak_disable(); 1227 kmemleak_disable();
1235 else if (strncmp(buf, "stack=on", 8) == 0) 1228 else if (strncmp(buf, "stack=on", 8) == 0)
@@ -1242,11 +1235,10 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
1242 stop_scan_thread(); 1235 stop_scan_thread();
1243 else if (strncmp(buf, "scan=", 5) == 0) { 1236 else if (strncmp(buf, "scan=", 5) == 0) {
1244 unsigned long secs; 1237 unsigned long secs;
1245 int err;
1246 1238
1247 err = strict_strtoul(buf + 5, 0, &secs); 1239 ret = strict_strtoul(buf + 5, 0, &secs);
1248 if (err < 0) 1240 if (ret < 0)
1249 return err; 1241 goto out;
1250 stop_scan_thread(); 1242 stop_scan_thread();
1251 if (secs) { 1243 if (secs) {
1252 jiffies_scan_wait = msecs_to_jiffies(secs * 1000); 1244 jiffies_scan_wait = msecs_to_jiffies(secs * 1000);
@@ -1255,7 +1247,12 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
1255 } else if (strncmp(buf, "scan", 4) == 0) 1247 } else if (strncmp(buf, "scan", 4) == 0)
1256 kmemleak_scan(); 1248 kmemleak_scan();
1257 else 1249 else
1258 return -EINVAL; 1250 ret = -EINVAL;
1251
1252out:
1253 mutex_unlock(&scan_mutex);
1254 if (ret < 0)
1255 return ret;
1259 1256
1260 /* ignore the rest of the buffer, only one command at a time */ 1257 /* ignore the rest of the buffer, only one command at a time */
1261 *ppos += size; 1258 *ppos += size;