From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758233AbcHCTmb (ORCPT ); Wed, 3 Aug 2016 15:42:31 -0400 Received: from merlin.infradead.org ([205.233.59.134]:46520 "EHLO merlin.infradead.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757135AbcHCTm2 (ORCPT ); Wed, 3 Aug 2016 15:42:28 -0400 Date: Wed, 3 Aug 2016 20:11:28 +0200 From: Peter Zijlstra To: Bart Van Assche Cc: "mingo@kernel.org" , Andrew Morton , Johannes Weiner , Neil Brown , Michael Shaver , "linux-kernel@vger.kernel.org" , Oleg Nesterov Subject: Re: [PATCH] sched: Avoid that __wait_on_bit_lock() hangs Message-ID: <20160803181128.GH6879@twins.programming.kicks-ass.net> References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.23.1 (2014-03-12) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Wed, Aug 03, 2016 at 09:35:03AM -0700, Bart Van Assche wrote: > 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(). I'm dense.. what!? CPU0 CPU1 CPU2 __lock_page_killable() __wait_on_bit_lock() bit_wait_io() schedule() __wake_up_bit() __wake_up(.nr_exclusive=1) spin_lock(&q->lock) __wake_up_common() autoremove_wake_func() try_to_wake_up(p, TASK_NORMAL) list_del_init(&wait->task_list) spin_unlock(&q->lock) complete_signal(p) signal_wake_up(p, 1) sigaddset(&p->pending.signal, SIGKILL) try_to_wake_up(p, TASK_WAKEKILL) if (signal_pending_state(TASK_KILLABLE)) return -EINTR; abort_exclusive_wait() __set_current_state(RUNNING) spin_lock(q->lock) if (!list_empty()) /* empty */ else if (waitqueue_active()) /* pending ? */ __wake_up_locked_key(q, mode, key) spin_unlock(q->lock) That seems to do the right thing, so clearly I misunderstand. Please clarify. > +++ 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); That just feels wrong,.. very wrong.