| From 146fbb766934dc003fcbf755b519acef683576bf Mon Sep 17 00:00:00 2001 |
| From: Andrey Ryabinin <aryabinin@virtuozzo.com> |
| Date: Fri, 10 Feb 2017 12:54:05 +0300 |
| Subject: x86/mm/ptdump: Fix soft lockup in page table walker |
| |
| From: Andrey Ryabinin <aryabinin@virtuozzo.com> |
| |
| commit 146fbb766934dc003fcbf755b519acef683576bf upstream. |
| |
| CONFIG_KASAN=y needs a lot of virtual memory mapped for its shadow. |
| In that case ptdump_walk_pgd_level_core() takes a lot of time to |
| walk across all page tables and doing this without |
| a rescheduling causes soft lockups: |
| |
| NMI watchdog: BUG: soft lockup - CPU#3 stuck for 23s! [swapper/0:1] |
| ... |
| Call Trace: |
| ptdump_walk_pgd_level_core+0x40c/0x550 |
| ptdump_walk_pgd_level_checkwx+0x17/0x20 |
| mark_rodata_ro+0x13b/0x150 |
| kernel_init+0x2f/0x120 |
| ret_from_fork+0x2c/0x40 |
| |
| I guess that this issue might arise even without KASAN on huge machines |
| with several terabytes of RAM. |
| |
| Stick cond_resched() in pgd loop to fix this. |
| |
| Reported-by: Tobias Regnery <tobias.regnery@gmail.com> |
| Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com> |
| Cc: kasan-dev@googlegroups.com |
| Cc: Alexander Potapenko <glider@google.com> |
| Cc: "Paul E . McKenney" <paulmck@linux.vnet.ibm.com> |
| Cc: Dmitry Vyukov <dvyukov@google.com> |
| Link: http://lkml.kernel.org/r/20170210095405.31802-1-aryabinin@virtuozzo.com |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/mm/dump_pagetables.c | 2 ++ |
| 1 file changed, 2 insertions(+) |
| |
| --- a/arch/x86/mm/dump_pagetables.c |
| +++ b/arch/x86/mm/dump_pagetables.c |
| @@ -15,6 +15,7 @@ |
| #include <linux/debugfs.h> |
| #include <linux/mm.h> |
| #include <linux/init.h> |
| +#include <linux/sched.h> |
| #include <linux/seq_file.h> |
| |
| #include <asm/pgtable.h> |
| @@ -406,6 +407,7 @@ static void ptdump_walk_pgd_level_core(s |
| } else |
| note_page(m, &st, __pgprot(0), 1); |
| |
| + cond_resched(); |
| start++; |
| } |
| |