11cf4323eSThomas Huth #include "qemu/osdep.h" 21cf4323eSThomas Huth #include <sys/wait.h> 31cf4323eSThomas Huth 4*907b5105SMarc-André Lureau #include "../libqtest.h" 5a2ce7dbdSPaolo Bonzini #include "libqos.h" 6a2ce7dbdSPaolo Bonzini #include "pci.h" 71cf4323eSThomas Huth #include "qapi/qmp/qdict.h" 81cf4323eSThomas Huth 91cf4323eSThomas Huth /*** Test Setup & Teardown ***/ 101cf4323eSThomas Huth 111cf4323eSThomas Huth /** 121cf4323eSThomas Huth * Launch QEMU with the given command line, 131cf4323eSThomas Huth * and then set up interrupts and our guest malloc interface. 141cf4323eSThomas Huth * Never returns NULL: 151cf4323eSThomas Huth * Terminates the application in case an error is encountered. 161cf4323eSThomas Huth */ 171cf4323eSThomas Huth QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) 181cf4323eSThomas Huth { 191cf4323eSThomas Huth char *cmdline; 201cf4323eSThomas Huth 211cf4323eSThomas Huth QOSState *qs = g_new0(QOSState, 1); 221cf4323eSThomas Huth 231cf4323eSThomas Huth cmdline = g_strdup_vprintf(cmdline_fmt, ap); 241cf4323eSThomas Huth qs->qts = qtest_init(cmdline); 251cf4323eSThomas Huth qs->ops = ops; 261cf4323eSThomas Huth if (ops) { 271cf4323eSThomas Huth ops->alloc_init(&qs->alloc, qs->qts, ALLOC_NO_FLAGS); 281cf4323eSThomas Huth qs->pcibus = ops->qpci_new(qs->qts, &qs->alloc); 291cf4323eSThomas Huth } 301cf4323eSThomas Huth 311cf4323eSThomas Huth g_free(cmdline); 321cf4323eSThomas Huth return qs; 331cf4323eSThomas Huth } 341cf4323eSThomas Huth 351cf4323eSThomas Huth /** 361cf4323eSThomas Huth * Launch QEMU with the given command line, 371cf4323eSThomas Huth * and then set up interrupts and our guest malloc interface. 381cf4323eSThomas Huth */ 391cf4323eSThomas Huth QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...) 401cf4323eSThomas Huth { 411cf4323eSThomas Huth QOSState *qs; 421cf4323eSThomas Huth va_list ap; 431cf4323eSThomas Huth 441cf4323eSThomas Huth va_start(ap, cmdline_fmt); 451cf4323eSThomas Huth qs = qtest_vboot(ops, cmdline_fmt, ap); 461cf4323eSThomas Huth va_end(ap); 471cf4323eSThomas Huth 481cf4323eSThomas Huth return qs; 491cf4323eSThomas Huth } 501cf4323eSThomas Huth 511cf4323eSThomas Huth /** 521cf4323eSThomas Huth * Tear down the QEMU instance. 531cf4323eSThomas Huth */ 541cf4323eSThomas Huth void qtest_common_shutdown(QOSState *qs) 551cf4323eSThomas Huth { 561cf4323eSThomas Huth if (qs->ops) { 571cf4323eSThomas Huth if (qs->pcibus && qs->ops->qpci_free) { 581cf4323eSThomas Huth qs->ops->qpci_free(qs->pcibus); 591cf4323eSThomas Huth qs->pcibus = NULL; 601cf4323eSThomas Huth } 611cf4323eSThomas Huth } 621cf4323eSThomas Huth alloc_destroy(&qs->alloc); 631cf4323eSThomas Huth qtest_quit(qs->qts); 641cf4323eSThomas Huth g_free(qs); 651cf4323eSThomas Huth } 661cf4323eSThomas Huth 671cf4323eSThomas Huth void qtest_shutdown(QOSState *qs) 681cf4323eSThomas Huth { 691cf4323eSThomas Huth if (qs->ops && qs->ops->shutdown) { 701cf4323eSThomas Huth qs->ops->shutdown(qs); 711cf4323eSThomas Huth } else { 721cf4323eSThomas Huth qtest_common_shutdown(qs); 731cf4323eSThomas Huth } 741cf4323eSThomas Huth } 751cf4323eSThomas Huth 761cf4323eSThomas Huth static QDict *qmp_execute(QTestState *qts, const char *command) 771cf4323eSThomas Huth { 781cf4323eSThomas Huth return qtest_qmp(qts, "{ 'execute': %s }", command); 791cf4323eSThomas Huth } 801cf4323eSThomas Huth 811cf4323eSThomas Huth void migrate(QOSState *from, QOSState *to, const char *uri) 821cf4323eSThomas Huth { 831cf4323eSThomas Huth const char *st; 841cf4323eSThomas Huth QDict *rsp, *sub; 851cf4323eSThomas Huth bool running; 861cf4323eSThomas Huth 871cf4323eSThomas Huth /* Is the machine currently running? */ 881cf4323eSThomas Huth rsp = qmp_execute(from->qts, "query-status"); 891cf4323eSThomas Huth g_assert(qdict_haskey(rsp, "return")); 901cf4323eSThomas Huth sub = qdict_get_qdict(rsp, "return"); 911cf4323eSThomas Huth g_assert(qdict_haskey(sub, "running")); 921cf4323eSThomas Huth running = qdict_get_bool(sub, "running"); 931cf4323eSThomas Huth qobject_unref(rsp); 941cf4323eSThomas Huth 951cf4323eSThomas Huth /* Issue the migrate command. */ 961cf4323eSThomas Huth rsp = qtest_qmp(from->qts, 971cf4323eSThomas Huth "{ 'execute': 'migrate', 'arguments': { 'uri': %s }}", 981cf4323eSThomas Huth uri); 991cf4323eSThomas Huth g_assert(qdict_haskey(rsp, "return")); 1001cf4323eSThomas Huth qobject_unref(rsp); 1011cf4323eSThomas Huth 1021cf4323eSThomas Huth /* Wait for STOP event, but only if we were running: */ 1031cf4323eSThomas Huth if (running) { 1041cf4323eSThomas Huth qtest_qmp_eventwait(from->qts, "STOP"); 1051cf4323eSThomas Huth } 1061cf4323eSThomas Huth 1071cf4323eSThomas Huth /* If we were running, we can wait for an event. */ 1081cf4323eSThomas Huth if (running) { 1091cf4323eSThomas Huth migrate_allocator(&from->alloc, &to->alloc); 1101cf4323eSThomas Huth qtest_qmp_eventwait(to->qts, "RESUME"); 1111cf4323eSThomas Huth return; 1121cf4323eSThomas Huth } 1131cf4323eSThomas Huth 1141cf4323eSThomas Huth /* Otherwise, we need to wait: poll until migration is completed. */ 1151cf4323eSThomas Huth while (1) { 1161cf4323eSThomas Huth rsp = qmp_execute(from->qts, "query-migrate"); 1171cf4323eSThomas Huth g_assert(qdict_haskey(rsp, "return")); 1181cf4323eSThomas Huth sub = qdict_get_qdict(rsp, "return"); 1191cf4323eSThomas Huth g_assert(qdict_haskey(sub, "status")); 1201cf4323eSThomas Huth st = qdict_get_str(sub, "status"); 1211cf4323eSThomas Huth 1221cf4323eSThomas Huth /* "setup", "active", "completed", "failed", "cancelled" */ 1231cf4323eSThomas Huth if (strcmp(st, "completed") == 0) { 1241cf4323eSThomas Huth qobject_unref(rsp); 1251cf4323eSThomas Huth break; 1261cf4323eSThomas Huth } 1271cf4323eSThomas Huth 1281cf4323eSThomas Huth if ((strcmp(st, "setup") == 0) || (strcmp(st, "active") == 0) 1291cf4323eSThomas Huth || (strcmp(st, "wait-unplug") == 0)) { 1301cf4323eSThomas Huth qobject_unref(rsp); 1311cf4323eSThomas Huth g_usleep(5000); 1321cf4323eSThomas Huth continue; 1331cf4323eSThomas Huth } 1341cf4323eSThomas Huth 1351cf4323eSThomas Huth fprintf(stderr, "Migration did not complete, status: %s\n", st); 1361cf4323eSThomas Huth g_assert_not_reached(); 1371cf4323eSThomas Huth } 1381cf4323eSThomas Huth 1391cf4323eSThomas Huth migrate_allocator(&from->alloc, &to->alloc); 1401cf4323eSThomas Huth } 1411cf4323eSThomas Huth 1421cf4323eSThomas Huth bool have_qemu_img(void) 1431cf4323eSThomas Huth { 1441cf4323eSThomas Huth char *rpath; 1451cf4323eSThomas Huth const char *path = getenv("QTEST_QEMU_IMG"); 1461cf4323eSThomas Huth if (!path) { 1471cf4323eSThomas Huth return false; 1481cf4323eSThomas Huth } 1491cf4323eSThomas Huth 1501cf4323eSThomas Huth rpath = realpath(path, NULL); 1511cf4323eSThomas Huth if (!rpath) { 1521cf4323eSThomas Huth return false; 1531cf4323eSThomas Huth } else { 1541cf4323eSThomas Huth free(rpath); 1551cf4323eSThomas Huth return true; 1561cf4323eSThomas Huth } 1571cf4323eSThomas Huth } 1581cf4323eSThomas Huth 1591cf4323eSThomas Huth void mkimg(const char *file, const char *fmt, unsigned size_mb) 1601cf4323eSThomas Huth { 1611cf4323eSThomas Huth gchar *cli; 1621cf4323eSThomas Huth bool ret; 1631cf4323eSThomas Huth int rc; 1641cf4323eSThomas Huth GError *err = NULL; 1651cf4323eSThomas Huth char *qemu_img_path; 1661cf4323eSThomas Huth gchar *out, *out2; 1671cf4323eSThomas Huth char *qemu_img_abs_path; 1681cf4323eSThomas Huth 1691cf4323eSThomas Huth qemu_img_path = getenv("QTEST_QEMU_IMG"); 1701cf4323eSThomas Huth g_assert(qemu_img_path); 1711cf4323eSThomas Huth qemu_img_abs_path = realpath(qemu_img_path, NULL); 1721cf4323eSThomas Huth g_assert(qemu_img_abs_path); 1731cf4323eSThomas Huth 1741cf4323eSThomas Huth cli = g_strdup_printf("%s create -f %s %s %uM", qemu_img_abs_path, 1751cf4323eSThomas Huth fmt, file, size_mb); 1761cf4323eSThomas Huth ret = g_spawn_command_line_sync(cli, &out, &out2, &rc, &err); 1771cf4323eSThomas Huth if (err || !g_spawn_check_exit_status(rc, &err)) { 1781cf4323eSThomas Huth fprintf(stderr, "%s\n", err->message); 1791cf4323eSThomas Huth g_error_free(err); 1801cf4323eSThomas Huth } 1811cf4323eSThomas Huth g_assert(ret && !err); 1821cf4323eSThomas Huth 1831cf4323eSThomas Huth g_free(out); 1841cf4323eSThomas Huth g_free(out2); 1851cf4323eSThomas Huth g_free(cli); 1861cf4323eSThomas Huth free(qemu_img_abs_path); 1871cf4323eSThomas Huth } 1881cf4323eSThomas Huth 1891cf4323eSThomas Huth void mkqcow2(const char *file, unsigned size_mb) 1901cf4323eSThomas Huth { 1911cf4323eSThomas Huth return mkimg(file, "qcow2", size_mb); 1921cf4323eSThomas Huth } 1931cf4323eSThomas Huth 1941cf4323eSThomas Huth void prepare_blkdebug_script(const char *debug_fn, const char *event) 1951cf4323eSThomas Huth { 1961cf4323eSThomas Huth FILE *debug_file = fopen(debug_fn, "w"); 1971cf4323eSThomas Huth int ret; 1981cf4323eSThomas Huth 1991cf4323eSThomas Huth fprintf(debug_file, "[inject-error]\n"); 2001cf4323eSThomas Huth fprintf(debug_file, "event = \"%s\"\n", event); 2011cf4323eSThomas Huth fprintf(debug_file, "errno = \"5\"\n"); 2021cf4323eSThomas Huth fprintf(debug_file, "state = \"1\"\n"); 2031cf4323eSThomas Huth fprintf(debug_file, "immediately = \"off\"\n"); 2041cf4323eSThomas Huth fprintf(debug_file, "once = \"on\"\n"); 2051cf4323eSThomas Huth 2061cf4323eSThomas Huth fprintf(debug_file, "[set-state]\n"); 2071cf4323eSThomas Huth fprintf(debug_file, "event = \"%s\"\n", event); 2081cf4323eSThomas Huth fprintf(debug_file, "new_state = \"2\"\n"); 2091cf4323eSThomas Huth fflush(debug_file); 2101cf4323eSThomas Huth g_assert(!ferror(debug_file)); 2111cf4323eSThomas Huth 2121cf4323eSThomas Huth ret = fclose(debug_file); 2131cf4323eSThomas Huth g_assert(ret == 0); 2141cf4323eSThomas Huth } 2151cf4323eSThomas Huth 2161cf4323eSThomas Huth void generate_pattern(void *buffer, size_t len, size_t cycle_len) 2171cf4323eSThomas Huth { 2181cf4323eSThomas Huth int i, j; 2191cf4323eSThomas Huth unsigned char *tx = (unsigned char *)buffer; 2201cf4323eSThomas Huth unsigned char p; 2211cf4323eSThomas Huth size_t *sx; 2221cf4323eSThomas Huth 2231cf4323eSThomas Huth /* Write an indicative pattern that varies and is unique per-cycle */ 2241cf4323eSThomas Huth p = rand() % 256; 2251cf4323eSThomas Huth for (i = 0; i < len; i++) { 2261cf4323eSThomas Huth tx[i] = p++ % 256; 2271cf4323eSThomas Huth if (i % cycle_len == 0) { 2281cf4323eSThomas Huth p = rand() % 256; 2291cf4323eSThomas Huth } 2301cf4323eSThomas Huth } 2311cf4323eSThomas Huth 2321cf4323eSThomas Huth /* force uniqueness by writing an id per-cycle */ 2331cf4323eSThomas Huth for (i = 0; i < len / cycle_len; i++) { 2341cf4323eSThomas Huth j = i * cycle_len; 2351cf4323eSThomas Huth if (j + sizeof(*sx) <= len) { 2361cf4323eSThomas Huth sx = (size_t *)&tx[j]; 2371cf4323eSThomas Huth *sx = i; 2381cf4323eSThomas Huth } 2391cf4323eSThomas Huth } 2401cf4323eSThomas Huth } 241