Merge tag 'pull-loongarch-20241016' of https://gitlab.com/gaosong/qemu into staging
[qemu/armbru.git] / tests / qtest / vhost-user-blk-test.c
blobea90d41232ee90e6285ef2c1ea7c3acecc7c609f
1 /*
2 * QTest testcase for Vhost-user Block Device
4 * Based on tests/qtest//virtio-blk-test.c
6 * Copyright (c) 2014 SUSE LINUX Products GmbH
7 * Copyright (c) 2014 Marc MarĂ­
8 * Copyright (c) 2020 Coiby Xu
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
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"
24 #define TEST_IMAGE_SIZE (64 * 1024 * 1024)
25 #define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
26 #define PCI_SLOT_HP 0x06
28 typedef struct {
29 pid_t pid;
30 } QemuStorageDaemonState;
32 typedef struct QVirtioBlkReq {
33 uint32_t type;
34 uint32_t ioprio;
35 uint64_t sector;
36 char *data;
37 uint8_t status;
38 } QVirtioBlkReq;
40 #if HOST_BIG_ENDIAN
41 static const bool host_is_big_endian = true;
42 #else
43 static const bool host_is_big_endian; /* false */
44 #endif
46 static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
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);
55 static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
56 struct virtio_blk_discard_write_zeroes *dwz_hdr)
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);
65 static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
66 QVirtioBlkReq *req, uint64_t data_size)
68 uint64_t addr;
69 uint8_t status = 0xFF;
70 QTestState *qts = global_qtest;
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);
86 addr = guest_alloc(alloc, sizeof(*req) + data_size);
88 virtio_blk_fix_request(d, req);
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));
94 return addr;
97 static void test_invalid_discard_write_zeroes(QVirtioDevice *dev,
98 QGuestAllocator *alloc,
99 QTestState *qts,
100 QVirtQueue *vq,
101 uint32_t type)
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;
110 /* More than one dwz is not supported */
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;
120 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[0]);
121 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[1]);
123 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr2));
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);
130 qvirtqueue_kick(qts, dev, vq, free_head);
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);
137 guest_free(alloc, req_addr);
139 /* num_sectors must be less than config->max_write_zeroes_sectors */
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;
146 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
148 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
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);
155 qvirtqueue_kick(qts, dev, vq, free_head);
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);
162 guest_free(alloc, req_addr);
164 /* sector must be less than the device capacity */
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;
171 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
173 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
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);
180 qvirtqueue_kick(qts, dev, vq, free_head);
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);
187 guest_free(alloc, req_addr);
189 /* reserved flag bits must be zero */
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;
196 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
198 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
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);
205 qvirtqueue_kick(qts, dev, vq, free_head);
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);
212 guest_free(alloc, req_addr);
215 /* Returns the request virtqueue so the caller can perform further tests */
216 static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
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;
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);
235 capacity = qvirtio_config_readq(dev, 0);
236 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
238 vq = qvirtqueue_setup(dev, alloc, 0);
240 qvirtio_set_driver_ok(dev);
242 /* Write and read with 3 descriptor layout */
243 /* Write request */
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");
250 req_addr = virtio_blk_request(alloc, dev, &req, 512);
252 g_free(req.data);
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);
258 qvirtqueue_kick(qts, dev, vq, free_head);
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);
265 guest_free(alloc, req_addr);
267 /* Read request */
268 req.type = VIRTIO_BLK_T_IN;
269 req.ioprio = 1;
270 req.sector = 0;
271 req.data = g_malloc0(512);
273 req_addr = virtio_blk_request(alloc, dev, &req, 512);
275 g_free(req.data);
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);
281 qvirtqueue_kick(qts, dev, vq, free_head);
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);
288 data = g_malloc0(512);
289 qtest_memread(qts, req_addr + 16, data, 512);
290 g_assert_cmpstr(data, ==, "TEST");
291 g_free(data);
293 guest_free(alloc, req_addr);
295 if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
296 struct virtio_blk_discard_write_zeroes dwz_hdr;
297 void *expected;
300 * WRITE_ZEROES request on the same sector of previous test where
301 * we wrote "TEST".
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;
309 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
311 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
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);
318 qvirtqueue_kick(qts, dev, vq, free_head);
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);
325 guest_free(alloc, req_addr);
327 /* Read request to check if the sector contains all zeroes */
328 req.type = VIRTIO_BLK_T_IN;
329 req.ioprio = 1;
330 req.sector = 0;
331 req.data = g_malloc0(512);
333 req_addr = virtio_blk_request(alloc, dev, &req, 512);
335 g_free(req.data);
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);
341 qvirtqueue_kick(qts, dev, vq, free_head);
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);
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);
355 guest_free(alloc, req_addr);
357 test_invalid_discard_write_zeroes(dev, alloc, qts, vq,
358 VIRTIO_BLK_T_WRITE_ZEROES);
361 if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
362 struct virtio_blk_discard_write_zeroes dwz_hdr;
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;
370 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
372 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
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);
379 qvirtqueue_kick(qts, dev, vq, free_head);
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);
386 guest_free(alloc, req_addr);
388 test_invalid_discard_write_zeroes(dev, alloc, qts, vq,
389 VIRTIO_BLK_T_DISCARD);
392 if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
393 /* Write and read with 2 descriptor layout */
394 /* Write request */
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");
401 req_addr = virtio_blk_request(alloc, dev, &req, 512);
403 g_free(req.data);
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);
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);
414 guest_free(alloc, req_addr);
416 /* Read request */
417 req.type = VIRTIO_BLK_T_IN;
418 req.ioprio = 1;
419 req.sector = 1;
420 req.data = g_malloc0(512);
422 req_addr = virtio_blk_request(alloc, dev, &req, 512);
424 g_free(req.data);
426 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
427 qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
429 qvirtqueue_kick(qts, dev, vq, free_head);
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);
436 data = g_malloc0(512);
437 qtest_memread(qts, req_addr + 16, data, 512);
438 g_assert_cmpstr(data, ==, "TEST");
439 g_free(data);
441 guest_free(alloc, req_addr);
444 return vq;
447 static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
449 QVhostUserBlk *blk_if = obj;
450 QVirtQueue *vq;
452 vq = test_basic(blk_if->vdev, t_alloc);
453 qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
457 static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
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;
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);
479 capacity = qvirtio_config_readq(dev, 0);
480 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
482 vq = qvirtqueue_setup(dev, t_alloc, 0);
483 qvirtio_set_driver_ok(dev);
485 /* Write request */
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");
492 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
494 g_free(req.data);
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);
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);
507 g_free(indirect);
508 guest_free(t_alloc, req_addr);
510 /* Read request */
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");
517 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
519 g_free(req.data);
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);
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);
532 data = g_malloc0(512);
533 qtest_memread(qts, req_addr + 16, data, 512);
534 g_assert_cmpstr(data, ==, "TEST");
535 g_free(data);
537 g_free(indirect);
538 guest_free(t_alloc, req_addr);
539 qvirtqueue_cleanup(dev->bus, vq, t_alloc);
542 static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
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;
561 if (qpci_check_buggy_msi(pci_dev)) {
562 return;
565 qpci_msix_enable(pdev->pdev);
566 qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
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);
575 capacity = qvirtio_config_readq(dev, 0);
576 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
578 vq = qvirtqueue_setup(dev, t_alloc, 0);
579 qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
581 qvirtio_set_driver_ok(dev);
584 * libvhost-user signals the call fd in VHOST_USER_SET_VRING_CALL, make
585 * sure to wait for the isr here so we don't race and confuse it later on.
587 qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
589 /* Write request */
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");
596 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
598 g_free(req.data);
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);
605 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
606 QVIRTIO_BLK_TIMEOUT_US);
608 /* Write request */
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");
615 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
617 g_free(req.data);
619 /* Notify after processing the third request */
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;
627 /* No notification expected */
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);
633 guest_free(t_alloc, req_addr);
635 /* Read request */
636 req.type = VIRTIO_BLK_T_IN;
637 req.ioprio = 1;
638 req.sector = 1;
639 req.data = g_malloc0(512);
641 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
643 g_free(req.data);
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);
649 qvirtqueue_kick(qts, dev, vq, free_head);
651 /* We get just one notification for both requests */
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);
657 status = readb(req_addr + 528);
658 g_assert_cmpint(status, ==, 0);
660 data = g_malloc0(512);
661 qtest_memread(qts, req_addr + 16, data, 512);
662 g_assert_cmpstr(data, ==, "TEST");
663 g_free(data);
665 guest_free(t_alloc, req_addr);
667 /* End test */
668 qpci_msix_disable(pdev->pdev);
670 qvirtqueue_cleanup(dev->bus, vq, t_alloc);
673 static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
675 QVirtioPCIDevice *dev1 = obj;
676 QVirtioPCIDevice *dev;
677 QTestState *qts = dev1->pdev->bus->qts;
679 if (dev1->pdev->bus->not_hotpluggable) {
680 g_test_skip("pci bus does not support hotplug");
681 return;
684 /* plug secondary disk */
685 qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
686 "{'addr': %s, 'chardev': 'char2'}",
687 stringify(PCI_SLOT_HP) ".0");
689 dev = virtio_pci_new(dev1->pdev->bus,
690 &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
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);
697 /* unplug secondary disk */
698 qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
701 static void multiqueue(void *obj, void *data, QGuestAllocator *t_alloc)
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;
711 if (pdev1->pdev->bus->not_hotpluggable) {
712 g_test_skip("bus pci.0 does not support hotplug");
713 return;
717 * The primary device has 1 queue and VIRTIO_BLK_F_MQ is not enabled. The
718 * VIRTIO specification allows VIRTIO_BLK_F_MQ to be enabled when there is
719 * only 1 virtqueue, but --device vhost-user-blk-pci doesn't do this (which
720 * is also spec-compliant).
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);
730 /* Hotplug a secondary device with 8 queues */
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");
735 pdev8 = virtio_pci_new(pdev1->pdev->bus,
736 &(QPCIAddress) {
737 .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
739 g_assert_nonnull(pdev8);
740 g_assert_cmpint(pdev8->vdev.device_type, ==, VIRTIO_ID_BLOCK);
742 qos_object_start_hw(&pdev8->obj);
744 dev8 = &pdev8->vdev;
745 features = qvirtio_get_features(dev8);
746 g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ),
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);
756 num_queues = qvirtio_config_readw(dev8,
757 offsetof(struct virtio_blk_config, num_queues));
758 g_assert_cmpint(num_queues, ==, 8);
760 qvirtio_pci_device_disable(pdev8);
761 qos_object_destroy(&pdev8->obj);
763 /* unplug secondary disk */
764 qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
768 * Check that setting the vring addr on a non-existent virtqueue does
769 * not crash.
771 static void test_nonexistent_virtqueue(void *obj, void *data,
772 QGuestAllocator *t_alloc)
774 QVhostUserBlkPCI *blk = obj;
775 QVirtioPCIDevice *pdev = &blk->pci_vdev;
776 QPCIBar bar0;
777 QPCIDevice *dev;
779 dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
780 g_assert(dev != NULL);
781 qpci_device_enable(dev);
783 bar0 = qpci_iomap(dev, 0, NULL);
785 qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
786 qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
788 g_free(dev);
791 static const char *qtest_qemu_storage_daemon_binary(void)
793 const char *qemu_storage_daemon_bin;
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);
802 /* If we've got a path to the binary, check whether we can access it */
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);
810 return qemu_storage_daemon_bin;
813 /* g_test_queue_destroy() cleanup function for files */
814 static void destroy_file(void *path)
816 unlink(path);
817 g_free(path);
818 qos_invalidate_command_line();
821 static char *drive_create(void)
823 int fd, ret;
824 /** vhost-user-blk won't recognize drive located in /tmp */
825 char *t_path = g_strdup("qtest.XXXXXX");
827 /** Create a temporary raw image */
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);
834 g_test_queue_destroy(destroy_file, t_path);
835 return t_path;
838 static char *create_listen_socket(int *fd)
840 int tmp_fd;
841 char *path;
843 /* No race because our pid makes the path unique */
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);
851 *fd = qtest_socket_server(path);
852 g_test_queue_destroy(destroy_file, path);
853 return path;
857 * g_test_queue_destroy() and qtest_add_abrt_handler() cleanup function for
858 * qemu-storage-daemon.
860 static void quit_storage_daemon(void *data)
862 QemuStorageDaemonState *qsd = data;
863 int wstatus;
864 pid_t pid;
867 * If we were invoked as a g_test_queue_destroy() cleanup function we need
868 * to remove the abrt handler to avoid being called again if the code below
869 * aborts. Also, we must not leave the abrt handler installed after
870 * cleanup.
872 qtest_remove_abrt_handler(data);
874 /* Before quitting storage-daemon, quit qemu to avoid dubious messages */
875 qtest_kill_qemu(global_qtest);
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();
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();
892 g_free(data);
895 static void start_vhost_user_blk(GString *cmd_line, int vus_instances,
896 int num_queues)
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;
904 g_string_append_printf(storage_daemon_command,
905 "exec %s ",
906 vhost_user_blk_bin);
908 g_string_append_printf(cmd_line,
909 " -object memory-backend-shm,id=mem,size=256M "
910 " -M memory-backend=mem -m 256M ");
912 for (i = 0; i < vus_instances; i++) {
913 int fd;
914 char *sock_path = create_listen_socket(&fd);
916 /* create image file */
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);
924 g_string_append_printf(cmd_line, "-chardev socket,id=char%d,path=%s ",
925 i + 1, sock_path);
928 g_test_message("starting vhost-user backend: %s",
929 storage_daemon_command->str);
930 pid_t pid = fork();
931 if (pid == 0) {
933 * Close standard file descriptors so tap-driver.pl pipe detects when
934 * our parent terminates.
936 close(0);
937 close(1);
938 open("/dev/null", O_RDONLY);
939 open("/dev/null", O_WRONLY);
941 execlp("/bin/sh", "sh", "-c", storage_daemon_command->str, NULL);
942 exit(1);
944 g_string_free(storage_daemon_command, true);
946 qsd = g_new(QemuStorageDaemonState, 1);
947 qsd->pid = pid;
949 /* Make sure qemu-storage-daemon is stopped */
950 qtest_add_abrt_handler(quit_storage_daemon, qsd);
951 g_test_queue_destroy(quit_storage_daemon, qsd);
954 static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg)
956 start_vhost_user_blk(cmd_line, 1, 1);
957 return arg;
961 * Setup for hotplug.
963 * Since vhost-user server only serves one vhost-user client one time,
964 * another export
967 static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *arg)
969 /* "-chardev socket,id=char2" is used for pci_hotplug*/
970 start_vhost_user_blk(cmd_line, 2, 1);
971 return arg;
974 static void *vhost_user_blk_multiqueue_test_setup(GString *cmd_line, void *arg)
976 start_vhost_user_blk(cmd_line, 2, 8);
977 return arg;
980 static void register_vhost_user_blk_test(void)
982 QOSGraphTestOptions opts = {
983 .before = vhost_user_blk_test_setup,
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;
993 * tests for vhost-user-blk and vhost-user-blk-pci
994 * The tests are borrowed from tests/virtio-blk-test.c. But some tests
995 * regarding block_resize don't work for vhost-user-blk.
996 * vhost-user-blk device doesn't have -drive, so tests containing
997 * block_resize are also abandoned,
998 * - config
999 * - resize
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);
1007 opts.before = vhost_user_blk_hotplug_test_setup;
1008 qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts);
1010 opts.before = vhost_user_blk_multiqueue_test_setup;
1011 qos_add_test("multiqueue", "vhost-user-blk-pci", multiqueue, &opts);
1014 libqos_init(register_vhost_user_blk_test);