tools/virtio: Add --reset
authorEugenio Pérez <eperezma@redhat.com>
Sat, 18 Apr 2020 10:22:13 +0000 (12:22 +0200)
committerMichael S. Tsirkin <mst@redhat.com>
Mon, 22 Jun 2020 16:34:21 +0000 (12:34 -0400)
Currently, it only removes and add backend, but it will reset vq
position in future commits.

Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
Link: https://lore.kernel.org/r/20200418102217.32327-5-eperezma@redhat.com
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
drivers/vhost/test.c
drivers/vhost/test.h
tools/virtio/virtio_test.c

index 0466921..a09dedc 100644 (file)
@@ -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))
index 7dd265b..822bc4b 100644 (file)
@@ -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
index 4a2b9d1..6bc3e17 100644 (file)
@@ -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;
@@ -271,6 +289,11 @@ const struct option longopts[] = {
                .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;
 }