From 54db63c2ca153ebf0c868cdf79f52ec9e701d38c Mon Sep 17 00:00:00 2001 From: Asias He Date: Mon, 6 May 2013 11:15:59 +0800 Subject: [PATCH 1/8] vhost: Export vhost_dev_set_owner Signed-off-by: Asias He Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 2 +- drivers/vhost/vhost.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 749b5ab5bfbb..de9441a1b158 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -344,7 +344,7 @@ static int vhost_attach_cgroups(struct vhost_dev *dev) } /* Caller should have device mutex */ -static long vhost_dev_set_owner(struct vhost_dev *dev) +long vhost_dev_set_owner(struct vhost_dev *dev) { struct task_struct *worker; int err; diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index b58f4ae82cb8..cc23bc456d15 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -135,6 +135,7 @@ struct vhost_dev { }; long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs, int nvqs); +long vhost_dev_set_owner(struct vhost_dev *dev); long vhost_dev_check_owner(struct vhost_dev *); struct vhost_memory *vhost_dev_reset_owner_prepare(void); void vhost_dev_reset_owner(struct vhost_dev *, struct vhost_memory *); From b1ad8496c9f47d8b545ed4e948ab4271627c8bcf Mon Sep 17 00:00:00 2001 From: Asias He Date: Mon, 6 May 2013 11:16:00 +0800 Subject: [PATCH 2/8] vhost-net: Free ubuf when vhost_dev_set_owner fails Signed-off-by: Asias He Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index a3645bd163d8..354665a3ecd8 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -146,6 +146,19 @@ void vhost_ubuf_put_and_wait(struct vhost_ubuf_ref *ubufs) kfree(ubufs); } +static void vhost_net_clear_ubuf_info(struct vhost_net *n) +{ + + bool zcopy; + int i; + + for (i = 0; i < n->dev.nvqs; ++i) { + zcopy = vhost_zcopy_mask & (0x1 << i); + if (zcopy) + kfree(n->vqs[i].ubuf_info); + } +} + int vhost_net_set_ubuf_info(struct vhost_net *n) { bool zcopy; @@ -1027,6 +1040,23 @@ static int vhost_net_set_features(struct vhost_net *n, u64 features) return 0; } +static long vhost_net_set_owner(struct vhost_net *n) +{ + int r; + + mutex_lock(&n->dev.mutex); + r = vhost_net_set_ubuf_info(n); + if (r) + goto out; + r = vhost_dev_set_owner(&n->dev); + if (r) + vhost_net_clear_ubuf_info(n); + vhost_net_flush(n); +out: + mutex_unlock(&n->dev.mutex); + return r; +} + static long vhost_net_ioctl(struct file *f, unsigned int ioctl, unsigned long arg) { @@ -1055,19 +1085,15 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl, return vhost_net_set_features(n, features); case VHOST_RESET_OWNER: return vhost_net_reset_owner(n); + case VHOST_SET_OWNER: + return vhost_net_set_owner(n); default: mutex_lock(&n->dev.mutex); - if (ioctl == VHOST_SET_OWNER) { - r = vhost_net_set_ubuf_info(n); - if (r) - goto out; - } r = vhost_dev_ioctl(&n->dev, ioctl, argp); if (r == -ENOIOCTLCMD) r = vhost_vring_ioctl(&n->dev, ioctl, argp); else vhost_net_flush(n); -out: mutex_unlock(&n->dev.mutex); return r; } From 8570a6e72c5bfb1aee8225b8c4814cdc28417a20 Mon Sep 17 00:00:00 2001 From: Asias He Date: Mon, 6 May 2013 16:38:20 +0800 Subject: [PATCH 3/8] vhost: Move VHOST_NET_FEATURES to net.c vhost.h should not depend on device specific marcos like VHOST_NET_F_VIRTIO_NET_HDR and VIRTIO_NET_F_MRG_RXBUF. Signed-off-by: Asias He Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 6 ++++++ drivers/vhost/vhost.h | 3 --- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 354665a3ecd8..06b2447bce71 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -58,6 +58,12 @@ MODULE_PARM_DESC(experimental_zcopytx, "Enable Zero Copy TX;" #define VHOST_DMA_IS_DONE(len) ((len) >= VHOST_DMA_DONE_LEN) +enum { + VHOST_NET_FEATURES = VHOST_FEATURES | + (1ULL << VHOST_NET_F_VIRTIO_NET_HDR) | + (1ULL << VIRTIO_NET_F_MRG_RXBUF), +}; + enum { VHOST_NET_VQ_RX = 0, VHOST_NET_VQ_TX = 1, diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index cc23bc456d15..08ebf58dfcf4 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -178,9 +178,6 @@ enum { (1ULL << VIRTIO_RING_F_INDIRECT_DESC) | (1ULL << VIRTIO_RING_F_EVENT_IDX) | (1ULL << VHOST_F_LOG_ALL), - VHOST_NET_FEATURES = VHOST_FEATURES | - (1ULL << VHOST_NET_F_VIRTIO_NET_HDR) | - (1ULL << VIRTIO_NET_F_MRG_RXBUF), }; static inline int vhost_has_feature(struct vhost_dev *dev, int bit) From ab00c42a567b21024383db3fac98118497d6270b Mon Sep 17 00:00:00 2001 From: Asias He Date: Mon, 6 May 2013 16:38:22 +0800 Subject: [PATCH 4/8] vhost: Remove comments for hdr in vhost.h It is supposed to be removed when hdr is moved into vhost_net_virtqueue. Signed-off-by: Asias He Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 08ebf58dfcf4..ec72686a2797 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -99,9 +99,6 @@ struct vhost_virtqueue { u64 log_addr; struct iovec iov[UIO_MAXIOV]; - /* hdr is used to store the virtio header. - * Since each iovec has >= 1 byte length, we never need more than - * header length entries to store the header. */ struct iovec *indirect; struct vring_used_elem *heads; /* We use a kind of RCU to access private pointer. From e40ab7484f8e9cc9f5e59ae53214800e50f5615e Mon Sep 17 00:00:00 2001 From: Asias He Date: Mon, 6 May 2013 16:38:19 +0800 Subject: [PATCH 5/8] vhost: Remove vhost_enable_zcopy in vhost.h It is net.c specific. Signed-off-by: Asias He Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index ec72686a2797..a7ad63592987 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -186,7 +186,4 @@ static inline int vhost_has_feature(struct vhost_dev *dev, int bit) acked_features = rcu_dereference_index_check(dev->acked_features, 1); return acked_features & (1 << bit); } - -void vhost_enable_zcopy(int vq); - #endif From fe729a57c8d85b6b38d62b64215d5f064e682940 Mon Sep 17 00:00:00 2001 From: Asias He Date: Mon, 6 May 2013 16:38:24 +0800 Subject: [PATCH 6/8] vhost-net: Cleanup vhost_ubuf and vhost_zcopy - Rename vhost_ubuf to vhost_net_ubuf - Rename vhost_zcopy_mask to vhost_net_zcopy_mask - Make funcs static Signed-off-by: Asias He Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 58 +++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 06b2447bce71..2b51e2336aa2 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -70,7 +70,7 @@ enum { VHOST_NET_VQ_MAX = 2, }; -struct vhost_ubuf_ref { +struct vhost_net_ubuf_ref { struct kref kref; wait_queue_head_t wait; struct vhost_virtqueue *vq; @@ -93,7 +93,7 @@ struct vhost_net_virtqueue { struct ubuf_info *ubuf_info; /* Reference counting for outstanding ubufs. * Protected by vq mutex. Writers must also take device mutex. */ - struct vhost_ubuf_ref *ubufs; + struct vhost_net_ubuf_ref *ubufs; }; struct vhost_net { @@ -110,24 +110,25 @@ struct vhost_net { bool tx_flush; }; -static unsigned vhost_zcopy_mask __read_mostly; +static unsigned vhost_net_zcopy_mask __read_mostly; -void vhost_enable_zcopy(int vq) +static void vhost_net_enable_zcopy(int vq) { - vhost_zcopy_mask |= 0x1 << vq; + vhost_net_zcopy_mask |= 0x1 << vq; } -static void vhost_zerocopy_done_signal(struct kref *kref) +static void vhost_net_zerocopy_done_signal(struct kref *kref) { - struct vhost_ubuf_ref *ubufs = container_of(kref, struct vhost_ubuf_ref, - kref); + struct vhost_net_ubuf_ref *ubufs; + + ubufs = container_of(kref, struct vhost_net_ubuf_ref, kref); wake_up(&ubufs->wait); } -struct vhost_ubuf_ref *vhost_ubuf_alloc(struct vhost_virtqueue *vq, - bool zcopy) +static struct vhost_net_ubuf_ref * +vhost_net_ubuf_alloc(struct vhost_virtqueue *vq, bool zcopy) { - struct vhost_ubuf_ref *ubufs; + struct vhost_net_ubuf_ref *ubufs; /* No zero copy backend? Nothing to count. */ if (!zcopy) return NULL; @@ -140,14 +141,14 @@ struct vhost_ubuf_ref *vhost_ubuf_alloc(struct vhost_virtqueue *vq, return ubufs; } -void vhost_ubuf_put(struct vhost_ubuf_ref *ubufs) +static void vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs) { - kref_put(&ubufs->kref, vhost_zerocopy_done_signal); + kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal); } -void vhost_ubuf_put_and_wait(struct vhost_ubuf_ref *ubufs) +static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs) { - kref_put(&ubufs->kref, vhost_zerocopy_done_signal); + kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal); wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount)); kfree(ubufs); } @@ -159,7 +160,7 @@ static void vhost_net_clear_ubuf_info(struct vhost_net *n) int i; for (i = 0; i < n->dev.nvqs; ++i) { - zcopy = vhost_zcopy_mask & (0x1 << i); + zcopy = vhost_net_zcopy_mask & (0x1 << i); if (zcopy) kfree(n->vqs[i].ubuf_info); } @@ -171,7 +172,7 @@ int vhost_net_set_ubuf_info(struct vhost_net *n) int i; for (i = 0; i < n->dev.nvqs; ++i) { - zcopy = vhost_zcopy_mask & (0x1 << i); + zcopy = vhost_net_zcopy_mask & (0x1 << i); if (!zcopy) continue; n->vqs[i].ubuf_info = kmalloc(sizeof(*n->vqs[i].ubuf_info) * @@ -183,7 +184,7 @@ int vhost_net_set_ubuf_info(struct vhost_net *n) err: while (i--) { - zcopy = vhost_zcopy_mask & (0x1 << i); + zcopy = vhost_net_zcopy_mask & (0x1 << i); if (!zcopy) continue; kfree(n->vqs[i].ubuf_info); @@ -305,7 +306,7 @@ static int vhost_zerocopy_signal_used(struct vhost_net *net, static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success) { - struct vhost_ubuf_ref *ubufs = ubuf->ctx; + struct vhost_net_ubuf_ref *ubufs = ubuf->ctx; struct vhost_virtqueue *vq = ubufs->vq; int cnt = atomic_read(&ubufs->kref.refcount); @@ -322,7 +323,7 @@ static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success) /* set len to mark this desc buffers done DMA */ vq->heads[ubuf->desc].len = success ? VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN; - vhost_ubuf_put(ubufs); + vhost_net_ubuf_put(ubufs); } /* Expects to be always run from workqueue - which acts as @@ -345,7 +346,7 @@ static void handle_tx(struct vhost_net *net) int err; size_t hdr_size; struct socket *sock; - struct vhost_ubuf_ref *uninitialized_var(ubufs); + struct vhost_net_ubuf_ref *uninitialized_var(ubufs); bool zcopy, zcopy_used; /* TODO: check that we are running from vhost_worker? */ @@ -441,7 +442,7 @@ static void handle_tx(struct vhost_net *net) if (unlikely(err < 0)) { if (zcopy_used) { if (ubufs) - vhost_ubuf_put(ubufs); + vhost_net_ubuf_put(ubufs); nvq->upend_idx = ((unsigned)nvq->upend_idx - 1) % UIO_MAXIOV; } @@ -795,7 +796,7 @@ static void vhost_net_flush(struct vhost_net *n) n->tx_flush = true; mutex_unlock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex); /* Wait for all lower device DMAs done. */ - vhost_ubuf_put_and_wait(n->vqs[VHOST_NET_VQ_TX].ubufs); + vhost_net_ubuf_put_and_wait(n->vqs[VHOST_NET_VQ_TX].ubufs); mutex_lock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex); n->tx_flush = false; kref_init(&n->vqs[VHOST_NET_VQ_TX].ubufs->kref); @@ -896,7 +897,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) struct socket *sock, *oldsock; struct vhost_virtqueue *vq; struct vhost_net_virtqueue *nvq; - struct vhost_ubuf_ref *ubufs, *oldubufs = NULL; + struct vhost_net_ubuf_ref *ubufs, *oldubufs = NULL; int r; mutex_lock(&n->dev.mutex); @@ -927,7 +928,8 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) oldsock = rcu_dereference_protected(vq->private_data, lockdep_is_held(&vq->mutex)); if (sock != oldsock) { - ubufs = vhost_ubuf_alloc(vq, sock && vhost_sock_zcopy(sock)); + ubufs = vhost_net_ubuf_alloc(vq, + sock && vhost_sock_zcopy(sock)); if (IS_ERR(ubufs)) { r = PTR_ERR(ubufs); goto err_ubufs; @@ -953,7 +955,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) mutex_unlock(&vq->mutex); if (oldubufs) { - vhost_ubuf_put_and_wait(oldubufs); + vhost_net_ubuf_put_and_wait(oldubufs); mutex_lock(&vq->mutex); vhost_zerocopy_signal_used(n, vq); mutex_unlock(&vq->mutex); @@ -971,7 +973,7 @@ err_used: rcu_assign_pointer(vq->private_data, oldsock); vhost_net_enable_vq(n, vq); if (ubufs) - vhost_ubuf_put_and_wait(ubufs); + vhost_net_ubuf_put_and_wait(ubufs); err_ubufs: fput(sock->file); err_vq: @@ -1133,7 +1135,7 @@ static struct miscdevice vhost_net_misc = { static int vhost_net_init(void) { if (experimental_zcopytx) - vhost_enable_zcopy(VHOST_NET_VQ_TX); + vhost_net_enable_zcopy(VHOST_NET_VQ_TX); return misc_register(&vhost_net_misc); } module_init(vhost_net_init); From 7542a6b0d273ba4338028d39bc0e6e8cbfc68898 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 6 May 2013 13:29:36 +0300 Subject: [PATCH 7/8] vhost: drop virtio_net.h dependency There's no net specific code in vhost.c anymore, don't include the virtio_net.h header. Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index de9441a1b158..beee7f5787e6 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -13,7 +13,7 @@ #include #include -#include +#include /* memcpy_fromiovec */ #include #include #include From a18cc421649dfdc21edb6c4c867dd05447d7df8c Mon Sep 17 00:00:00 2001 From: Asias He Date: Tue, 7 May 2013 14:51:49 +0800 Subject: [PATCH 8/8] vhost-scsi: Enable VIRTIO_RING_F_EVENT_IDX It was disabled as a workaround. Now userspace bits work fine with it. The broken version was not ever committed to QEMU, I guess the same is true for nlkt. So, let's enable it. Signed-off-by: Asias He Acked-by: Paolo Bonzini Signed-off-by: Michael S. Tsirkin --- drivers/vhost/scsi.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 5179f7aa1b0b..701420297225 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -162,14 +162,8 @@ enum { VHOST_SCSI_VQ_IO = 2, }; -/* - * VIRTIO_RING_F_EVENT_IDX seems broken. Not sure the bug is in - * kernel but disabling it helps. - * TODO: debug and remove the workaround. - */ enum { - VHOST_SCSI_FEATURES = (VHOST_FEATURES & (~VIRTIO_RING_F_EVENT_IDX)) | - (1ULL << VIRTIO_SCSI_F_HOTPLUG) + VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG) }; #define VHOST_SCSI_MAX_TARGET 256