sched/wait: Avoid abort_exclusive_wait() in __wait_on_bit_lock()
authorOleg Nesterov <oleg@redhat.com>
Tue, 6 Sep 2016 14:00:53 +0000 (16:00 +0200)
committerIngo Molnar <mingo@kernel.org>
Fri, 30 Sep 2016 08:54:03 +0000 (10:54 +0200)
__wait_on_bit_lock() doesn't need abort_exclusive_wait() too. Right
now it can't use prepare_to_wait_event() (see the next change), but
it can do the additional finish_wait() if action() fails.

abort_exclusive_wait() no longer has callers, remove it.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Bart Van Assche <bvanassche@acm.org>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Neil Brown <neilb@suse.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160906140053.GA6164@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
include/linux/wait.h
kernel/sched/wait.c

index 7261dcbe5afe7d4020bccbc5cb01eeabbca0c1f0..19c75f9545cef5f2e56ce9fa8ebd9ac9ceeaffc4 100644 (file)
@@ -984,7 +984,6 @@ void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state);
 void prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state);
 long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state);
 void finish_wait(wait_queue_head_t *q, wait_queue_t *wait);
-void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait, void *key);
 long wait_woken(wait_queue_t *wait, unsigned mode, long timeout);
 int woken_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
 int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
index 2612393922581e571f861b5b14c9ebe0d55dbe89..0cb615d6901357412e0d40fa12d42470a84da87b 100644 (file)
@@ -270,37 +270,6 @@ void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
 }
 EXPORT_SYMBOL(finish_wait);
 
-/**
- * abort_exclusive_wait - abort exclusive waiting in a queue
- * @q: waitqueue waited on
- * @wait: wait descriptor
- * @key: key to identify a wait bit queue or %NULL
- *
- * Sets current thread back to running state and removes
- * the wait descriptor from the given waitqueue if still
- * queued.
- *
- * Wakes up the next waiter if the caller is concurrently
- * woken up through the queue.
- *
- * This prevents waiter starvation where an exclusive waiter
- * aborts and is woken up concurrently and no one wakes up
- * the next waiter.
- */
-void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait, void *key)
-{
-       unsigned long flags;
-
-       __set_current_state(TASK_RUNNING);
-       spin_lock_irqsave(&q->lock, flags);
-       if (!list_empty(&wait->task_list))
-               list_del_init(&wait->task_list);
-       else if (waitqueue_active(q))
-               __wake_up_locked_key(q, TASK_NORMAL, key);
-       spin_unlock_irqrestore(&q->lock, flags);
-}
-EXPORT_SYMBOL(abort_exclusive_wait);
-
 int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
 {
        int ret = default_wake_function(wait, mode, sync, key);
@@ -438,20 +407,29 @@ int __sched
 __wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q,
                        wait_bit_action_f *action, unsigned mode)
 {
-       do {
-               int ret;
+       int ret = 0;
 
+       for (;;) {
                prepare_to_wait_exclusive(wq, &q->wait, mode);
-               if (!test_bit(q->key.bit_nr, q->key.flags))
-                       continue;
-               ret = action(&q->key, mode);
-               if (!ret)
-                       continue;
-               abort_exclusive_wait(wq, &q->wait, &q->key);
-               return ret;
-       } while (test_and_set_bit(q->key.bit_nr, q->key.flags));
-       finish_wait(wq, &q->wait);
-       return 0;
+               if (test_bit(q->key.bit_nr, q->key.flags)) {
+                       ret = action(&q->key, mode);
+                       /*
+                        * See the comment in prepare_to_wait_event().
+                        * finish_wait() does not necessarily takes wq->lock,
+                        * but test_and_set_bit() implies mb() which pairs with
+                        * smp_mb__after_atomic() before wake_up_page().
+                        */
+                       if (ret)
+                               finish_wait(wq, &q->wait);
+               }
+               if (!test_and_set_bit(q->key.bit_nr, q->key.flags)) {
+                       if (!ret)
+                               finish_wait(wq, &q->wait);
+                       return 0;
+               } else if (ret) {
+                       return ret;
+               }
+       }
 }
 EXPORT_SYMBOL(__wait_on_bit_lock);