Skip to content

Commit 67cd2e2

Browse files
committed
Merge patch series "poll_wait: add mb() to fix theoretical race between waitqueue_active() and .poll()"
Oleg Nesterov <[email protected]> says: The waitqueue_active() helper can only be used if both waker and waiter have memory barriers that pair with each other. But __pollwait() is broken in this respect. Fix it. * patches from https://lore.kernel.org/r/[email protected]: poll: kill poll_does_not_wait() sock_poll_wait: kill the no longer necessary barrier after poll_wait() io_uring_poll: kill the no longer necessary barrier after poll_wait() poll_wait: kill the obsolete wait_address check poll_wait: add mb() to fix theoretical race between waitqueue_active() and .poll() Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Christian Brauner <[email protected]>
2 parents 40384c8 + f005bf1 commit 67cd2e2

File tree

3 files changed

+23
-29
lines changed

3 files changed

+23
-29
lines changed

include/linux/poll.h

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@
2525

2626
struct poll_table_struct;
2727

28-
/*
28+
/*
2929
* structures and helpers for f_op->poll implementations
3030
*/
3131
typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *);
3232

3333
/*
34-
* Do not touch the structure directly, use the access functions
35-
* poll_does_not_wait() and poll_requested_events() instead.
34+
* Do not touch the structure directly, use the access function
35+
* poll_requested_events() instead.
3636
*/
3737
typedef struct poll_table_struct {
3838
poll_queue_proc _qproc;
@@ -41,18 +41,16 @@ typedef struct poll_table_struct {
4141

4242
static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
4343
{
44-
if (p && p->_qproc && wait_address)
44+
if (p && p->_qproc) {
4545
p->_qproc(filp, wait_address, p);
46-
}
47-
48-
/*
49-
* Return true if it is guaranteed that poll will not wait. This is the case
50-
* if the poll() of another file descriptor in the set got an event, so there
51-
* is no need for waiting.
52-
*/
53-
static inline bool poll_does_not_wait(const poll_table *p)
54-
{
55-
return p == NULL || p->_qproc == NULL;
46+
/*
47+
* This memory barrier is paired in the wq_has_sleeper().
48+
* See the comment above prepare_to_wait(), we need to
49+
* ensure that subsequent tests in this thread can't be
50+
* reordered with __add_wait_queue() in _qproc() paths.
51+
*/
52+
smp_mb();
53+
}
5654
}
5755

5856
/*

include/net/sock.h

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2291,7 +2291,7 @@ static inline bool skwq_has_sleeper(struct socket_wq *wq)
22912291
}
22922292

22932293
/**
2294-
* sock_poll_wait - place memory barrier behind the poll_wait call.
2294+
* sock_poll_wait - wrapper for the poll_wait call.
22952295
* @filp: file
22962296
* @sock: socket to wait on
22972297
* @p: poll_table
@@ -2301,15 +2301,12 @@ static inline bool skwq_has_sleeper(struct socket_wq *wq)
23012301
static inline void sock_poll_wait(struct file *filp, struct socket *sock,
23022302
poll_table *p)
23032303
{
2304-
if (!poll_does_not_wait(p)) {
2305-
poll_wait(filp, &sock->wq.wait, p);
2306-
/* We need to be sure we are in sync with the
2307-
* socket flags modification.
2308-
*
2309-
* This memory barrier is paired in the wq_has_sleeper.
2310-
*/
2311-
smp_mb();
2312-
}
2304+
/* Provides a barrier we need to be sure we are in sync
2305+
* with the socket flags modification.
2306+
*
2307+
* This memory barrier is paired in the wq_has_sleeper.
2308+
*/
2309+
poll_wait(filp, &sock->wq.wait, p);
23132310
}
23142311

23152312
static inline void skb_set_hash_from_sk(struct sk_buff *skb, struct sock *sk)

io_uring/io_uring.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2809,13 +2809,12 @@ static __poll_t io_uring_poll(struct file *file, poll_table *wait)
28092809

28102810
if (unlikely(!ctx->poll_activated))
28112811
io_activate_pollwq(ctx);
2812-
2813-
poll_wait(file, &ctx->poll_wq, wait);
28142812
/*
2815-
* synchronizes with barrier from wq_has_sleeper call in
2816-
* io_commit_cqring
2813+
* provides mb() which pairs with barrier from wq_has_sleeper
2814+
* call in io_commit_cqring
28172815
*/
2818-
smp_rmb();
2816+
poll_wait(file, &ctx->poll_wq, wait);
2817+
28192818
if (!io_sqring_full(ctx))
28202819
mask |= EPOLLOUT | EPOLLWRNORM;
28212820

0 commit comments

Comments
 (0)