^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #define _GNU_SOURCE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <getopt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <limits.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <poll.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <sys/eventfd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <assert.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <sys/ioctl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <sys/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <sys/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <fcntl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <stdbool.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/virtio_types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/vhost.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/virtio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/virtio_ring.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "../../drivers/vhost/test.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define RANDOM_BATCH -1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /* Unused */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct vq_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) int kick;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) int call;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) int num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) void *ring;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /* copy used for control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct vring vring;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct virtqueue *vq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct vdev_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct virtio_device vdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct pollfd fds[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct vq_info vqs[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) int nvqs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) void *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) size_t buf_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) struct vhost_memory *mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static const struct vhost_vring_file no_backend = { .fd = -1 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) backend = { .fd = 1 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static const struct vhost_vring_state null_state = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) bool vq_notify(struct virtqueue *vq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct vq_info *info = vq->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) unsigned long long v = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) r = write(info->kick, &v, sizeof v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) assert(r == sizeof v);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) void vq_callback(struct virtqueue *vq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) void vhost_vq_setup(struct vdev_info *dev, struct vq_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct vhost_vring_state state = { .index = info->idx };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct vhost_vring_file file = { .index = info->idx };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) unsigned long long features = dev->vdev.features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct vhost_vring_addr addr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) .index = info->idx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) .desc_user_addr = (uint64_t)(unsigned long)info->vring.desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) .avail_user_addr = (uint64_t)(unsigned long)info->vring.avail,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) .used_user_addr = (uint64_t)(unsigned long)info->vring.used,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) r = ioctl(dev->control, VHOST_SET_FEATURES, &features);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) state.num = info->vring.num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) r = ioctl(dev->control, VHOST_SET_VRING_NUM, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) state.num = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) r = ioctl(dev->control, VHOST_SET_VRING_BASE, &state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) r = ioctl(dev->control, VHOST_SET_VRING_ADDR, &addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) file.fd = info->kick;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) r = ioctl(dev->control, VHOST_SET_VRING_KICK, &file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) file.fd = info->call;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) r = ioctl(dev->control, VHOST_SET_VRING_CALL, &file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static void vq_reset(struct vq_info *info, int num, struct virtio_device *vdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (info->vq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) vring_del_virtqueue(info->vq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) memset(info->ring, 0, vring_size(num, 4096));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) vring_init(&info->vring, num, info->ring, 4096);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) info->vq = __vring_new_virtqueue(info->idx, info->vring, vdev, true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) false, vq_notify, vq_callback, "test");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) assert(info->vq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) info->vq->priv = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static void vq_info_add(struct vdev_info *dev, int num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct vq_info *info = &dev->vqs[dev->nvqs];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) info->idx = dev->nvqs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) info->kick = eventfd(0, EFD_NONBLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) info->call = eventfd(0, EFD_NONBLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) r = posix_memalign(&info->ring, 4096, vring_size(num, 4096));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) vq_reset(info, num, &dev->vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) vhost_vq_setup(dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) dev->fds[info->idx].fd = info->call;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) dev->fds[info->idx].events = POLLIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) dev->nvqs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) static void vdev_info_init(struct vdev_info* dev, unsigned long long features)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) memset(dev, 0, sizeof *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) dev->vdev.features = features;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) INIT_LIST_HEAD(&dev->vdev.vqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) spin_lock_init(&dev->vdev.vqs_list_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) dev->buf_size = 1024;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) dev->buf = malloc(dev->buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) assert(dev->buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) dev->control = open("/dev/vhost-test", O_RDWR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) assert(dev->control >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) r = ioctl(dev->control, VHOST_SET_OWNER, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) dev->mem = malloc(offsetof(struct vhost_memory, regions) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) sizeof dev->mem->regions[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) assert(dev->mem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) memset(dev->mem, 0, offsetof(struct vhost_memory, regions) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) sizeof dev->mem->regions[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) dev->mem->nregions = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) dev->mem->regions[0].guest_phys_addr = (long)dev->buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) dev->mem->regions[0].userspace_addr = (long)dev->buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) dev->mem->regions[0].memory_size = dev->buf_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) r = ioctl(dev->control, VHOST_SET_MEM_TABLE, dev->mem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* TODO: this is pretty bad: we get a cache line bounce
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * for the wait queue on poll and another one on read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * plus the read which is there just to clear the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * current state. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static void wait_for_interrupt(struct vdev_info *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) unsigned long long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) poll(dev->fds, dev->nvqs, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) for (i = 0; i < dev->nvqs; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (dev->fds[i].revents & POLLIN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) read(dev->fds[i].fd, &val, sizeof val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static void run_test(struct vdev_info *dev, struct vq_info *vq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) bool delayed, int batch, int reset_n, int bufs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) struct scatterlist sl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) long started = 0, completed = 0, next_reset = reset_n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) long completed_before, started_before;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) int r, test = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) unsigned len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) long long spurious = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) const bool random_batch = batch == RANDOM_BATCH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) r = ioctl(dev->control, VHOST_TEST_RUN, &test);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) if (!reset_n) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) next_reset = INT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) virtqueue_disable_cb(vq->vq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) completed_before = completed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) started_before = started;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) const bool reset = completed > next_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (random_batch)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) batch = (random() % vq->vring.num) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) while (started < bufs &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) (started - completed) < batch) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) sg_init_one(&sl, dev->buf, dev->buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) r = virtqueue_add_outbuf(vq->vq, &sl, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) dev->buf + started,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) if (unlikely(r != 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (r == -ENOSPC &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) started > started_before)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) r = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) ++started;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (unlikely(!virtqueue_kick(vq->vq))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) r = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (started >= bufs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) r = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (reset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) r = ioctl(dev->control, VHOST_TEST_SET_BACKEND,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) &no_backend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) assert(!r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) /* Flush out completed bufs if any */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) while (virtqueue_get_buf(vq->vq, &len)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) ++completed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (reset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) struct vhost_vring_state s = { .index = 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) vq_reset(vq, vq->vring.num, &dev->vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) r = ioctl(dev->control, VHOST_GET_VRING_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) &s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) assert(!r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) s.num = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) r = ioctl(dev->control, VHOST_SET_VRING_BASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) &null_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) assert(!r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) r = ioctl(dev->control, VHOST_TEST_SET_BACKEND,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) &backend);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) assert(!r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) started = completed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) while (completed > next_reset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) next_reset += completed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) } while (r == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (completed == completed_before && started == started_before)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) ++spurious;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) assert(completed <= bufs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) assert(started <= bufs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (completed == bufs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (delayed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (virtqueue_enable_cb_delayed(vq->vq))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) wait_for_interrupt(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (virtqueue_enable_cb(vq->vq))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) wait_for_interrupt(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) test = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) r = ioctl(dev->control, VHOST_TEST_RUN, &test);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) assert(r >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) fprintf(stderr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) "spurious wakeups: 0x%llx started=0x%lx completed=0x%lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) spurious, started, completed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) const char optstring[] = "h";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) const struct option longopts[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) .name = "help",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) .val = 'h',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) .name = "event-idx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) .val = 'E',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) .name = "no-event-idx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) .val = 'e',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) .name = "indirect",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) .val = 'I',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) .name = "no-indirect",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) .val = 'i',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) .name = "virtio-1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) .val = '1',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) .name = "no-virtio-1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) .val = '0',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) .name = "delayed-interrupt",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) .val = 'D',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) .name = "no-delayed-interrupt",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) .val = 'd',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) .name = "batch",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) .val = 'b',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .has_arg = required_argument,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) .name = "reset",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) .val = 'r',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) .has_arg = optional_argument,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) static void help(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) fprintf(stderr, "Usage: virtio_test [--help]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) " [--no-indirect]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) " [--no-event-idx]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) " [--no-virtio-1]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) " [--delayed-interrupt]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) " [--batch=random/N]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) " [--reset=N]"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) int main(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) struct vdev_info dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) (1ULL << VIRTIO_RING_F_EVENT_IDX) | (1ULL << VIRTIO_F_VERSION_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) long batch = 1, reset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) int o;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) bool delayed = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) o = getopt_long(argc, argv, optstring, longopts, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) switch (o) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) case -1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) case '?':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) help();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) exit(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) case 'e':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) features &= ~(1ULL << VIRTIO_RING_F_EVENT_IDX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) case 'h':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) help();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) case 'i':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) features &= ~(1ULL << VIRTIO_RING_F_INDIRECT_DESC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) case '0':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) features &= ~(1ULL << VIRTIO_F_VERSION_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) case 'D':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) delayed = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) case 'b':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) if (0 == strcmp(optarg, "random")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) batch = RANDOM_BATCH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) batch = strtol(optarg, NULL, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) assert(batch > 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) assert(batch < (long)INT_MAX + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) case 'r':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if (!optarg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) reset = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) reset = strtol(optarg, NULL, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) assert(reset > 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) assert(reset < (long)INT_MAX + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) assert(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) vdev_info_init(&dev, features);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) vq_info_add(&dev, 256);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) run_test(&dev, &dev.vqs[0], delayed, batch, reset, 0x100000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }