vhost-user-blk-test.c (31510B)
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 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#ifdef HOST_WORDS_BIGENDIAN 41static const bool host_is_big_endian = true; 42#else 43static const bool host_is_big_endian; /* false */ 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 /* 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 */ 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 /* 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 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 /* 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 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 * 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 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 /* plug secondary disk */ 680 qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1", 681 "{'addr': %s, 'chardev': 'char2'}", 682 stringify(PCI_SLOT_HP) ".0"); 683 684 dev = virtio_pci_new(dev1->pdev->bus, 685 &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0) 686 }); 687 g_assert_nonnull(dev); 688 g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK); 689 qvirtio_pci_device_disable(dev); 690 qos_object_destroy((QOSGraphObject *)dev); 691 692 /* unplug secondary disk */ 693 qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP); 694} 695 696static void multiqueue(void *obj, void *data, QGuestAllocator *t_alloc) 697{ 698 QVirtioPCIDevice *pdev1 = obj; 699 QVirtioDevice *dev1 = &pdev1->vdev; 700 QVirtioPCIDevice *pdev8; 701 QVirtioDevice *dev8; 702 QTestState *qts = pdev1->pdev->bus->qts; 703 uint64_t features; 704 uint16_t num_queues; 705 706 /* 707 * The primary device has 1 queue and VIRTIO_BLK_F_MQ is not enabled. The 708 * VIRTIO specification allows VIRTIO_BLK_F_MQ to be enabled when there is 709 * only 1 virtqueue, but --device vhost-user-blk-pci doesn't do this (which 710 * is also spec-compliant). 711 */ 712 features = qvirtio_get_features(dev1); 713 g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ), ==, 0); 714 features = features & ~(QVIRTIO_F_BAD_FEATURE | 715 (1u << VIRTIO_RING_F_INDIRECT_DESC) | 716 (1u << VIRTIO_F_NOTIFY_ON_EMPTY) | 717 (1u << VIRTIO_BLK_F_SCSI)); 718 qvirtio_set_features(dev1, features); 719 720 /* Hotplug a secondary device with 8 queues */ 721 qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1", 722 "{'addr': %s, 'chardev': 'char2', 'num-queues': 8}", 723 stringify(PCI_SLOT_HP) ".0"); 724 725 pdev8 = virtio_pci_new(pdev1->pdev->bus, 726 &(QPCIAddress) { 727 .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0) 728 }); 729 g_assert_nonnull(pdev8); 730 g_assert_cmpint(pdev8->vdev.device_type, ==, VIRTIO_ID_BLOCK); 731 732 qos_object_start_hw(&pdev8->obj); 733 734 dev8 = &pdev8->vdev; 735 features = qvirtio_get_features(dev8); 736 g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ), 737 ==, 738 (1u << VIRTIO_BLK_F_MQ)); 739 features = features & ~(QVIRTIO_F_BAD_FEATURE | 740 (1u << VIRTIO_RING_F_INDIRECT_DESC) | 741 (1u << VIRTIO_F_NOTIFY_ON_EMPTY) | 742 (1u << VIRTIO_BLK_F_SCSI) | 743 (1u << VIRTIO_BLK_F_MQ)); 744 qvirtio_set_features(dev8, features); 745 746 num_queues = qvirtio_config_readw(dev8, 747 offsetof(struct virtio_blk_config, num_queues)); 748 g_assert_cmpint(num_queues, ==, 8); 749 750 qvirtio_pci_device_disable(pdev8); 751 qos_object_destroy(&pdev8->obj); 752 753 /* unplug secondary disk */ 754 qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP); 755} 756 757/* 758 * Check that setting the vring addr on a non-existent virtqueue does 759 * not crash. 760 */ 761static void test_nonexistent_virtqueue(void *obj, void *data, 762 QGuestAllocator *t_alloc) 763{ 764 QVhostUserBlkPCI *blk = obj; 765 QVirtioPCIDevice *pdev = &blk->pci_vdev; 766 QPCIBar bar0; 767 QPCIDevice *dev; 768 769 dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0)); 770 g_assert(dev != NULL); 771 qpci_device_enable(dev); 772 773 bar0 = qpci_iomap(dev, 0, NULL); 774 775 qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2); 776 qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1); 777 778 g_free(dev); 779} 780 781static const char *qtest_qemu_storage_daemon_binary(void) 782{ 783 const char *qemu_storage_daemon_bin; 784 785 qemu_storage_daemon_bin = getenv("QTEST_QEMU_STORAGE_DAEMON_BINARY"); 786 if (!qemu_storage_daemon_bin) { 787 fprintf(stderr, "Environment variable " 788 "QTEST_QEMU_STORAGE_DAEMON_BINARY required\n"); 789 exit(0); 790 } 791 792 /* If we've got a path to the binary, check whether we can access it */ 793 if (strchr(qemu_storage_daemon_bin, '/') && 794 access(qemu_storage_daemon_bin, X_OK) != 0) { 795 fprintf(stderr, "ERROR: '%s' is not accessible\n", 796 qemu_storage_daemon_bin); 797 exit(1); 798 } 799 800 return qemu_storage_daemon_bin; 801} 802 803/* g_test_queue_destroy() cleanup function for files */ 804static void destroy_file(void *path) 805{ 806 unlink(path); 807 g_free(path); 808 qos_invalidate_command_line(); 809} 810 811static char *drive_create(void) 812{ 813 int fd, ret; 814 /** vhost-user-blk won't recognize drive located in /tmp */ 815 char *t_path = g_strdup("qtest.XXXXXX"); 816 817 /** Create a temporary raw image */ 818 fd = mkstemp(t_path); 819 g_assert_cmpint(fd, >=, 0); 820 ret = ftruncate(fd, TEST_IMAGE_SIZE); 821 g_assert_cmpint(ret, ==, 0); 822 close(fd); 823 824 g_test_queue_destroy(destroy_file, t_path); 825 return t_path; 826} 827 828static char *create_listen_socket(int *fd) 829{ 830 int tmp_fd; 831 char *path; 832 833 /* No race because our pid makes the path unique */ 834 path = g_strdup_printf("/tmp/qtest-%d-sock.XXXXXX", getpid()); 835 tmp_fd = mkstemp(path); 836 g_assert_cmpint(tmp_fd, >=, 0); 837 close(tmp_fd); 838 unlink(path); 839 840 *fd = qtest_socket_server(path); 841 g_test_queue_destroy(destroy_file, path); 842 return path; 843} 844 845/* 846 * g_test_queue_destroy() and qtest_add_abrt_handler() cleanup function for 847 * qemu-storage-daemon. 848 */ 849static void quit_storage_daemon(void *data) 850{ 851 QemuStorageDaemonState *qsd = data; 852 int wstatus; 853 pid_t pid; 854 855 /* 856 * If we were invoked as a g_test_queue_destroy() cleanup function we need 857 * to remove the abrt handler to avoid being called again if the code below 858 * aborts. Also, we must not leave the abrt handler installed after 859 * cleanup. 860 */ 861 qtest_remove_abrt_handler(data); 862 863 /* Before quitting storage-daemon, quit qemu to avoid dubious messages */ 864 qtest_kill_qemu(global_qtest); 865 866 kill(qsd->pid, SIGTERM); 867 pid = waitpid(qsd->pid, &wstatus, 0); 868 g_assert_cmpint(pid, ==, qsd->pid); 869 if (!WIFEXITED(wstatus)) { 870 fprintf(stderr, "%s: expected qemu-storage-daemon to exit\n", 871 __func__); 872 abort(); 873 } 874 if (WEXITSTATUS(wstatus) != 0) { 875 fprintf(stderr, "%s: expected qemu-storage-daemon to exit " 876 "successfully, got %d\n", 877 __func__, WEXITSTATUS(wstatus)); 878 abort(); 879 } 880 881 g_free(data); 882} 883 884static void start_vhost_user_blk(GString *cmd_line, int vus_instances, 885 int num_queues) 886{ 887 const char *vhost_user_blk_bin = qtest_qemu_storage_daemon_binary(); 888 int i; 889 gchar *img_path; 890 GString *storage_daemon_command = g_string_new(NULL); 891 QemuStorageDaemonState *qsd; 892 893 g_string_append_printf(storage_daemon_command, 894 "exec %s ", 895 vhost_user_blk_bin); 896 897 g_string_append_printf(cmd_line, 898 " -object memory-backend-memfd,id=mem,size=256M,share=on " 899 " -M memory-backend=mem -m 256M "); 900 901 for (i = 0; i < vus_instances; i++) { 902 int fd; 903 char *sock_path = create_listen_socket(&fd); 904 905 /* create image file */ 906 img_path = drive_create(); 907 g_string_append_printf(storage_daemon_command, 908 "--blockdev driver=file,node-name=disk%d,filename=%s " 909 "--export type=vhost-user-blk,id=disk%d,addr.type=unix,addr.path=%s," 910 "node-name=disk%i,writable=on,num-queues=%d ", 911 i, img_path, i, sock_path, i, num_queues); 912 913 g_string_append_printf(cmd_line, "-chardev socket,id=char%d,path=%s ", 914 i + 1, sock_path); 915 } 916 917 g_test_message("starting vhost-user backend: %s", 918 storage_daemon_command->str); 919 pid_t pid = fork(); 920 if (pid == 0) { 921 /* 922 * Close standard file descriptors so tap-driver.pl pipe detects when 923 * our parent terminates. 924 */ 925 close(0); 926 close(1); 927 open("/dev/null", O_RDONLY); 928 open("/dev/null", O_WRONLY); 929 930 execlp("/bin/sh", "sh", "-c", storage_daemon_command->str, NULL); 931 exit(1); 932 } 933 g_string_free(storage_daemon_command, true); 934 935 qsd = g_new(QemuStorageDaemonState, 1); 936 qsd->pid = pid; 937 938 /* Make sure qemu-storage-daemon is stopped */ 939 qtest_add_abrt_handler(quit_storage_daemon, qsd); 940 g_test_queue_destroy(quit_storage_daemon, qsd); 941} 942 943static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg) 944{ 945 start_vhost_user_blk(cmd_line, 1, 1); 946 return arg; 947} 948 949/* 950 * Setup for hotplug. 951 * 952 * Since vhost-user server only serves one vhost-user client one time, 953 * another exprot 954 * 955 */ 956static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *arg) 957{ 958 /* "-chardev socket,id=char2" is used for pci_hotplug*/ 959 start_vhost_user_blk(cmd_line, 2, 1); 960 return arg; 961} 962 963static void *vhost_user_blk_multiqueue_test_setup(GString *cmd_line, void *arg) 964{ 965 start_vhost_user_blk(cmd_line, 2, 8); 966 return arg; 967} 968 969static void register_vhost_user_blk_test(void) 970{ 971 QOSGraphTestOptions opts = { 972 .before = vhost_user_blk_test_setup, 973 }; 974 975 /* 976 * tests for vhost-user-blk and vhost-user-blk-pci 977 * The tests are borrowed from tests/virtio-blk-test.c. But some tests 978 * regarding block_resize don't work for vhost-user-blk. 979 * vhost-user-blk device doesn't have -drive, so tests containing 980 * block_resize are also abandoned, 981 * - config 982 * - resize 983 */ 984 qos_add_test("basic", "vhost-user-blk", basic, &opts); 985 qos_add_test("indirect", "vhost-user-blk", indirect, &opts); 986 qos_add_test("idx", "vhost-user-blk-pci", idx, &opts); 987 qos_add_test("nxvirtq", "vhost-user-blk-pci", 988 test_nonexistent_virtqueue, &opts); 989 990 opts.before = vhost_user_blk_hotplug_test_setup; 991 qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts); 992 993 opts.before = vhost_user_blk_multiqueue_test_setup; 994 qos_add_test("multiqueue", "vhost-user-blk-pci", multiqueue, &opts); 995} 996 997libqos_init(register_vhost_user_blk_test);