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"); 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 snprintf(driver, sizeof(driver), "virtio-blk-%s", 196 qvirtio_get_dev_type()); 197 198 qts = qtest_init("-drive if=none,id=drive0"); 199 200 /* Make device_add fail. If this leaks the virtio-blk device then a 201 * reference to drive0 will also be held (via qdev properties). 202 */ 203 response = qtest_qmp(qts, "{'execute': 'device_add'," 204 " 'arguments': {" 205 " 'driver': %s," 206 " 'drive': 'drive0'" 207 "}}", driver); 208 g_assert(response); 209 qmp_expect_error_and_unref(response, "GenericError"); 210 211 /* Delete the drive */ 212 drive_del(qts); 213 214 /* Try to re-add the drive. This fails with duplicate IDs if a leaked 215 * virtio-blk device exists that holds a reference to the old drive0. 216 */ 217 drive_add(qts); 218 219 qtest_quit(qts); 220 } 221 222 static void test_drive_del_device_del(void) 223 { 224 QTestState *qts; 225 226 if (!has_device_builtin("virtio-scsi")) { 227 g_test_skip("Device virtio-scsi is not available"); 228 return; 229 } 230 231 /* Start with a drive used by a device that unplugs instantaneously */ 232 qts = qtest_initf("-drive if=none,id=drive0,file=null-co://," 233 "file.read-zeroes=on,format=raw" 234 " -device virtio-scsi-%s" 235 " -device scsi-hd,drive=drive0,id=dev0", 236 qvirtio_get_dev_type()); 237 238 /* 239 * Delete the drive, and then the device 240 * Doing it in this order takes notoriously tricky special paths 241 */ 242 drive_del(qts); 243 device_del(qts, false); 244 g_assert(!has_drive(qts)); 245 246 qtest_quit(qts); 247 } 248 249 static void test_cli_device_del(void) 250 { 251 QTestState *qts; 252 const char *arch = qtest_get_arch(); 253 const char *machine_addition = ""; 254 255 if (!has_device_builtin("virtio-blk")) { 256 g_test_skip("Device virtio-blk is not available"); 257 return; 258 } 259 260 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 261 machine_addition = "-machine pc"; 262 } 263 264 /* 265 * -drive/-device and device_del. Start with a drive used by a 266 * device that unplugs after reset. 267 */ 268 qts = qtest_initf("%s -drive if=none,id=drive0,file=null-co://," 269 "file.read-zeroes=on,format=raw" 270 " -device virtio-blk-%s,drive=drive0,id=dev0", 271 machine_addition, 272 qvirtio_get_dev_type()); 273 274 device_del(qts, true); 275 g_assert(!has_drive(qts)); 276 277 qtest_quit(qts); 278 } 279 280 static void test_cli_device_del_q35(void) 281 { 282 QTestState *qts; 283 284 if (!has_device_builtin("virtio-blk")) { 285 g_test_skip("Device virtio-blk is not available"); 286 return; 287 } 288 289 /* 290 * -drive/-device and device_del. Start with a drive used by a 291 * device that unplugs after reset. 292 */ 293 qts = qtest_initf("-drive if=none,id=drive0,file=null-co://," 294 "file.read-zeroes=on,format=raw " 295 "-machine q35 -device pcie-root-port,id=p1 " 296 "-device pcie-pci-bridge,bus=p1,id=b1 " 297 "-device virtio-blk-%s,drive=drive0,bus=b1,id=dev0", 298 qvirtio_get_dev_type()); 299 300 device_del(qts, true); 301 g_assert(!has_drive(qts)); 302 303 qtest_quit(qts); 304 } 305 306 static void test_empty_device_del(void) 307 { 308 QTestState *qts; 309 310 if (!has_device_builtin("virtio-scsi")) { 311 g_test_skip("Device virtio-scsi is not available"); 312 return; 313 } 314 315 /* device_del with no drive plugged. */ 316 qts = qtest_initf("-device virtio-scsi-%s -device scsi-cd,id=dev0", 317 qvirtio_get_dev_type()); 318 319 device_del(qts, false); 320 qtest_quit(qts); 321 } 322 323 static void test_device_add_and_del(void) 324 { 325 QTestState *qts; 326 const char *arch = qtest_get_arch(); 327 const char *machine_addition = ""; 328 329 if (!has_device_builtin("virtio-blk")) { 330 g_test_skip("Device virtio-blk is not available"); 331 return; 332 } 333 334 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 335 machine_addition = "-machine pc"; 336 } 337 338 /* 339 * -drive/device_add and device_del. Start with a drive used by a 340 * device that unplugs after reset. 341 */ 342 qts = qtest_initf("%s -drive if=none,id=drive0,file=null-co://," 343 "file.read-zeroes=on,format=raw", machine_addition); 344 345 device_add(qts); 346 device_del(qts, true); 347 g_assert(!has_drive(qts)); 348 349 qtest_quit(qts); 350 } 351 352 static void device_add_q35(QTestState *qts) 353 { 354 g_autofree char *driver = g_strdup_printf("virtio-blk-%s", 355 qvirtio_get_dev_type()); 356 QDict *response = 357 qtest_qmp(qts, "{'execute': 'device_add'," 358 " 'arguments': {" 359 " 'driver': %s," 360 " 'drive': 'drive0'," 361 " 'id': 'dev0'," 362 " 'bus': 'b1'" 363 "}}", driver); 364 g_assert(response); 365 g_assert(qdict_haskey(response, "return")); 366 qobject_unref(response); 367 } 368 369 static void test_device_add_and_del_q35(void) 370 { 371 QTestState *qts; 372 373 if (!has_device_builtin("virtio-blk")) { 374 g_test_skip("Device virtio-blk is not available"); 375 return; 376 } 377 378 /* 379 * -drive/device_add and device_del. Start with a drive used by a 380 * device that unplugs after reset. 381 */ 382 qts = qtest_initf("-machine q35 -device pcie-root-port,id=p1 " 383 "-device pcie-pci-bridge,bus=p1,id=b1 " 384 "-drive if=none,id=drive0,file=null-co://," 385 "file.read-zeroes=on,format=raw"); 386 387 device_add_q35(qts); 388 device_del(qts, true); 389 g_assert(!has_drive(qts)); 390 391 qtest_quit(qts); 392 } 393 394 static void test_drive_add_device_add_and_del(void) 395 { 396 QTestState *qts; 397 const char *arch = qtest_get_arch(); 398 const char *machine_addition = ""; 399 400 if (!has_device_builtin("virtio-blk")) { 401 g_test_skip("Device virtio-blk is not available"); 402 return; 403 } 404 405 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 406 machine_addition = "-machine pc"; 407 } 408 409 qts = qtest_init(machine_addition); 410 411 /* 412 * drive_add/device_add and device_del. The drive is used by a 413 * device that unplugs after reset. 414 */ 415 drive_add_with_media(qts); 416 device_add(qts); 417 device_del(qts, true); 418 g_assert(!has_drive(qts)); 419 420 qtest_quit(qts); 421 } 422 423 static void test_drive_add_device_add_and_del_q35(void) 424 { 425 QTestState *qts; 426 427 if (!has_device_builtin("virtio-blk")) { 428 g_test_skip("Device virtio-blk is not available"); 429 return; 430 } 431 432 qts = qtest_init("-machine q35 -device pcie-root-port,id=p1 " 433 "-device pcie-pci-bridge,bus=p1,id=b1"); 434 435 /* 436 * drive_add/device_add and device_del. The drive is used by a 437 * device that unplugs after reset. 438 */ 439 drive_add_with_media(qts); 440 device_add_q35(qts); 441 device_del(qts, true); 442 g_assert(!has_drive(qts)); 443 444 qtest_quit(qts); 445 } 446 447 static void test_blockdev_add_device_add_and_del(void) 448 { 449 QTestState *qts; 450 const char *arch = qtest_get_arch(); 451 const char *machine_addition = ""; 452 453 if (!has_device_builtin("virtio-blk")) { 454 g_test_skip("Device virtio-blk is not available"); 455 return; 456 } 457 458 if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { 459 machine_addition = "-machine pc"; 460 } 461 462 qts = qtest_init(machine_addition); 463 464 /* 465 * blockdev_add/device_add and device_del. The drive is used by a 466 * device that unplugs after reset, but it doesn't go away. 467 */ 468 blockdev_add_with_media(qts); 469 device_add(qts); 470 device_del(qts, true); 471 g_assert(has_blockdev(qts)); 472 473 qtest_quit(qts); 474 } 475 476 static void test_blockdev_add_device_add_and_del_q35(void) 477 { 478 QTestState *qts; 479 480 if (!has_device_builtin("virtio-blk")) { 481 g_test_skip("Device virtio-blk is not available"); 482 return; 483 } 484 485 qts = qtest_init("-machine q35 -device pcie-root-port,id=p1 " 486 "-device pcie-pci-bridge,bus=p1,id=b1"); 487 488 /* 489 * blockdev_add/device_add and device_del. The drive is used by a 490 * device that unplugs after reset, but it doesn't go away. 491 */ 492 blockdev_add_with_media(qts); 493 device_add_q35(qts); 494 device_del(qts, true); 495 g_assert(has_blockdev(qts)); 496 497 qtest_quit(qts); 498 } 499 500 int main(int argc, char **argv) 501 { 502 g_test_init(&argc, &argv, NULL); 503 504 qtest_add_func("/drive_del/without-dev", test_drive_without_dev); 505 506 if (qvirtio_get_dev_type() != NULL) { 507 qtest_add_func("/drive_del/after_failed_device_add", 508 test_after_failed_device_add); 509 qtest_add_func("/drive_del/drive_del_device_del", 510 test_drive_del_device_del); 511 qtest_add_func("/device_del/drive/cli_device", 512 test_cli_device_del); 513 qtest_add_func("/device_del/drive/device_add", 514 test_device_add_and_del); 515 qtest_add_func("/device_del/drive/drive_add_device_add", 516 test_drive_add_device_add_and_del); 517 qtest_add_func("/device_del/empty", 518 test_empty_device_del); 519 qtest_add_func("/device_del/blockdev", 520 test_blockdev_add_device_add_and_del); 521 522 if (qtest_has_machine("q35")) { 523 qtest_add_func("/device_del/drive/cli_device_q35", 524 test_cli_device_del_q35); 525 qtest_add_func("/device_del/drive/device_add_q35", 526 test_device_add_and_del_q35); 527 qtest_add_func("/device_del/drive/drive_add_device_add_q35", 528 test_drive_add_device_add_and_del_q35); 529 qtest_add_func("/device_del/blockdev_q35", 530 test_blockdev_add_device_add_and_del_q35); 531 } 532 } 533 534 return g_test_run(); 535 } 536