]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
sched/wait: Add a waitqueue helper for fully exclusive priority waiters
authorSean Christopherson <seanjc@google.com>
Thu, 22 May 2025 23:52:18 +0000 (16:52 -0700)
committerSean Christopherson <seanjc@google.com>
Mon, 23 Jun 2025 16:50:58 +0000 (09:50 -0700)
Add a waitqueue helper to add a priority waiter that requires exclusive
wakeups, i.e. that requires that it be the _only_ priority waiter.  The
API will be used by KVM to ensure that at most one of KVM's irqfds is
bound to a single eventfd (across the entire kernel).

Open code the helper instead of using __add_wait_queue() so that the
common path doesn't need to "handle" impossible failures.

Cc: K Prateek Nayak <kprateek.nayak@amd.com>
Reviewed-by: K Prateek Nayak <kprateek.nayak@amd.com>
Tested-by: K Prateek Nayak <kprateek.nayak@amd.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20250522235223.3178519-9-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
include/linux/wait.h
kernel/sched/wait.c

index 965a19809c7e563f5ef2b70cfbf21bc92e20afe3..09855d8194180e1848db857b2af95112df91128c 100644 (file)
@@ -164,6 +164,8 @@ static inline bool wq_has_sleeper(struct wait_queue_head *wq_head)
 extern void add_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
 extern void add_wait_queue_exclusive(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
 extern void add_wait_queue_priority(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
+extern int add_wait_queue_priority_exclusive(struct wait_queue_head *wq_head,
+                                            struct wait_queue_entry *wq_entry);
 extern void remove_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
 
 static inline void __add_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)
index 4ab3ab195277a413cc3eae15d50d51b66ab15fb5..15632c89c4f24d37fef3fbd4e49367f6b27860ca 100644 (file)
@@ -47,6 +47,24 @@ void add_wait_queue_priority(struct wait_queue_head *wq_head, struct wait_queue_
 }
 EXPORT_SYMBOL_GPL(add_wait_queue_priority);
 
+int add_wait_queue_priority_exclusive(struct wait_queue_head *wq_head,
+                                     struct wait_queue_entry *wq_entry)
+{
+       struct list_head *head = &wq_head->head;
+
+       wq_entry->flags |= WQ_FLAG_EXCLUSIVE | WQ_FLAG_PRIORITY;
+
+       guard(spinlock_irqsave)(&wq_head->lock);
+
+       if (!list_empty(head) &&
+           (list_first_entry(head, typeof(*wq_entry), entry)->flags & WQ_FLAG_PRIORITY))
+               return -EBUSY;
+
+       list_add(&wq_entry->entry, head);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(add_wait_queue_priority_exclusive);
+
 void remove_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)
 {
        unsigned long flags;