Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b211616d authored by Michael S. Tsirkin's avatar Michael S. Tsirkin Committed by David S. Miller
Browse files

vhost: move -net specific code out



Zerocopy handling code is vhost-net specific.
Move it from vhost.c/vhost.h out to net.c

Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c4fcb586
Loading
Loading
Loading
Loading
+45 −0
Original line number Original line Diff line number Diff line
@@ -126,6 +126,42 @@ static void tx_poll_start(struct vhost_net *net, struct socket *sock)
	net->tx_poll_state = VHOST_NET_POLL_STARTED;
	net->tx_poll_state = VHOST_NET_POLL_STARTED;
}
}


/* In case of DMA done not in order in lower device driver for some reason.
 * upend_idx is used to track end of used idx, done_idx is used to track head
 * of used idx. Once lower device DMA done contiguously, we will signal KVM
 * guest used idx.
 */
int vhost_zerocopy_signal_used(struct vhost_virtqueue *vq)
{
	int i;
	int j = 0;

	for (i = vq->done_idx; i != vq->upend_idx; i = (i + 1) % UIO_MAXIOV) {
		if (VHOST_DMA_IS_DONE(vq->heads[i].len)) {
			vq->heads[i].len = VHOST_DMA_CLEAR_LEN;
			vhost_add_used_and_signal(vq->dev, vq,
						  vq->heads[i].id, 0);
			++j;
		} else
			break;
	}
	if (j)
		vq->done_idx = i;
	return j;
}

static void vhost_zerocopy_callback(struct ubuf_info *ubuf, int status)
{
	struct vhost_ubuf_ref *ubufs = ubuf->ctx;
	struct vhost_virtqueue *vq = ubufs->vq;

	vhost_poll_queue(&vq->poll);
	/* set len to mark this desc buffers done DMA */
	vq->heads[ubuf->desc].len = status ?
		VHOST_DMA_FAILED_LEN : VHOST_DMA_DONE_LEN;
	vhost_ubuf_put(ubufs);
}

/* Expects to be always run from workqueue - which acts as
/* Expects to be always run from workqueue - which acts as
 * read-size critical section for our kind of RCU. */
 * read-size critical section for our kind of RCU. */
static void handle_tx(struct vhost_net *net)
static void handle_tx(struct vhost_net *net)
@@ -594,9 +630,18 @@ static int vhost_net_release(struct inode *inode, struct file *f)
	struct vhost_net *n = f->private_data;
	struct vhost_net *n = f->private_data;
	struct socket *tx_sock;
	struct socket *tx_sock;
	struct socket *rx_sock;
	struct socket *rx_sock;
	int i;


	vhost_net_stop(n, &tx_sock, &rx_sock);
	vhost_net_stop(n, &tx_sock, &rx_sock);
	vhost_net_flush(n);
	vhost_net_flush(n);
	vhost_dev_stop(&n->dev);
	for (i = 0; i < n->dev.nvqs; ++i) {
		/* Wait for all lower device DMAs done. */
		if (n->dev.vqs[i].ubufs)
			vhost_ubuf_put_and_wait(n->dev.vqs[i].ubufs);

		vhost_zerocopy_signal_used(n, &n->dev.vqs[i]);
	}
	vhost_dev_cleanup(&n->dev, false);
	vhost_dev_cleanup(&n->dev, false);
	if (tx_sock)
	if (tx_sock)
		fput(tx_sock->file);
		fput(tx_sock->file);
+1 −0
Original line number Original line Diff line number Diff line
@@ -895,6 +895,7 @@ static int vhost_scsi_release(struct inode *inode, struct file *f)
		vhost_scsi_clear_endpoint(s, &backend);
		vhost_scsi_clear_endpoint(s, &backend);
	}
	}


	vhost_dev_stop(&s->dev);
	vhost_dev_cleanup(&s->dev, false);
	vhost_dev_cleanup(&s->dev, false);
	kfree(s);
	kfree(s);
	return 0;
	return 0;
+7 −46
Original line number Original line Diff line number Diff line
@@ -26,10 +26,6 @@
#include <linux/kthread.h>
#include <linux/kthread.h>
#include <linux/cgroup.h>
#include <linux/cgroup.h>


#include <linux/net.h>
#include <linux/if_packet.h>
#include <linux/if_arp.h>

#include "vhost.h"
#include "vhost.h"


enum {
enum {
@@ -414,28 +410,16 @@ long vhost_dev_reset_owner(struct vhost_dev *dev)
	return 0;
	return 0;
}
}


/* In case of DMA done not in order in lower device driver for some reason.
void vhost_dev_stop(struct vhost_dev *dev)
 * upend_idx is used to track end of used idx, done_idx is used to track head
 * of used idx. Once lower device DMA done contiguously, we will signal KVM
 * guest used idx.
 */
int vhost_zerocopy_signal_used(struct vhost_virtqueue *vq)
{
{
	int i;
	int i;
	int j = 0;


	for (i = 0; i < dev->nvqs; ++i) {
	for (i = vq->done_idx; i != vq->upend_idx; i = (i + 1) % UIO_MAXIOV) {
		if (dev->vqs[i].kick && dev->vqs[i].handle_kick) {
		if (VHOST_DMA_IS_DONE(vq->heads[i].len)) {
			vhost_poll_stop(&dev->vqs[i].poll);
			vq->heads[i].len = VHOST_DMA_CLEAR_LEN;
			vhost_poll_flush(&dev->vqs[i].poll);
			vhost_add_used_and_signal(vq->dev, vq,
		}
						  vq->heads[i].id, 0);
			++j;
		} else
			break;
	}
	}
	if (j)
		vq->done_idx = i;
	return j;
}
}


/* Caller should have device mutex if and only if locked is set */
/* Caller should have device mutex if and only if locked is set */
@@ -444,17 +428,6 @@ void vhost_dev_cleanup(struct vhost_dev *dev, bool locked)
	int i;
	int i;


	for (i = 0; i < dev->nvqs; ++i) {
	for (i = 0; i < dev->nvqs; ++i) {
		if (dev->vqs[i].kick && dev->vqs[i].handle_kick) {
			vhost_poll_stop(&dev->vqs[i].poll);
			vhost_poll_flush(&dev->vqs[i].poll);
		}
		/* Wait for all lower device DMAs done. */
		if (dev->vqs[i].ubufs)
			vhost_ubuf_put_and_wait(dev->vqs[i].ubufs);

		/* Signal guest as appropriate. */
		vhost_zerocopy_signal_used(&dev->vqs[i]);

		if (dev->vqs[i].error_ctx)
		if (dev->vqs[i].error_ctx)
			eventfd_ctx_put(dev->vqs[i].error_ctx);
			eventfd_ctx_put(dev->vqs[i].error_ctx);
		if (dev->vqs[i].error)
		if (dev->vqs[i].error)
@@ -1599,15 +1572,3 @@ void vhost_ubuf_put_and_wait(struct vhost_ubuf_ref *ubufs)
	wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount));
	wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount));
	kfree(ubufs);
	kfree(ubufs);
}
}

void vhost_zerocopy_callback(struct ubuf_info *ubuf, int status)
{
	struct vhost_ubuf_ref *ubufs = ubuf->ctx;
	struct vhost_virtqueue *vq = ubufs->vq;

	vhost_poll_queue(&vq->poll);
	/* set len to mark this desc buffers done DMA */
	vq->heads[ubuf->desc].len = status ?
		VHOST_DMA_FAILED_LEN : VHOST_DMA_DONE_LEN;
	kref_put(&ubufs->kref, vhost_zerocopy_done_signal);
}
+3 −18
Original line number Original line Diff line number Diff line
@@ -7,27 +7,11 @@
#include <linux/mutex.h>
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/poll.h>
#include <linux/file.h>
#include <linux/file.h>
#include <linux/skbuff.h>
#include <linux/uio.h>
#include <linux/uio.h>
#include <linux/virtio_config.h>
#include <linux/virtio_config.h>
#include <linux/virtio_ring.h>
#include <linux/virtio_ring.h>
#include <linux/atomic.h>
#include <linux/atomic.h>


/*
 * For transmit, used buffer len is unused; we override it to track buffer
 * status internally; used for zerocopy tx only.
 */
/* Lower device DMA failed */
#define VHOST_DMA_FAILED_LEN	3
/* Lower device DMA done */
#define VHOST_DMA_DONE_LEN	2
/* Lower device DMA in progress */
#define VHOST_DMA_IN_PROGRESS	1
/* Buffer unused */
#define VHOST_DMA_CLEAR_LEN	0

#define VHOST_DMA_IS_DONE(len) ((len) >= VHOST_DMA_DONE_LEN)

struct vhost_device;
struct vhost_device;


struct vhost_work;
struct vhost_work;
@@ -80,6 +64,8 @@ struct vhost_ubuf_ref *vhost_ubuf_alloc(struct vhost_virtqueue *, bool zcopy);
void vhost_ubuf_put(struct vhost_ubuf_ref *);
void vhost_ubuf_put(struct vhost_ubuf_ref *);
void vhost_ubuf_put_and_wait(struct vhost_ubuf_ref *);
void vhost_ubuf_put_and_wait(struct vhost_ubuf_ref *);


struct ubuf_info;

/* The virtqueue structure describes a queue attached to a device. */
/* The virtqueue structure describes a queue attached to a device. */
struct vhost_virtqueue {
struct vhost_virtqueue {
	struct vhost_dev *dev;
	struct vhost_dev *dev;
@@ -177,6 +163,7 @@ long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue *vqs, int nvqs);
long vhost_dev_check_owner(struct vhost_dev *);
long vhost_dev_check_owner(struct vhost_dev *);
long vhost_dev_reset_owner(struct vhost_dev *);
long vhost_dev_reset_owner(struct vhost_dev *);
void vhost_dev_cleanup(struct vhost_dev *, bool locked);
void vhost_dev_cleanup(struct vhost_dev *, bool locked);
void vhost_dev_stop(struct vhost_dev *);
long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg);
long vhost_dev_ioctl(struct vhost_dev *, unsigned int ioctl, unsigned long arg);
int vhost_vq_access_ok(struct vhost_virtqueue *vq);
int vhost_vq_access_ok(struct vhost_virtqueue *vq);
int vhost_log_access_ok(struct vhost_dev *);
int vhost_log_access_ok(struct vhost_dev *);
@@ -201,8 +188,6 @@ bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *);


int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
		    unsigned int log_num, u64 len);
		    unsigned int log_num, u64 len);
void vhost_zerocopy_callback(struct ubuf_info *, bool);
int vhost_zerocopy_signal_used(struct vhost_virtqueue *vq);


#define vq_err(vq, fmt, ...) do {                                  \
#define vq_err(vq, fmt, ...) do {                                  \
		pr_debug(pr_fmt(fmt), ##__VA_ARGS__);       \
		pr_debug(pr_fmt(fmt), ##__VA_ARGS__);       \