blob: 3deed2b91d5123007384317a766e58ae00f6ac0c [file] [log] [blame]
From e94445b78dc821e0e9de5a9bf5bd263f5ae2c471 Mon Sep 17 00:00:00 2001
From: Mike Galbraith <mgalbraith@suse.de>
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] [<ffffffff8236b45c>] ? schedule+0x1c/0x30
[25689.709066] [<ffffffff8236b99d>] ? schedule_timeout+0x26d/0x2b0
[25689.709069] [<ffffffff8203932e>] ? enqueue_task_rt+0x12e/0x290
[25689.709074] [<ffffffff8236a804>] ? wait_for_common+0xc4/0x1a0
[25689.709077] [<ffffffff82040700>] ? default_wake_function+0x0/0x10
[25689.709080] [<ffffffff820b3d90>] ? drain_local_pages_work+0x0/0x10
[25689.709084] [<ffffffff82059c1c>] ? flush_work+0x6c/0xc0
[25689.709086] [<ffffffff82059e40>] ? wq_barrier_func+0x0/0x10
[25689.709088] [<ffffffff82059ccf>] ? __queue_work+0x5f/0x70
[25689.709090] [<ffffffff8205a233>] ? schedule_on_each_cpu+0x113/0x160
[25689.709093] [<ffffffff820b6e5d>] ? __alloc_pages_nodemask+0x61d/0x760
[25689.709095] [<ffffffff820b59f9>] ? __get_free_pages+0x9/0x50
[25689.709098] [<ffffffff820434ea>] ? copy_process+0xea/0x13f0
[25689.709101] [<ffffffff82033da0>] ? enqueue_task+0x60/0x70
[25689.709103] [<ffffffff82033eb4>] ? activate_task+0x24/0x30
[25689.709105] [<ffffffff8204488b>] ? do_fork+0x9b/0x3d0
[25689.709107] [<ffffffff820354ae>] ? update_curr+0xae/0x140
[25689.709111] [<ffffffff8200178b>] ? __switch_to+0xeb/0x350
[25689.709114] [<ffffffff8200b5bc>] ? kernel_thread+0x7c/0x90
[25689.709117] [<ffffffff8205d9d0>] ? kthread+0x0/0xa0
[25689.709119] [<ffffffff82003e20>] ? kernel_thread_helper+0x0/0x10
[25689.709121] [<ffffffff8236b45c>] ? schedule+0x1c/0x30
[25689.709123] [<ffffffff8205d98f>] ? kthreadd+0x14f/0x190
[25689.709125] [<ffffffff82003e24>] ? kernel_thread_helper+0x4/0x10
[25689.709127] [<ffffffff8205d840>] ? kthreadd+0x0/0x190
[25689.709129] [<ffffffff82003e20>] ? 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] [<ffffffff82119190>] ? bdi_sched_wait+0x0/0x10
[25689.709160] [<ffffffff8236b45c>] ? schedule+0x1c/0x30
[25689.709162] [<ffffffff82119199>] ? bdi_sched_wait+0x9/0x10
[25689.709164] [<ffffffff8236bbd0>] ? __wait_on_bit+0x50/0x80
[25689.709166] [<ffffffff82119190>] ? bdi_sched_wait+0x0/0x10
[25689.709167] [<ffffffff8236bc79>] ? out_of_line_wait_on_bit+0x79/0xa0
[25689.709169] [<ffffffff8205de20>] ? wake_bit_function+0x0/0x20
[25689.709171] [<ffffffff82119748>] ? bdi_start_writeback+0xc8/0xd0
[25689.709174] [<ffffffff8211dbda>] ? __sync_filesystem+0x3a/0x90
[25689.709177] [<ffffffff8211ddea>] ? sync_filesystem+0x2a/0x50
[25689.709180] [<ffffffff820fa8d1>] ? generic_shutdown_super+0x21/0x110
[25689.709182] [<ffffffff820faa19>] ? kill_anon_super+0x9/0x50
[25689.709192] [<ffffffffa044cded>] ? nfs_kill_super+0x1d/0x40 [nfs]
[25689.709194] [<ffffffff820fb2b3>] ? deactivate_super+0x83/0xb0
[25689.709197] [<ffffffff82112e0b>] ? release_mounts+0xab/0xd0
[25689.709199] [<ffffffff82112ffa>] ? mark_mounts_for_expiry+0x11a/0x130
[25689.709207] [<ffffffffa0456c00>] ? nfs_expire_automounts+0x0/0x40 [nfs]
[25689.709215] [<ffffffffa0456c10>] ? nfs_expire_automounts+0x10/0x40 [nfs]
[25689.709217] [<ffffffff820597dc>] ? worker_thread+0x15c/0x230
[25689.709219] [<ffffffff8205ddf0>] ? autoremove_wake_function+0x0/0x30
[25689.709221] [<ffffffff82059680>] ? worker_thread+0x0/0x230
[25689.709223] [<ffffffff8205da66>] ? kthread+0x96/0xa0
[25689.709225] [<ffffffff8203dd1a>] ? finish_task_switch+0x4a/0x100
[25689.709227] [<ffffffff82003e24>] ? kernel_thread_helper+0x4/0x10
[25689.709229] [<ffffffff8205d9d0>] ? kthread+0x0/0xa0
[25689.709231] [<ffffffff82003e20>] ? 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] [<ffffffff8236b45c>] ? schedule+0x1c/0x30
[25689.709245] [<ffffffff8236b99d>] ? schedule_timeout+0x26d/0x2b0
[25689.709247] [<ffffffff8236a804>] ? wait_for_common+0xc4/0x1a0
[25689.709250] [<ffffffff82040700>] ? default_wake_function+0x0/0x10
[25689.709252] [<ffffffff8203dd1a>] ? finish_task_switch+0x4a/0x100
[25689.709254] [<ffffffff8205dc28>] ? kthread_create+0x98/0x130
[25689.709256] [<ffffffff820c5540>] ? bdi_start_fn+0x0/0xf0
[25689.709260] [<ffffffff82051f50>] ? process_timeout+0x0/0x10
[25689.709262] [<ffffffff820c53aa>] ? bdi_forker_task+0x19a/0x330
[25689.709263] [<ffffffff8236ada6>] ? __schedule+0x426/0x960
[25689.709265] [<ffffffff820c5210>] ? bdi_forker_task+0x0/0x330
[25689.709268] [<ffffffff8205da66>] ? kthread+0x96/0xa0
[25689.709270] [<ffffffff8203dd1a>] ? finish_task_switch+0x4a/0x100
[25689.709272] [<ffffffff82003e24>] ? kernel_thread_helper+0x4/0x10
[25689.709274] [<ffffffff8205d9d0>] ? kthread+0x0/0xa0
[25689.709276] [<ffffffff82003e20>] ? kernel_thread_helper+0x0/0x10
etc etc etc...
Signed-off-by: Mike Galbraith <mgalbraith@suse.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra <peterz@infradead.org>
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index bde9ea1..81f9359 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1121,6 +1121,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
*/
@@ -1146,7 +1155,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.1.1