Commit a66e3656 authored by Daniel Borkmann's avatar Daniel Borkmann Committed by David S. Miller

netlink, mmap: don't walk rx ring on poll if receive queue non-empty

In case of netlink mmap, there can be situations where received frames
have to be placed into the normal receive queue. The ring buffer indicates
this through NL_MMAP_STATUS_COPY, so the user is asked to pick them up
via recvmsg(2) syscall, and to put the slot back to NL_MMAP_STATUS_UNUSED.

Commit 0ef70770 ("netlink: rx mmap: fix POLLIN condition") changed
polling, so that we walk in the worst case the whole ring through the
new netlink_has_valid_frame(), for example, when the ring would have no
NL_MMAP_STATUS_VALID, but at least one NL_MMAP_STATUS_COPY frame.

Since we do a datagram_poll() already earlier to pick up a mask that could
possibly contain POLLIN | POLLRDNORM already (due to NL_MMAP_STATUS_COPY),
we can skip checking the rx ring entirely.

In case the kernel is compiled with !CONFIG_NETLINK_MMAP, then all this is
irrelevant anyway as netlink_poll() is just defined as datagram_poll().
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f2be053c
...@@ -674,12 +674,19 @@ static unsigned int netlink_poll(struct file *file, struct socket *sock, ...@@ -674,12 +674,19 @@ static unsigned int netlink_poll(struct file *file, struct socket *sock,
mask = datagram_poll(file, sock, wait); mask = datagram_poll(file, sock, wait);
spin_lock_bh(&sk->sk_receive_queue.lock); /* We could already have received frames in the normal receive
if (nlk->rx_ring.pg_vec) { * queue, that will show up as NL_MMAP_STATUS_COPY in the ring,
if (netlink_has_valid_frame(&nlk->rx_ring)) * so if mask contains pollin/etc already, there's no point
mask |= POLLIN | POLLRDNORM; * walking the ring.
*/
if ((mask & (POLLIN | POLLRDNORM)) != (POLLIN | POLLRDNORM)) {
spin_lock_bh(&sk->sk_receive_queue.lock);
if (nlk->rx_ring.pg_vec) {
if (netlink_has_valid_frame(&nlk->rx_ring))
mask |= POLLIN | POLLRDNORM;
}
spin_unlock_bh(&sk->sk_receive_queue.lock);
} }
spin_unlock_bh(&sk->sk_receive_queue.lock);
spin_lock_bh(&sk->sk_write_queue.lock); spin_lock_bh(&sk->sk_write_queue.lock);
if (nlk->tx_ring.pg_vec) { if (nlk->tx_ring.pg_vec) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment