1 /* 2 * blockdev.c test cases 3 * 4 * Copyright (C) 2013-2014 Red Hat Inc. 5 * 6 * Authors: 7 * Stefan Hajnoczi <stefanha@redhat.com> 8 * 9 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 10 * See the COPYING.LIB file in the top-level directory. 11 */ 12 13 #include "qemu/osdep.h" 14 #include "libqtest.h" 15 #include "libqos/virtio.h" 16 #include "qapi/qmp/qdict.h" 17 #include "qapi/qmp/qlist.h" 18 19 static const char *qvirtio_get_dev_type(void); 20 21 static bool look_for_drive0(QTestState *qts, const char *command, const char *key) 22 { 23 QDict *response; 24 QList *ret; 25 QListEntry *entry; 26 bool found; 27 28 response = qtest_qmp(qts, "{'execute': %s}", command); 29 g_assert(response && qdict_haskey(response, "return")); 30 ret = qdict_get_qlist(response, "return"); 31 32 found = false; 33 QLIST_FOREACH_ENTRY(ret, entry) { 34 QDict *entry_dict = qobject_to(QDict, entry->value); 35 if (!strcmp(qdict_get_str(entry_dict, key), "drive0")) { 36 found = true; 37 break; 38 } 39 } 40 41 qobject_unref(response); 42 return found; 43 } 44 45 /* 46 * This covers the possible absence of a device due to QEMU build 47 * options. 48 */ 49 static bool has_device_builtin(const char *dev) 50 { 51 gchar *device = g_strdup_printf("%s-%s", dev, qvirtio_get_dev_type()); 52 bool rc = qtest_has_device(device); 53 54 g_free(device); 55 return rc; 56 } 57 58 static bool has_drive(QTestState *qts) 59 { 60 return look_for_drive0(qts, "query-block", "device"); 61 } 62 63 static bool has_blockdev(QTestState *qts) 64 { 65 return look_for_drive0(qts, "query-named-block-nodes", "node-name"); 66 } 67 68 static void blockdev_add_with_media(QTestState *qts) 69 { 70 QDict *response; 71 72 response = qtest_qmp(qts, 73 "{ 'execute': 'blockdev-add'," 74 " 'arguments': {" 75 " 'driver': 'raw'," 76 " 'node-name': 'drive0'," 77 " 'file': {" 78 " 'driver': 'null-co'," 79 " 'read-zeroes': true" 80 " }" 81 " }" 82 "}"); 83 84 g_assert(response); 85 g_assert(qdict_haskey(response, "return")); 86 qobject_unref(response); 87 g_assert(has_blockdev(qts)); 88 } 89 90 static void drive_add(QTestState *qts) 91 { 92 char *resp = qtest_hmp(qts, "drive_add 0 if=none,id=drive0"); 93 94 g_assert_cmpstr(resp, ==, "OK\r\n"); 95 g_assert(has_drive(qts)); 96 g_free(resp); 97 } 98 99 static void drive_add_with_media(QTestState *qts) 100 { 101 char *resp = qtest_hmp(qts, 102 "drive_add 0 if=none,id=drive0,file=null-co://," 103 "file.read-zeroes=on,format=raw"); 104 105 g_assert_cmpstr(resp, ==, "OK\r\n"); 106 g_assert(has_drive(qts)); 107 g_free(resp); 108 } 109 110 static void drive_del(QTestState *qts) 111 { 112 char *resp; 113 114 g_assert(has_drive(qts)); 115 resp = qtest_hmp(qts, "drive_del drive0"); 116 g_assert_cmpstr(resp, ==, ""); 117 g_assert(!has_drive(qts)); 118 g_free(resp); 119 } 120 121 /* 122 * qvirtio_get_dev_type: 123 * Returns: the preferred virtio bus/device type for the current architecture. 124 * TODO: delete this 125 */ 126 static const char *qvirtio_get_dev_type(void) 127 { 128 const char *arch = qtest_get_arch(); 129 130 if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) { 131 return "device"; /* for virtio-mmio */ 132 } else if (g_str_equal(arch, "s390x")) { 133 return "ccw"; 134 } else { 135 return "pci"; 136 } 137 } 138 139 static void device_add(QTestState *qts) 140 { 141 g_autofree char *driver = g_strdup_printf("virtio-blk-%s", 142 qvirtio_get_dev_type()); 143 QDict *response = 144 qtest_qmp(qts, "{'execute': 'device_add'," 145 " 'arguments': {" 146 " 'driver': %s," 147 " 'drive': 'drive0'," 148 " 'id': 'dev0'" 149 "}}", driver); 150 g_assert(response); 151 g_assert(qdict_haskey(response, "return")); 152 qobject_unref(response); 153 } 154 155 static void device_del(QTestState *qts, bool and_reset) 156 { 157 QDict *response; 158 159 qtest_qmp_device_del_send(qts, "dev0"); 160 161 if (and_reset) { 162 response = qtest_qmp(qts, "{'execute': 'system_reset' }"); 163 g_assert(response); 164 g_assert(qdict_haskey(response, "return")); 165 qobject_unref(response); 166 } 167 168 qtest_qmp_eventwait(qts, "DEVICE_DELETED"); 169 } 170 171 static void test_drive_without_dev(void) 172 { 173 QTestState *qts; 174 175 /* Start with an empty drive */ 176 qts = qtest_init("-drive if=none,id=drive0 -M none"); 177 178 /* Delete the drive */ 179 drive_del(qts); 180 181 /* Ensure re-adding the drive works - there should be no duplicate ID error 182 * because the old drive must be gone. 183 */ 184 drive_add(qts); 185 186 qtest_quit(qts); 187 } 188 189 static void test_after_failed_device_add(void) 190 { 191 char driver[32]; 192 QDict *response; 193 QTestState *qts; 194 195 if (!has_device_builtin("virtio-blk")) { 196 g_test_skip("Device virtio-blk is not available"); 197 return; 198 } 199 200 snprintf(driver, sizeof(driver), "virtio-blk-%s", 201 qvirtio_get_dev_type()); 202 203 qts = qtest_init("-drive if=none,id=drive0"); 204 205 /* Make device_add fail. If this leaks the virtio-blk device then a 206 * reference to drive0 will also be held (via qdev properties). 207 */ 208 response = qtest_qmp(qts, "{'execute': 'device_add'," 209 " 'arguments': {" 210 " 'driver': %s," 211 " 'drive': 'drive0'" 212 "}}", driver); 213 g_assert(response); 214 qmp_expect_error_and_unref(response, "GenericError"); 215 216 /* Delete the drive */ 217 drive_del(qts); 218 219 /* Try to re-add the drive. This fails with duplicate IDs if a leaked 220 * virtio-blk device exists that holds a reference to the old drive0. 221 */ 222 drive_add(qts); 223 224 qtest_quit(qts); 225 } 226 227 static void test_drive_del_device_del(void) 228 { 229 QTestState *qts; 230 231 if (!has_device_builtin("virtio-scsi")) { 232 g_test_skip("Device virtio-scsi is not available"); 233 return; 234 } 235 236 /* Start with a drive used by a device that unplugs instantaneously */ 237 qts = qtest_initf("-drive if=none,id=drive0,file=null-co://," 238 "file.read-zeroes=on,format=raw" 239 " -device virtio-scsi-%s" 240 " -device scsi-hd,drive=drive0,id=dev0", 241 qvirtio_get_dev_type()); 242 243 /* 244 * Delete the drive, and then the device 245 * Doing it in this order takes notoriously tricky special paths 246 */ 247 drive_del(qts); 248 device_del(qts, false); 249 g_assert(!has_drive(qts)); 250 251 qtest_quit(qts); 252 } 253 254 static void test_cli_device_del(void) 255 { 256 QTestState *qts; 257 const char *arch = qtest_get_arch(); 258 const char *machine_addition = ""; 259 260 if (!has_device_builtin("virtio-blk")) { 261 g_test_skip("Device virtio-blk is not available"); 262 return; 263 } 264 265 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 266 machine_addition = "-machine pc"; 267 } 268 269 /* 270 * -drive/-device and device_del. Start with a drive used by a 271 * device that unplugs after reset. 272 */ 273 qts = qtest_initf("%s -drive if=none,id=drive0,file=null-co://," 274 "file.read-zeroes=on,format=raw" 275 " -device virtio-blk-%s,drive=drive0,id=dev0", 276 machine_addition, 277 qvirtio_get_dev_type()); 278 279 device_del(qts, true); 280 g_assert(!has_drive(qts)); 281 282 qtest_quit(qts); 283 } 284 285 static void test_cli_device_del_q35(void) 286 { 287 QTestState *qts; 288 289 if (!has_device_builtin("virtio-blk")) { 290 g_test_skip("Device virtio-blk is not available"); 291 return; 292 } 293 294 /* 295 * -drive/-device and device_del. Start with a drive used by a 296 * device that unplugs after reset. 297 */ 298 qts = qtest_initf("-drive if=none,id=drive0,file=null-co://," 299 "file.read-zeroes=on,format=raw " 300 "-machine q35 -device pcie-root-port,id=p1 " 301 "-device pcie-pci-bridge,bus=p1,id=b1 " 302 "-device virtio-blk-%s,drive=drive0,bus=b1,id=dev0", 303 qvirtio_get_dev_type()); 304 305 device_del(qts, true); 306 g_assert(!has_drive(qts)); 307 308 qtest_quit(qts); 309 } 310 311 static void test_empty_device_del(void) 312 { 313 QTestState *qts; 314 315 if (!has_device_builtin("virtio-scsi")) { 316 g_test_skip("Device virtio-scsi is not available"); 317 return; 318 } 319 320 /* device_del with no drive plugged. */ 321 qts = qtest_initf("-device virtio-scsi-%s -device scsi-cd,id=dev0", 322 qvirtio_get_dev_type()); 323 324 device_del(qts, false); 325 qtest_quit(qts); 326 } 327 328 static void test_device_add_and_del(void) 329 { 330 QTestState *qts; 331 const char *arch = qtest_get_arch(); 332 const char *machine_addition = ""; 333 334 if (!has_device_builtin("virtio-blk")) { 335 g_test_skip("Device virtio-blk is not available"); 336 return; 337 } 338 339 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 340 machine_addition = "-machine pc"; 341 } 342 343 /* 344 * -drive/device_add and device_del. Start with a drive used by a 345 * device that unplugs after reset. 346 */ 347 qts = qtest_initf("%s -drive if=none,id=drive0,file=null-co://," 348 "file.read-zeroes=on,format=raw", machine_addition); 349 350 device_add(qts); 351 device_del(qts, true); 352 g_assert(!has_drive(qts)); 353 354 qtest_quit(qts); 355 } 356 357 static void device_add_q35(QTestState *qts) 358 { 359 g_autofree char *driver = g_strdup_printf("virtio-blk-%s", 360 qvirtio_get_dev_type()); 361 QDict *response = 362 qtest_qmp(qts, "{'execute': 'device_add'," 363 " 'arguments': {" 364 " 'driver': %s," 365 " 'drive': 'drive0'," 366 " 'id': 'dev0'," 367 " 'bus': 'b1'" 368 "}}", driver); 369 g_assert(response); 370 g_assert(qdict_haskey(response, "return")); 371 qobject_unref(response); 372 } 373 374 static void test_device_add_and_del_q35(void) 375 { 376 QTestState *qts; 377 378 if (!has_device_builtin("virtio-blk")) { 379 g_test_skip("Device virtio-blk is not available"); 380 return; 381 } 382 383 /* 384 * -drive/device_add and device_del. Start with a drive used by a 385 * device that unplugs after reset. 386 */ 387 qts = qtest_initf("-machine q35 -device pcie-root-port,id=p1 " 388 "-device pcie-pci-bridge,bus=p1,id=b1 " 389 "-drive if=none,id=drive0,file=null-co://," 390 "file.read-zeroes=on,format=raw"); 391 392 device_add_q35(qts); 393 device_del(qts, true); 394 g_assert(!has_drive(qts)); 395 396 qtest_quit(qts); 397 } 398 399 static void test_drive_add_device_add_and_del(void) 400 { 401 QTestState *qts; 402 const char *arch = qtest_get_arch(); 403 const char *machine_addition = ""; 404 405 if (!has_device_builtin("virtio-blk")) { 406 g_test_skip("Device virtio-blk is not available"); 407 return; 408 } 409 410 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 411 machine_addition = "-machine pc"; 412 } 413 414 qts = qtest_init(machine_addition); 415 416 /* 417 * drive_add/device_add and device_del. The drive is used by a 418 * device that unplugs after reset. 419 */ 420 drive_add_with_media(qts); 421 device_add(qts); 422 device_del(qts, true); 423 g_assert(!has_drive(qts)); 424 425 qtest_quit(qts); 426 } 427 428 static void test_drive_add_device_add_and_del_q35(void) 429 { 430 QTestState *qts; 431 432 if (!has_device_builtin("virtio-blk")) { 433 g_test_skip("Device virtio-blk is not available"); 434 return; 435 } 436 437 qts = qtest_init("-machine q35 -device pcie-root-port,id=p1 " 438 "-device pcie-pci-bridge,bus=p1,id=b1"); 439 440 /* 441 * drive_add/device_add and device_del. The drive is used by a 442 * device that unplugs after reset. 443 */ 444 drive_add_with_media(qts); 445 device_add_q35(qts); 446 device_del(qts, true); 447 g_assert(!has_drive(qts)); 448 449 qtest_quit(qts); 450 } 451 452 static void test_blockdev_add_device_add_and_del(void) 453 { 454 QTestState *qts; 455 const char *arch = qtest_get_arch(); 456 const char *machine_addition = ""; 457 458 if (!has_device_builtin("virtio-blk")) { 459 g_test_skip("Device virtio-blk is not available"); 460 return; 461 } 462 463 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 464 machine_addition = "-machine pc"; 465 } 466 467 qts = qtest_init(machine_addition); 468 469 /* 470 * blockdev_add/device_add and device_del. The drive is used by a 471 * device that unplugs after reset, but it doesn't go away. 472 */ 473 blockdev_add_with_media(qts); 474 device_add(qts); 475 device_del(qts, true); 476 g_assert(has_blockdev(qts)); 477 478 qtest_quit(qts); 479 } 480 481 static void test_blockdev_add_device_add_and_del_q35(void) 482 { 483 QTestState *qts; 484 485 if (!has_device_builtin("virtio-blk")) { 486 g_test_skip("Device virtio-blk is not available"); 487 return; 488 } 489 490 qts = qtest_init("-machine q35 -device pcie-root-port,id=p1 " 491 "-device pcie-pci-bridge,bus=p1,id=b1"); 492 493 /* 494 * blockdev_add/device_add and device_del. The drive is used by a 495 * device that unplugs after reset, but it doesn't go away. 496 */ 497 blockdev_add_with_media(qts); 498 device_add_q35(qts); 499 device_del(qts, true); 500 g_assert(has_blockdev(qts)); 501 502 qtest_quit(qts); 503 } 504 505 int main(int argc, char **argv) 506 { 507 g_test_init(&argc, &argv, NULL); 508 509 qtest_add_func("/drive_del/without-dev", test_drive_without_dev); 510 511 if (qvirtio_get_dev_type() != NULL) { 512 qtest_add_func("/drive_del/after_failed_device_add", 513 test_after_failed_device_add); 514 qtest_add_func("/drive_del/drive_del_device_del", 515 test_drive_del_device_del); 516 qtest_add_func("/device_del/drive/cli_device", 517 test_cli_device_del); 518 qtest_add_func("/device_del/drive/device_add", 519 test_device_add_and_del); 520 qtest_add_func("/device_del/drive/drive_add_device_add", 521 test_drive_add_device_add_and_del); 522 qtest_add_func("/device_del/empty", 523 test_empty_device_del); 524 qtest_add_func("/device_del/blockdev", 525 test_blockdev_add_device_add_and_del); 526 527 if (qtest_has_machine("q35")) { 528 qtest_add_func("/device_del/drive/cli_device_q35", 529 test_cli_device_del_q35); 530 qtest_add_func("/device_del/drive/device_add_q35", 531 test_device_add_and_del_q35); 532 qtest_add_func("/device_del/drive/drive_add_device_add_q35", 533 test_drive_add_device_add_and_del_q35); 534 qtest_add_func("/device_del/blockdev_q35", 535 test_blockdev_add_device_add_and_del_q35); 536 } 537 } 538 539 return g_test_run(); 540 } 541