1
2
3
4
5
6
7
8
9
10
11
12
13
14#include "qemu/osdep.h"
15#include "libqtest-single.h"
16#include "qemu/bswap.h"
17#include "qemu/module.h"
18#include "standard-headers/linux/virtio_blk.h"
19#include "standard-headers/linux/virtio_pci.h"
20#include "libqos/qgraph.h"
21#include "libqos/vhost-user-blk.h"
22#include "libqos/libqos-pc.h"
23
24#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
25#define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
26#define PCI_SLOT_HP 0x06
27
28typedef struct {
29 pid_t pid;
30} QemuStorageDaemonState;
31
32typedef struct QVirtioBlkReq {
33 uint32_t type;
34 uint32_t ioprio;
35 uint64_t sector;
36 char *data;
37 uint8_t status;
38} QVirtioBlkReq;
39
40#if HOST_BIG_ENDIAN
41static const bool host_is_big_endian = true;
42#else
43static const bool host_is_big_endian;
44#endif
45
46static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
47{
48 if (qvirtio_is_big_endian(d) != host_is_big_endian) {
49 req->type = bswap32(req->type);
50 req->ioprio = bswap32(req->ioprio);
51 req->sector = bswap64(req->sector);
52 }
53}
54
55static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
56 struct virtio_blk_discard_write_zeroes *dwz_hdr)
57{
58 if (qvirtio_is_big_endian(d) != host_is_big_endian) {
59 dwz_hdr->sector = bswap64(dwz_hdr->sector);
60 dwz_hdr->num_sectors = bswap32(dwz_hdr->num_sectors);
61 dwz_hdr->flags = bswap32(dwz_hdr->flags);
62 }
63}
64
65static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
66 QVirtioBlkReq *req, uint64_t data_size)
67{
68 uint64_t addr;
69 uint8_t status = 0xFF;
70 QTestState *qts = global_qtest;
71
72 switch (req->type) {
73 case VIRTIO_BLK_T_IN:
74 case VIRTIO_BLK_T_OUT:
75 g_assert_cmpuint(data_size % 512, ==, 0);
76 break;
77 case VIRTIO_BLK_T_DISCARD:
78 case VIRTIO_BLK_T_WRITE_ZEROES:
79 g_assert_cmpuint(data_size %
80 sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
81 break;
82 default:
83 g_assert_cmpuint(data_size, ==, 0);
84 }
85
86 addr = guest_alloc(alloc, sizeof(*req) + data_size);
87
88 virtio_blk_fix_request(d, req);
89
90 qtest_memwrite(qts, addr, req, 16);
91 qtest_memwrite(qts, addr + 16, req->data, data_size);
92 qtest_memwrite(qts, addr + 16 + data_size, &status, sizeof(status));
93
94 return addr;
95}
96
97static void test_invalid_discard_write_zeroes(QVirtioDevice *dev,
98 QGuestAllocator *alloc,
99 QTestState *qts,
100 QVirtQueue *vq,
101 uint32_t type)
102{
103 QVirtioBlkReq req;
104 struct virtio_blk_discard_write_zeroes dwz_hdr;
105 struct virtio_blk_discard_write_zeroes dwz_hdr2[2];
106 uint64_t req_addr;
107 uint32_t free_head;
108 uint8_t status;
109
110
111 req.type = type;
112 req.data = (char *) dwz_hdr2;
113 dwz_hdr2[0].sector = 0;
114 dwz_hdr2[0].num_sectors = 1;
115 dwz_hdr2[0].flags = 0;
116 dwz_hdr2[1].sector = 1;
117 dwz_hdr2[1].num_sectors = 1;
118 dwz_hdr2[1].flags = 0;
119
120 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[0]);
121 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[1]);
122
123 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr2));
124
125 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
126 qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr2), false, true);
127 qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr2), 1, true,
128 false);
129
130 qvirtqueue_kick(qts, dev, vq, free_head);
131
132 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
133 QVIRTIO_BLK_TIMEOUT_US);
134 status = readb(req_addr + 16 + sizeof(dwz_hdr2));
135 g_assert_cmpint(status, ==, VIRTIO_BLK_S_UNSUPP);
136
137 guest_free(alloc, req_addr);
138
139
140 req.type = type;
141 req.data = (char *) &dwz_hdr;
142 dwz_hdr.sector = 0;
143 dwz_hdr.num_sectors = 0xffffffff;
144 dwz_hdr.flags = 0;
145
146 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
147
148 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
149
150 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
151 qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
152 qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
153 false);
154
155 qvirtqueue_kick(qts, dev, vq, free_head);
156
157 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
158 QVIRTIO_BLK_TIMEOUT_US);
159 status = readb(req_addr + 16 + sizeof(dwz_hdr));
160 g_assert_cmpint(status, ==, VIRTIO_BLK_S_IOERR);
161
162 guest_free(alloc, req_addr);
163
164
165 req.type = type;
166 req.data = (char *) &dwz_hdr;
167 dwz_hdr.sector = TEST_IMAGE_SIZE / 512 + 1;
168 dwz_hdr.num_sectors = 1;
169 dwz_hdr.flags = 0;
170
171 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
172
173 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
174
175 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
176 qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
177 qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
178 false);
179
180 qvirtqueue_kick(qts, dev, vq, free_head);
181
182 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
183 QVIRTIO_BLK_TIMEOUT_US);
184 status = readb(req_addr + 16 + sizeof(dwz_hdr));
185 g_assert_cmpint(status, ==, VIRTIO_BLK_S_IOERR);
186
187 guest_free(alloc, req_addr);
188
189
190 req.type = type;
191 req.data = (char *) &dwz_hdr;
192 dwz_hdr.sector = 0;
193 dwz_hdr.num_sectors = 1;
194 dwz_hdr.flags = ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP;
195
196 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
197
198 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
199
200 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
201 qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
202 qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
203 false);
204
205 qvirtqueue_kick(qts, dev, vq, free_head);
206
207 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
208 QVIRTIO_BLK_TIMEOUT_US);
209 status = readb(req_addr + 16 + sizeof(dwz_hdr));
210 g_assert_cmpint(status, ==, VIRTIO_BLK_S_UNSUPP);
211
212 guest_free(alloc, req_addr);
213}
214
215
216static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
217{
218 QVirtioBlkReq req;
219 uint64_t req_addr;
220 uint64_t capacity;
221 uint64_t features;
222 uint32_t free_head;
223 uint8_t status;
224 char *data;
225 QTestState *qts = global_qtest;
226 QVirtQueue *vq;
227
228 features = qvirtio_get_features(dev);
229 features = features & ~(QVIRTIO_F_BAD_FEATURE |
230 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
231 (1u << VIRTIO_RING_F_EVENT_IDX) |
232 (1u << VIRTIO_BLK_F_SCSI));
233 qvirtio_set_features(dev, features);
234
235 capacity = qvirtio_config_readq(dev, 0);
236 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
237
238 vq = qvirtqueue_setup(dev, alloc, 0);
239
240 qvirtio_set_driver_ok(dev);
241
242
243
244 req.type = VIRTIO_BLK_T_OUT;
245 req.ioprio = 1;
246 req.sector = 0;
247 req.data = g_malloc0(512);
248 strcpy(req.data, "TEST");
249
250 req_addr = virtio_blk_request(alloc, dev, &req, 512);
251
252 g_free(req.data);
253
254 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
255 qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
256 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
257
258 qvirtqueue_kick(qts, dev, vq, free_head);
259
260 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
261 QVIRTIO_BLK_TIMEOUT_US);
262 status = readb(req_addr + 528);
263 g_assert_cmpint(status, ==, 0);
264
265 guest_free(alloc, req_addr);
266
267
268 req.type = VIRTIO_BLK_T_IN;
269 req.ioprio = 1;
270 req.sector = 0;
271 req.data = g_malloc0(512);
272
273 req_addr = virtio_blk_request(alloc, dev, &req, 512);
274
275 g_free(req.data);
276
277 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
278 qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
279 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
280
281 qvirtqueue_kick(qts, dev, vq, free_head);
282
283 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
284 QVIRTIO_BLK_TIMEOUT_US);
285 status = readb(req_addr + 528);
286 g_assert_cmpint(status, ==, 0);
287
288 data = g_malloc0(512);
289 qtest_memread(qts, req_addr + 16, data, 512);
290 g_assert_cmpstr(data, ==, "TEST");
291 g_free(data);
292
293 guest_free(alloc, req_addr);
294
295 if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
296 struct virtio_blk_discard_write_zeroes dwz_hdr;
297 void *expected;
298
299
300
301
302
303 req.type = VIRTIO_BLK_T_WRITE_ZEROES;
304 req.data = (char *) &dwz_hdr;
305 dwz_hdr.sector = 0;
306 dwz_hdr.num_sectors = 1;
307 dwz_hdr.flags = 0;
308
309 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
310
311 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
312
313 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
314 qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
315 qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
316 false);
317
318 qvirtqueue_kick(qts, dev, vq, free_head);
319
320 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
321 QVIRTIO_BLK_TIMEOUT_US);
322 status = readb(req_addr + 16 + sizeof(dwz_hdr));
323 g_assert_cmpint(status, ==, 0);
324
325 guest_free(alloc, req_addr);
326
327
328 req.type = VIRTIO_BLK_T_IN;
329 req.ioprio = 1;
330 req.sector = 0;
331 req.data = g_malloc0(512);
332
333 req_addr = virtio_blk_request(alloc, dev, &req, 512);
334
335 g_free(req.data);
336
337 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
338 qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
339 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
340
341 qvirtqueue_kick(qts, dev, vq, free_head);
342
343 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
344 QVIRTIO_BLK_TIMEOUT_US);
345 status = readb(req_addr + 528);
346 g_assert_cmpint(status, ==, 0);
347
348 data = g_malloc(512);
349 expected = g_malloc0(512);
350 qtest_memread(qts, req_addr + 16, data, 512);
351 g_assert_cmpmem(data, 512, expected, 512);
352 g_free(expected);
353 g_free(data);
354
355 guest_free(alloc, req_addr);
356
357 test_invalid_discard_write_zeroes(dev, alloc, qts, vq,
358 VIRTIO_BLK_T_WRITE_ZEROES);
359 }
360
361 if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
362 struct virtio_blk_discard_write_zeroes dwz_hdr;
363
364 req.type = VIRTIO_BLK_T_DISCARD;
365 req.data = (char *) &dwz_hdr;
366 dwz_hdr.sector = 0;
367 dwz_hdr.num_sectors = 1;
368 dwz_hdr.flags = 0;
369
370 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
371
372 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
373
374 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
375 qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
376 qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr),
377 1, true, false);
378
379 qvirtqueue_kick(qts, dev, vq, free_head);
380
381 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
382 QVIRTIO_BLK_TIMEOUT_US);
383 status = readb(req_addr + 16 + sizeof(dwz_hdr));
384 g_assert_cmpint(status, ==, 0);
385
386 guest_free(alloc, req_addr);
387
388 test_invalid_discard_write_zeroes(dev, alloc, qts, vq,
389 VIRTIO_BLK_T_DISCARD);
390 }
391
392 if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
393
394
395 req.type = VIRTIO_BLK_T_OUT;
396 req.ioprio = 1;
397 req.sector = 1;
398 req.data = g_malloc0(512);
399 strcpy(req.data, "TEST");
400
401 req_addr = virtio_blk_request(alloc, dev, &req, 512);
402
403 g_free(req.data);
404
405 free_head = qvirtqueue_add(qts, vq, req_addr, 528, false, true);
406 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
407 qvirtqueue_kick(qts, dev, vq, free_head);
408
409 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
410 QVIRTIO_BLK_TIMEOUT_US);
411 status = readb(req_addr + 528);
412 g_assert_cmpint(status, ==, 0);
413
414 guest_free(alloc, req_addr);
415
416
417 req.type = VIRTIO_BLK_T_IN;
418 req.ioprio = 1;
419 req.sector = 1;
420 req.data = g_malloc0(512);
421
422 req_addr = virtio_blk_request(alloc, dev, &req, 512);
423
424 g_free(req.data);
425
426 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
427 qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
428
429 qvirtqueue_kick(qts, dev, vq, free_head);
430
431 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
432 QVIRTIO_BLK_TIMEOUT_US);
433 status = readb(req_addr + 528);
434 g_assert_cmpint(status, ==, 0);
435
436 data = g_malloc0(512);
437 qtest_memread(qts, req_addr + 16, data, 512);
438 g_assert_cmpstr(data, ==, "TEST");
439 g_free(data);
440
441 guest_free(alloc, req_addr);
442 }
443
444 return vq;
445}
446
447static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
448{
449 QVhostUserBlk *blk_if = obj;
450 QVirtQueue *vq;
451
452 vq = test_basic(blk_if->vdev, t_alloc);
453 qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
454
455}
456
457static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
458{
459 QVirtQueue *vq;
460 QVhostUserBlk *blk_if = obj;
461 QVirtioDevice *dev = blk_if->vdev;
462 QVirtioBlkReq req;
463 QVRingIndirectDesc *indirect;
464 uint64_t req_addr;
465 uint64_t capacity;
466 uint64_t features;
467 uint32_t free_head;
468 uint8_t status;
469 char *data;
470 QTestState *qts = global_qtest;
471
472 features = qvirtio_get_features(dev);
473 g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
474 features = features & ~(QVIRTIO_F_BAD_FEATURE |
475 (1u << VIRTIO_RING_F_EVENT_IDX) |
476 (1u << VIRTIO_BLK_F_SCSI));
477 qvirtio_set_features(dev, features);
478
479 capacity = qvirtio_config_readq(dev, 0);
480 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
481
482 vq = qvirtqueue_setup(dev, t_alloc, 0);
483 qvirtio_set_driver_ok(dev);
484
485
486 req.type = VIRTIO_BLK_T_OUT;
487 req.ioprio = 1;
488 req.sector = 0;
489 req.data = g_malloc0(512);
490 strcpy(req.data, "TEST");
491
492 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
493
494 g_free(req.data);
495
496 indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
497 qvring_indirect_desc_add(dev, qts, indirect, req_addr, 528, false);
498 qvring_indirect_desc_add(dev, qts, indirect, req_addr + 528, 1, true);
499 free_head = qvirtqueue_add_indirect(qts, vq, indirect);
500 qvirtqueue_kick(qts, dev, vq, free_head);
501
502 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
503 QVIRTIO_BLK_TIMEOUT_US);
504 status = readb(req_addr + 528);
505 g_assert_cmpint(status, ==, 0);
506
507 g_free(indirect);
508 guest_free(t_alloc, req_addr);
509
510
511 req.type = VIRTIO_BLK_T_IN;
512 req.ioprio = 1;
513 req.sector = 0;
514 req.data = g_malloc0(512);
515 strcpy(req.data, "TEST");
516
517 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
518
519 g_free(req.data);
520
521 indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
522 qvring_indirect_desc_add(dev, qts, indirect, req_addr, 16, false);
523 qvring_indirect_desc_add(dev, qts, indirect, req_addr + 16, 513, true);
524 free_head = qvirtqueue_add_indirect(qts, vq, indirect);
525 qvirtqueue_kick(qts, dev, vq, free_head);
526
527 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
528 QVIRTIO_BLK_TIMEOUT_US);
529 status = readb(req_addr + 528);
530 g_assert_cmpint(status, ==, 0);
531
532 data = g_malloc0(512);
533 qtest_memread(qts, req_addr + 16, data, 512);
534 g_assert_cmpstr(data, ==, "TEST");
535 g_free(data);
536
537 g_free(indirect);
538 guest_free(t_alloc, req_addr);
539 qvirtqueue_cleanup(dev->bus, vq, t_alloc);
540}
541
542static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
543{
544 QVirtQueue *vq;
545 QVhostUserBlkPCI *blk = obj;
546 QVirtioPCIDevice *pdev = &blk->pci_vdev;
547 QVirtioDevice *dev = &pdev->vdev;
548 QVirtioBlkReq req;
549 uint64_t req_addr;
550 uint64_t capacity;
551 uint64_t features;
552 uint32_t free_head;
553 uint32_t write_head;
554 uint32_t desc_idx;
555 uint8_t status;
556 char *data;
557 QOSGraphObject *blk_object = obj;
558 QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
559 QTestState *qts = global_qtest;
560
561 if (qpci_check_buggy_msi(pci_dev)) {
562 return;
563 }
564
565 qpci_msix_enable(pdev->pdev);
566 qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
567
568 features = qvirtio_get_features(dev);
569 features = features & ~(QVIRTIO_F_BAD_FEATURE |
570 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
571 (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
572 (1u << VIRTIO_BLK_F_SCSI));
573 qvirtio_set_features(dev, features);
574
575 capacity = qvirtio_config_readq(dev, 0);
576 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
577
578 vq = qvirtqueue_setup(dev, t_alloc, 0);
579 qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
580
581 qvirtio_set_driver_ok(dev);
582
583
584
585
586
587 qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
588
589
590 req.type = VIRTIO_BLK_T_OUT;
591 req.ioprio = 1;
592 req.sector = 0;
593 req.data = g_malloc0(512);
594 strcpy(req.data, "TEST");
595
596 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
597
598 g_free(req.data);
599
600 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
601 qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
602 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
603 qvirtqueue_kick(qts, dev, vq, free_head);
604
605 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
606 QVIRTIO_BLK_TIMEOUT_US);
607
608
609 req.type = VIRTIO_BLK_T_OUT;
610 req.ioprio = 1;
611 req.sector = 1;
612 req.data = g_malloc0(512);
613 strcpy(req.data, "TEST");
614
615 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
616
617 g_free(req.data);
618
619
620 qvirtqueue_set_used_event(qts, vq, 2);
621 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
622 qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
623 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
624 qvirtqueue_kick(qts, dev, vq, free_head);
625 write_head = free_head;
626
627
628 status = qvirtio_wait_status_byte_no_isr(qts, dev,
629 vq, req_addr + 528,
630 QVIRTIO_BLK_TIMEOUT_US);
631 g_assert_cmpint(status, ==, 0);
632
633 guest_free(t_alloc, req_addr);
634
635
636 req.type = VIRTIO_BLK_T_IN;
637 req.ioprio = 1;
638 req.sector = 1;
639 req.data = g_malloc0(512);
640
641 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
642
643 g_free(req.data);
644
645 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
646 qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
647 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
648
649 qvirtqueue_kick(qts, dev, vq, free_head);
650
651
652 qvirtio_wait_used_elem(qts, dev, vq, write_head, NULL,
653 QVIRTIO_BLK_TIMEOUT_US);
654 g_assert(qvirtqueue_get_buf(qts, vq, &desc_idx, NULL));
655 g_assert_cmpint(desc_idx, ==, free_head);
656
657 status = readb(req_addr + 528);
658 g_assert_cmpint(status, ==, 0);
659
660 data = g_malloc0(512);
661 qtest_memread(qts, req_addr + 16, data, 512);
662 g_assert_cmpstr(data, ==, "TEST");
663 g_free(data);
664
665 guest_free(t_alloc, req_addr);
666
667
668 qpci_msix_disable(pdev->pdev);
669
670 qvirtqueue_cleanup(dev->bus, vq, t_alloc);
671}
672
673static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
674{
675 QVirtioPCIDevice *dev1 = obj;
676 QVirtioPCIDevice *dev;
677 QTestState *qts = dev1->pdev->bus->qts;
678
679 if (dev1->pdev->bus->not_hotpluggable) {
680 g_test_skip("pci bus does not support hotplug");
681 return;
682 }
683
684
685 qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
686 "{'addr': %s, 'chardev': 'char2'}",
687 stringify(PCI_SLOT_HP) ".0");
688
689 dev = virtio_pci_new(dev1->pdev->bus,
690 &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
691 });
692 g_assert_nonnull(dev);
693 g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
694 qvirtio_pci_device_disable(dev);
695 qos_object_destroy((QOSGraphObject *)dev);
696
697
698 qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
699}
700
701static void multiqueue(void *obj, void *data, QGuestAllocator *t_alloc)
702{
703 QVirtioPCIDevice *pdev1 = obj;
704 QVirtioDevice *dev1 = &pdev1->vdev;
705 QVirtioPCIDevice *pdev8;
706 QVirtioDevice *dev8;
707 QTestState *qts = pdev1->pdev->bus->qts;
708 uint64_t features;
709 uint16_t num_queues;
710
711 if (pdev1->pdev->bus->not_hotpluggable) {
712 g_test_skip("bus pci.0 does not support hotplug");
713 return;
714 }
715
716
717
718
719
720
721
722 features = qvirtio_get_features(dev1);
723 g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ), ==, 0);
724 features = features & ~(QVIRTIO_F_BAD_FEATURE |
725 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
726 (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
727 (1u << VIRTIO_BLK_F_SCSI));
728 qvirtio_set_features(dev1, features);
729
730
731 qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
732 "{'addr': %s, 'chardev': 'char2', 'num-queues': 8}",
733 stringify(PCI_SLOT_HP) ".0");
734
735 pdev8 = virtio_pci_new(pdev1->pdev->bus,
736 &(QPCIAddress) {
737 .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
738 });
739 g_assert_nonnull(pdev8);
740 g_assert_cmpint(pdev8->vdev.device_type, ==, VIRTIO_ID_BLOCK);
741
742 qos_object_start_hw(&pdev8->obj);
743
744 dev8 = &pdev8->vdev;
745 features = qvirtio_get_features(dev8);
746 g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ),
747 ==,
748 (1u << VIRTIO_BLK_F_MQ));
749 features = features & ~(QVIRTIO_F_BAD_FEATURE |
750 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
751 (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
752 (1u << VIRTIO_BLK_F_SCSI) |
753 (1u << VIRTIO_BLK_F_MQ));
754 qvirtio_set_features(dev8, features);
755
756 num_queues = qvirtio_config_readw(dev8,
757 offsetof(struct virtio_blk_config, num_queues));
758 g_assert_cmpint(num_queues, ==, 8);
759
760 qvirtio_pci_device_disable(pdev8);
761 qos_object_destroy(&pdev8->obj);
762
763
764 qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
765}
766
767
768
769
770
771static void test_nonexistent_virtqueue(void *obj, void *data,
772 QGuestAllocator *t_alloc)
773{
774 QVhostUserBlkPCI *blk = obj;
775 QVirtioPCIDevice *pdev = &blk->pci_vdev;
776 QPCIBar bar0;
777 QPCIDevice *dev;
778
779 dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
780 g_assert(dev != NULL);
781 qpci_device_enable(dev);
782
783 bar0 = qpci_iomap(dev, 0, NULL);
784
785 qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
786 qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
787
788 g_free(dev);
789}
790
791static const char *qtest_qemu_storage_daemon_binary(void)
792{
793 const char *qemu_storage_daemon_bin;
794
795 qemu_storage_daemon_bin = getenv("QTEST_QEMU_STORAGE_DAEMON_BINARY");
796 if (!qemu_storage_daemon_bin) {
797 fprintf(stderr, "Environment variable "
798 "QTEST_QEMU_STORAGE_DAEMON_BINARY required\n");
799 exit(0);
800 }
801
802
803 if (strchr(qemu_storage_daemon_bin, '/') &&
804 access(qemu_storage_daemon_bin, X_OK) != 0) {
805 fprintf(stderr, "ERROR: '%s' is not accessible\n",
806 qemu_storage_daemon_bin);
807 exit(1);
808 }
809
810 return qemu_storage_daemon_bin;
811}
812
813
814static void destroy_file(void *path)
815{
816 unlink(path);
817 g_free(path);
818 qos_invalidate_command_line();
819}
820
821static char *drive_create(void)
822{
823 int fd, ret;
824
825 char *t_path = g_strdup("qtest.XXXXXX");
826
827
828 fd = mkstemp(t_path);
829 g_assert_cmpint(fd, >=, 0);
830 ret = ftruncate(fd, TEST_IMAGE_SIZE);
831 g_assert_cmpint(ret, ==, 0);
832 close(fd);
833
834 g_test_queue_destroy(destroy_file, t_path);
835 return t_path;
836}
837
838static char *create_listen_socket(int *fd)
839{
840 int tmp_fd;
841 char *path;
842
843
844 path = g_strdup_printf("%s/qtest-%d-sock.XXXXXX",
845 g_get_tmp_dir(), getpid());
846 tmp_fd = mkstemp(path);
847 g_assert_cmpint(tmp_fd, >=, 0);
848 close(tmp_fd);
849 unlink(path);
850
851 *fd = qtest_socket_server(path);
852 g_test_queue_destroy(destroy_file, path);
853 return path;
854}
855
856
857
858
859
860static void quit_storage_daemon(void *data)
861{
862 QemuStorageDaemonState *qsd = data;
863 int wstatus;
864 pid_t pid;
865
866
867
868
869
870
871
872 qtest_remove_abrt_handler(data);
873
874
875 qtest_kill_qemu(global_qtest);
876
877 kill(qsd->pid, SIGTERM);
878 pid = waitpid(qsd->pid, &wstatus, 0);
879 g_assert_cmpint(pid, ==, qsd->pid);
880 if (!WIFEXITED(wstatus)) {
881 fprintf(stderr, "%s: expected qemu-storage-daemon to exit\n",
882 __func__);
883 abort();
884 }
885 if (WEXITSTATUS(wstatus) != 0) {
886 fprintf(stderr, "%s: expected qemu-storage-daemon to exit "
887 "successfully, got %d\n",
888 __func__, WEXITSTATUS(wstatus));
889 abort();
890 }
891
892 g_free(data);
893}
894
895static void start_vhost_user_blk(GString *cmd_line, int vus_instances,
896 int num_queues)
897{
898 const char *vhost_user_blk_bin = qtest_qemu_storage_daemon_binary();
899 int i;
900 gchar *img_path;
901 GString *storage_daemon_command = g_string_new(NULL);
902 QemuStorageDaemonState *qsd;
903
904 g_string_append_printf(storage_daemon_command,
905 "exec %s ",
906 vhost_user_blk_bin);
907
908 g_string_append_printf(cmd_line,
909 " -object memory-backend-memfd,id=mem,size=256M,share=on "
910 " -M memory-backend=mem -m 256M ");
911
912 for (i = 0; i < vus_instances; i++) {
913 int fd;
914 char *sock_path = create_listen_socket(&fd);
915
916
917 img_path = drive_create();
918 g_string_append_printf(storage_daemon_command,
919 "--blockdev driver=file,node-name=disk%d,filename=%s "
920 "--export type=vhost-user-blk,id=disk%d,addr.type=fd,addr.str=%d,"
921 "node-name=disk%i,writable=on,num-queues=%d ",
922 i, img_path, i, fd, i, num_queues);
923
924 g_string_append_printf(cmd_line, "-chardev socket,id=char%d,path=%s ",
925 i + 1, sock_path);
926 }
927
928 g_test_message("starting vhost-user backend: %s",
929 storage_daemon_command->str);
930 pid_t pid = fork();
931 if (pid == 0) {
932
933
934
935
936 close(0);
937 close(1);
938 open("/dev/null", O_RDONLY);
939 open("/dev/null", O_WRONLY);
940
941 execlp("/bin/sh", "sh", "-c", storage_daemon_command->str, NULL);
942 exit(1);
943 }
944 g_string_free(storage_daemon_command, true);
945
946 qsd = g_new(QemuStorageDaemonState, 1);
947 qsd->pid = pid;
948
949
950 qtest_add_abrt_handler(quit_storage_daemon, qsd);
951 g_test_queue_destroy(quit_storage_daemon, qsd);
952}
953
954static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg)
955{
956 start_vhost_user_blk(cmd_line, 1, 1);
957 return arg;
958}
959
960
961
962
963
964
965
966
967static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *arg)
968{
969
970 start_vhost_user_blk(cmd_line, 2, 1);
971 return arg;
972}
973
974static void *vhost_user_blk_multiqueue_test_setup(GString *cmd_line, void *arg)
975{
976 start_vhost_user_blk(cmd_line, 2, 8);
977 return arg;
978}
979
980static void register_vhost_user_blk_test(void)
981{
982 QOSGraphTestOptions opts = {
983 .before = vhost_user_blk_test_setup,
984 };
985
986 if (!getenv("QTEST_QEMU_STORAGE_DAEMON_BINARY")) {
987 g_test_message("QTEST_QEMU_STORAGE_DAEMON_BINARY not defined, "
988 "skipping vhost-user-blk-test");
989 return;
990 }
991
992
993
994
995
996
997
998
999
1000
1001 qos_add_test("basic", "vhost-user-blk", basic, &opts);
1002 qos_add_test("indirect", "vhost-user-blk", indirect, &opts);
1003 qos_add_test("idx", "vhost-user-blk-pci", idx, &opts);
1004 qos_add_test("nxvirtq", "vhost-user-blk-pci",
1005 test_nonexistent_virtqueue, &opts);
1006
1007 opts.before = vhost_user_blk_hotplug_test_setup;
1008 qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts);
1009
1010 opts.before = vhost_user_blk_multiqueue_test_setup;
1011 qos_add_test("multiqueue", "vhost-user-blk-pci", multiqueue, &opts);
1012}
1013
1014libqos_init(register_vhost_user_blk_test);
1015