Commit eac84105 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost

Pull more vhost fixes from Michael Tsirkin:
 "This fixes some minor issues in the patches that have been merged.

  We also finally drop the workaround disabling event_idx for scsi: it
  was always questionable, and now we know it's not needed.

  There's also a memory leak fix"

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost:
  vhost-scsi: Enable VIRTIO_RING_F_EVENT_IDX
  vhost: drop virtio_net.h dependency
  vhost-net: Cleanup vhost_ubuf and vhost_zcopy
  vhost: Remove vhost_enable_zcopy in vhost.h
  vhost: Remove comments for hdr in vhost.h
  vhost: Move VHOST_NET_FEATURES to net.c
  vhost-net: Free ubuf when vhost_dev_set_owner fails
  vhost: Export vhost_dev_set_owner
parents a26ea93a a18cc421
...@@ -58,13 +58,19 @@ MODULE_PARM_DESC(experimental_zcopytx, "Enable Zero Copy TX;" ...@@ -58,13 +58,19 @@ MODULE_PARM_DESC(experimental_zcopytx, "Enable Zero Copy TX;"
#define VHOST_DMA_IS_DONE(len) ((len) >= VHOST_DMA_DONE_LEN) #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 { enum {
VHOST_NET_VQ_RX = 0, VHOST_NET_VQ_RX = 0,
VHOST_NET_VQ_TX = 1, VHOST_NET_VQ_TX = 1,
VHOST_NET_VQ_MAX = 2, VHOST_NET_VQ_MAX = 2,
}; };
struct vhost_ubuf_ref { struct vhost_net_ubuf_ref {
struct kref kref; struct kref kref;
wait_queue_head_t wait; wait_queue_head_t wait;
struct vhost_virtqueue *vq; struct vhost_virtqueue *vq;
...@@ -87,7 +93,7 @@ struct vhost_net_virtqueue { ...@@ -87,7 +93,7 @@ struct vhost_net_virtqueue {
struct ubuf_info *ubuf_info; struct ubuf_info *ubuf_info;
/* Reference counting for outstanding ubufs. /* Reference counting for outstanding ubufs.
* Protected by vq mutex. Writers must also take device mutex. */ * Protected by vq mutex. Writers must also take device mutex. */
struct vhost_ubuf_ref *ubufs; struct vhost_net_ubuf_ref *ubufs;
}; };
struct vhost_net { struct vhost_net {
...@@ -104,24 +110,25 @@ struct vhost_net { ...@@ -104,24 +110,25 @@ struct vhost_net {
bool tx_flush; 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, struct vhost_net_ubuf_ref *ubufs;
kref);
ubufs = container_of(kref, struct vhost_net_ubuf_ref, kref);
wake_up(&ubufs->wait); wake_up(&ubufs->wait);
} }
struct vhost_ubuf_ref *vhost_ubuf_alloc(struct vhost_virtqueue *vq, static struct vhost_net_ubuf_ref *
bool zcopy) 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. */ /* No zero copy backend? Nothing to count. */
if (!zcopy) if (!zcopy)
return NULL; return NULL;
...@@ -134,25 +141,38 @@ struct vhost_ubuf_ref *vhost_ubuf_alloc(struct vhost_virtqueue *vq, ...@@ -134,25 +141,38 @@ struct vhost_ubuf_ref *vhost_ubuf_alloc(struct vhost_virtqueue *vq,
return ubufs; 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)); wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount));
kfree(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_net_zcopy_mask & (0x1 << i);
if (zcopy)
kfree(n->vqs[i].ubuf_info);
}
}
int vhost_net_set_ubuf_info(struct vhost_net *n) int vhost_net_set_ubuf_info(struct vhost_net *n)
{ {
bool zcopy; bool zcopy;
int i; int i;
for (i = 0; i < n->dev.nvqs; ++i) { for (i = 0; i < n->dev.nvqs; ++i) {
zcopy = vhost_zcopy_mask & (0x1 << i); zcopy = vhost_net_zcopy_mask & (0x1 << i);
if (!zcopy) if (!zcopy)
continue; continue;
n->vqs[i].ubuf_info = kmalloc(sizeof(*n->vqs[i].ubuf_info) * n->vqs[i].ubuf_info = kmalloc(sizeof(*n->vqs[i].ubuf_info) *
...@@ -164,7 +184,7 @@ int vhost_net_set_ubuf_info(struct vhost_net *n) ...@@ -164,7 +184,7 @@ int vhost_net_set_ubuf_info(struct vhost_net *n)
err: err:
while (i--) { while (i--) {
zcopy = vhost_zcopy_mask & (0x1 << i); zcopy = vhost_net_zcopy_mask & (0x1 << i);
if (!zcopy) if (!zcopy)
continue; continue;
kfree(n->vqs[i].ubuf_info); kfree(n->vqs[i].ubuf_info);
...@@ -286,7 +306,7 @@ static int vhost_zerocopy_signal_used(struct vhost_net *net, ...@@ -286,7 +306,7 @@ static int vhost_zerocopy_signal_used(struct vhost_net *net,
static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success) 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; struct vhost_virtqueue *vq = ubufs->vq;
int cnt = atomic_read(&ubufs->kref.refcount); int cnt = atomic_read(&ubufs->kref.refcount);
...@@ -303,7 +323,7 @@ static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success) ...@@ -303,7 +323,7 @@ static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success)
/* set len to mark this desc buffers done DMA */ /* set len to mark this desc buffers done DMA */
vq->heads[ubuf->desc].len = success ? vq->heads[ubuf->desc].len = success ?
VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN; 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 /* Expects to be always run from workqueue - which acts as
...@@ -326,7 +346,7 @@ static void handle_tx(struct vhost_net *net) ...@@ -326,7 +346,7 @@ static void handle_tx(struct vhost_net *net)
int err; int err;
size_t hdr_size; size_t hdr_size;
struct socket *sock; struct socket *sock;
struct vhost_ubuf_ref *uninitialized_var(ubufs); struct vhost_net_ubuf_ref *uninitialized_var(ubufs);
bool zcopy, zcopy_used; bool zcopy, zcopy_used;
/* TODO: check that we are running from vhost_worker? */ /* TODO: check that we are running from vhost_worker? */
...@@ -422,7 +442,7 @@ static void handle_tx(struct vhost_net *net) ...@@ -422,7 +442,7 @@ static void handle_tx(struct vhost_net *net)
if (unlikely(err < 0)) { if (unlikely(err < 0)) {
if (zcopy_used) { if (zcopy_used) {
if (ubufs) if (ubufs)
vhost_ubuf_put(ubufs); vhost_net_ubuf_put(ubufs);
nvq->upend_idx = ((unsigned)nvq->upend_idx - 1) nvq->upend_idx = ((unsigned)nvq->upend_idx - 1)
% UIO_MAXIOV; % UIO_MAXIOV;
} }
...@@ -776,7 +796,7 @@ static void vhost_net_flush(struct vhost_net *n) ...@@ -776,7 +796,7 @@ static void vhost_net_flush(struct vhost_net *n)
n->tx_flush = true; n->tx_flush = true;
mutex_unlock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex); mutex_unlock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex);
/* Wait for all lower device DMAs done. */ /* 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); mutex_lock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex);
n->tx_flush = false; n->tx_flush = false;
kref_init(&n->vqs[VHOST_NET_VQ_TX].ubufs->kref); kref_init(&n->vqs[VHOST_NET_VQ_TX].ubufs->kref);
...@@ -877,7 +897,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) ...@@ -877,7 +897,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
struct socket *sock, *oldsock; struct socket *sock, *oldsock;
struct vhost_virtqueue *vq; struct vhost_virtqueue *vq;
struct vhost_net_virtqueue *nvq; struct vhost_net_virtqueue *nvq;
struct vhost_ubuf_ref *ubufs, *oldubufs = NULL; struct vhost_net_ubuf_ref *ubufs, *oldubufs = NULL;
int r; int r;
mutex_lock(&n->dev.mutex); mutex_lock(&n->dev.mutex);
...@@ -908,7 +928,8 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) ...@@ -908,7 +928,8 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
oldsock = rcu_dereference_protected(vq->private_data, oldsock = rcu_dereference_protected(vq->private_data,
lockdep_is_held(&vq->mutex)); lockdep_is_held(&vq->mutex));
if (sock != oldsock) { 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)) { if (IS_ERR(ubufs)) {
r = PTR_ERR(ubufs); r = PTR_ERR(ubufs);
goto err_ubufs; goto err_ubufs;
...@@ -934,7 +955,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) ...@@ -934,7 +955,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
mutex_unlock(&vq->mutex); mutex_unlock(&vq->mutex);
if (oldubufs) { if (oldubufs) {
vhost_ubuf_put_and_wait(oldubufs); vhost_net_ubuf_put_and_wait(oldubufs);
mutex_lock(&vq->mutex); mutex_lock(&vq->mutex);
vhost_zerocopy_signal_used(n, vq); vhost_zerocopy_signal_used(n, vq);
mutex_unlock(&vq->mutex); mutex_unlock(&vq->mutex);
...@@ -952,7 +973,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) ...@@ -952,7 +973,7 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
rcu_assign_pointer(vq->private_data, oldsock); rcu_assign_pointer(vq->private_data, oldsock);
vhost_net_enable_vq(n, vq); vhost_net_enable_vq(n, vq);
if (ubufs) if (ubufs)
vhost_ubuf_put_and_wait(ubufs); vhost_net_ubuf_put_and_wait(ubufs);
err_ubufs: err_ubufs:
fput(sock->file); fput(sock->file);
err_vq: err_vq:
...@@ -1027,6 +1048,23 @@ static int vhost_net_set_features(struct vhost_net *n, u64 features) ...@@ -1027,6 +1048,23 @@ static int vhost_net_set_features(struct vhost_net *n, u64 features)
return 0; 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, static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
unsigned long arg) unsigned long arg)
{ {
...@@ -1055,19 +1093,15 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl, ...@@ -1055,19 +1093,15 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
return vhost_net_set_features(n, features); return vhost_net_set_features(n, features);
case VHOST_RESET_OWNER: case VHOST_RESET_OWNER:
return vhost_net_reset_owner(n); return vhost_net_reset_owner(n);
case VHOST_SET_OWNER:
return vhost_net_set_owner(n);
default: default:
mutex_lock(&n->dev.mutex); 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); r = vhost_dev_ioctl(&n->dev, ioctl, argp);
if (r == -ENOIOCTLCMD) if (r == -ENOIOCTLCMD)
r = vhost_vring_ioctl(&n->dev, ioctl, argp); r = vhost_vring_ioctl(&n->dev, ioctl, argp);
else else
vhost_net_flush(n); vhost_net_flush(n);
out:
mutex_unlock(&n->dev.mutex); mutex_unlock(&n->dev.mutex);
return r; return r;
} }
...@@ -1101,7 +1135,7 @@ static struct miscdevice vhost_net_misc = { ...@@ -1101,7 +1135,7 @@ static struct miscdevice vhost_net_misc = {
static int vhost_net_init(void) static int vhost_net_init(void)
{ {
if (experimental_zcopytx) if (experimental_zcopytx)
vhost_enable_zcopy(VHOST_NET_VQ_TX); vhost_net_enable_zcopy(VHOST_NET_VQ_TX);
return misc_register(&vhost_net_misc); return misc_register(&vhost_net_misc);
} }
module_init(vhost_net_init); module_init(vhost_net_init);
......
...@@ -162,14 +162,8 @@ enum { ...@@ -162,14 +162,8 @@ enum {
VHOST_SCSI_VQ_IO = 2, 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 { enum {
VHOST_SCSI_FEATURES = (VHOST_FEATURES & (~VIRTIO_RING_F_EVENT_IDX)) | VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG)
(1ULL << VIRTIO_SCSI_F_HOTPLUG)
}; };
#define VHOST_SCSI_MAX_TARGET 256 #define VHOST_SCSI_MAX_TARGET 256
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <linux/eventfd.h> #include <linux/eventfd.h>
#include <linux/vhost.h> #include <linux/vhost.h>
#include <linux/virtio_net.h> #include <linux/socket.h> /* memcpy_fromiovec */
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/mmu_context.h> #include <linux/mmu_context.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
...@@ -344,7 +344,7 @@ static int vhost_attach_cgroups(struct vhost_dev *dev) ...@@ -344,7 +344,7 @@ static int vhost_attach_cgroups(struct vhost_dev *dev)
} }
/* Caller should have device mutex */ /* 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; struct task_struct *worker;
int err; int err;
......
...@@ -99,9 +99,6 @@ struct vhost_virtqueue { ...@@ -99,9 +99,6 @@ struct vhost_virtqueue {
u64 log_addr; u64 log_addr;
struct iovec iov[UIO_MAXIOV]; 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 iovec *indirect;
struct vring_used_elem *heads; struct vring_used_elem *heads;
/* We use a kind of RCU to access private pointer. /* We use a kind of RCU to access private pointer.
...@@ -135,6 +132,7 @@ struct vhost_dev { ...@@ -135,6 +132,7 @@ struct vhost_dev {
}; };
long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs, int nvqs); 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 *); long vhost_dev_check_owner(struct vhost_dev *);
struct vhost_memory *vhost_dev_reset_owner_prepare(void); struct vhost_memory *vhost_dev_reset_owner_prepare(void);
void vhost_dev_reset_owner(struct vhost_dev *, struct vhost_memory *); void vhost_dev_reset_owner(struct vhost_dev *, struct vhost_memory *);
...@@ -177,9 +175,6 @@ enum { ...@@ -177,9 +175,6 @@ enum {
(1ULL << VIRTIO_RING_F_INDIRECT_DESC) | (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
(1ULL << VIRTIO_RING_F_EVENT_IDX) | (1ULL << VIRTIO_RING_F_EVENT_IDX) |
(1ULL << VHOST_F_LOG_ALL), (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) static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
...@@ -191,7 +186,4 @@ static inline int vhost_has_feature(struct vhost_dev *dev, int bit) ...@@ -191,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); acked_features = rcu_dereference_index_check(dev->acked_features, 1);
return acked_features & (1 << bit); return acked_features & (1 << bit);
} }
void vhost_enable_zcopy(int vq);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment