Commit 0a7f682d authored by Michal Hocko's avatar Michal Hocko Committed by Linus Torvalds

mm: do not rely on preempt_count in print_vma_addr

The preempt count check on print_vma_addr has been added by commit
e8bff74a ("x86: fix "BUG: sleeping function called from invalid
context" in print_vma_addr()") and it relied on the elevated preempt
count from preempt_conditional_sti because preempt_count check doesn't
work on non preemptive kernels by default.

The code has evolved though and commit d99e1bd1 ("x86/entry/traps:
Refactor preemption and interrupt flag handling") has replaced
preempt_conditional_sti by an explicit preempt_disable which is noop on
!PREEMPT so the check in print_vma_addr is broken.

Fix the issue by using trylock on mmap_sem rather than chacking the
preempt count.  The allocation we are relying on has to be GFP_NOWAIT as
well.  There is a chance that we won't dump the vma state if the lock is
contended or the memory short but this is acceptable outcome and much
less fragile than the not working preemption check or tricks around it.

Link: http://lkml.kernel.org/r/20171106134031.g6dbelg55mrbyc6i@dhcp22.suse.cz
Fixes: d99e1bd1 ("x86/entry/traps: Refactor preemption and interrupt flag handling")
Signed-off-by: default avatarMichal Hocko <mhocko@suse.com>
Acked-by: default avatarVlastimil Babka <vbabka@suse.cz>
Acked-by: default avatarYang Shi <yang.s@alibaba-inc.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent fcdaf842
...@@ -4485,17 +4485,15 @@ void print_vma_addr(char *prefix, unsigned long ip) ...@@ -4485,17 +4485,15 @@ void print_vma_addr(char *prefix, unsigned long ip)
struct vm_area_struct *vma; struct vm_area_struct *vma;
/* /*
* Do not print if we are in atomic * we might be running from an atomic context so we cannot sleep
* contexts (in exception stacks, etc.):
*/ */
if (preempt_count()) if (!down_read_trylock(&mm->mmap_sem))
return; return;
down_read(&mm->mmap_sem);
vma = find_vma(mm, ip); vma = find_vma(mm, ip);
if (vma && vma->vm_file) { if (vma && vma->vm_file) {
struct file *f = vma->vm_file; struct file *f = vma->vm_file;
char *buf = (char *)__get_free_page(GFP_KERNEL); char *buf = (char *)__get_free_page(GFP_NOWAIT);
if (buf) { if (buf) {
char *p; char *p;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment