On Mon, May 19, 2025 at 11:55:08AM -0700, Sean Christopherson wrote: > 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. > > Note, the priority_exclusive() name is obviously confusing as the plain > priority() API also sets WQ_FLAG_EXCLUSIVE. This will be remedied once > KVM switches to add_wait_queue_priority_exclusive(), as the only other > user of add_wait_queue_priority(), Xen's privcmd, doesn't actually operate > in exclusive mode (more than likely, the detail was overlooked when privcmd > copy-pasted (sorry, "was inspired by") KVM's implementation). > > Cc: K Prateek Nayak <kprateek.nayak@xxxxxxx> > Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx> > --- > include/linux/wait.h | 2 ++ > kernel/sched/wait.c | 18 ++++++++++++++++++ > 2 files changed, 20 insertions(+) > > diff --git a/include/linux/wait.h b/include/linux/wait.h > index 965a19809c7e..09855d819418 100644 > --- a/include/linux/wait.h > +++ b/include/linux/wait.h > @@ -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) > diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c > index 51e38f5f4701..03252badb8e8 100644 > --- a/kernel/sched/wait.c > +++ b/kernel/sched/wait.c > @@ -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(add_wait_queue_priority_exclusive); add_wait_queue_priority() is a GPL export, leading me to believe the whole priority thing is _GPL only, should we maintain that?