Skip to content

Commit

Permalink
net: vhost: factor out busy polling logic to vhost_net_busy_poll()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Tonghao Zhang authored and David S. Miller committed Sep 27, 2018
1 parent a6a67a2 commit dc15128
Showing 1 changed file with 70 additions and 40 deletions.
110 changes: 70 additions & 40 deletions drivers/vhost/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,74 @@ static void vhost_tx_batch(struct vhost_net *net,
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,
Expand Down Expand Up @@ -897,58 +965,20 @@ 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)
{
struct vhost_net_virtqueue *rnvq = &net->vqs[VHOST_NET_VQ_RX];
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);
}
Expand Down

0 comments on commit dc15128

Please sign in to comment.