diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2009-06-26 12:38:27 -0400 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2009-06-26 12:38:27 -0400 |
commit | 4698c1f2bbe44ce852ef1a6716973c1f5401a4c4 (patch) | |
tree | 9ca3be2353d3757e2926689351eff2bb09aaf6f7 /mm/kmemleak.c | |
parent | bab4a34afc301fdb81b6ea0e3098d96fc356e03a (diff) |
kmemleak: Do not trigger a scan when reading the debug/kmemleak file
Since there is a kernel thread for automatically scanning the memory, it
makes sense for the debug/kmemleak file to only show its findings. This
patch also adds support for "echo scan > debug/kmemleak" to trigger an
intermediate memory scan and eliminates the kmemleak_mutex (scan_mutex
covers all the cases now).
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'mm/kmemleak.c')
-rw-r--r-- | mm/kmemleak.c | 90 |
1 files changed, 40 insertions, 50 deletions
diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 4130a4889fa..e96e0ec6a56 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c | |||
@@ -48,10 +48,10 @@ | |||
48 | * scanned. This list is only modified during a scanning episode when the | 48 | * scanned. This list is only modified during a scanning episode when the |
49 | * scan_mutex is held. At the end of a scan, the gray_list is always empty. | 49 | * scan_mutex is held. At the end of a scan, the gray_list is always empty. |
50 | * Note that the kmemleak_object.use_count is incremented when an object is | 50 | * Note that the kmemleak_object.use_count is incremented when an object is |
51 | * added to the gray_list and therefore cannot be freed | 51 | * added to the gray_list and therefore cannot be freed. This mutex also |
52 | * - kmemleak_mutex (mutex): prevents multiple users of the "kmemleak" debugfs | 52 | * prevents multiple users of the "kmemleak" debugfs file together with |
53 | * file together with modifications to the memory scanning parameters | 53 | * modifications to the memory scanning parameters including the scan_thread |
54 | * including the scan_thread pointer | 54 | * pointer |
55 | * | 55 | * |
56 | * The kmemleak_object structures have a use_count incremented or decremented | 56 | * The kmemleak_object structures have a use_count incremented or decremented |
57 | * using the get_object()/put_object() functions. When the use_count becomes | 57 | * using the get_object()/put_object() functions. When the use_count becomes |
@@ -195,10 +195,8 @@ static unsigned long jiffies_min_age; | |||
195 | static signed long jiffies_scan_wait; | 195 | static signed long jiffies_scan_wait; |
196 | /* enables or disables the task stacks scanning */ | 196 | /* enables or disables the task stacks scanning */ |
197 | static int kmemleak_stack_scan = 1; | 197 | static int kmemleak_stack_scan = 1; |
198 | /* mutex protecting the memory scanning */ | 198 | /* protects the memory scanning, parameters and debug/kmemleak file access */ |
199 | static DEFINE_MUTEX(scan_mutex); | 199 | static DEFINE_MUTEX(scan_mutex); |
200 | /* mutex protecting the access to the /sys/kernel/debug/kmemleak file */ | ||
201 | static DEFINE_MUTEX(kmemleak_mutex); | ||
202 | 200 | ||
203 | /* number of leaks reported (for limitation purposes) */ | 201 | /* number of leaks reported (for limitation purposes) */ |
204 | static int reported_leaks; | 202 | static int reported_leaks; |
@@ -927,6 +925,7 @@ static void kmemleak_scan(void) | |||
927 | struct kmemleak_object *object, *tmp; | 925 | struct kmemleak_object *object, *tmp; |
928 | struct task_struct *task; | 926 | struct task_struct *task; |
929 | int i; | 927 | int i; |
928 | int new_leaks = 0; | ||
930 | 929 | ||
931 | /* prepare the kmemleak_object's */ | 930 | /* prepare the kmemleak_object's */ |
932 | rcu_read_lock(); | 931 | rcu_read_lock(); |
@@ -1024,6 +1023,26 @@ static void kmemleak_scan(void) | |||
1024 | object = tmp; | 1023 | object = tmp; |
1025 | } | 1024 | } |
1026 | WARN_ON(!list_empty(&gray_list)); | 1025 | WARN_ON(!list_empty(&gray_list)); |
1026 | |||
1027 | /* | ||
1028 | * Scanning result reporting. | ||
1029 | */ | ||
1030 | rcu_read_lock(); | ||
1031 | list_for_each_entry_rcu(object, &object_list, object_list) { | ||
1032 | spin_lock_irqsave(&object->lock, flags); | ||
1033 | if (unreferenced_object(object) && | ||
1034 | !(object->flags & OBJECT_REPORTED)) { | ||
1035 | object->flags |= OBJECT_REPORTED; | ||
1036 | new_leaks++; | ||
1037 | } | ||
1038 | spin_unlock_irqrestore(&object->lock, flags); | ||
1039 | } | ||
1040 | rcu_read_unlock(); | ||
1041 | |||
1042 | if (new_leaks) | ||
1043 | pr_info("%d new suspected memory leaks (see " | ||
1044 | "/sys/kernel/debug/kmemleak)\n", new_leaks); | ||
1045 | |||
1027 | } | 1046 | } |
1028 | 1047 | ||
1029 | /* | 1048 | /* |
@@ -1045,33 +1064,12 @@ static int kmemleak_scan_thread(void *arg) | |||
1045 | } | 1064 | } |
1046 | 1065 | ||
1047 | while (!kthread_should_stop()) { | 1066 | while (!kthread_should_stop()) { |
1048 | struct kmemleak_object *object; | ||
1049 | signed long timeout = jiffies_scan_wait; | 1067 | signed long timeout = jiffies_scan_wait; |
1050 | int new_leaks = 0; | ||
1051 | 1068 | ||
1052 | mutex_lock(&scan_mutex); | 1069 | mutex_lock(&scan_mutex); |
1053 | |||
1054 | kmemleak_scan(); | 1070 | kmemleak_scan(); |
1055 | |||
1056 | rcu_read_lock(); | ||
1057 | list_for_each_entry_rcu(object, &object_list, object_list) { | ||
1058 | unsigned long flags; | ||
1059 | |||
1060 | spin_lock_irqsave(&object->lock, flags); | ||
1061 | if (unreferenced_object(object) && | ||
1062 | !(object->flags & OBJECT_REPORTED)) { | ||
1063 | object->flags |= OBJECT_REPORTED; | ||
1064 | new_leaks++; | ||
1065 | } | ||
1066 | spin_unlock_irqrestore(&object->lock, flags); | ||
1067 | } | ||
1068 | rcu_read_unlock(); | ||
1069 | |||
1070 | if (new_leaks) | ||
1071 | pr_info("%d new suspected memory leaks (see " | ||
1072 | "/sys/kernel/debug/kmemleak)\n", new_leaks); | ||
1073 | |||
1074 | mutex_unlock(&scan_mutex); | 1071 | mutex_unlock(&scan_mutex); |
1072 | |||
1075 | /* wait before the next scan */ | 1073 | /* wait before the next scan */ |
1076 | while (timeout && !kthread_should_stop()) | 1074 | while (timeout && !kthread_should_stop()) |
1077 | timeout = schedule_timeout_interruptible(timeout); | 1075 | timeout = schedule_timeout_interruptible(timeout); |
@@ -1084,7 +1082,7 @@ static int kmemleak_scan_thread(void *arg) | |||
1084 | 1082 | ||
1085 | /* | 1083 | /* |
1086 | * Start the automatic memory scanning thread. This function must be called | 1084 | * Start the automatic memory scanning thread. This function must be called |
1087 | * with the kmemleak_mutex held. | 1085 | * with the scan_mutex held. |
1088 | */ | 1086 | */ |
1089 | void start_scan_thread(void) | 1087 | void start_scan_thread(void) |
1090 | { | 1088 | { |
@@ -1099,7 +1097,7 @@ void start_scan_thread(void) | |||
1099 | 1097 | ||
1100 | /* | 1098 | /* |
1101 | * Stop the automatic memory scanning thread. This function must be called | 1099 | * Stop the automatic memory scanning thread. This function must be called |
1102 | * with the kmemleak_mutex held. | 1100 | * with the scan_mutex held. |
1103 | */ | 1101 | */ |
1104 | void stop_scan_thread(void) | 1102 | void stop_scan_thread(void) |
1105 | { | 1103 | { |
@@ -1119,10 +1117,8 @@ static void *kmemleak_seq_start(struct seq_file *seq, loff_t *pos) | |||
1119 | struct kmemleak_object *object; | 1117 | struct kmemleak_object *object; |
1120 | loff_t n = *pos; | 1118 | loff_t n = *pos; |
1121 | 1119 | ||
1122 | if (!n) { | 1120 | if (!n) |
1123 | kmemleak_scan(); | ||
1124 | reported_leaks = 0; | 1121 | reported_leaks = 0; |
1125 | } | ||
1126 | if (reported_leaks >= REPORTS_NR) | 1122 | if (reported_leaks >= REPORTS_NR) |
1127 | return NULL; | 1123 | return NULL; |
1128 | 1124 | ||
@@ -1206,13 +1202,10 @@ static int kmemleak_open(struct inode *inode, struct file *file) | |||
1206 | if (!atomic_read(&kmemleak_enabled)) | 1202 | if (!atomic_read(&kmemleak_enabled)) |
1207 | return -EBUSY; | 1203 | return -EBUSY; |
1208 | 1204 | ||
1209 | ret = mutex_lock_interruptible(&kmemleak_mutex); | 1205 | ret = mutex_lock_interruptible(&scan_mutex); |
1210 | if (ret < 0) | 1206 | if (ret < 0) |
1211 | goto out; | 1207 | goto out; |
1212 | if (file->f_mode & FMODE_READ) { | 1208 | if (file->f_mode & FMODE_READ) { |
1213 | ret = mutex_lock_interruptible(&scan_mutex); | ||
1214 | if (ret < 0) | ||
1215 | goto kmemleak_unlock; | ||
1216 | ret = seq_open(file, &kmemleak_seq_ops); | 1209 | ret = seq_open(file, &kmemleak_seq_ops); |
1217 | if (ret < 0) | 1210 | if (ret < 0) |
1218 | goto scan_unlock; | 1211 | goto scan_unlock; |
@@ -1221,8 +1214,6 @@ static int kmemleak_open(struct inode *inode, struct file *file) | |||
1221 | 1214 | ||
1222 | scan_unlock: | 1215 | scan_unlock: |
1223 | mutex_unlock(&scan_mutex); | 1216 | mutex_unlock(&scan_mutex); |
1224 | kmemleak_unlock: | ||
1225 | mutex_unlock(&kmemleak_mutex); | ||
1226 | out: | 1217 | out: |
1227 | return ret; | 1218 | return ret; |
1228 | } | 1219 | } |
@@ -1231,11 +1222,9 @@ static int kmemleak_release(struct inode *inode, struct file *file) | |||
1231 | { | 1222 | { |
1232 | int ret = 0; | 1223 | int ret = 0; |
1233 | 1224 | ||
1234 | if (file->f_mode & FMODE_READ) { | 1225 | if (file->f_mode & FMODE_READ) |
1235 | seq_release(inode, file); | 1226 | seq_release(inode, file); |
1236 | mutex_unlock(&scan_mutex); | 1227 | mutex_unlock(&scan_mutex); |
1237 | } | ||
1238 | mutex_unlock(&kmemleak_mutex); | ||
1239 | 1228 | ||
1240 | return ret; | 1229 | return ret; |
1241 | } | 1230 | } |
@@ -1250,6 +1239,7 @@ static int kmemleak_release(struct inode *inode, struct file *file) | |||
1250 | * scan=off - stop the automatic memory scanning thread | 1239 | * scan=off - stop the automatic memory scanning thread |
1251 | * scan=... - set the automatic memory scanning period in seconds (0 to | 1240 | * scan=... - set the automatic memory scanning period in seconds (0 to |
1252 | * disable it) | 1241 | * disable it) |
1242 | * scan - trigger a memory scan | ||
1253 | */ | 1243 | */ |
1254 | static ssize_t kmemleak_write(struct file *file, const char __user *user_buf, | 1244 | static ssize_t kmemleak_write(struct file *file, const char __user *user_buf, |
1255 | size_t size, loff_t *ppos) | 1245 | size_t size, loff_t *ppos) |
@@ -1287,7 +1277,9 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf, | |||
1287 | jiffies_scan_wait = msecs_to_jiffies(secs * 1000); | 1277 | jiffies_scan_wait = msecs_to_jiffies(secs * 1000); |
1288 | start_scan_thread(); | 1278 | start_scan_thread(); |
1289 | } | 1279 | } |
1290 | } else | 1280 | } else if (strncmp(buf, "scan", 4) == 0) |
1281 | kmemleak_scan(); | ||
1282 | else | ||
1291 | return -EINVAL; | 1283 | return -EINVAL; |
1292 | 1284 | ||
1293 | /* ignore the rest of the buffer, only one command at a time */ | 1285 | /* ignore the rest of the buffer, only one command at a time */ |
@@ -1312,11 +1304,9 @@ static int kmemleak_cleanup_thread(void *arg) | |||
1312 | { | 1304 | { |
1313 | struct kmemleak_object *object; | 1305 | struct kmemleak_object *object; |
1314 | 1306 | ||
1315 | mutex_lock(&kmemleak_mutex); | 1307 | mutex_lock(&scan_mutex); |
1316 | stop_scan_thread(); | 1308 | stop_scan_thread(); |
1317 | mutex_unlock(&kmemleak_mutex); | ||
1318 | 1309 | ||
1319 | mutex_lock(&scan_mutex); | ||
1320 | rcu_read_lock(); | 1310 | rcu_read_lock(); |
1321 | list_for_each_entry_rcu(object, &object_list, object_list) | 1311 | list_for_each_entry_rcu(object, &object_list, object_list) |
1322 | delete_object(object->pointer); | 1312 | delete_object(object->pointer); |
@@ -1458,9 +1448,9 @@ static int __init kmemleak_late_init(void) | |||
1458 | &kmemleak_fops); | 1448 | &kmemleak_fops); |
1459 | if (!dentry) | 1449 | if (!dentry) |
1460 | pr_warning("Failed to create the debugfs kmemleak file\n"); | 1450 | pr_warning("Failed to create the debugfs kmemleak file\n"); |
1461 | mutex_lock(&kmemleak_mutex); | 1451 | mutex_lock(&scan_mutex); |
1462 | start_scan_thread(); | 1452 | start_scan_thread(); |
1463 | mutex_unlock(&kmemleak_mutex); | 1453 | mutex_unlock(&scan_mutex); |
1464 | 1454 | ||
1465 | pr_info("Kernel memory leak detector initialized\n"); | 1455 | pr_info("Kernel memory leak detector initialized\n"); |
1466 | 1456 | ||