hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/tools/virtio/virtio_test.c
....@@ -1,6 +1,7 @@
11 // SPDX-License-Identifier: GPL-2.0
22 #define _GNU_SOURCE
33 #include <getopt.h>
4
+#include <limits.h>
45 #include <string.h>
56 #include <poll.h>
67 #include <sys/eventfd.h>
....@@ -17,6 +18,8 @@
1718 #include <linux/virtio.h>
1819 #include <linux/virtio_ring.h>
1920 #include "../../drivers/vhost/test.h"
21
+
22
+#define RANDOM_BATCH -1
2023
2124 /* Unused */
2225 void *__kmalloc_fake, *__kfree_ignore_start, *__kfree_ignore_end;
....@@ -42,6 +45,10 @@
4245 size_t buf_size;
4346 struct vhost_memory *mem;
4447 };
48
+
49
+static const struct vhost_vring_file no_backend = { .fd = -1 },
50
+ backend = { .fd = 1 };
51
+static const struct vhost_vring_state null_state = {};
4552
4653 bool vq_notify(struct virtqueue *vq)
4754 {
....@@ -88,6 +95,19 @@
8895 assert(r >= 0);
8996 }
9097
98
+static void vq_reset(struct vq_info *info, int num, struct virtio_device *vdev)
99
+{
100
+ if (info->vq)
101
+ vring_del_virtqueue(info->vq);
102
+
103
+ memset(info->ring, 0, vring_size(num, 4096));
104
+ vring_init(&info->vring, num, info->ring, 4096);
105
+ info->vq = __vring_new_virtqueue(info->idx, info->vring, vdev, true,
106
+ false, vq_notify, vq_callback, "test");
107
+ assert(info->vq);
108
+ info->vq->priv = info;
109
+}
110
+
91111 static void vq_info_add(struct vdev_info *dev, int num)
92112 {
93113 struct vq_info *info = &dev->vqs[dev->nvqs];
....@@ -97,14 +117,7 @@
97117 info->call = eventfd(0, EFD_NONBLOCK);
98118 r = posix_memalign(&info->ring, 4096, vring_size(num, 4096));
99119 assert(r >= 0);
100
- memset(info->ring, 0, vring_size(num, 4096));
101
- vring_init(&info->vring, num, info->ring, 4096);
102
- info->vq = vring_new_virtqueue(info->idx,
103
- info->vring.num, 4096, &dev->vdev,
104
- true, false, info->ring,
105
- vq_notify, vq_callback, "test");
106
- assert(info->vq);
107
- info->vq->priv = info;
120
+ vq_reset(info, num, &dev->vdev);
108121 vhost_vq_setup(dev, info);
109122 dev->fds[info->idx].fd = info->call;
110123 dev->fds[info->idx].events = POLLIN;
....@@ -116,6 +129,8 @@
116129 int r;
117130 memset(dev, 0, sizeof *dev);
118131 dev->vdev.features = features;
132
+ INIT_LIST_HEAD(&dev->vdev.vqs);
133
+ spin_lock_init(&dev->vdev.vqs_list_lock);
119134 dev->buf_size = 1024;
120135 dev->buf = malloc(dev->buf_size);
121136 assert(dev->buf);
....@@ -152,41 +167,93 @@
152167 }
153168
154169 static void run_test(struct vdev_info *dev, struct vq_info *vq,
155
- bool delayed, int bufs)
170
+ bool delayed, int batch, int reset_n, int bufs)
156171 {
157172 struct scatterlist sl;
158
- long started = 0, completed = 0;
159
- long completed_before;
173
+ long started = 0, completed = 0, next_reset = reset_n;
174
+ long completed_before, started_before;
160175 int r, test = 1;
161176 unsigned len;
162177 long long spurious = 0;
178
+ const bool random_batch = batch == RANDOM_BATCH;
179
+
163180 r = ioctl(dev->control, VHOST_TEST_RUN, &test);
164181 assert(r >= 0);
182
+ if (!reset_n) {
183
+ next_reset = INT_MAX;
184
+ }
185
+
165186 for (;;) {
166187 virtqueue_disable_cb(vq->vq);
167188 completed_before = completed;
189
+ started_before = started;
168190 do {
169
- if (started < bufs) {
191
+ const bool reset = completed > next_reset;
192
+ if (random_batch)
193
+ batch = (random() % vq->vring.num) + 1;
194
+
195
+ while (started < bufs &&
196
+ (started - completed) < batch) {
170197 sg_init_one(&sl, dev->buf, dev->buf_size);
171198 r = virtqueue_add_outbuf(vq->vq, &sl, 1,
172199 dev->buf + started,
173200 GFP_ATOMIC);
174
- if (likely(r == 0)) {
175
- ++started;
176
- if (unlikely(!virtqueue_kick(vq->vq)))
201
+ if (unlikely(r != 0)) {
202
+ if (r == -ENOSPC &&
203
+ started > started_before)
204
+ r = 0;
205
+ else
177206 r = -1;
207
+ break;
178208 }
179
- } else
209
+
210
+ ++started;
211
+
212
+ if (unlikely(!virtqueue_kick(vq->vq))) {
213
+ r = -1;
214
+ break;
215
+ }
216
+ }
217
+
218
+ if (started >= bufs)
180219 r = -1;
181220
221
+ if (reset) {
222
+ r = ioctl(dev->control, VHOST_TEST_SET_BACKEND,
223
+ &no_backend);
224
+ assert(!r);
225
+ }
226
+
182227 /* Flush out completed bufs if any */
183
- if (virtqueue_get_buf(vq->vq, &len)) {
228
+ while (virtqueue_get_buf(vq->vq, &len)) {
184229 ++completed;
185230 r = 0;
186231 }
187232
233
+ if (reset) {
234
+ struct vhost_vring_state s = { .index = 0 };
235
+
236
+ vq_reset(vq, vq->vring.num, &dev->vdev);
237
+
238
+ r = ioctl(dev->control, VHOST_GET_VRING_BASE,
239
+ &s);
240
+ assert(!r);
241
+
242
+ s.num = 0;
243
+ r = ioctl(dev->control, VHOST_SET_VRING_BASE,
244
+ &null_state);
245
+ assert(!r);
246
+
247
+ r = ioctl(dev->control, VHOST_TEST_SET_BACKEND,
248
+ &backend);
249
+ assert(!r);
250
+
251
+ started = completed;
252
+ while (completed > next_reset)
253
+ next_reset += completed;
254
+ }
188255 } while (r == 0);
189
- if (completed == completed_before)
256
+ if (completed == completed_before && started == started_before)
190257 ++spurious;
191258 assert(completed <= bufs);
192259 assert(started <= bufs);
....@@ -203,7 +270,9 @@
203270 test = 0;
204271 r = ioctl(dev->control, VHOST_TEST_RUN, &test);
205272 assert(r >= 0);
206
- fprintf(stderr, "spurious wakeups: 0x%llx\n", spurious);
273
+ fprintf(stderr,
274
+ "spurious wakeups: 0x%llx started=0x%lx completed=0x%lx\n",
275
+ spurious, started, completed);
207276 }
208277
209278 const char optstring[] = "h";
....@@ -245,6 +314,16 @@
245314 .val = 'd',
246315 },
247316 {
317
+ .name = "batch",
318
+ .val = 'b',
319
+ .has_arg = required_argument,
320
+ },
321
+ {
322
+ .name = "reset",
323
+ .val = 'r',
324
+ .has_arg = optional_argument,
325
+ },
326
+ {
248327 }
249328 };
250329
....@@ -255,6 +334,8 @@
255334 " [--no-event-idx]"
256335 " [--no-virtio-1]"
257336 " [--delayed-interrupt]"
337
+ " [--batch=random/N]"
338
+ " [--reset=N]"
258339 "\n");
259340 }
260341
....@@ -263,6 +344,7 @@
263344 struct vdev_info dev;
264345 unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
265346 (1ULL << VIRTIO_RING_F_EVENT_IDX) | (1ULL << VIRTIO_F_VERSION_1);
347
+ long batch = 1, reset = 0;
266348 int o;
267349 bool delayed = false;
268350
....@@ -289,6 +371,24 @@
289371 case 'D':
290372 delayed = true;
291373 break;
374
+ case 'b':
375
+ if (0 == strcmp(optarg, "random")) {
376
+ batch = RANDOM_BATCH;
377
+ } else {
378
+ batch = strtol(optarg, NULL, 10);
379
+ assert(batch > 0);
380
+ assert(batch < (long)INT_MAX + 1);
381
+ }
382
+ break;
383
+ case 'r':
384
+ if (!optarg) {
385
+ reset = 1;
386
+ } else {
387
+ reset = strtol(optarg, NULL, 10);
388
+ assert(reset > 0);
389
+ assert(reset < (long)INT_MAX + 1);
390
+ }
391
+ break;
292392 default:
293393 assert(0);
294394 break;
....@@ -298,6 +398,6 @@
298398 done:
299399 vdev_info_init(&dev, features);
300400 vq_info_add(&dev, 256);
301
- run_test(&dev, &dev.vqs[0], delayed, 0x100000);
401
+ run_test(&dev, &dev.vqs[0], delayed, batch, reset, 0x100000);
302402 return 0;
303403 }