From 633fae33d562dc2538cc3d6033a2d5e277050783 Mon Sep 17 00:00:00 2001 From: Eugenio Pérez Date: Sat, 18 Apr 2020 12:22:11 +0200 Subject: tools/virtio: Add --batch option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allow to test vhost having >1 buffers in flight Signed-off-by: Eugenio Pérez Link: https://lore.kernel.org/r/20200401183118.8334-5-eperezma@redhat.com Signed-off-by: Michael S. Tsirkin Link: https://lore.kernel.org/r/20200418102217.32327-3-eperezma@redhat.com Signed-off-by: Michael S. Tsirkin --- tools/virtio/virtio_test.c | 47 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) (limited to 'tools') diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index b427def67e7e..c30de9088f3c 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #define _GNU_SOURCE #include +#include #include #include #include @@ -152,11 +153,11 @@ static void wait_for_interrupt(struct vdev_info *dev) } static void run_test(struct vdev_info *dev, struct vq_info *vq, - bool delayed, int bufs) + bool delayed, int batch, int bufs) { struct scatterlist sl; long started = 0, completed = 0; - long completed_before; + long completed_before, started_before; int r, test = 1; unsigned len; long long spurious = 0; @@ -165,28 +166,42 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, for (;;) { virtqueue_disable_cb(vq->vq); completed_before = completed; + started_before = started; do { - if (started < bufs) { + while (started < bufs && + (started - completed) < batch) { sg_init_one(&sl, dev->buf, dev->buf_size); r = virtqueue_add_outbuf(vq->vq, &sl, 1, dev->buf + started, GFP_ATOMIC); - if (likely(r == 0)) { - ++started; - if (unlikely(!virtqueue_kick(vq->vq))) + if (unlikely(r != 0)) { + if (r == -ENOSPC && + started > started_before) + r = 0; + else r = -1; + break; } - } else + + ++started; + + if (unlikely(!virtqueue_kick(vq->vq))) { + r = -1; + break; + } + } + + if (started >= bufs) r = -1; /* Flush out completed bufs if any */ - if (virtqueue_get_buf(vq->vq, &len)) { + while (virtqueue_get_buf(vq->vq, &len)) { ++completed; r = 0; } } while (r == 0); - if (completed == completed_before) + if (completed == completed_before && started == started_before) ++spurious; assert(completed <= bufs); assert(started <= bufs); @@ -244,6 +259,11 @@ const struct option longopts[] = { .name = "no-delayed-interrupt", .val = 'd', }, + { + .name = "batch", + .val = 'b', + .has_arg = required_argument, + }, { } }; @@ -255,6 +275,7 @@ static void help(void) " [--no-event-idx]" " [--no-virtio-1]" " [--delayed-interrupt]" + " [--batch=N]" "\n"); } @@ -263,6 +284,7 @@ int main(int argc, char **argv) struct vdev_info dev; unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) | (1ULL << VIRTIO_RING_F_EVENT_IDX) | (1ULL << VIRTIO_F_VERSION_1); + long batch = 1; int o; bool delayed = false; @@ -289,6 +311,11 @@ int main(int argc, char **argv) case 'D': delayed = true; break; + case 'b': + batch = strtol(optarg, NULL, 10); + assert(batch > 0); + assert(batch < (long)INT_MAX + 1); + break; default: assert(0); break; @@ -298,6 +325,6 @@ int main(int argc, char **argv) done: vdev_info_init(&dev, features); vq_info_add(&dev, 256); - run_test(&dev, &dev.vqs[0], delayed, 0x100000); + run_test(&dev, &dev.vqs[0], delayed, batch, 0x100000); return 0; } -- cgit v1.2.3 From 7add78b2a6b76d98fcf35e981c5f84b3c91459f5 Mon Sep 17 00:00:00 2001 From: Eugenio Pérez Date: Sat, 18 Apr 2020 12:22:12 +0200 Subject: tools/virtio: Add --batch=random option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So we can test with non-deterministic batches in flight. Signed-off-by: Eugenio Pérez Link: https://lore.kernel.org/r/20200418102217.32327-4-eperezma@redhat.com Signed-off-by: Michael S. Tsirkin --- tools/virtio/virtio_test.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index c30de9088f3c..4a2b9d11f287 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -19,6 +19,8 @@ #include #include "../../drivers/vhost/test.h" +#define RANDOM_BATCH -1 + /* Unused */ void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end; @@ -161,6 +163,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, int r, test = 1; unsigned len; long long spurious = 0; + const bool random_batch = batch == RANDOM_BATCH; r = ioctl(dev->control, VHOST_TEST_RUN, &test); assert(r >= 0); for (;;) { @@ -168,6 +171,9 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, completed_before = completed; started_before = started; do { + if (random_batch) + batch = (random() % vq->vring.num) + 1; + while (started < bufs && (started - completed) < batch) { sg_init_one(&sl, dev->buf, dev->buf_size); @@ -275,7 +281,7 @@ static void help(void) " [--no-event-idx]" " [--no-virtio-1]" " [--delayed-interrupt]" - " [--batch=N]" + " [--batch=random/N]" "\n"); } @@ -312,9 +318,13 @@ int main(int argc, char **argv) delayed = true; break; case 'b': - batch = strtol(optarg, NULL, 10); - assert(batch > 0); - assert(batch < (long)INT_MAX + 1); + if (0 == strcmp(optarg, "random")) { + batch = RANDOM_BATCH; + } else { + batch = strtol(optarg, NULL, 10); + assert(batch > 0); + assert(batch < (long)INT_MAX + 1); + } break; default: assert(0); -- cgit v1.2.3 From 264ee5aa81ec87eebfb0e2fb70cc0a38df80bab2 Mon Sep 17 00:00:00 2001 From: Eugenio Pérez Date: Sat, 18 Apr 2020 12:22:13 +0200 Subject: tools/virtio: Add --reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, it only removes and add backend, but it will reset vq position in future commits. Signed-off-by: Eugenio Pérez Link: https://lore.kernel.org/r/20200418102217.32327-5-eperezma@redhat.com Signed-off-by: Michael S. Tsirkin --- drivers/vhost/test.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/vhost/test.h | 1 + tools/virtio/virtio_test.c | 41 +++++++++++++++++++++++++++++---- 3 files changed, 95 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/drivers/vhost/test.c b/drivers/vhost/test.c index 0466921f4772..a09dedc79f68 100644 --- a/drivers/vhost/test.c +++ b/drivers/vhost/test.c @@ -263,9 +263,62 @@ static int vhost_test_set_features(struct vhost_test *n, u64 features) return 0; } +static long vhost_test_set_backend(struct vhost_test *n, unsigned index, int fd) +{ + static void *backend; + + const bool enable = fd != -1; + struct vhost_virtqueue *vq; + int r; + + mutex_lock(&n->dev.mutex); + r = vhost_dev_check_owner(&n->dev); + if (r) + goto err; + + if (index >= VHOST_TEST_VQ_MAX) { + r = -ENOBUFS; + goto err; + } + vq = &n->vqs[index]; + mutex_lock(&vq->mutex); + + /* Verify that ring has been setup correctly. */ + if (!vhost_vq_access_ok(vq)) { + r = -EFAULT; + goto err_vq; + } + if (!enable) { + vhost_poll_stop(&vq->poll); + backend = vhost_vq_get_backend(vq); + vhost_vq_set_backend(vq, NULL); + } else { + vhost_vq_set_backend(vq, backend); + r = vhost_vq_init_access(vq); + if (r == 0) + r = vhost_poll_start(&vq->poll, vq->kick); + } + + mutex_unlock(&vq->mutex); + + if (enable) { + vhost_test_flush_vq(n, index); + } + + mutex_unlock(&n->dev.mutex); + return 0; + +err_vq: + mutex_unlock(&vq->mutex); +err: + mutex_unlock(&n->dev.mutex); + return r; +} + static long vhost_test_ioctl(struct file *f, unsigned int ioctl, unsigned long arg) { + struct vhost_vring_file backend; struct vhost_test *n = f->private_data; void __user *argp = (void __user *)arg; u64 __user *featurep = argp; @@ -277,6 +330,10 @@ static long vhost_test_ioctl(struct file *f, unsigned int ioctl, if (copy_from_user(&test, argp, sizeof test)) return -EFAULT; return vhost_test_run(n, test); + case VHOST_TEST_SET_BACKEND: + if (copy_from_user(&backend, argp, sizeof backend)) + return -EFAULT; + return vhost_test_set_backend(n, backend.index, backend.fd); case VHOST_GET_FEATURES: features = VHOST_FEATURES; if (copy_to_user(featurep, &features, sizeof features)) diff --git a/drivers/vhost/test.h b/drivers/vhost/test.h index 7dd265bfdf81..822bc4bee03a 100644 --- a/drivers/vhost/test.h +++ b/drivers/vhost/test.h @@ -4,5 +4,6 @@ /* Start a given test on the virtio null device. 0 stops all tests. */ #define VHOST_TEST_RUN _IOW(VHOST_VIRTIO, 0x31, int) +#define VHOST_TEST_SET_BACKEND _IOW(VHOST_VIRTIO, 0x32, int) #endif diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index 4a2b9d11f287..6bc3e172cc9b 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -46,6 +46,9 @@ struct vdev_info { struct vhost_memory *mem; }; +static const struct vhost_vring_file no_backend = { .fd = -1 }, + backend = { .fd = 1 }; + bool vq_notify(struct virtqueue *vq) { struct vq_info *info = vq->priv; @@ -155,10 +158,10 @@ static void wait_for_interrupt(struct vdev_info *dev) } static void run_test(struct vdev_info *dev, struct vq_info *vq, - bool delayed, int batch, int bufs) + bool delayed, int batch, int reset_n, int bufs) { struct scatterlist sl; - long started = 0, completed = 0; + long started = 0, completed = 0, next_reset = reset_n; long completed_before, started_before; int r, test = 1; unsigned len; @@ -171,6 +174,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, completed_before = completed; started_before = started; do { + const bool reset = reset_n && completed > next_reset; if (random_batch) batch = (random() % vq->vring.num) + 1; @@ -200,12 +204,26 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, if (started >= bufs) r = -1; + if (reset) { + r = ioctl(dev->control, VHOST_TEST_SET_BACKEND, + &no_backend); + assert(!r); + } + /* Flush out completed bufs if any */ while (virtqueue_get_buf(vq->vq, &len)) { ++completed; r = 0; } + if (reset) { + r = ioctl(dev->control, VHOST_TEST_SET_BACKEND, + &backend); + assert(!r); + + while (completed > next_reset) + next_reset += completed; + } } while (r == 0); if (completed == completed_before && started == started_before) ++spurious; @@ -270,6 +288,11 @@ const struct option longopts[] = { .val = 'b', .has_arg = required_argument, }, + { + .name = "reset", + .val = 'r', + .has_arg = optional_argument, + }, { } }; @@ -282,6 +305,7 @@ static void help(void) " [--no-virtio-1]" " [--delayed-interrupt]" " [--batch=random/N]" + " [--reset=N]" "\n"); } @@ -290,7 +314,7 @@ int main(int argc, char **argv) struct vdev_info dev; unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) | (1ULL << VIRTIO_RING_F_EVENT_IDX) | (1ULL << VIRTIO_F_VERSION_1); - long batch = 1; + long batch = 1, reset = 0; int o; bool delayed = false; @@ -326,6 +350,15 @@ int main(int argc, char **argv) assert(batch < (long)INT_MAX + 1); } break; + case 'r': + if (!optarg) { + reset = 1; + } else { + reset = strtol(optarg, NULL, 10); + assert(reset > 0); + assert(reset < (long)INT_MAX + 1); + } + break; default: assert(0); break; @@ -335,6 +368,6 @@ int main(int argc, char **argv) done: vdev_info_init(&dev, features); vq_info_add(&dev, 256); - run_test(&dev, &dev.vqs[0], delayed, batch, 0x100000); + run_test(&dev, &dev.vqs[0], delayed, batch, reset, 0x100000); return 0; } -- cgit v1.2.3 From 4cfb93935337d8f9680d865b0987583e462cfcc7 Mon Sep 17 00:00:00 2001 From: Eugenio Pérez Date: Sat, 18 Apr 2020 12:22:14 +0200 Subject: tools/virtio: Use __vring_new_virtqueue in virtio_test.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As updated in ("2a2d1382fe9d virtio: Add improved queue allocation API") Signed-off-by: Eugenio Pérez Link: https://lore.kernel.org/r/20200418102217.32327-6-eperezma@redhat.com Signed-off-by: Michael S. Tsirkin --- tools/virtio/virtio_test.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index 6bc3e172cc9b..0a247ba3b899 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -105,10 +105,9 @@ static void vq_info_add(struct vdev_info *dev, int num) assert(r >= 0); memset(info->ring, 0, vring_size(num, 4096)); vring_init(&info->vring, num, info->ring, 4096); - info->vq = vring_new_virtqueue(info->idx, - info->vring.num, 4096, &dev->vdev, - true, false, info->ring, - vq_notify, vq_callback, "test"); + info->vq = + __vring_new_virtqueue(info->idx, info->vring, &dev->vdev, true, + false, vq_notify, vq_callback, "test"); assert(info->vq); info->vq->priv = info; vhost_vq_setup(dev, info); -- cgit v1.2.3 From 6741239260293e46a32a141fb61bf2c062b0b6ed Mon Sep 17 00:00:00 2001 From: Eugenio Pérez Date: Sat, 18 Apr 2020 12:22:15 +0200 Subject: tools/virtio: Extract virtqueue initialization in vq_reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So we can reset after that in the main loop. Signed-off-by: Eugenio Pérez Link: https://lore.kernel.org/r/20200418102217.32327-7-eperezma@redhat.com Signed-off-by: Michael S. Tsirkin --- tools/virtio/virtio_test.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'tools') diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index 0a247ba3b899..bc16c818bda3 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -94,6 +94,19 @@ void vhost_vq_setup(struct vdev_info *dev, struct vq_info *info) assert(r >= 0); } +static void vq_reset(struct vq_info *info, int num, struct virtio_device *vdev) +{ + if (info->vq) + vring_del_virtqueue(info->vq); + + memset(info->ring, 0, vring_size(num, 4096)); + vring_init(&info->vring, num, info->ring, 4096); + info->vq = __vring_new_virtqueue(info->idx, info->vring, vdev, true, + false, vq_notify, vq_callback, "test"); + assert(info->vq); + info->vq->priv = info; +} + static void vq_info_add(struct vdev_info *dev, int num) { struct vq_info *info = &dev->vqs[dev->nvqs]; @@ -103,13 +116,7 @@ static void vq_info_add(struct vdev_info *dev, int num) info->call = eventfd(0, EFD_NONBLOCK); r = posix_memalign(&info->ring, 4096, vring_size(num, 4096)); assert(r >= 0); - memset(info->ring, 0, vring_size(num, 4096)); - vring_init(&info->vring, num, info->ring, 4096); - info->vq = - __vring_new_virtqueue(info->idx, info->vring, &dev->vdev, true, - false, vq_notify, vq_callback, "test"); - assert(info->vq); - info->vq->priv = info; + vq_reset(info, num, &dev->vdev); vhost_vq_setup(dev, info); dev->fds[info->idx].fd = info->call; dev->fds[info->idx].events = POLLIN; -- cgit v1.2.3 From 1d8bf5c3a3a1b90c39ccbafb3aa63ffc5196b142 Mon Sep 17 00:00:00 2001 From: Eugenio Pérez Date: Sat, 18 Apr 2020 12:22:16 +0200 Subject: tools/virtio: Reset index in virtio_test --reset. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way behavior for vhost is more like a VM. Signed-off-by: Eugenio Pérez Link: https://lore.kernel.org/r/20200418102217.32327-8-eperezma@redhat.com Signed-off-by: Michael S. Tsirkin --- tools/virtio/virtio_test.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index bc16c818bda3..82902fc3ba2a 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -48,6 +48,7 @@ struct vdev_info { static const struct vhost_vring_file no_backend = { .fd = -1 }, backend = { .fd = 1 }; +static const struct vhost_vring_state null_state = {}; bool vq_notify(struct virtqueue *vq) { @@ -173,14 +174,19 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, unsigned len; long long spurious = 0; const bool random_batch = batch == RANDOM_BATCH; + r = ioctl(dev->control, VHOST_TEST_RUN, &test); assert(r >= 0); + if (!reset_n) { + next_reset = INT_MAX; + } + for (;;) { virtqueue_disable_cb(vq->vq); completed_before = completed; started_before = started; do { - const bool reset = reset_n && completed > next_reset; + const bool reset = completed > next_reset; if (random_batch) batch = (random() % vq->vring.num) + 1; @@ -223,10 +229,24 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, } if (reset) { + struct vhost_vring_state s = { .index = 0 }; + + vq_reset(vq, vq->vring.num, &dev->vdev); + + r = ioctl(dev->control, VHOST_GET_VRING_BASE, + &s); + assert(!r); + + s.num = 0; + r = ioctl(dev->control, VHOST_SET_VRING_BASE, + &null_state); + assert(!r); + r = ioctl(dev->control, VHOST_TEST_SET_BACKEND, &backend); assert(!r); + started = completed; while (completed > next_reset) next_reset += completed; } @@ -248,7 +268,9 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq, test = 0; r = ioctl(dev->control, VHOST_TEST_RUN, &test); assert(r >= 0); - fprintf(stderr, "spurious wakeups: 0x%llx\n", spurious); + fprintf(stderr, + "spurious wakeups: 0x%llx started=0x%lx completed=0x%lx\n", + spurious, started, completed); } const char optstring[] = "h"; -- cgit v1.2.3 From cb91909e48a4809261ef4e967464e2009b214f06 Mon Sep 17 00:00:00 2001 From: Eugenio Pérez Date: Sat, 18 Apr 2020 12:22:17 +0200 Subject: tools/virtio: Use tools/include/list.h instead of stubs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It should not make any significant difference but reduce stub code. Signed-off-by: Eugenio Pérez Link: https://lore.kernel.org/r/20200418102217.32327-9-eperezma@redhat.com Signed-off-by: Michael S. Tsirkin --- tools/virtio/linux/kernel.h | 7 +------ tools/virtio/linux/virtio.h | 5 ++--- tools/virtio/virtio_test.c | 1 + tools/virtio/vringh_test.c | 2 ++ 4 files changed, 6 insertions(+), 9 deletions(-) (limited to 'tools') diff --git a/tools/virtio/linux/kernel.h b/tools/virtio/linux/kernel.h index 6683b4a70b05..caab980211a6 100644 --- a/tools/virtio/linux/kernel.h +++ b/tools/virtio/linux/kernel.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -135,10 +136,4 @@ static inline void free_page(unsigned long addr) (void) (&_min1 == &_min2); \ _min1 < _min2 ? _min1 : _min2; }) -/* TODO: empty stubs for now. Broken but enough for virtio_ring.c */ -#define list_add_tail(a, b) do {} while (0) -#define list_del(a) do {} while (0) -#define list_for_each_entry(a, b, c) while (0) -/* end of stubs */ - #endif /* KERNEL_H */ diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h index b751350d4ce8..5d90254ddae4 100644 --- a/tools/virtio/linux/virtio.h +++ b/tools/virtio/linux/virtio.h @@ -11,12 +11,11 @@ struct device { struct virtio_device { struct device dev; u64 features; + struct list_head vqs; }; struct virtqueue { - /* TODO: commented as list macros are empty stubs for now. - * Broken but enough for virtio_ring.c - * struct list_head list; */ + struct list_head list; void (*callback)(struct virtqueue *vq); const char *name; struct virtio_device *vdev; diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c index 82902fc3ba2a..cb3f29c09aff 100644 --- a/tools/virtio/virtio_test.c +++ b/tools/virtio/virtio_test.c @@ -129,6 +129,7 @@ static void vdev_info_init(struct vdev_info* dev, unsigned long long features) int r; memset(dev, 0, sizeof *dev); dev->vdev.features = features; + INIT_LIST_HEAD(&dev->vdev.vqs); dev->buf_size = 1024; dev->buf = malloc(dev->buf_size); assert(dev->buf); diff --git a/tools/virtio/vringh_test.c b/tools/virtio/vringh_test.c index 293653463303..fa87b58bd5fa 100644 --- a/tools/virtio/vringh_test.c +++ b/tools/virtio/vringh_test.c @@ -307,6 +307,7 @@ static int parallel_test(u64 features, close(to_host[0]); gvdev.vdev.features = features; + INIT_LIST_HEAD(&gvdev.vdev.vqs); gvdev.to_host_fd = to_host[1]; gvdev.notifies = 0; @@ -453,6 +454,7 @@ int main(int argc, char *argv[]) getrange = getrange_iov; vdev.features = 0; + INIT_LIST_HEAD(&vdev.vqs); while (argv[1]) { if (strcmp(argv[1], "--indirect") == 0) -- cgit v1.2.3