From bea7da20dfda356a776ff912e4986cf348b1f979 Mon Sep 17 00:00:00 2001 From: Mike Galbraith Date: Wed, 8 Dec 2010 08:11:50 +0100 Subject: [PATCH] rt: mm: fix kthreadd livelock in drain_local_pages_work commit e94445b78dc821e0e9de5a9bf5bd263f5ae2c471 in tip. In a low memory situation, kthreadd may call schedule_on_each_cpu() while trying to spawn a worker, and the system grinds to a halt as below. [25689.675353] SysRq : Show Blocked State [25689.682919] task PC stack pid father [25689.694781] kthreadd D 00000000ffffffff 0 2 0 0x00000000 [25689.708613] ffff88013fb37810 0000000000000046 0000000000000000 000000000000b3f0 [25689.708616] ffff88013fa93040 ffff88013fa93308 000000023fa93408 0000000000000000 [25689.708619] 0000000000000000 ffff88013faadfd8 ffff88013faadb50 0000000000000004 [25689.709058] Call Trace: [25689.709064] [] ? schedule+0x1c/0x30 [25689.709066] [] ? schedule_timeout+0x26d/0x2b0 [25689.709069] [] ? enqueue_task_rt+0x12e/0x290 [25689.709074] [] ? wait_for_common+0xc4/0x1a0 [25689.709077] [] ? default_wake_function+0x0/0x10 [25689.709080] [] ? drain_local_pages_work+0x0/0x10 [25689.709084] [] ? flush_work+0x6c/0xc0 [25689.709086] [] ? wq_barrier_func+0x0/0x10 [25689.709088] [] ? __queue_work+0x5f/0x70 [25689.709090] [] ? schedule_on_each_cpu+0x113/0x160 [25689.709093] [] ? __alloc_pages_nodemask+0x61d/0x760 [25689.709095] [] ? __get_free_pages+0x9/0x50 [25689.709098] [] ? copy_process+0xea/0x13f0 [25689.709101] [] ? enqueue_task+0x60/0x70 [25689.709103] [] ? activate_task+0x24/0x30 [25689.709105] [] ? do_fork+0x9b/0x3d0 [25689.709107] [] ? update_curr+0xae/0x140 [25689.709111] [] ? __switch_to+0xeb/0x350 [25689.709114] [] ? kernel_thread+0x7c/0x90 [25689.709117] [] ? kthread+0x0/0xa0 [25689.709119] [] ? kernel_thread_helper+0x0/0x10 [25689.709121] [] ? schedule+0x1c/0x30 [25689.709123] [] ? kthreadd+0x14f/0x190 [25689.709125] [] ? kernel_thread_helper+0x4/0x10 [25689.709127] [] ? kthreadd+0x0/0x190 [25689.709129] [] ? kernel_thread_helper+0x0/0x10 [25689.709147] events/0 D ffff88000d29d1d0 0 211 2 0x00000000 [25689.709150] ffff88013f282080 0000000000000046 0000000000000400 000000000000f540 [25689.709152] ffff88013f231040 ffff88013f231308 000000000000f540 000000000000f540 [25689.709153] 0000000000000008 ffff88013f255fd8 ffff88013f255bf0 ffff88013f255c00 [25689.709155] Call Trace: [25689.709159] [] ? bdi_sched_wait+0x0/0x10 [25689.709160] [] ? schedule+0x1c/0x30 [25689.709162] [] ? bdi_sched_wait+0x9/0x10 [25689.709164] [] ? __wait_on_bit+0x50/0x80 [25689.709166] [] ? bdi_sched_wait+0x0/0x10 [25689.709167] [] ? out_of_line_wait_on_bit+0x79/0xa0 [25689.709169] [] ? wake_bit_function+0x0/0x20 [25689.709171] [] ? bdi_start_writeback+0xc8/0xd0 [25689.709174] [] ? __sync_filesystem+0x3a/0x90 [25689.709177] [] ? sync_filesystem+0x2a/0x50 [25689.709180] [] ? generic_shutdown_super+0x21/0x110 [25689.709182] [] ? kill_anon_super+0x9/0x50 [25689.709192] [] ? nfs_kill_super+0x1d/0x40 [nfs] [25689.709194] [] ? deactivate_super+0x83/0xb0 [25689.709197] [] ? release_mounts+0xab/0xd0 [25689.709199] [] ? mark_mounts_for_expiry+0x11a/0x130 [25689.709207] [] ? nfs_expire_automounts+0x0/0x40 [nfs] [25689.709215] [] ? nfs_expire_automounts+0x10/0x40 [nfs] [25689.709217] [] ? worker_thread+0x15c/0x230 [25689.709219] [] ? autoremove_wake_function+0x0/0x30 [25689.709221] [] ? worker_thread+0x0/0x230 [25689.709223] [] ? kthread+0x96/0xa0 [25689.709225] [] ? finish_task_switch+0x4a/0x100 [25689.709227] [] ? kernel_thread_helper+0x4/0x10 [25689.709229] [] ? kthread+0x0/0xa0 [25689.709231] [] ? kernel_thread_helper+0x0/0x10 [25689.709234] bdi-default D 0000000000000000 0 233 2 0x00000000 [25689.709236] ffffffff8260e020 0000000000000046 0000000000000000 000000000000b3f0 [25689.709238] ffff88013f282080 ffff88013f282348 000000000000f540 0000000000000000 [25689.709240] 0000000000000000 ffff88013f36bfd8 ffff88013f36bd38 0000000000000004 [25689.709242] Call Trace: [25689.709243] [] ? schedule+0x1c/0x30 [25689.709245] [] ? schedule_timeout+0x26d/0x2b0 [25689.709247] [] ? wait_for_common+0xc4/0x1a0 [25689.709250] [] ? default_wake_function+0x0/0x10 [25689.709252] [] ? finish_task_switch+0x4a/0x100 [25689.709254] [] ? kthread_create+0x98/0x130 [25689.709256] [] ? bdi_start_fn+0x0/0xf0 [25689.709260] [] ? process_timeout+0x0/0x10 [25689.709262] [] ? bdi_forker_task+0x19a/0x330 [25689.709263] [] ? __schedule+0x426/0x960 [25689.709265] [] ? bdi_forker_task+0x0/0x330 [25689.709268] [] ? kthread+0x96/0xa0 [25689.709270] [] ? finish_task_switch+0x4a/0x100 [25689.709272] [] ? kernel_thread_helper+0x4/0x10 [25689.709274] [] ? kthread+0x0/0xa0 [25689.709276] [] ? kernel_thread_helper+0x0/0x10 etc etc etc... Signed-off-by: Mike Galbraith Signed-off-by: Thomas Gleixner Acked-by: Peter Zijlstra Signed-off-by: Paul Gortmaker --- mm/page_alloc.c | 11 ++++++++++- 1 files changed, 10 insertions(+), 1 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index a81bf78..3bcf962 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1147,6 +1147,15 @@ static void drain_local_pages_work(struct work_struct *wrk) } #endif +#ifdef CONFIG_PREEMPT_RT +extern struct task_struct *kthreadd_task; + +static inline int is_kthreadd(struct task_struct *p) +{ + return p == kthreadd_task; +} +#endif + /* * Spill all the per-cpu pages from all CPUs back into the buddy allocator */ @@ -1172,7 +1181,7 @@ void drain_all_pages(void) * * And yes, this is one big hack. Please fix ;-) */ - if (sizeof(void *)*nr_cpu_ids < PAGE_SIZE) + if (!is_kthreadd(current) && sizeof(void *)*nr_cpu_ids < PAGE_SIZE) schedule_on_each_cpu(drain_local_pages_work); else { static int once; -- 1.7.0.4