1 /* 2 * QTest testcase for Vhost-user Block Device 3 * 4 * Based on tests/qtest//virtio-blk-test.c 5 6 * Copyright (c) 2014 SUSE LINUX Products GmbH 7 * Copyright (c) 2014 Marc Marí 8 * Copyright (c) 2020 Coiby Xu 9 * 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. 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 28 typedef struct { 29 pid_t pid; 30 } QemuStorageDaemonState; 31 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; 39 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 45 46 static 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 55 static 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 65 static 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 97 static 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 /* 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; 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 /* 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; 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 /* 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; 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 /* 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; 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 /* Returns the request virtqueue so the caller can perform further tests */ 216 static 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 /* 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"); 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 /* Read request */ 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 * WRITE_ZEROES request on the same sector of previous test where 301 * we wrote "TEST". 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 /* 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); 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 /* 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"); 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 /* Read request */ 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 447 static 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 457 static 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 /* 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"); 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 /* 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"); 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 542 static 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 * 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. 586 */ 587 qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US); 588 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"); 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 /* 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"); 614 615 req_addr = virtio_blk_request(t_alloc, dev, &req, 512); 616 617 g_free(req.data); 618 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; 626 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); 632 633 guest_free(t_alloc, req_addr); 634 635 /* Read request */ 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 /* 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); 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 /* End test */ 668 qpci_msix_disable(pdev->pdev); 669 670 qvirtqueue_cleanup(dev->bus, vq, t_alloc); 671 } 672 673 static 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 /* 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"); 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 /* unplug secondary disk */ 698 qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP); 699 } 700 701 static 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 * 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). 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 /* 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"); 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 /* unplug secondary disk */ 764 qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP); 765 } 766 767 /* 768 * Check that setting the vring addr on a non-existent virtqueue does 769 * not crash. 770 */ 771 static 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 791 static 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 /* 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); 808 } 809 810 return qemu_storage_daemon_bin; 811 } 812 813 /* g_test_queue_destroy() cleanup function for files */ 814 static void destroy_file(void *path) 815 { 816 unlink(path); 817 g_free(path); 818 qos_invalidate_command_line(); 819 } 820 821 static char *drive_create(void) 822 { 823 int fd, ret; 824 /** vhost-user-blk won't recognize drive located in /tmp */ 825 char *t_path = g_strdup("qtest.XXXXXX"); 826 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); 833 834 g_test_queue_destroy(destroy_file, t_path); 835 return t_path; 836 } 837 838 static char *create_listen_socket(int *fd) 839 { 840 int tmp_fd; 841 char *path; 842 843 /* No race because our pid makes the path unique */ 844 path = g_strdup_printf("/tmp/qtest-%d-sock.XXXXXX", getpid()); 845 tmp_fd = mkstemp(path); 846 g_assert_cmpint(tmp_fd, >=, 0); 847 close(tmp_fd); 848 unlink(path); 849 850 *fd = qtest_socket_server(path); 851 g_test_queue_destroy(destroy_file, path); 852 return path; 853 } 854 855 /* 856 * g_test_queue_destroy() and qtest_add_abrt_handler() cleanup function for 857 * qemu-storage-daemon. 858 */ 859 static void quit_storage_daemon(void *data) 860 { 861 QemuStorageDaemonState *qsd = data; 862 int wstatus; 863 pid_t pid; 864 865 /* 866 * If we were invoked as a g_test_queue_destroy() cleanup function we need 867 * to remove the abrt handler to avoid being called again if the code below 868 * aborts. Also, we must not leave the abrt handler installed after 869 * cleanup. 870 */ 871 qtest_remove_abrt_handler(data); 872 873 /* Before quitting storage-daemon, quit qemu to avoid dubious messages */ 874 qtest_kill_qemu(global_qtest); 875 876 kill(qsd->pid, SIGTERM); 877 pid = waitpid(qsd->pid, &wstatus, 0); 878 g_assert_cmpint(pid, ==, qsd->pid); 879 if (!WIFEXITED(wstatus)) { 880 fprintf(stderr, "%s: expected qemu-storage-daemon to exit\n", 881 __func__); 882 abort(); 883 } 884 if (WEXITSTATUS(wstatus) != 0) { 885 fprintf(stderr, "%s: expected qemu-storage-daemon to exit " 886 "successfully, got %d\n", 887 __func__, WEXITSTATUS(wstatus)); 888 abort(); 889 } 890 891 g_free(data); 892 } 893 894 static void start_vhost_user_blk(GString *cmd_line, int vus_instances, 895 int num_queues) 896 { 897 const char *vhost_user_blk_bin = qtest_qemu_storage_daemon_binary(); 898 int i; 899 gchar *img_path; 900 GString *storage_daemon_command = g_string_new(NULL); 901 QemuStorageDaemonState *qsd; 902 903 g_string_append_printf(storage_daemon_command, 904 "exec %s ", 905 vhost_user_blk_bin); 906 907 g_string_append_printf(cmd_line, 908 " -object memory-backend-memfd,id=mem,size=256M,share=on " 909 " -M memory-backend=mem -m 256M "); 910 911 for (i = 0; i < vus_instances; i++) { 912 int fd; 913 char *sock_path = create_listen_socket(&fd); 914 915 /* create image file */ 916 img_path = drive_create(); 917 g_string_append_printf(storage_daemon_command, 918 "--blockdev driver=file,node-name=disk%d,filename=%s " 919 "--export type=vhost-user-blk,id=disk%d,addr.type=fd,addr.str=%d," 920 "node-name=disk%i,writable=on,num-queues=%d ", 921 i, img_path, i, fd, i, num_queues); 922 923 g_string_append_printf(cmd_line, "-chardev socket,id=char%d,path=%s ", 924 i + 1, sock_path); 925 } 926 927 g_test_message("starting vhost-user backend: %s", 928 storage_daemon_command->str); 929 pid_t pid = fork(); 930 if (pid == 0) { 931 /* 932 * Close standard file descriptors so tap-driver.pl pipe detects when 933 * our parent terminates. 934 */ 935 close(0); 936 close(1); 937 open("/dev/null", O_RDONLY); 938 open("/dev/null", O_WRONLY); 939 940 execlp("/bin/sh", "sh", "-c", storage_daemon_command->str, NULL); 941 exit(1); 942 } 943 g_string_free(storage_daemon_command, true); 944 945 qsd = g_new(QemuStorageDaemonState, 1); 946 qsd->pid = pid; 947 948 /* Make sure qemu-storage-daemon is stopped */ 949 qtest_add_abrt_handler(quit_storage_daemon, qsd); 950 g_test_queue_destroy(quit_storage_daemon, qsd); 951 } 952 953 static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg) 954 { 955 start_vhost_user_blk(cmd_line, 1, 1); 956 return arg; 957 } 958 959 /* 960 * Setup for hotplug. 961 * 962 * Since vhost-user server only serves one vhost-user client one time, 963 * another exprot 964 * 965 */ 966 static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *arg) 967 { 968 /* "-chardev socket,id=char2" is used for pci_hotplug*/ 969 start_vhost_user_blk(cmd_line, 2, 1); 970 return arg; 971 } 972 973 static void *vhost_user_blk_multiqueue_test_setup(GString *cmd_line, void *arg) 974 { 975 start_vhost_user_blk(cmd_line, 2, 8); 976 return arg; 977 } 978 979 static void register_vhost_user_blk_test(void) 980 { 981 QOSGraphTestOptions opts = { 982 .before = vhost_user_blk_test_setup, 983 }; 984 985 /* 986 * tests for vhost-user-blk and vhost-user-blk-pci 987 * The tests are borrowed from tests/virtio-blk-test.c. But some tests 988 * regarding block_resize don't work for vhost-user-blk. 989 * vhost-user-blk device doesn't have -drive, so tests containing 990 * block_resize are also abandoned, 991 * - config 992 * - resize 993 */ 994 qos_add_test("basic", "vhost-user-blk", basic, &opts); 995 qos_add_test("indirect", "vhost-user-blk", indirect, &opts); 996 qos_add_test("idx", "vhost-user-blk-pci", idx, &opts); 997 qos_add_test("nxvirtq", "vhost-user-blk-pci", 998 test_nonexistent_virtqueue, &opts); 999 1000 opts.before = vhost_user_blk_hotplug_test_setup; 1001 qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts); 1002 1003 opts.before = vhost_user_blk_multiqueue_test_setup; 1004 qos_add_test("multiqueue", "vhost-user-blk-pci", multiqueue, &opts); 1005 } 1006 1007 libqos_init(register_vhost_user_blk_test); 1008