Messages in this thread Patch in this message | | | From | Bart Van Assche <> | Subject | [PATCH] sched: Avoid that __wait_on_bit_lock() hangs | Date | Wed, 3 Aug 2016 09:35:03 -0700 |
| |
If try_to_wakeup() reads the task state before abort_exclusive_wait() sets the task state and if autoremove_wake_function() is called after abort_exclusive_wait() has removed a task from a wait list then the cascading mechanism for exclusive wakeups in abort_exclusive_wait() won't be triggered. Avoid this by serializing the task state change in abort_exclusive_wait() and try_to_wakeup(). This patch fixes the following hang:
INFO: task systemd-udevd:10111 blocked for more than 480 seconds. Not tainted 4.7.0-dbg+ #1 Call Trace: [<ffffffff8161f397>] schedule+0x37/0x90 [<ffffffff816239ef>] schedule_timeout+0x27f/0x470 [<ffffffff8161e76f>] io_schedule_timeout+0x9f/0x110 [<ffffffff8161fb36>] bit_wait_io+0x16/0x60 [<ffffffff8161f929>] __wait_on_bit_lock+0x49/0xa0 [<ffffffff8114fe69>] __lock_page+0xb9/0xc0 [<ffffffff81165d90>] truncate_inode_pages_range+0x3e0/0x760 [<ffffffff81166120>] truncate_inode_pages+0x10/0x20 [<ffffffff81212a20>] kill_bdev+0x30/0x40 [<ffffffff81213d41>] __blkdev_put+0x71/0x360 [<ffffffff81214079>] blkdev_put+0x49/0x170 [<ffffffff812141c0>] blkdev_close+0x20/0x30 [<ffffffff811d48e8>] __fput+0xe8/0x1f0 [<ffffffff811d4a29>] ____fput+0x9/0x10 [<ffffffff810842d3>] task_work_run+0x83/0xb0 [<ffffffff8106606e>] do_exit+0x3ee/0xc40 [<ffffffff8106694b>] do_group_exit+0x4b/0xc0 [<ffffffff81073d9a>] get_signal+0x2ca/0x940 [<ffffffff8101bf43>] do_signal+0x23/0x660 [<ffffffff810022b3>] exit_to_usermode_loop+0x73/0xb0 [<ffffffff81002cb0>] syscall_return_slowpath+0xb0/0xc0 [<ffffffff81624e33>] entry_SYSCALL_64_fastpath+0xa6/0xa8
Fixes: 777c6c5f1f6e ("wait: prevent exclusive waiter starvation") Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Neil Brown <neilb@suse.de> Cc: Michael Shaver <jmshaver@gmail.com> Cc: <stable@vger.kernel.org> # v2.6.33+ --- kernel/sched/wait.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c index f15d6b6..93d1f50 100644 --- a/kernel/sched/wait.c +++ b/kernel/sched/wait.c @@ -277,10 +277,17 @@ void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait, unsigned int mode, void *key) { unsigned long flags; + long wake_up; + + /* Serialize against try_to_wake_up() */ + raw_spin_lock_irqsave(¤t->pi_lock, flags); + wake_up = current->state & (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE); + if (wake_up) + __set_current_state(TASK_RUNNING); + raw_spin_unlock_irqrestore(¤t->pi_lock, flags); - __set_current_state(TASK_RUNNING); spin_lock_irqsave(&q->lock, flags); - if (!list_empty(&wait->task_list)) + if (wake_up) list_del_init(&wait->task_list); else if (waitqueue_active(q)) __wake_up_locked_key(q, mode, key); -- 2.9.2
| |