aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2015-09-09 19:20:46 -0400
committerDavid S. Miller <davem@davemloft.net>2015-09-10 00:42:51 -0400
commita66e36568e30ed3714c0e3a12bd3b64696343ff5 (patch)
tree31f62f5e6258b1eaf5b7e7deede0dc8466031d17
parentf2be053c83ee93888fc09d90df2bded0deb28947 (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.c17
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) {