]> git.proxmox.com Git - mirror_qemu.git/blob - tests/qtest/virtio-blk-test.c
netdev: set timeout depending on loadavg
[mirror_qemu.git] / tests / qtest / virtio-blk-test.c
1 /*
2 * QTest testcase for VirtIO Block Device
3 *
4 * Copyright (c) 2014 SUSE LINUX Products GmbH
5 * Copyright (c) 2014 Marc MarĂ­
6 *
7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
8 * See the COPYING file in the top-level directory.
9 */
10
11 #include "qemu/osdep.h"
12 #include "libqtest-single.h"
13 #include "qemu/bswap.h"
14 #include "qemu/module.h"
15 #include "standard-headers/linux/virtio_blk.h"
16 #include "standard-headers/linux/virtio_pci.h"
17 #include "libqos/qgraph.h"
18 #include "libqos/virtio-blk.h"
19
20 #define TEST_IMAGE_SIZE (64 * 1024 * 1024)
21 #define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
22 #define PCI_SLOT_HP 0x06
23
24 typedef struct QVirtioBlkReq {
25 uint32_t type;
26 uint32_t ioprio;
27 uint64_t sector;
28 char *data;
29 uint8_t status;
30 } QVirtioBlkReq;
31
32
33 #if HOST_BIG_ENDIAN
34 const bool host_is_big_endian = true;
35 #else
36 const bool host_is_big_endian; /* false */
37 #endif
38
39 static void drive_destroy(void *path)
40 {
41 unlink(path);
42 g_free(path);
43 qos_invalidate_command_line();
44 }
45
46 static char *drive_create(void)
47 {
48 int fd, ret;
49 char *t_path;
50
51 /* Create a temporary raw image */
52 fd = g_file_open_tmp("qtest.XXXXXX", &t_path, NULL);
53 g_assert_cmpint(fd, >=, 0);
54 ret = ftruncate(fd, TEST_IMAGE_SIZE);
55 g_assert_cmpint(ret, ==, 0);
56 close(fd);
57
58 g_test_queue_destroy(drive_destroy, t_path);
59 return t_path;
60 }
61
62 static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
63 {
64 if (qvirtio_is_big_endian(d) != host_is_big_endian) {
65 req->type = bswap32(req->type);
66 req->ioprio = bswap32(req->ioprio);
67 req->sector = bswap64(req->sector);
68 }
69 }
70
71
72 static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
73 struct virtio_blk_discard_write_zeroes *dwz_hdr)
74 {
75 if (qvirtio_is_big_endian(d) != host_is_big_endian) {
76 dwz_hdr->sector = bswap64(dwz_hdr->sector);
77 dwz_hdr->num_sectors = bswap32(dwz_hdr->num_sectors);
78 dwz_hdr->flags = bswap32(dwz_hdr->flags);
79 }
80 }
81
82 static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
83 QVirtioBlkReq *req, uint64_t data_size)
84 {
85 uint64_t addr;
86 uint8_t status = 0xFF;
87
88 switch (req->type) {
89 case VIRTIO_BLK_T_IN:
90 case VIRTIO_BLK_T_OUT:
91 g_assert_cmpuint(data_size % 512, ==, 0);
92 break;
93 case VIRTIO_BLK_T_DISCARD:
94 case VIRTIO_BLK_T_WRITE_ZEROES:
95 g_assert_cmpuint(data_size %
96 sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
97 break;
98 default:
99 g_assert_cmpuint(data_size, ==, 0);
100 }
101
102 addr = guest_alloc(alloc, sizeof(*req) + data_size);
103
104 virtio_blk_fix_request(d, req);
105
106 memwrite(addr, req, 16);
107 memwrite(addr + 16, req->data, data_size);
108 memwrite(addr + 16 + data_size, &status, sizeof(status));
109
110 return addr;
111 }
112
113 /* Returns the request virtqueue so the caller can perform further tests */
114 static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
115 {
116 QVirtioBlkReq req;
117 uint64_t req_addr;
118 uint64_t capacity;
119 uint64_t features;
120 uint32_t free_head;
121 uint8_t status;
122 char *data;
123 QTestState *qts = global_qtest;
124 QVirtQueue *vq;
125
126 features = qvirtio_get_features(dev);
127 features = features & ~(QVIRTIO_F_BAD_FEATURE |
128 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
129 (1u << VIRTIO_RING_F_EVENT_IDX) |
130 (1u << VIRTIO_BLK_F_SCSI));
131 qvirtio_set_features(dev, features);
132
133 capacity = qvirtio_config_readq(dev, 0);
134 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
135
136 vq = qvirtqueue_setup(dev, alloc, 0);
137
138 qvirtio_set_driver_ok(dev);
139
140 /* Write and read with 3 descriptor layout */
141 /* Write request */
142 req.type = VIRTIO_BLK_T_OUT;
143 req.ioprio = 1;
144 req.sector = 0;
145 req.data = g_malloc0(512);
146 strcpy(req.data, "TEST");
147
148 req_addr = virtio_blk_request(alloc, dev, &req, 512);
149
150 g_free(req.data);
151
152 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
153 qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
154 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
155
156 qvirtqueue_kick(qts, dev, vq, free_head);
157
158 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
159 QVIRTIO_BLK_TIMEOUT_US);
160 status = readb(req_addr + 528);
161 g_assert_cmpint(status, ==, 0);
162
163 guest_free(alloc, req_addr);
164
165 /* Read request */
166 req.type = VIRTIO_BLK_T_IN;
167 req.ioprio = 1;
168 req.sector = 0;
169 req.data = g_malloc0(512);
170
171 req_addr = virtio_blk_request(alloc, dev, &req, 512);
172
173 g_free(req.data);
174
175 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
176 qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
177 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
178
179 qvirtqueue_kick(qts, dev, vq, free_head);
180
181 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
182 QVIRTIO_BLK_TIMEOUT_US);
183 status = readb(req_addr + 528);
184 g_assert_cmpint(status, ==, 0);
185
186 data = g_malloc0(512);
187 memread(req_addr + 16, data, 512);
188 g_assert_cmpstr(data, ==, "TEST");
189 g_free(data);
190
191 guest_free(alloc, req_addr);
192
193 if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
194 struct virtio_blk_discard_write_zeroes dwz_hdr;
195 void *expected;
196
197 /*
198 * WRITE_ZEROES request on the same sector of previous test where
199 * we wrote "TEST".
200 */
201 req.type = VIRTIO_BLK_T_WRITE_ZEROES;
202 req.data = (char *) &dwz_hdr;
203 dwz_hdr.sector = 0;
204 dwz_hdr.num_sectors = 1;
205 dwz_hdr.flags = 0;
206
207 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
208
209 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
210
211 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
212 qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
213 qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
214 false);
215
216 qvirtqueue_kick(qts, dev, vq, free_head);
217
218 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
219 QVIRTIO_BLK_TIMEOUT_US);
220 status = readb(req_addr + 16 + sizeof(dwz_hdr));
221 g_assert_cmpint(status, ==, 0);
222
223 guest_free(alloc, req_addr);
224
225 /* Read request to check if the sector contains all zeroes */
226 req.type = VIRTIO_BLK_T_IN;
227 req.ioprio = 1;
228 req.sector = 0;
229 req.data = g_malloc0(512);
230
231 req_addr = virtio_blk_request(alloc, dev, &req, 512);
232
233 g_free(req.data);
234
235 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
236 qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
237 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
238
239 qvirtqueue_kick(qts, dev, vq, free_head);
240
241 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
242 QVIRTIO_BLK_TIMEOUT_US);
243 status = readb(req_addr + 528);
244 g_assert_cmpint(status, ==, 0);
245
246 data = g_malloc(512);
247 expected = g_malloc0(512);
248 memread(req_addr + 16, data, 512);
249 g_assert_cmpmem(data, 512, expected, 512);
250 g_free(expected);
251 g_free(data);
252
253 guest_free(alloc, req_addr);
254 }
255
256 if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
257 struct virtio_blk_discard_write_zeroes dwz_hdr;
258
259 req.type = VIRTIO_BLK_T_DISCARD;
260 req.data = (char *) &dwz_hdr;
261 dwz_hdr.sector = 0;
262 dwz_hdr.num_sectors = 1;
263 dwz_hdr.flags = 0;
264
265 virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
266
267 req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
268
269 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
270 qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
271 qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false);
272
273 qvirtqueue_kick(qts, dev, vq, free_head);
274
275 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
276 QVIRTIO_BLK_TIMEOUT_US);
277 status = readb(req_addr + 16 + sizeof(dwz_hdr));
278 g_assert_cmpint(status, ==, 0);
279
280 guest_free(alloc, req_addr);
281 }
282
283 if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
284 /* Write and read with 2 descriptor layout */
285 /* Write request */
286 req.type = VIRTIO_BLK_T_OUT;
287 req.ioprio = 1;
288 req.sector = 1;
289 req.data = g_malloc0(512);
290 strcpy(req.data, "TEST");
291
292 req_addr = virtio_blk_request(alloc, dev, &req, 512);
293
294 g_free(req.data);
295
296 free_head = qvirtqueue_add(qts, vq, req_addr, 528, false, true);
297 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
298 qvirtqueue_kick(qts, dev, vq, free_head);
299
300 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
301 QVIRTIO_BLK_TIMEOUT_US);
302 status = readb(req_addr + 528);
303 g_assert_cmpint(status, ==, 0);
304
305 guest_free(alloc, req_addr);
306
307 /* Read request */
308 req.type = VIRTIO_BLK_T_IN;
309 req.ioprio = 1;
310 req.sector = 1;
311 req.data = g_malloc0(512);
312
313 req_addr = virtio_blk_request(alloc, dev, &req, 512);
314
315 g_free(req.data);
316
317 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
318 qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
319
320 qvirtqueue_kick(qts, dev, vq, free_head);
321
322 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
323 QVIRTIO_BLK_TIMEOUT_US);
324 status = readb(req_addr + 528);
325 g_assert_cmpint(status, ==, 0);
326
327 data = g_malloc0(512);
328 memread(req_addr + 16, data, 512);
329 g_assert_cmpstr(data, ==, "TEST");
330 g_free(data);
331
332 guest_free(alloc, req_addr);
333 }
334
335 return vq;
336 }
337
338 static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
339 {
340 QVirtioBlk *blk_if = obj;
341 QVirtQueue *vq;
342
343 vq = test_basic(blk_if->vdev, t_alloc);
344 qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
345
346 }
347
348 static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
349 {
350 QVirtQueue *vq;
351 QVirtioBlk *blk_if = obj;
352 QVirtioDevice *dev = blk_if->vdev;
353 QVirtioBlkReq req;
354 QVRingIndirectDesc *indirect;
355 uint64_t req_addr;
356 uint64_t capacity;
357 uint64_t features;
358 uint32_t free_head;
359 uint8_t status;
360 char *data;
361 QTestState *qts = global_qtest;
362
363 features = qvirtio_get_features(dev);
364 g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
365 features = features & ~(QVIRTIO_F_BAD_FEATURE |
366 (1u << VIRTIO_RING_F_EVENT_IDX) |
367 (1u << VIRTIO_BLK_F_SCSI));
368 qvirtio_set_features(dev, features);
369
370 capacity = qvirtio_config_readq(dev, 0);
371 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
372
373 vq = qvirtqueue_setup(dev, t_alloc, 0);
374 qvirtio_set_driver_ok(dev);
375
376 /* Write request */
377 req.type = VIRTIO_BLK_T_OUT;
378 req.ioprio = 1;
379 req.sector = 0;
380 req.data = g_malloc0(512);
381 strcpy(req.data, "TEST");
382
383 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
384
385 g_free(req.data);
386
387 indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
388 qvring_indirect_desc_add(dev, qts, indirect, req_addr, 528, false);
389 qvring_indirect_desc_add(dev, qts, indirect, req_addr + 528, 1, true);
390 free_head = qvirtqueue_add_indirect(qts, vq, indirect);
391 qvirtqueue_kick(qts, dev, vq, free_head);
392
393 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
394 QVIRTIO_BLK_TIMEOUT_US);
395 status = readb(req_addr + 528);
396 g_assert_cmpint(status, ==, 0);
397
398 g_free(indirect);
399 guest_free(t_alloc, req_addr);
400
401 /* Read request */
402 req.type = VIRTIO_BLK_T_IN;
403 req.ioprio = 1;
404 req.sector = 0;
405 req.data = g_malloc0(512);
406 strcpy(req.data, "TEST");
407
408 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
409
410 g_free(req.data);
411
412 indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
413 qvring_indirect_desc_add(dev, qts, indirect, req_addr, 16, false);
414 qvring_indirect_desc_add(dev, qts, indirect, req_addr + 16, 513, true);
415 free_head = qvirtqueue_add_indirect(qts, vq, indirect);
416 qvirtqueue_kick(qts, dev, vq, free_head);
417
418 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
419 QVIRTIO_BLK_TIMEOUT_US);
420 status = readb(req_addr + 528);
421 g_assert_cmpint(status, ==, 0);
422
423 data = g_malloc0(512);
424 memread(req_addr + 16, data, 512);
425 g_assert_cmpstr(data, ==, "TEST");
426 g_free(data);
427
428 g_free(indirect);
429 guest_free(t_alloc, req_addr);
430 qvirtqueue_cleanup(dev->bus, vq, t_alloc);
431 }
432
433 static void config(void *obj, void *data, QGuestAllocator *t_alloc)
434 {
435 QVirtioBlk *blk_if = obj;
436 QVirtioDevice *dev = blk_if->vdev;
437 int n_size = TEST_IMAGE_SIZE / 2;
438 uint64_t features;
439 uint64_t capacity;
440
441 features = qvirtio_get_features(dev);
442 features = features & ~(QVIRTIO_F_BAD_FEATURE |
443 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
444 (1u << VIRTIO_RING_F_EVENT_IDX) |
445 (1u << VIRTIO_BLK_F_SCSI));
446 qvirtio_set_features(dev, features);
447
448 capacity = qvirtio_config_readq(dev, 0);
449 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
450
451 qvirtio_set_driver_ok(dev);
452
453 qtest_qmp_assert_success(global_qtest,
454 "{ 'execute': 'block_resize', "
455 " 'arguments': { 'device': 'drive0', "
456 " 'size': %d } }", n_size);
457 qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
458
459 capacity = qvirtio_config_readq(dev, 0);
460 g_assert_cmpint(capacity, ==, n_size / 512);
461 }
462
463 static void msix(void *obj, void *u_data, QGuestAllocator *t_alloc)
464 {
465 QVirtQueue *vq;
466 QVirtioBlkPCI *blk = obj;
467 QVirtioPCIDevice *pdev = &blk->pci_vdev;
468 QVirtioDevice *dev = &pdev->vdev;
469 QVirtioBlkReq req;
470 int n_size = TEST_IMAGE_SIZE / 2;
471 uint64_t req_addr;
472 uint64_t capacity;
473 uint64_t features;
474 uint32_t free_head;
475 uint8_t status;
476 char *data;
477 QOSGraphObject *blk_object = obj;
478 QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
479 QTestState *qts = global_qtest;
480
481 if (qpci_check_buggy_msi(pci_dev)) {
482 return;
483 }
484
485 qpci_msix_enable(pdev->pdev);
486 qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
487
488 features = qvirtio_get_features(dev);
489 features = features & ~(QVIRTIO_F_BAD_FEATURE |
490 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
491 (1u << VIRTIO_RING_F_EVENT_IDX) |
492 (1u << VIRTIO_BLK_F_SCSI));
493 qvirtio_set_features(dev, features);
494
495 capacity = qvirtio_config_readq(dev, 0);
496 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
497
498 vq = qvirtqueue_setup(dev, t_alloc, 0);
499 qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
500
501 qvirtio_set_driver_ok(dev);
502
503 qtest_qmp_assert_success(global_qtest,
504 "{ 'execute': 'block_resize', "
505 " 'arguments': { 'device': 'drive0', "
506 " 'size': %d } }", n_size);
507
508 qvirtio_wait_config_isr(dev, QVIRTIO_BLK_TIMEOUT_US);
509
510 capacity = qvirtio_config_readq(dev, 0);
511 g_assert_cmpint(capacity, ==, n_size / 512);
512
513 /* Write request */
514 req.type = VIRTIO_BLK_T_OUT;
515 req.ioprio = 1;
516 req.sector = 0;
517 req.data = g_malloc0(512);
518 strcpy(req.data, "TEST");
519
520 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
521
522 g_free(req.data);
523
524 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
525 qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
526 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
527 qvirtqueue_kick(qts, dev, vq, free_head);
528
529 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
530 QVIRTIO_BLK_TIMEOUT_US);
531
532 status = readb(req_addr + 528);
533 g_assert_cmpint(status, ==, 0);
534
535 guest_free(t_alloc, req_addr);
536
537 /* Read request */
538 req.type = VIRTIO_BLK_T_IN;
539 req.ioprio = 1;
540 req.sector = 0;
541 req.data = g_malloc0(512);
542
543 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
544
545 g_free(req.data);
546
547 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
548 qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
549 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
550
551 qvirtqueue_kick(qts, dev, vq, free_head);
552
553
554 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
555 QVIRTIO_BLK_TIMEOUT_US);
556
557 status = readb(req_addr + 528);
558 g_assert_cmpint(status, ==, 0);
559
560 data = g_malloc0(512);
561 memread(req_addr + 16, data, 512);
562 g_assert_cmpstr(data, ==, "TEST");
563 g_free(data);
564
565 guest_free(t_alloc, req_addr);
566
567 /* End test */
568 qpci_msix_disable(pdev->pdev);
569 qvirtqueue_cleanup(dev->bus, vq, t_alloc);
570 }
571
572 static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
573 {
574 QVirtQueue *vq;
575 QVirtioBlkPCI *blk = obj;
576 QVirtioPCIDevice *pdev = &blk->pci_vdev;
577 QVirtioDevice *dev = &pdev->vdev;
578 QVirtioBlkReq req;
579 uint64_t req_addr;
580 uint64_t capacity;
581 uint64_t features;
582 uint32_t free_head;
583 uint32_t write_head;
584 uint32_t desc_idx;
585 uint8_t status;
586 char *data;
587 QOSGraphObject *blk_object = obj;
588 QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
589 QTestState *qts = global_qtest;
590
591 if (qpci_check_buggy_msi(pci_dev)) {
592 return;
593 }
594
595 qpci_msix_enable(pdev->pdev);
596 qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
597
598 features = qvirtio_get_features(dev);
599 features = features & ~(QVIRTIO_F_BAD_FEATURE |
600 (1u << VIRTIO_RING_F_INDIRECT_DESC) |
601 (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
602 (1u << VIRTIO_BLK_F_SCSI));
603 qvirtio_set_features(dev, features);
604
605 capacity = qvirtio_config_readq(dev, 0);
606 g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
607
608 vq = qvirtqueue_setup(dev, t_alloc, 0);
609 qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
610
611 qvirtio_set_driver_ok(dev);
612
613 /* Write request */
614 req.type = VIRTIO_BLK_T_OUT;
615 req.ioprio = 1;
616 req.sector = 0;
617 req.data = g_malloc0(512);
618 strcpy(req.data, "TEST");
619
620 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
621
622 g_free(req.data);
623
624 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
625 qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
626 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
627 qvirtqueue_kick(qts, dev, vq, free_head);
628
629 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
630 QVIRTIO_BLK_TIMEOUT_US);
631
632 /* Write request */
633 req.type = VIRTIO_BLK_T_OUT;
634 req.ioprio = 1;
635 req.sector = 1;
636 req.data = g_malloc0(512);
637 strcpy(req.data, "TEST");
638
639 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
640
641 g_free(req.data);
642
643 /* Notify after processing the third request */
644 qvirtqueue_set_used_event(qts, vq, 2);
645 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
646 qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
647 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
648 qvirtqueue_kick(qts, dev, vq, free_head);
649 write_head = free_head;
650
651 /* No notification expected */
652 status = qvirtio_wait_status_byte_no_isr(qts, dev,
653 vq, req_addr + 528,
654 QVIRTIO_BLK_TIMEOUT_US);
655 g_assert_cmpint(status, ==, 0);
656
657 guest_free(t_alloc, req_addr);
658
659 /* Read request */
660 req.type = VIRTIO_BLK_T_IN;
661 req.ioprio = 1;
662 req.sector = 1;
663 req.data = g_malloc0(512);
664
665 req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
666
667 g_free(req.data);
668
669 free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
670 qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
671 qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
672
673 qvirtqueue_kick(qts, dev, vq, free_head);
674
675 /* We get just one notification for both requests */
676 qvirtio_wait_used_elem(qts, dev, vq, write_head, NULL,
677 QVIRTIO_BLK_TIMEOUT_US);
678 g_assert(qvirtqueue_get_buf(qts, vq, &desc_idx, NULL));
679 g_assert_cmpint(desc_idx, ==, free_head);
680
681 status = readb(req_addr + 528);
682 g_assert_cmpint(status, ==, 0);
683
684 data = g_malloc0(512);
685 memread(req_addr + 16, data, 512);
686 g_assert_cmpstr(data, ==, "TEST");
687 g_free(data);
688
689 guest_free(t_alloc, req_addr);
690
691 /* End test */
692 qpci_msix_disable(pdev->pdev);
693
694 qvirtqueue_cleanup(dev->bus, vq, t_alloc);
695 }
696
697 static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
698 {
699 QVirtioPCIDevice *dev1 = obj;
700 QVirtioPCIDevice *dev;
701 QTestState *qts = dev1->pdev->bus->qts;
702
703 if (dev1->pdev->bus->not_hotpluggable) {
704 g_test_skip("pci bus does not support hotplug");
705 return;
706 }
707
708 /* plug secondary disk */
709 qtest_qmp_device_add(qts, "virtio-blk-pci", "drv1",
710 "{'addr': %s, 'drive': 'drive1'}",
711 stringify(PCI_SLOT_HP) ".0");
712
713 dev = virtio_pci_new(dev1->pdev->bus,
714 &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0) });
715 g_assert_nonnull(dev);
716 g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
717 qvirtio_pci_device_disable(dev);
718 qos_object_destroy((QOSGraphObject *)dev);
719
720 /* unplug secondary disk */
721 qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
722 }
723
724 /*
725 * Check that setting the vring addr on a non-existent virtqueue does
726 * not crash.
727 */
728 static void test_nonexistent_virtqueue(void *obj, void *data,
729 QGuestAllocator *t_alloc)
730 {
731 QVirtioBlkPCI *blk = obj;
732 QVirtioPCIDevice *pdev = &blk->pci_vdev;
733 QPCIBar bar0;
734 QPCIDevice *dev;
735
736 dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
737 g_assert(dev != NULL);
738 qpci_device_enable(dev);
739
740 bar0 = qpci_iomap(dev, 0, NULL);
741
742 qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
743 qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
744
745
746 g_free(dev);
747 }
748
749 static void resize(void *obj, void *data, QGuestAllocator *t_alloc)
750 {
751 QVirtioBlk *blk_if = obj;
752 QVirtioDevice *dev = blk_if->vdev;
753 int n_size = TEST_IMAGE_SIZE / 2;
754 uint64_t capacity;
755 QVirtQueue *vq;
756 QTestState *qts = global_qtest;
757
758 vq = test_basic(dev, t_alloc);
759
760 qtest_qmp_assert_success(global_qtest,
761 "{ 'execute': 'block_resize', "
762 " 'arguments': { 'device': 'drive0', "
763 " 'size': %d } }", n_size);
764
765 qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
766
767 capacity = qvirtio_config_readq(dev, 0);
768 g_assert_cmpint(capacity, ==, n_size / 512);
769
770 qvirtqueue_cleanup(dev->bus, vq, t_alloc);
771
772 }
773
774 static void *virtio_blk_test_setup(GString *cmd_line, void *arg)
775 {
776 char *tmp_path = drive_create();
777
778 g_string_append_printf(cmd_line,
779 " -drive if=none,id=drive0,file=%s,"
780 "format=raw,auto-read-only=off "
781 "-drive if=none,id=drive1,file=null-co://,"
782 "file.read-zeroes=on,format=raw ",
783 tmp_path);
784
785 return arg;
786 }
787
788 static void register_virtio_blk_test(void)
789 {
790 QOSGraphTestOptions opts = {
791 .before = virtio_blk_test_setup,
792 };
793
794 qos_add_test("indirect", "virtio-blk", indirect, &opts);
795 qos_add_test("config", "virtio-blk", config, &opts);
796 qos_add_test("basic", "virtio-blk", basic, &opts);
797 qos_add_test("resize", "virtio-blk", resize, &opts);
798
799 /* tests just for virtio-blk-pci */
800 qos_add_test("msix", "virtio-blk-pci", msix, &opts);
801 qos_add_test("idx", "virtio-blk-pci", idx, &opts);
802 qos_add_test("nxvirtq", "virtio-blk-pci",
803 test_nonexistent_virtqueue, &opts);
804 qos_add_test("hotplug", "virtio-blk-pci", pci_hotplug, &opts);
805 }
806
807 libqos_init(register_virtio_blk_test);