diff options
author | Daniel Borkmann <daniel@iogearbox.net> | 2015-09-09 19:20:46 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-09-10 00:42:51 -0400 |
commit | a66e36568e30ed3714c0e3a12bd3b64696343ff5 (patch) | |
tree | 31f62f5e6258b1eaf5b7e7deede0dc8466031d17 | |
parent | f2be053c83ee93888fc09d90df2bded0deb28947 (diff) |
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 0ef707700f1c ("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: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/netlink/af_netlink.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 50889be1517d..173817a5dfad 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -674,12 +674,19 @@ static unsigned int netlink_poll(struct file *file, struct socket *sock, | |||
674 | 674 | ||
675 | mask = datagram_poll(file, sock, wait); | 675 | mask = datagram_poll(file, sock, wait); |
676 | 676 | ||
677 | spin_lock_bh(&sk->sk_receive_queue.lock); | 677 | /* We could already have received frames in the normal receive |
678 | if (nlk->rx_ring.pg_vec) { | 678 | * queue, that will show up as NL_MMAP_STATUS_COPY in the ring, |
679 | if (netlink_has_valid_frame(&nlk->rx_ring)) | 679 | * so if mask contains pollin/etc already, there's no point |
680 | mask |= POLLIN | POLLRDNORM; | 680 | * walking the ring. |
681 | */ | ||
682 | if ((mask & (POLLIN | POLLRDNORM)) != (POLLIN | POLLRDNORM)) { | ||
683 | spin_lock_bh(&sk->sk_receive_queue.lock); | ||
684 | if (nlk->rx_ring.pg_vec) { | ||
685 | if (netlink_has_valid_frame(&nlk->rx_ring)) | ||
686 | mask |= POLLIN | POLLRDNORM; | ||
687 | } | ||
688 | spin_unlock_bh(&sk->sk_receive_queue.lock); | ||
681 | } | 689 | } |
682 | spin_unlock_bh(&sk->sk_receive_queue.lock); | ||
683 | 690 | ||
684 | spin_lock_bh(&sk->sk_write_queue.lock); | 691 | spin_lock_bh(&sk->sk_write_queue.lock); |
685 | if (nlk->tx_ring.pg_vec) { | 692 | if (nlk->tx_ring.pg_vec) { |