net: vhost: factor out busy polling logic to vhost_net_busy_poll()
authorTonghao Zhang <xiangxia.m.yue@gmail.com>
Tue, 25 Sep 2018 12:36:51 +0000 (05:36 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 27 Sep 2018 03:25:55 +0000 (20:25 -0700)
Factor out generic busy polling logic and will be
used for in tx path in the next patch. And with the patch,
qemu can set differently the busyloop_timeout for rx queue.

To avoid duplicate codes, introduce the helper functions:
* sock_has_rx_data(changed from sk_has_rx_data)
* vhost_net_busy_poll_try_queue

Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/vhost/net.c

index 5fe57ab..ac0b954 100644 (file)
@@ -480,6 +480,74 @@ signal_used:
        nvq->batched_xdp = 0;
 }
 
+static int sock_has_rx_data(struct socket *sock)
+{
+       if (unlikely(!sock))
+               return 0;
+
+       if (sock->ops->peek_len)
+               return sock->ops->peek_len(sock);
+
+       return skb_queue_empty(&sock->sk->sk_receive_queue);
+}
+
+static void vhost_net_busy_poll_try_queue(struct vhost_net *net,
+                                         struct vhost_virtqueue *vq)
+{
+       if (!vhost_vq_avail_empty(&net->dev, vq)) {
+               vhost_poll_queue(&vq->poll);
+       } else if (unlikely(vhost_enable_notify(&net->dev, vq))) {
+               vhost_disable_notify(&net->dev, vq);
+               vhost_poll_queue(&vq->poll);
+       }
+}
+
+static void vhost_net_busy_poll(struct vhost_net *net,
+                               struct vhost_virtqueue *rvq,
+                               struct vhost_virtqueue *tvq,
+                               bool *busyloop_intr,
+                               bool poll_rx)
+{
+       unsigned long busyloop_timeout;
+       unsigned long endtime;
+       struct socket *sock;
+       struct vhost_virtqueue *vq = poll_rx ? tvq : rvq;
+
+       mutex_lock_nested(&vq->mutex, poll_rx ? VHOST_NET_VQ_TX: VHOST_NET_VQ_RX);
+       vhost_disable_notify(&net->dev, vq);
+       sock = rvq->private_data;
+
+       busyloop_timeout = poll_rx ? rvq->busyloop_timeout:
+                                    tvq->busyloop_timeout;
+
+       preempt_disable();
+       endtime = busy_clock() + busyloop_timeout;
+
+       while (vhost_can_busy_poll(endtime)) {
+               if (vhost_has_work(&net->dev)) {
+                       *busyloop_intr = true;
+                       break;
+               }
+
+               if ((sock_has_rx_data(sock) &&
+                    !vhost_vq_avail_empty(&net->dev, rvq)) ||
+                   !vhost_vq_avail_empty(&net->dev, tvq))
+                       break;
+
+               cpu_relax();
+       }
+
+       preempt_enable();
+
+       if (poll_rx || sock_has_rx_data(sock))
+               vhost_net_busy_poll_try_queue(net, vq);
+       else if (!poll_rx) /* On tx here, sock has no rx data. */
+               vhost_enable_notify(&net->dev, rvq);
+
+       mutex_unlock(&vq->mutex);
+}
+
+
 static int vhost_net_tx_get_vq_desc(struct vhost_net *net,
                                    struct vhost_net_virtqueue *nvq,
                                    unsigned int *out_num, unsigned int *in_num,
@@ -897,16 +965,6 @@ static int peek_head_len(struct vhost_net_virtqueue *rvq, struct sock *sk)
        return len;
 }
 
-static int sk_has_rx_data(struct sock *sk)
-{
-       struct socket *sock = sk->sk_socket;
-
-       if (sock->ops->peek_len)
-               return sock->ops->peek_len(sock);
-
-       return skb_queue_empty(&sk->sk_receive_queue);
-}
-
 static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk,
                                      bool *busyloop_intr)
 {
@@ -914,41 +972,13 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk,
        struct vhost_net_virtqueue *tnvq = &net->vqs[VHOST_NET_VQ_TX];
        struct vhost_virtqueue *rvq = &rnvq->vq;
        struct vhost_virtqueue *tvq = &tnvq->vq;
-       unsigned long uninitialized_var(endtime);
        int len = peek_head_len(rnvq, sk);
 
-       if (!len && tvq->busyloop_timeout) {
+       if (!len && rvq->busyloop_timeout) {
                /* Flush batched heads first */
                vhost_net_signal_used(rnvq);
                /* Both tx vq and rx socket were polled here */
-               mutex_lock_nested(&tvq->mutex, VHOST_NET_VQ_TX);
-               vhost_disable_notify(&net->dev, tvq);
-
-               preempt_disable();
-               endtime = busy_clock() + tvq->busyloop_timeout;
-
-               while (vhost_can_busy_poll(endtime)) {
-                       if (vhost_has_work(&net->dev)) {
-                               *busyloop_intr = true;
-                               break;
-                       }
-                       if ((sk_has_rx_data(sk) &&
-                            !vhost_vq_avail_empty(&net->dev, rvq)) ||
-                           !vhost_vq_avail_empty(&net->dev, tvq))
-                               break;
-                       cpu_relax();
-               }
-
-               preempt_enable();
-
-               if (!vhost_vq_avail_empty(&net->dev, tvq)) {
-                       vhost_poll_queue(&tvq->poll);
-               } else if (unlikely(vhost_enable_notify(&net->dev, tvq))) {
-                       vhost_disable_notify(&net->dev, tvq);
-                       vhost_poll_queue(&tvq->poll);
-               }
-
-               mutex_unlock(&tvq->mutex);
+               vhost_net_busy_poll(net, rvq, tvq, busyloop_intr, true);
 
                len = peek_head_len(rnvq, sk);
        }