diff options
author | Anton Vorontsov <anton.vorontsov@linaro.org> | 2012-05-31 19:26:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-31 20:49:30 -0400 |
commit | 2214f707de257c35773d5cd68cec9e31b91e01ca (patch) | |
tree | c25a6a2b3f83704fbf03efa6d6c5f8e6ee15c856 /arch/blackfin/kernel/trace.c | |
parent | 1198c8b9af611bb697d92259095d7cc20f5c961d (diff) |
blackfin: a couple of task->mm handling fixes
The patch fixes two problems:
1. Working with task->mm w/o getting mm or grabing the task lock is
dangerous as ->mm might disappear (exit_mm() assigns NULL under
task_lock(), so tasklist lock is not enough).
We can't use get_task_mm()/mmput() pair as mmput() might sleep,
so we have to take the task lock while handle its mm.
2. Checking for process->mm is not enough because process' main
thread may exit or detach its mm via use_mm(), but other threads
may still have a valid mm.
To catch this we use find_lock_task_mm(), which walks up all
threads and returns an appropriate task (with task lock held).
Suggested-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Anton Vorontsov <anton.vorontsov@linaro.org>
Cc: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/blackfin/kernel/trace.c')
-rw-r--r-- | arch/blackfin/kernel/trace.c | 26 |
1 files changed, 13 insertions, 13 deletions
diff --git a/arch/blackfin/kernel/trace.c b/arch/blackfin/kernel/trace.c index 44bbf2f564cb..d08f0e3e2dcc 100644 --- a/arch/blackfin/kernel/trace.c +++ b/arch/blackfin/kernel/trace.c | |||
@@ -10,6 +10,8 @@ | |||
10 | #include <linux/hardirq.h> | 10 | #include <linux/hardirq.h> |
11 | #include <linux/thread_info.h> | 11 | #include <linux/thread_info.h> |
12 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
13 | #include <linux/oom.h> | ||
14 | #include <linux/sched.h> | ||
13 | #include <linux/uaccess.h> | 15 | #include <linux/uaccess.h> |
14 | #include <linux/module.h> | 16 | #include <linux/module.h> |
15 | #include <linux/kallsyms.h> | 17 | #include <linux/kallsyms.h> |
@@ -28,7 +30,6 @@ void decode_address(char *buf, unsigned long address) | |||
28 | struct task_struct *p; | 30 | struct task_struct *p; |
29 | struct mm_struct *mm; | 31 | struct mm_struct *mm; |
30 | unsigned long flags, offset; | 32 | unsigned long flags, offset; |
31 | unsigned char in_atomic = (bfin_read_IPEND() & 0x10) || in_atomic(); | ||
32 | struct rb_node *n; | 33 | struct rb_node *n; |
33 | 34 | ||
34 | #ifdef CONFIG_KALLSYMS | 35 | #ifdef CONFIG_KALLSYMS |
@@ -114,15 +115,15 @@ void decode_address(char *buf, unsigned long address) | |||
114 | */ | 115 | */ |
115 | write_lock_irqsave(&tasklist_lock, flags); | 116 | write_lock_irqsave(&tasklist_lock, flags); |
116 | for_each_process(p) { | 117 | for_each_process(p) { |
117 | mm = (in_atomic ? p->mm : get_task_mm(p)); | 118 | struct task_struct *t; |
118 | if (!mm) | ||
119 | continue; | ||
120 | 119 | ||
121 | if (!down_read_trylock(&mm->mmap_sem)) { | 120 | t = find_lock_task_mm(p); |
122 | if (!in_atomic) | 121 | if (!t) |
123 | mmput(mm); | ||
124 | continue; | 122 | continue; |
125 | } | 123 | |
124 | mm = t->mm; | ||
125 | if (!down_read_trylock(&mm->mmap_sem)) | ||
126 | goto __continue; | ||
126 | 127 | ||
127 | for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) { | 128 | for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) { |
128 | struct vm_area_struct *vma; | 129 | struct vm_area_struct *vma; |
@@ -131,7 +132,7 @@ void decode_address(char *buf, unsigned long address) | |||
131 | 132 | ||
132 | if (address >= vma->vm_start && address < vma->vm_end) { | 133 | if (address >= vma->vm_start && address < vma->vm_end) { |
133 | char _tmpbuf[256]; | 134 | char _tmpbuf[256]; |
134 | char *name = p->comm; | 135 | char *name = t->comm; |
135 | struct file *file = vma->vm_file; | 136 | struct file *file = vma->vm_file; |
136 | 137 | ||
137 | if (file) { | 138 | if (file) { |
@@ -164,8 +165,7 @@ void decode_address(char *buf, unsigned long address) | |||
164 | name, vma->vm_start, vma->vm_end); | 165 | name, vma->vm_start, vma->vm_end); |
165 | 166 | ||
166 | up_read(&mm->mmap_sem); | 167 | up_read(&mm->mmap_sem); |
167 | if (!in_atomic) | 168 | task_unlock(t); |
168 | mmput(mm); | ||
169 | 169 | ||
170 | if (buf[0] == '\0') | 170 | if (buf[0] == '\0') |
171 | sprintf(buf, "[ %s ] dynamic memory", name); | 171 | sprintf(buf, "[ %s ] dynamic memory", name); |
@@ -175,8 +175,8 @@ void decode_address(char *buf, unsigned long address) | |||
175 | } | 175 | } |
176 | 176 | ||
177 | up_read(&mm->mmap_sem); | 177 | up_read(&mm->mmap_sem); |
178 | if (!in_atomic) | 178 | __continue: |
179 | mmput(mm); | 179 | task_unlock(t); |
180 | } | 180 | } |
181 | 181 | ||
182 | /* | 182 | /* |