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>
This commit is contained in:
		
							parent
							
								
									6166e5330c
								
							
						
					
					
						commit
						e82b9b0727
					
				| @ -604,12 +604,6 @@ static size_t init_iov_iter(struct vhost_virtqueue *vq, struct iov_iter *iter, | ||||
| 	return iov_iter_count(iter); | ||||
| } | ||||
| 
 | ||||
| static bool vhost_exceeds_weight(int pkts, int total_len) | ||||
| { | ||||
| 	return total_len >= VHOST_NET_WEIGHT || | ||||
| 	       pkts >= VHOST_NET_PKT_WEIGHT; | ||||
| } | ||||
| 
 | ||||
| static int get_tx_bufs(struct vhost_net *net, | ||||
| 		       struct vhost_net_virtqueue *nvq, | ||||
| 		       struct msghdr *msg, | ||||
| @ -845,10 +839,8 @@ done: | ||||
| 		vq->heads[nvq->done_idx].id = cpu_to_vhost32(vq, head); | ||||
| 		vq->heads[nvq->done_idx].len = 0; | ||||
| 		++nvq->done_idx; | ||||
| 		if (vhost_exceeds_weight(++sent_pkts, total_len)) { | ||||
| 			vhost_poll_queue(&vq->poll); | ||||
| 		if (vhost_exceeds_weight(vq, ++sent_pkts, total_len)) | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	vhost_tx_batch(net, nvq, sock, &msg); | ||||
| @ -951,10 +943,9 @@ static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock) | ||||
| 		else | ||||
| 			vhost_zerocopy_signal_used(net, vq); | ||||
| 		vhost_net_tx_packet(net); | ||||
| 		if (unlikely(vhost_exceeds_weight(++sent_pkts, total_len))) { | ||||
| 			vhost_poll_queue(&vq->poll); | ||||
| 		if (unlikely(vhost_exceeds_weight(vq, ++sent_pkts, | ||||
| 						  total_len))) | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -1239,10 +1230,8 @@ static void handle_rx(struct vhost_net *net) | ||||
| 			vhost_log_write(vq, vq_log, log, vhost_len, | ||||
| 					vq->iov, in); | ||||
| 		total_len += vhost_len; | ||||
| 		if (unlikely(vhost_exceeds_weight(++recv_pkts, total_len))) { | ||||
| 			vhost_poll_queue(&vq->poll); | ||||
| 		if (unlikely(vhost_exceeds_weight(vq, ++recv_pkts, total_len))) | ||||
| 			goto out; | ||||
| 		} | ||||
| 	} | ||||
| 	if (unlikely(busyloop_intr)) | ||||
| 		vhost_poll_queue(&vq->poll); | ||||
| @ -1338,7 +1327,8 @@ static int vhost_net_open(struct inode *inode, struct file *f) | ||||
| 		vhost_net_buf_init(&n->vqs[i].rxq); | ||||
| 	} | ||||
| 	vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX, | ||||
| 		       UIO_MAXIOV + VHOST_NET_BATCH); | ||||
| 		       UIO_MAXIOV + VHOST_NET_BATCH, | ||||
| 		       VHOST_NET_WEIGHT, VHOST_NET_PKT_WEIGHT); | ||||
| 
 | ||||
| 	vhost_poll_init(n->poll + VHOST_NET_VQ_TX, handle_tx_net, EPOLLOUT, dev); | ||||
| 	vhost_poll_init(n->poll + VHOST_NET_VQ_RX, handle_rx_net, EPOLLIN, dev); | ||||
|  | ||||
| @ -57,6 +57,12 @@ | ||||
| #define VHOST_SCSI_PREALLOC_UPAGES 2048 | ||||
| #define VHOST_SCSI_PREALLOC_PROT_SGLS 2048 | ||||
| 
 | ||||
| /* Max number of requests before requeueing the job.
 | ||||
|  * Using this limit prevents one virtqueue from starving others with | ||||
|  * request. | ||||
|  */ | ||||
| #define VHOST_SCSI_WEIGHT 256 | ||||
| 
 | ||||
| struct vhost_scsi_inflight { | ||||
| 	/* Wait for the flush operation to finish */ | ||||
| 	struct completion comp; | ||||
| @ -1621,7 +1627,8 @@ static int vhost_scsi_open(struct inode *inode, struct file *f) | ||||
| 		vqs[i] = &vs->vqs[i].vq; | ||||
| 		vs->vqs[i].vq.handle_kick = vhost_scsi_handle_kick; | ||||
| 	} | ||||
| 	vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ, UIO_MAXIOV); | ||||
| 	vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ, UIO_MAXIOV, | ||||
| 		       VHOST_SCSI_WEIGHT, 0); | ||||
| 
 | ||||
| 	vhost_scsi_init_inflight(vs, NULL); | ||||
| 
 | ||||
|  | ||||
| @ -413,8 +413,24 @@ static void vhost_dev_free_iovecs(struct vhost_dev *dev) | ||||
| 		vhost_vq_free_iovecs(dev->vqs[i]); | ||||
| } | ||||
| 
 | ||||
| bool vhost_exceeds_weight(struct vhost_virtqueue *vq, | ||||
| 			  int pkts, int total_len) | ||||
| { | ||||
| 	struct vhost_dev *dev = vq->dev; | ||||
| 
 | ||||
| 	if ((dev->byte_weight && total_len >= dev->byte_weight) || | ||||
| 	    pkts >= dev->weight) { | ||||
| 		vhost_poll_queue(&vq->poll); | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(vhost_exceeds_weight); | ||||
| 
 | ||||
| void vhost_dev_init(struct vhost_dev *dev, | ||||
| 		    struct vhost_virtqueue **vqs, int nvqs, int iov_limit) | ||||
| 		    struct vhost_virtqueue **vqs, int nvqs, | ||||
| 		    int iov_limit, int weight, int byte_weight) | ||||
| { | ||||
| 	struct vhost_virtqueue *vq; | ||||
| 	int i; | ||||
| @ -428,6 +444,8 @@ void vhost_dev_init(struct vhost_dev *dev, | ||||
| 	dev->mm = NULL; | ||||
| 	dev->worker = NULL; | ||||
| 	dev->iov_limit = iov_limit; | ||||
| 	dev->weight = weight; | ||||
| 	dev->byte_weight = byte_weight; | ||||
| 	init_llist_head(&dev->work_list); | ||||
| 	init_waitqueue_head(&dev->wait); | ||||
| 	INIT_LIST_HEAD(&dev->read_list); | ||||
|  | ||||
| @ -171,10 +171,13 @@ struct vhost_dev { | ||||
| 	struct list_head pending_list; | ||||
| 	wait_queue_head_t wait; | ||||
| 	int iov_limit; | ||||
| 	int weight; | ||||
| 	int byte_weight; | ||||
| }; | ||||
| 
 | ||||
| bool vhost_exceeds_weight(struct vhost_virtqueue *vq, int pkts, int total_len); | ||||
| void vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs, | ||||
| 		    int nvqs, int iov_limit); | ||||
| 		    int nvqs, int iov_limit, int weight, int byte_weight); | ||||
| long vhost_dev_set_owner(struct vhost_dev *dev); | ||||
| bool vhost_dev_has_owner(struct vhost_dev *dev); | ||||
| long vhost_dev_check_owner(struct vhost_dev *); | ||||
|  | ||||
| @ -21,6 +21,14 @@ | ||||
| #include "vhost.h" | ||||
| 
 | ||||
| #define VHOST_VSOCK_DEFAULT_HOST_CID	2 | ||||
| /* Max number of bytes transferred before requeueing the job.
 | ||||
|  * Using this limit prevents one virtqueue from starving others. */ | ||||
| #define VHOST_VSOCK_WEIGHT 0x80000 | ||||
| /* Max number of packets transferred before requeueing the job.
 | ||||
|  * Using this limit prevents one virtqueue from starving others with | ||||
|  * small pkts. | ||||
|  */ | ||||
| #define VHOST_VSOCK_PKT_WEIGHT 256 | ||||
| 
 | ||||
| enum { | ||||
| 	VHOST_VSOCK_FEATURES = VHOST_FEATURES, | ||||
| @ -531,7 +539,9 @@ static int vhost_vsock_dev_open(struct inode *inode, struct file *file) | ||||
| 	vsock->vqs[VSOCK_VQ_TX].handle_kick = vhost_vsock_handle_tx_kick; | ||||
| 	vsock->vqs[VSOCK_VQ_RX].handle_kick = vhost_vsock_handle_rx_kick; | ||||
| 
 | ||||
| 	vhost_dev_init(&vsock->dev, vqs, ARRAY_SIZE(vsock->vqs), UIO_MAXIOV); | ||||
| 	vhost_dev_init(&vsock->dev, vqs, ARRAY_SIZE(vsock->vqs), | ||||
| 		       UIO_MAXIOV, VHOST_VSOCK_PKT_WEIGHT, | ||||
| 		       VHOST_VSOCK_WEIGHT); | ||||
| 
 | ||||
| 	file->private_data = vsock; | ||||
| 	spin_lock_init(&vsock->send_pkt_list_lock); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user