tools/virtio: Add --reset

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>
This commit is contained in:
Eugenio Pérez 2020-04-18 12:22:13 +02:00 committed by Michael S. Tsirkin
parent 7add78b2a6
commit 264ee5aa81
3 changed files with 95 additions and 4 deletions

View File

@ -263,9 +263,62 @@ static int vhost_test_set_features(struct vhost_test *n, u64 features)
return 0; 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, static long vhost_test_ioctl(struct file *f, unsigned int ioctl,
unsigned long arg) unsigned long arg)
{ {
struct vhost_vring_file backend;
struct vhost_test *n = f->private_data; struct vhost_test *n = f->private_data;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
u64 __user *featurep = argp; 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)) if (copy_from_user(&test, argp, sizeof test))
return -EFAULT; return -EFAULT;
return vhost_test_run(n, test); 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: case VHOST_GET_FEATURES:
features = VHOST_FEATURES; features = VHOST_FEATURES;
if (copy_to_user(featurep, &features, sizeof features)) if (copy_to_user(featurep, &features, sizeof features))

View File

@ -4,5 +4,6 @@
/* Start a given test on the virtio null device. 0 stops all tests. */ /* 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_RUN _IOW(VHOST_VIRTIO, 0x31, int)
#define VHOST_TEST_SET_BACKEND _IOW(VHOST_VIRTIO, 0x32, int)
#endif #endif

View File

@ -46,6 +46,9 @@ struct vdev_info {
struct vhost_memory *mem; struct vhost_memory *mem;
}; };
static const struct vhost_vring_file no_backend = { .fd = -1 },
backend = { .fd = 1 };
bool vq_notify(struct virtqueue *vq) bool vq_notify(struct virtqueue *vq)
{ {
struct vq_info *info = vq->priv; 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, 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; struct scatterlist sl;
long started = 0, completed = 0; long started = 0, completed = 0, next_reset = reset_n;
long completed_before, started_before; long completed_before, started_before;
int r, test = 1; int r, test = 1;
unsigned len; unsigned len;
@ -171,6 +174,7 @@ static void run_test(struct vdev_info *dev, struct vq_info *vq,
completed_before = completed; completed_before = completed;
started_before = started; started_before = started;
do { do {
const bool reset = reset_n && completed > next_reset;
if (random_batch) if (random_batch)
batch = (random() % vq->vring.num) + 1; 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) if (started >= bufs)
r = -1; r = -1;
if (reset) {
r = ioctl(dev->control, VHOST_TEST_SET_BACKEND,
&no_backend);
assert(!r);
}
/* Flush out completed bufs if any */ /* Flush out completed bufs if any */
while (virtqueue_get_buf(vq->vq, &len)) { while (virtqueue_get_buf(vq->vq, &len)) {
++completed; ++completed;
r = 0; 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); } while (r == 0);
if (completed == completed_before && started == started_before) if (completed == completed_before && started == started_before)
++spurious; ++spurious;
@ -270,6 +288,11 @@ const struct option longopts[] = {
.val = 'b', .val = 'b',
.has_arg = required_argument, .has_arg = required_argument,
}, },
{
.name = "reset",
.val = 'r',
.has_arg = optional_argument,
},
{ {
} }
}; };
@ -282,6 +305,7 @@ static void help(void)
" [--no-virtio-1]" " [--no-virtio-1]"
" [--delayed-interrupt]" " [--delayed-interrupt]"
" [--batch=random/N]" " [--batch=random/N]"
" [--reset=N]"
"\n"); "\n");
} }
@ -290,7 +314,7 @@ int main(int argc, char **argv)
struct vdev_info dev; struct vdev_info dev;
unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) | unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
(1ULL << VIRTIO_RING_F_EVENT_IDX) | (1ULL << VIRTIO_F_VERSION_1); (1ULL << VIRTIO_RING_F_EVENT_IDX) | (1ULL << VIRTIO_F_VERSION_1);
long batch = 1; long batch = 1, reset = 0;
int o; int o;
bool delayed = false; bool delayed = false;
@ -326,6 +350,15 @@ int main(int argc, char **argv)
assert(batch < (long)INT_MAX + 1); assert(batch < (long)INT_MAX + 1);
} }
break; break;
case 'r':
if (!optarg) {
reset = 1;
} else {
reset = strtol(optarg, NULL, 10);
assert(reset > 0);
assert(reset < (long)INT_MAX + 1);
}
break;
default: default:
assert(0); assert(0);
break; break;
@ -335,6 +368,6 @@ int main(int argc, char **argv)
done: done:
vdev_info_init(&dev, features); vdev_info_init(&dev, features);
vq_info_add(&dev, 256); 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; return 0;
} }