Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vhost: introduce vhost_exceeds_weight()

We used to have vhost_exceeds_weight() for vhost-net to:

- prevent vhost kthread from hogging the cpu
- balance the time spent between TX and RX

This function could be useful for vsock and scsi as well. So move it
to vhost.c. Device must specify a weight which counts the number of
requests, or it can also specific a byte_weight which counts the
number of bytes that has been processed.

Signed-off-by: Jason Wang <jasowang@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

authored by

Jason Wang and committed by
Michael S. Tsirkin
e82b9b07 6166e533

+48 -20
+6 -16
drivers/vhost/net.c
··· 604 604 return iov_iter_count(iter); 605 605 } 606 606 607 - static bool vhost_exceeds_weight(int pkts, int total_len) 608 - { 609 - return total_len >= VHOST_NET_WEIGHT || 610 - pkts >= VHOST_NET_PKT_WEIGHT; 611 - } 612 - 613 607 static int get_tx_bufs(struct vhost_net *net, 614 608 struct vhost_net_virtqueue *nvq, 615 609 struct msghdr *msg, ··· 839 845 vq->heads[nvq->done_idx].id = cpu_to_vhost32(vq, head); 840 846 vq->heads[nvq->done_idx].len = 0; 841 847 ++nvq->done_idx; 842 - if (vhost_exceeds_weight(++sent_pkts, total_len)) { 843 - vhost_poll_queue(&vq->poll); 848 + if (vhost_exceeds_weight(vq, ++sent_pkts, total_len)) 844 849 break; 845 - } 846 850 } 847 851 848 852 vhost_tx_batch(net, nvq, sock, &msg); ··· 943 951 else 944 952 vhost_zerocopy_signal_used(net, vq); 945 953 vhost_net_tx_packet(net); 946 - if (unlikely(vhost_exceeds_weight(++sent_pkts, total_len))) { 947 - vhost_poll_queue(&vq->poll); 954 + if (unlikely(vhost_exceeds_weight(vq, ++sent_pkts, 955 + total_len))) 948 956 break; 949 - } 950 957 } 951 958 } 952 959 ··· 1230 1239 vhost_log_write(vq, vq_log, log, vhost_len, 1231 1240 vq->iov, in); 1232 1241 total_len += vhost_len; 1233 - if (unlikely(vhost_exceeds_weight(++recv_pkts, total_len))) { 1234 - vhost_poll_queue(&vq->poll); 1242 + if (unlikely(vhost_exceeds_weight(vq, ++recv_pkts, total_len))) 1235 1243 goto out; 1236 - } 1237 1244 } 1238 1245 if (unlikely(busyloop_intr)) 1239 1246 vhost_poll_queue(&vq->poll); ··· 1327 1338 vhost_net_buf_init(&n->vqs[i].rxq); 1328 1339 } 1329 1340 vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX, 1330 - UIO_MAXIOV + VHOST_NET_BATCH); 1341 + UIO_MAXIOV + VHOST_NET_BATCH, 1342 + VHOST_NET_WEIGHT, VHOST_NET_PKT_WEIGHT); 1331 1343 1332 1344 vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, EPOLLOUT, dev); 1333 1345 vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, EPOLLIN, dev);
+8 -1
drivers/vhost/scsi.c
··· 57 57 #define VHOST_SCSI_PREALLOC_UPAGES 2048 58 58 #define VHOST_SCSI_PREALLOC_PROT_SGLS 2048 59 59 60 + /* Max number of requests before requeueing the job. 61 + * Using this limit prevents one virtqueue from starving others with 62 + * request. 63 + */ 64 + #define VHOST_SCSI_WEIGHT 256 65 + 60 66 struct vhost_scsi_inflight { 61 67 /* Wait for the flush operation to finish */ 62 68 struct completion comp; ··· 1627 1621 vqs[i] = &vs->vqs[i].vq; 1628 1622 vs->vqs[i].vq.handle_kick = vhost_scsi_handle_kick; 1629 1623 } 1630 - vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ, UIO_MAXIOV); 1624 + vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ, UIO_MAXIOV, 1625 + VHOST_SCSI_WEIGHT, 0); 1631 1626 1632 1627 vhost_scsi_init_inflight(vs, NULL); 1633 1628
+19 -1
drivers/vhost/vhost.c
··· 413 413 vhost_vq_free_iovecs(dev->vqs[i]); 414 414 } 415 415 416 + bool vhost_exceeds_weight(struct vhost_virtqueue *vq, 417 + int pkts, int total_len) 418 + { 419 + struct vhost_dev *dev = vq->dev; 420 + 421 + if ((dev->byte_weight && total_len >= dev->byte_weight) || 422 + pkts >= dev->weight) { 423 + vhost_poll_queue(&vq->poll); 424 + return true; 425 + } 426 + 427 + return false; 428 + } 429 + EXPORT_SYMBOL_GPL(vhost_exceeds_weight); 430 + 416 431 void vhost_dev_init(struct vhost_dev *dev, 417 - struct vhost_virtqueue **vqs, int nvqs, int iov_limit) 432 + struct vhost_virtqueue **vqs, int nvqs, 433 + int iov_limit, int weight, int byte_weight) 418 434 { 419 435 struct vhost_virtqueue *vq; 420 436 int i; ··· 444 428 dev->mm = NULL; 445 429 dev->worker = NULL; 446 430 dev->iov_limit = iov_limit; 431 + dev->weight = weight; 432 + dev->byte_weight = byte_weight; 447 433 init_llist_head(&dev->work_list); 448 434 init_waitqueue_head(&dev->wait); 449 435 INIT_LIST_HEAD(&dev->read_list);
+4 -1
drivers/vhost/vhost.h
··· 171 171 struct list_head pending_list; 172 172 wait_queue_head_t wait; 173 173 int iov_limit; 174 + int weight; 175 + int byte_weight; 174 176 }; 175 177 178 + bool vhost_exceeds_weight(struct vhost_virtqueue *vq, int pkts, int total_len); 176 179 void vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs, 177 - int nvqs, int iov_limit); 180 + int nvqs, int iov_limit, int weight, int byte_weight); 178 181 long vhost_dev_set_owner(struct vhost_dev *dev); 179 182 bool vhost_dev_has_owner(struct vhost_dev *dev); 180 183 long vhost_dev_check_owner(struct vhost_dev *);
+11 -1
drivers/vhost/vsock.c
··· 21 21 #include "vhost.h" 22 22 23 23 #define VHOST_VSOCK_DEFAULT_HOST_CID 2 24 + /* Max number of bytes transferred before requeueing the job. 25 + * Using this limit prevents one virtqueue from starving others. */ 26 + #define VHOST_VSOCK_WEIGHT 0x80000 27 + /* Max number of packets transferred before requeueing the job. 28 + * Using this limit prevents one virtqueue from starving others with 29 + * small pkts. 30 + */ 31 + #define VHOST_VSOCK_PKT_WEIGHT 256 24 32 25 33 enum { 26 34 VHOST_VSOCK_FEATURES = VHOST_FEATURES, ··· 539 531 vsock->vqs[VSOCK_VQ_TX].handle_kick = vhost_vsock_handle_tx_kick; 540 532 vsock->vqs[VSOCK_VQ_RX].handle_kick = vhost_vsock_handle_rx_kick; 541 533 542 - vhost_dev_init(&vsock->dev, vqs, ARRAY_SIZE(vsock->vqs), UIO_MAXIOV); 534 + vhost_dev_init(&vsock->dev, vqs, ARRAY_SIZE(vsock->vqs), 535 + UIO_MAXIOV, VHOST_VSOCK_PKT_WEIGHT, 536 + VHOST_VSOCK_WEIGHT); 543 537 544 538 file->private_data = vsock; 545 539 spin_lock_init(&vsock->send_pkt_list_lock);