diff options
Diffstat (limited to 'tests')
31 files changed, 2273 insertions, 75 deletions
diff --git a/tests/.gitignore b/tests/.gitignore index 425757cfe1..1aed2249ff 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -20,6 +20,7 @@ test-qmp-commands test-qmp-input-strict test-qmp-marshal.c test-thread-pool +test-vmstate test-x86-cpuid test-xbzrle *-test diff --git a/tests/Makefile b/tests/Makefile index 379cdd9ad1..fd36eee641 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -52,6 +52,9 @@ check-unit-y += tests/test-int128$(EXESUF) gcov-files-test-int128-y = check-unit-y += tests/test-bitops$(EXESUF) check-unit-y += tests/test-qdev-global-props$(EXESUF) +check-unit-y += tests/check-qom-interface$(EXESUF) +gcov-files-check-qom-interface-y = qom/object.c +check-unit-y += tests/test-vmstate$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh @@ -64,6 +67,7 @@ check-qtest-i386-y += tests/ide-test$(EXESUF) check-qtest-i386-y += tests/hd-geo-test$(EXESUF) gcov-files-i386-y += hw/hd-geometry.c check-qtest-i386-y += tests/boot-order-test$(EXESUF) +check-qtest-i386-y += tests/acpi-test$(EXESUF) check-qtest-i386-y += tests/rtc-test$(EXESUF) check-qtest-i386-y += tests/i440fx-test$(EXESUF) check-qtest-i386-y += tests/fw_cfg-test$(EXESUF) @@ -137,6 +141,7 @@ test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o $(test-obj-y): QEMU_INCLUDES += -Itests QEMU_CFLAGS += -I$(SRC_PATH)/tests +qom-core-obj = qom/object.o qom/qom-qobject.o qom/container.o tests/test-x86-cpuid.o: QEMU_INCLUDES += -I$(SRC_PATH)/target-i386 @@ -146,6 +151,7 @@ tests/check-qdict$(EXESUF): tests/check-qdict.o libqemuutil.a tests/check-qlist$(EXESUF): tests/check-qlist.o libqemuutil.a tests/check-qfloat$(EXESUF): tests/check-qfloat.o libqemuutil.a tests/check-qjson$(EXESUF): tests/check-qjson.o libqemuutil.a libqemustub.a +tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(qom-core-obj) libqemuutil.a libqemustub.a tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(block-obj-y) libqemuutil.a libqemustub.a tests/test-aio$(EXESUF): tests/test-aio.o $(block-obj-y) libqemuutil.a libqemustub.a tests/test-throttle$(EXESUF): tests/test-throttle.o $(block-obj-y) libqemuutil.a libqemustub.a @@ -159,9 +165,12 @@ tests/test-int128$(EXESUF): tests/test-int128.o tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ hw/core/qdev.o hw/core/qdev-properties.o \ hw/core/irq.o \ - qom/object.o qom/container.o qom/qom-qobject.o \ + $(qom-core-obj) \ $(test-qapi-obj-y) \ libqemuutil.a libqemustub.a +tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ + vmstate.o qemu-file.o \ + libqemuutil.a tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py @@ -198,6 +207,7 @@ tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y) +tests/acpi-test$(EXESUF): tests/acpi-test.o $(libqos-obj-y) tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y) tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y) tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y) diff --git a/tests/acpi-test.c b/tests/acpi-test.c new file mode 100644 index 0000000000..df1af83158 --- /dev/null +++ b/tests/acpi-test.c @@ -0,0 +1,397 @@ +/* + * Boot order test cases. + * + * Copyright (c) 2013 Red Hat Inc. + * + * Authors: + * Michael S. Tsirkin <mst@redhat.com>, + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include <string.h> +#include <stdio.h> +#include <glib.h> +#include "qemu-common.h" +#include "libqtest.h" +#include "qemu/compiler.h" +#include "hw/i386/acpi-defs.h" + +/* DSDT and SSDTs format */ +typedef struct { + AcpiTableHeader header; + uint8_t *aml; + int aml_len; +} AcpiSdtTable; + +typedef struct { + uint32_t rsdp_addr; + AcpiRsdpDescriptor rsdp_table; + AcpiRsdtDescriptorRev1 rsdt_table; + AcpiFadtDescriptorRev1 fadt_table; + AcpiFacsDescriptorRev1 facs_table; + uint32_t *rsdt_tables_addr; + int rsdt_tables_nr; + AcpiSdtTable dsdt_table; + GArray *ssdt_tables; +} test_data; + +#define LOW(x) ((x) & 0xff) +#define HIGH(x) ((x) >> 8) + +#define SIGNATURE 0xdead +#define SIGNATURE_OFFSET 0x10 +#define BOOT_SECTOR_ADDRESS 0x7c00 + +#define ACPI_READ_FIELD(field, addr) \ + do { \ + switch (sizeof(field)) { \ + case 1: \ + field = readb(addr); \ + break; \ + case 2: \ + field = le16_to_cpu(readw(addr)); \ + break; \ + case 4: \ + field = le32_to_cpu(readl(addr)); \ + break; \ + case 8: \ + field = le64_to_cpu(readq(addr)); \ + break; \ + default: \ + g_assert(false); \ + } \ + addr += sizeof(field); \ + } while (0); + +#define ACPI_READ_ARRAY_PTR(arr, length, addr) \ + do { \ + int idx; \ + for (idx = 0; idx < length; ++idx) { \ + ACPI_READ_FIELD(arr[idx], addr); \ + } \ + } while (0); + +#define ACPI_READ_ARRAY(arr, addr) \ + ACPI_READ_ARRAY_PTR(arr, sizeof(arr)/sizeof(arr[0]), addr) + +#define ACPI_READ_TABLE_HEADER(table, addr) \ + do { \ + ACPI_READ_FIELD((table)->signature, addr); \ + ACPI_READ_FIELD((table)->length, addr); \ + ACPI_READ_FIELD((table)->revision, addr); \ + ACPI_READ_FIELD((table)->checksum, addr); \ + ACPI_READ_ARRAY((table)->oem_id, addr); \ + ACPI_READ_ARRAY((table)->oem_table_id, addr); \ + ACPI_READ_FIELD((table)->oem_revision, addr); \ + ACPI_READ_ARRAY((table)->asl_compiler_id, addr); \ + ACPI_READ_FIELD((table)->asl_compiler_revision, addr); \ + } while (0); + +/* Boot sector code: write SIGNATURE into memory, + * then halt. + */ +static uint8_t boot_sector[0x200] = { + /* 7c00: mov $0xdead,%ax */ + [0x00] = 0xb8, + [0x01] = LOW(SIGNATURE), + [0x02] = HIGH(SIGNATURE), + /* 7c03: mov %ax,0x7c10 */ + [0x03] = 0xa3, + [0x04] = LOW(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET), + [0x05] = HIGH(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET), + /* 7c06: cli */ + [0x06] = 0xfa, + /* 7c07: hlt */ + [0x07] = 0xf4, + /* 7c08: jmp 0x7c07=0x7c0a-3 */ + [0x08] = 0xeb, + [0x09] = LOW(-3), + /* We mov 0xdead here: set value to make debugging easier */ + [SIGNATURE_OFFSET] = LOW(0xface), + [SIGNATURE_OFFSET + 1] = HIGH(0xface), + /* End of boot sector marker */ + [0x1FE] = 0x55, + [0x1FF] = 0xAA, +}; + +static const char *disk = "tests/acpi-test-disk.raw"; + +static void free_test_data(test_data *data) +{ + int i; + + g_free(data->rsdt_tables_addr); + for (i = 0; i < data->ssdt_tables->len; ++i) { + g_free(g_array_index(data->ssdt_tables, AcpiSdtTable, i).aml); + } + g_array_free(data->ssdt_tables, false); + g_free(data->dsdt_table.aml); +} + +static uint8_t acpi_checksum(const uint8_t *data, int len) +{ + int i; + uint8_t sum = 0; + + for (i = 0; i < len; i++) { + sum += data[i]; + } + + return sum; +} + +static void test_acpi_rsdp_address(test_data *data) +{ + uint32_t off; + + /* OK, now find RSDP */ + for (off = 0xf0000; off < 0x100000; off += 0x10) { + uint8_t sig[] = "RSD PTR "; + int i; + + for (i = 0; i < sizeof sig - 1; ++i) { + sig[i] = readb(off + i); + } + + if (!memcmp(sig, "RSD PTR ", sizeof sig)) { + break; + } + } + + g_assert_cmphex(off, <, 0x100000); + data->rsdp_addr = off; +} + +static void test_acpi_rsdp_table(test_data *data) +{ + AcpiRsdpDescriptor *rsdp_table = &data->rsdp_table; + uint32_t addr = data->rsdp_addr; + + ACPI_READ_FIELD(rsdp_table->signature, addr); + g_assert_cmphex(rsdp_table->signature, ==, ACPI_RSDP_SIGNATURE); + + ACPI_READ_FIELD(rsdp_table->checksum, addr); + ACPI_READ_ARRAY(rsdp_table->oem_id, addr); + ACPI_READ_FIELD(rsdp_table->revision, addr); + ACPI_READ_FIELD(rsdp_table->rsdt_physical_address, addr); + ACPI_READ_FIELD(rsdp_table->length, addr); + + /* rsdp checksum is not for the whole table, but for the first 20 bytes */ + g_assert(!acpi_checksum((uint8_t *)rsdp_table, 20)); +} + +static void test_acpi_rsdt_table(test_data *data) +{ + AcpiRsdtDescriptorRev1 *rsdt_table = &data->rsdt_table; + uint32_t addr = data->rsdp_table.rsdt_physical_address; + uint32_t *tables; + int tables_nr; + uint8_t checksum; + + /* read the header */ + ACPI_READ_TABLE_HEADER(rsdt_table, addr); + g_assert_cmphex(rsdt_table->signature, ==, ACPI_RSDT_SIGNATURE); + + /* compute the table entries in rsdt */ + tables_nr = (rsdt_table->length - sizeof(AcpiRsdtDescriptorRev1)) / + sizeof(uint32_t); + g_assert_cmpint(tables_nr, >, 0); + + /* get the addresses of the tables pointed by rsdt */ + tables = g_new0(uint32_t, tables_nr); + ACPI_READ_ARRAY_PTR(tables, tables_nr, addr); + + checksum = acpi_checksum((uint8_t *)rsdt_table, rsdt_table->length) + + acpi_checksum((uint8_t *)tables, tables_nr * sizeof(uint32_t)); + g_assert(!checksum); + + /* SSDT tables after FADT */ + data->rsdt_tables_addr = tables; + data->rsdt_tables_nr = tables_nr; +} + +static void test_acpi_fadt_table(test_data *data) +{ + AcpiFadtDescriptorRev1 *fadt_table = &data->fadt_table; + uint32_t addr; + + /* FADT table comes first */ + addr = data->rsdt_tables_addr[0]; + ACPI_READ_TABLE_HEADER(fadt_table, addr); + + ACPI_READ_FIELD(fadt_table->firmware_ctrl, addr); + ACPI_READ_FIELD(fadt_table->dsdt, addr); + ACPI_READ_FIELD(fadt_table->model, addr); + ACPI_READ_FIELD(fadt_table->reserved1, addr); + ACPI_READ_FIELD(fadt_table->sci_int, addr); + ACPI_READ_FIELD(fadt_table->smi_cmd, addr); + ACPI_READ_FIELD(fadt_table->acpi_enable, addr); + ACPI_READ_FIELD(fadt_table->acpi_disable, addr); + ACPI_READ_FIELD(fadt_table->S4bios_req, addr); + ACPI_READ_FIELD(fadt_table->reserved2, addr); + ACPI_READ_FIELD(fadt_table->pm1a_evt_blk, addr); + ACPI_READ_FIELD(fadt_table->pm1b_evt_blk, addr); + ACPI_READ_FIELD(fadt_table->pm1a_cnt_blk, addr); + ACPI_READ_FIELD(fadt_table->pm1b_cnt_blk, addr); + ACPI_READ_FIELD(fadt_table->pm2_cnt_blk, addr); + ACPI_READ_FIELD(fadt_table->pm_tmr_blk, addr); + ACPI_READ_FIELD(fadt_table->gpe0_blk, addr); + ACPI_READ_FIELD(fadt_table->gpe1_blk, addr); + ACPI_READ_FIELD(fadt_table->pm1_evt_len, addr); + ACPI_READ_FIELD(fadt_table->pm1_cnt_len, addr); + ACPI_READ_FIELD(fadt_table->pm2_cnt_len, addr); + ACPI_READ_FIELD(fadt_table->pm_tmr_len, addr); + ACPI_READ_FIELD(fadt_table->gpe0_blk_len, addr); + ACPI_READ_FIELD(fadt_table->gpe1_blk_len, addr); + ACPI_READ_FIELD(fadt_table->gpe1_base, addr); + ACPI_READ_FIELD(fadt_table->reserved3, addr); + ACPI_READ_FIELD(fadt_table->plvl2_lat, addr); + ACPI_READ_FIELD(fadt_table->plvl3_lat, addr); + ACPI_READ_FIELD(fadt_table->flush_size, addr); + ACPI_READ_FIELD(fadt_table->flush_stride, addr); + ACPI_READ_FIELD(fadt_table->duty_offset, addr); + ACPI_READ_FIELD(fadt_table->duty_width, addr); + ACPI_READ_FIELD(fadt_table->day_alrm, addr); + ACPI_READ_FIELD(fadt_table->mon_alrm, addr); + ACPI_READ_FIELD(fadt_table->century, addr); + ACPI_READ_FIELD(fadt_table->reserved4, addr); + ACPI_READ_FIELD(fadt_table->reserved4a, addr); + ACPI_READ_FIELD(fadt_table->reserved4b, addr); + ACPI_READ_FIELD(fadt_table->flags, addr); + + g_assert_cmphex(fadt_table->signature, ==, ACPI_FACP_SIGNATURE); + g_assert(!acpi_checksum((uint8_t *)fadt_table, fadt_table->length)); +} + +static void test_acpi_facs_table(test_data *data) +{ + AcpiFacsDescriptorRev1 *facs_table = &data->facs_table; + uint32_t addr = data->fadt_table.firmware_ctrl; + + ACPI_READ_FIELD(facs_table->signature, addr); + ACPI_READ_FIELD(facs_table->length, addr); + ACPI_READ_FIELD(facs_table->hardware_signature, addr); + ACPI_READ_FIELD(facs_table->firmware_waking_vector, addr); + ACPI_READ_FIELD(facs_table->global_lock, addr); + ACPI_READ_FIELD(facs_table->flags, addr); + ACPI_READ_ARRAY(facs_table->resverved3, addr); + + g_assert_cmphex(facs_table->signature, ==, ACPI_FACS_SIGNATURE); +} + +static void test_dst_table(AcpiSdtTable *sdt_table, uint32_t addr) +{ + uint8_t checksum; + + ACPI_READ_TABLE_HEADER(&sdt_table->header, addr); + + sdt_table->aml_len = sdt_table->header.length - sizeof(AcpiTableHeader); + sdt_table->aml = g_malloc0(sdt_table->aml_len); + ACPI_READ_ARRAY_PTR(sdt_table->aml, sdt_table->aml_len, addr); + + checksum = acpi_checksum((uint8_t *)sdt_table, sizeof(AcpiTableHeader)) + + acpi_checksum(sdt_table->aml, sdt_table->aml_len); + g_assert(!checksum); +} + +static void test_acpi_dsdt_table(test_data *data) +{ + AcpiSdtTable *dsdt_table = &data->dsdt_table; + uint32_t addr = data->fadt_table.dsdt; + + test_dst_table(dsdt_table, addr); + g_assert_cmphex(dsdt_table->header.signature, ==, ACPI_DSDT_SIGNATURE); +} + +static void test_acpi_ssdt_tables(test_data *data) +{ + GArray *ssdt_tables; + int ssdt_tables_nr = data->rsdt_tables_nr - 1; /* fadt is first */ + int i; + + ssdt_tables = g_array_sized_new(false, true, sizeof(AcpiSdtTable), + ssdt_tables_nr); + for (i = 0; i < ssdt_tables_nr; i++) { + AcpiSdtTable ssdt_table; + uint32_t addr = data->rsdt_tables_addr[i + 1]; /* fadt is first */ + test_dst_table(&ssdt_table, addr); + g_array_append_val(ssdt_tables, ssdt_table); + } + data->ssdt_tables = ssdt_tables; +} + +static void test_acpi_one(const char *params, test_data *data) +{ + char *args; + uint8_t signature_low; + uint8_t signature_high; + uint16_t signature; + int i; + + memset(data, 0, sizeof(*data)); + args = g_strdup_printf("-net none -display none %s %s", + params ? params : "", disk); + qtest_start(args); + + /* Wait at most 1 minute */ +#define TEST_DELAY (1 * G_USEC_PER_SEC / 10) +#define TEST_CYCLES MAX((60 * G_USEC_PER_SEC / TEST_DELAY), 1) + + /* Poll until code has run and modified memory. Once it has we know BIOS + * initialization is done. TODO: check that IP reached the halt + * instruction. + */ + for (i = 0; i < TEST_CYCLES; ++i) { + signature_low = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET); + signature_high = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1); + signature = (signature_high << 8) | signature_low; + if (signature == SIGNATURE) { + break; + } + g_usleep(TEST_DELAY); + } + g_assert_cmphex(signature, ==, SIGNATURE); + + test_acpi_rsdp_address(data); + test_acpi_rsdp_table(data); + test_acpi_rsdt_table(data); + test_acpi_fadt_table(data); + test_acpi_facs_table(data); + test_acpi_dsdt_table(data); + test_acpi_ssdt_tables(data); + + qtest_quit(global_qtest); + g_free(args); +} + +static void test_acpi_tcg(void) +{ + test_data data; + + /* Supplying -machine accel argument overrides the default (qtest). + * This is to make guest actually run. + */ + test_acpi_one("-machine accel=tcg", &data); + + free_test_data(&data); +} + +int main(int argc, char *argv[]) +{ + const char *arch = qtest_get_arch(); + FILE *f = fopen(disk, "w"); + int ret; + fwrite(boot_sector, 1, sizeof boot_sector, f); + fclose(f); + + g_test_init(&argc, &argv, NULL); + + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + qtest_add_func("acpi/tcg", test_acpi_tcg); + } + ret = g_test_run(); + unlink(disk); + return ret; +} diff --git a/tests/check-qdict.c b/tests/check-qdict.c index dc5f05a85f..7a7461b0b2 100644 --- a/tests/check-qdict.c +++ b/tests/check-qdict.c @@ -227,6 +227,160 @@ static void qdict_iterapi_test(void) QDECREF(tests_dict); } +static void qdict_flatten_test(void) +{ + QList *list1 = qlist_new(); + QList *list2 = qlist_new(); + QDict *dict1 = qdict_new(); + QDict *dict2 = qdict_new(); + QDict *dict3 = qdict_new(); + + /* + * Test the flattening of + * + * { + * "e": [ + * 42, + * [ + * 23, + * 66, + * { + * "a": 0, + * "b": 1 + * } + * ] + * ], + * "f": { + * "c": 2, + * "d": 3, + * }, + * "g": 4 + * } + * + * to + * + * { + * "e.0": 42, + * "e.1.0": 23, + * "e.1.1": 66, + * "e.1.2.a": 0, + * "e.1.2.b": 1, + * "f.c": 2, + * "f.d": 3, + * "g": 4 + * } + */ + + qdict_put(dict1, "a", qint_from_int(0)); + qdict_put(dict1, "b", qint_from_int(1)); + + qlist_append_obj(list1, QOBJECT(qint_from_int(23))); + qlist_append_obj(list1, QOBJECT(qint_from_int(66))); + qlist_append_obj(list1, QOBJECT(dict1)); + qlist_append_obj(list2, QOBJECT(qint_from_int(42))); + qlist_append_obj(list2, QOBJECT(list1)); + + qdict_put(dict2, "c", qint_from_int(2)); + qdict_put(dict2, "d", qint_from_int(3)); + qdict_put_obj(dict3, "e", QOBJECT(list2)); + qdict_put_obj(dict3, "f", QOBJECT(dict2)); + qdict_put(dict3, "g", qint_from_int(4)); + + qdict_flatten(dict3); + + g_assert(qdict_get_int(dict3, "e.0") == 42); + g_assert(qdict_get_int(dict3, "e.1.0") == 23); + g_assert(qdict_get_int(dict3, "e.1.1") == 66); + g_assert(qdict_get_int(dict3, "e.1.2.a") == 0); + g_assert(qdict_get_int(dict3, "e.1.2.b") == 1); + g_assert(qdict_get_int(dict3, "f.c") == 2); + g_assert(qdict_get_int(dict3, "f.d") == 3); + g_assert(qdict_get_int(dict3, "g") == 4); + + g_assert(qdict_size(dict3) == 8); + + QDECREF(dict3); +} + +static void qdict_array_split_test(void) +{ + QDict *test_dict = qdict_new(); + QDict *dict1, *dict2; + QList *test_list; + + /* + * Test the split of + * + * { + * "1.x": 0, + * "3.y": 1, + * "0.a": 42, + * "o.o": 7, + * "0.b": 23 + * } + * + * to + * + * [ + * { + * "a": 42, + * "b": 23 + * }, + * { + * "x": 0 + * } + * ] + * + * and + * + * { + * "3.y": 1, + * "o.o": 7 + * } + * + * (remaining in the old QDict) + * + * This example is given in the comment of qdict_array_split(). + */ + + qdict_put(test_dict, "1.x", qint_from_int(0)); + qdict_put(test_dict, "3.y", qint_from_int(1)); + qdict_put(test_dict, "0.a", qint_from_int(42)); + qdict_put(test_dict, "o.o", qint_from_int(7)); + qdict_put(test_dict, "0.b", qint_from_int(23)); + + qdict_array_split(test_dict, &test_list); + + dict1 = qobject_to_qdict(qlist_pop(test_list)); + dict2 = qobject_to_qdict(qlist_pop(test_list)); + + g_assert(dict1); + g_assert(dict2); + g_assert(qlist_empty(test_list)); + + QDECREF(test_list); + + g_assert(qdict_get_int(dict1, "a") == 42); + g_assert(qdict_get_int(dict1, "b") == 23); + + g_assert(qdict_size(dict1) == 2); + + QDECREF(dict1); + + g_assert(qdict_get_int(dict2, "x") == 0); + + g_assert(qdict_size(dict2) == 1); + + QDECREF(dict2); + + g_assert(qdict_get_int(test_dict, "3.y") == 1); + g_assert(qdict_get_int(test_dict, "o.o") == 7); + + g_assert(qdict_size(test_dict) == 2); + + QDECREF(test_dict); +} + /* * Errors test-cases */ @@ -365,6 +519,8 @@ int main(int argc, char **argv) g_test_add_func("/public/del", qdict_del_test); g_test_add_func("/public/to_qdict", qobject_to_qdict_test); g_test_add_func("/public/iterapi", qdict_iterapi_test); + g_test_add_func("/public/flatten", qdict_flatten_test); + g_test_add_func("/public/array_split", qdict_array_split_test); g_test_add_func("/errors/put_exists", qdict_put_exists_test); g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test); diff --git a/tests/check-qom-interface.c b/tests/check-qom-interface.c new file mode 100644 index 0000000000..f06380ef14 --- /dev/null +++ b/tests/check-qom-interface.c @@ -0,0 +1,105 @@ +/* + * QOM interface test. + * + * Copyright (C) 2013 Red Hat Inc. + * + * Authors: + * Igor Mammedov <imammedo@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. + * See the COPYING.LIB file in the top-level directory. + */ +#include <glib.h> + +#include "qom/object.h" +#include "qemu/module.h" + + +#define TYPE_TEST_IF "test-interface" +#define TEST_IF_CLASS(klass) \ + OBJECT_CLASS_CHECK(TestIfClass, (klass), TYPE_TEST_IF) +#define TEST_IF_GET_CLASS(obj) \ + OBJECT_GET_CLASS(TestIfClass, (obj), TYPE_TEST_IF) +#define TEST_IF(obj) \ + INTERFACE_CHECK(TestIf, (obj), TYPE_TEST_IF) + +typedef struct TestIf { + Object parent_obj; +} TestIf; + +typedef struct TestIfClass { + InterfaceClass parent_class; + + uint32_t test; +} TestIfClass; + +static const TypeInfo test_if_info = { + .name = TYPE_TEST_IF, + .parent = TYPE_INTERFACE, + .class_size = sizeof(TestIfClass), +}; + +#define PATTERN 0xFAFBFCFD + +static void test_class_init(ObjectClass *oc, void *data) +{ + TestIfClass *tc = TEST_IF_CLASS(oc); + + g_assert(tc); + tc->test = PATTERN; +} + +#define TYPE_DIRECT_IMPL "direct-impl" + +static const TypeInfo direct_impl_info = { + .name = TYPE_DIRECT_IMPL, + .parent = TYPE_OBJECT, + .class_init = test_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_TEST_IF }, + { } + } +}; + +#define TYPE_INTERMEDIATE_IMPL "intermediate-impl" + +static const TypeInfo intermediate_impl_info = { + .name = TYPE_INTERMEDIATE_IMPL, + .parent = TYPE_DIRECT_IMPL, +}; + +static void test_interface_impl(const char *type) +{ + Object *obj = object_new(type); + TestIf *iobj = TEST_IF(obj); + TestIfClass *ioc = TEST_IF_GET_CLASS(iobj); + + g_assert(iobj); + g_assert(ioc->test == PATTERN); +} + +static void interface_direct_test(void) +{ + test_interface_impl(TYPE_DIRECT_IMPL); +} + +static void interface_intermediate_test(void) +{ + test_interface_impl(TYPE_INTERMEDIATE_IMPL); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + module_call_init(MODULE_INIT_QOM); + type_register_static(&test_if_info); + type_register_static(&direct_impl_info); + type_register_static(&intermediate_impl_info); + + g_test_add_func("/qom/interface/direct_impl", interface_direct_test); + g_test_add_func("/qom/interface/intermediate_impl", + interface_intermediate_test); + + return g_test_run(); +} diff --git a/tests/fdc-test.c b/tests/fdc-test.c index 38b5b178d0..37096dcc13 100644 --- a/tests/fdc-test.c +++ b/tests/fdc-test.c @@ -518,7 +518,6 @@ static void fuzz_registers(void) int main(int argc, char **argv) { const char *arch = qtest_get_arch(); - char *cmdline; int fd; int ret; @@ -538,9 +537,7 @@ int main(int argc, char **argv) /* Run the tests */ g_test_init(&argc, &argv, NULL); - cmdline = g_strdup_printf("-vnc none "); - - qtest_start(cmdline); + qtest_start(NULL); qtest_irq_intercept_in(global_qtest, "ioapic"); qtest_add_func("/fdc/cmos", test_cmos); qtest_add_func("/fdc/no_media_on_start", test_no_media_on_start); diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c index 65c786ca1e..fa3e3d6b87 100644 --- a/tests/i440fx-test.c +++ b/tests/i440fx-test.c @@ -2,9 +2,11 @@ * qtest I440FX test case * * Copyright IBM, Corp. 2012-2013 + * Copyright Red Hat, Inc. 2013 * * Authors: * Anthony Liguori <aliguori@us.ibm.com> + * Laszlo Ersek <lersek@redhat.com> * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. @@ -18,6 +20,11 @@ #include <glib.h> #include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <sys/mman.h> +#include <stdlib.h> #define BROKEN 1 @@ -26,16 +33,32 @@ typedef struct TestData { int num_cpus; - QPCIBus *bus; } TestData; +typedef struct FirmwareTestFixture { + /* decides whether we're testing -bios or -pflash */ + bool is_bios; +} FirmwareTestFixture; + +static QPCIBus *test_start_get_bus(const TestData *s) +{ + char *cmdline; + + cmdline = g_strdup_printf("-smp %d", s->num_cpus); + qtest_start(cmdline); + g_free(cmdline); + return qpci_init_pc(); +} + static void test_i440fx_defaults(gconstpointer opaque) { const TestData *s = opaque; + QPCIBus *bus; QPCIDevice *dev; uint32_t value; - dev = qpci_device_find(s->bus, QPCI_DEVFN(0, 0)); + bus = test_start_get_bus(s); + dev = qpci_device_find(bus, QPCI_DEVFN(0, 0)); g_assert(dev != NULL); /* 3.2.2 */ @@ -119,6 +142,8 @@ static void test_i440fx_defaults(gconstpointer opaque) g_assert_cmpint(qpci_config_readb(dev, 0x91), ==, 0x00); /* ERRSTS */ /* 3.2.26 */ g_assert_cmpint(qpci_config_readb(dev, 0x93), ==, 0x00); /* TRC */ + + qtest_end(); } #define PAM_RE 1 @@ -177,6 +202,7 @@ static void write_area(uint32_t start, uint32_t end, uint8_t value) static void test_i440fx_pam(gconstpointer opaque) { const TestData *s = opaque; + QPCIBus *bus; QPCIDevice *dev; int i; static struct { @@ -199,7 +225,8 @@ static void test_i440fx_pam(gconstpointer opaque) { 0xEC000, 0xEFFFF }, /* BIOS Extension */ }; - dev = qpci_device_find(s->bus, QPCI_DEVFN(0, 0)); + bus = test_start_get_bus(s); + dev = qpci_device_find(bus, QPCI_DEVFN(0, 0)); g_assert(dev != NULL); for (i = 0; i < ARRAY_SIZE(pam_area); i++) { @@ -252,34 +279,140 @@ static void test_i440fx_pam(gconstpointer opaque) /* Verify the area is not our new mask */ g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x82)); } + qtest_end(); +} + +#define BLOB_SIZE ((size_t)65536) +#define ISA_BIOS_MAXSZ ((size_t)(128 * 1024)) + +/* Create a blob file, and return its absolute pathname as a dynamically + * allocated string. + * The file is closed before the function returns. + * In case of error, NULL is returned. The function prints the error message. + */ +static char *create_blob_file(void) +{ + int ret, fd; + char *pathname; + GError *error = NULL; + + ret = -1; + fd = g_file_open_tmp("blob_XXXXXX", &pathname, &error); + if (fd == -1) { + fprintf(stderr, "unable to create blob file: %s\n", error->message); + g_error_free(error); + } else { + if (ftruncate(fd, BLOB_SIZE) == -1) { + fprintf(stderr, "ftruncate(\"%s\", %zu): %s\n", pathname, + BLOB_SIZE, strerror(errno)); + } else { + void *buf; + + buf = mmap(NULL, BLOB_SIZE, PROT_WRITE, MAP_SHARED, fd, 0); + if (buf == MAP_FAILED) { + fprintf(stderr, "mmap(\"%s\", %zu): %s\n", pathname, BLOB_SIZE, + strerror(errno)); + } else { + size_t i; + + for (i = 0; i < BLOB_SIZE; ++i) { + ((uint8_t *)buf)[i] = i; + } + munmap(buf, BLOB_SIZE); + ret = 0; + } + } + close(fd); + if (ret == -1) { + unlink(pathname); + g_free(pathname); + } + } + + return ret == -1 ? NULL : pathname; +} + +static void test_i440fx_firmware(FirmwareTestFixture *fixture, + gconstpointer user_data) +{ + char *fw_pathname, *cmdline; + uint8_t *buf; + size_t i, isa_bios_size; + + fw_pathname = create_blob_file(); + g_assert(fw_pathname != NULL); + + /* Better hope the user didn't put metacharacters in TMPDIR and co. */ + cmdline = g_strdup_printf("-S %s %s", + fixture->is_bios ? "-bios" : "-pflash", + fw_pathname); + g_test_message("qemu cmdline: %s", cmdline); + qtest_start(cmdline); + g_free(cmdline); + + /* Qemu has loaded the firmware (because qtest_start() only returns after + * the QMP handshake completes). We must unlink the firmware blob right + * here, because any assertion firing below would leak it in the + * filesystem. This is also the reason why we recreate the blob every time + * this function is invoked. + */ + unlink(fw_pathname); + g_free(fw_pathname); + + /* check below 4G */ + buf = g_malloc0(BLOB_SIZE); + memread(0x100000000ULL - BLOB_SIZE, buf, BLOB_SIZE); + for (i = 0; i < BLOB_SIZE; ++i) { + g_assert_cmphex(buf[i], ==, (uint8_t)i); + } + + /* check in ISA space too */ + memset(buf, 0, BLOB_SIZE); + isa_bios_size = ISA_BIOS_MAXSZ < BLOB_SIZE ? ISA_BIOS_MAXSZ : BLOB_SIZE; + memread(0x100000 - isa_bios_size, buf, isa_bios_size); + for (i = 0; i < isa_bios_size; ++i) { + g_assert_cmphex(buf[i], ==, + (uint8_t)((BLOB_SIZE - isa_bios_size) + i)); + } + + g_free(buf); + qtest_end(); +} + +static void add_firmware_test(const char *testpath, + void (*setup_fixture)(FirmwareTestFixture *f, + gconstpointer test_data)) +{ + g_test_add(testpath, FirmwareTestFixture, NULL, setup_fixture, + test_i440fx_firmware, NULL); +} + +static void request_bios(FirmwareTestFixture *fixture, + gconstpointer user_data) +{ + fixture->is_bios = true; +} + +static void request_pflash(FirmwareTestFixture *fixture, + gconstpointer user_data) +{ + fixture->is_bios = false; } int main(int argc, char **argv) { - QTestState *s; TestData data; - char *cmdline; int ret; g_test_init(&argc, &argv, NULL); data.num_cpus = 1; - cmdline = g_strdup_printf("-smp %d", data.num_cpus); - s = qtest_start(cmdline); - g_free(cmdline); - - data.bus = qpci_init_pc(); - g_test_add_data_func("/i440fx/defaults", &data, test_i440fx_defaults); g_test_add_data_func("/i440fx/pam", &data, test_i440fx_pam); - + add_firmware_test("/i440fx/firmware/bios", request_bios); + add_firmware_test("/i440fx/firmware/pflash", request_pflash); ret = g_test_run(); - - if (s) { - qtest_quit(s); - } - return ret; } diff --git a/tests/ide-test.c b/tests/ide-test.c index d5cec5a1fc..4a0d97f197 100644 --- a/tests/ide-test.c +++ b/tests/ide-test.c @@ -380,7 +380,6 @@ static void test_bmdma_no_busmaster(void) static void test_bmdma_setup(void) { ide_test_start( - "-vnc none " "-drive file=%s,if=ide,serial=%s,cache=writeback " "-global ide-hd.ver=%s", tmp_path, "testdisk", "version"); @@ -410,7 +409,6 @@ static void test_identify(void) int ret; ide_test_start( - "-vnc none " "-drive file=%s,if=ide,serial=%s,cache=writeback " "-global ide-hd.ver=%s", tmp_path, "testdisk", "version"); @@ -455,7 +453,6 @@ static void test_flush(void) uint8_t data; ide_test_start( - "-vnc none " "-drive file=blkdebug::%s,if=ide,cache=writeback", tmp_path); diff --git a/tests/qdev-monitor-test.c b/tests/qdev-monitor-test.c index 33a8ea4b9c..ba7f9cc238 100644 --- a/tests/qdev-monitor-test.c +++ b/tests/qdev-monitor-test.c @@ -32,10 +32,8 @@ static void test_device_add(void) "}}"); g_assert(response); error = qdict_get_qdict(response, "error"); - g_assert(!strcmp(qdict_get_try_str(error, "class") ?: "", - "GenericError")); g_assert(!strcmp(qdict_get_try_str(error, "desc") ?: "", - "Device initialization failed.")); + "Device needs media, but drive is empty")); QDECREF(response); /* Delete the drive */ diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017 index aba3faf712..3af3cdfbc3 100755 --- a/tests/qemu-iotests/017 +++ b/tests/qemu-iotests/017 @@ -43,6 +43,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow qcow2 vmdk qed _supported_proto generic _supported_os Linux +_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" TEST_OFFSETS="0 4294967296" diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018 index 15fcfe5670..6f7f0545d0 100755 --- a/tests/qemu-iotests/018 +++ b/tests/qemu-iotests/018 @@ -43,6 +43,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow qcow2 vmdk qed _supported_proto generic _supported_os Linux +_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" TEST_OFFSETS="0 4294967296" diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019 index 5bb18d0c0a..b43e70f3cb 100755 --- a/tests/qemu-iotests/019 +++ b/tests/qemu-iotests/019 @@ -47,6 +47,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow qcow2 vmdk qed _supported_proto generic _supported_os Linux +_unsupported_imgopts "subformat=monolithicFlat" \ + "subformat=twoGbMaxExtentFlat" \ + "subformat=twoGbMaxExtentSparse" TEST_OFFSETS="0 4294967296" CLUSTER_SIZE=65536 diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020 index b3c86d844e..73a0429481 100755 --- a/tests/qemu-iotests/020 +++ b/tests/qemu-iotests/020 @@ -45,6 +45,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow qcow2 vmdk qed _supported_proto generic _supported_os Linux +_unsupported_imgopts "subformat=monolithicFlat" \ + "subformat=twoGbMaxExtentFlat" \ + "subformat=twoGbMaxExtentSparse" TEST_OFFSETS="0 4294967296" diff --git a/tests/qemu-iotests/034 b/tests/qemu-iotests/034 index 67f1959690..7349789583 100755 --- a/tests/qemu-iotests/034 +++ b/tests/qemu-iotests/034 @@ -41,6 +41,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow qcow2 vmdk qed _supported_proto generic _supported_os Linux +_unsupported_imgopts "subformat=monolithicFlat" \ + "subformat=twoGbMaxExtentFlat" \ + "subformat=twoGbMaxExtentSparse" CLUSTER_SIZE=4k size=128M diff --git a/tests/qemu-iotests/037 b/tests/qemu-iotests/037 index 743bae33d3..e444349e6d 100755 --- a/tests/qemu-iotests/037 +++ b/tests/qemu-iotests/037 @@ -41,6 +41,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow qcow2 vmdk qed _supported_proto generic _supported_os Linux +_unsupported_imgopts "subformat=monolithicFlat" \ + "subformat=twoGbMaxExtentFlat" \ + "subformat=twoGbMaxExtentSparse" CLUSTER_SIZE=4k size=128M diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 index 18dcd61ef2..72eaad5b08 100755 --- a/tests/qemu-iotests/040 +++ b/tests/qemu-iotests/040 @@ -39,6 +39,29 @@ class ImageCommitTestCase(iotests.QMPTestCase): result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return', []) + def run_commit_test(self, top, base): + self.assert_no_active_commit() + result = self.vm.qmp('block-commit', device='drive0', top=top, base=base) + self.assert_qmp(result, 'return', {}) + + completed = False + while not completed: + for event in self.vm.get_qmp_events(wait=True): + if event['event'] == 'BLOCK_JOB_COMPLETED': + self.assert_qmp(event, 'data/type', 'commit') + self.assert_qmp(event, 'data/device', 'drive0') + self.assert_qmp(event, 'data/offset', self.image_len) + self.assert_qmp(event, 'data/len', self.image_len) + completed = True + elif event['event'] == 'BLOCK_JOB_READY': + self.assert_qmp(event, 'data/type', 'commit') + self.assert_qmp(event, 'data/device', 'drive0') + self.assert_qmp(event, 'data/len', self.image_len) + self.vm.qmp('block-job-complete', device='drive0') + + self.assert_no_active_commit() + self.vm.shutdown() + class TestSingleDrive(ImageCommitTestCase): image_len = 1 * 1024 * 1024 test_len = 1 * 1024 * 256 @@ -59,23 +82,7 @@ class TestSingleDrive(ImageCommitTestCase): os.remove(backing_img) def test_commit(self): - self.assert_no_active_commit() - result = self.vm.qmp('block-commit', device='drive0', top='%s' % mid_img) - self.assert_qmp(result, 'return', {}) - - completed = False - while not completed: - for event in self.vm.get_qmp_events(wait=True): - if event['event'] == 'BLOCK_JOB_COMPLETED': - self.assert_qmp(event, 'data/type', 'commit') - self.assert_qmp(event, 'data/device', 'drive0') - self.assert_qmp(event, 'data/offset', self.image_len) - self.assert_qmp(event, 'data/len', self.image_len) - completed = True - - self.assert_no_active_commit() - self.vm.shutdown() - + self.run_commit_test(mid_img, backing_img) self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) @@ -102,10 +109,9 @@ class TestSingleDrive(ImageCommitTestCase): self.assert_qmp(result, 'error/desc', 'Base \'badfile\' not found') def test_top_is_active(self): - self.assert_no_active_commit() - result = self.vm.qmp('block-commit', device='drive0', top='%s' % test_img, base='%s' % backing_img) - self.assert_qmp(result, 'error/class', 'GenericError') - self.assert_qmp(result, 'error/desc', 'Top image as the active layer is currently unsupported') + self.run_commit_test(test_img, backing_img) + self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) + self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) def test_top_and_base_reversed(self): self.assert_no_active_commit() @@ -166,23 +172,7 @@ class TestRelativePaths(ImageCommitTestCase): raise def test_commit(self): - self.assert_no_active_commit() - result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.mid_img) - self.assert_qmp(result, 'return', {}) - - completed = False - while not completed: - for event in self.vm.get_qmp_events(wait=True): - if event['event'] == 'BLOCK_JOB_COMPLETED': - self.assert_qmp(event, 'data/type', 'commit') - self.assert_qmp(event, 'data/device', 'drive0') - self.assert_qmp(event, 'data/offset', self.image_len) - self.assert_qmp(event, 'data/len', self.image_len) - completed = True - - self.assert_no_active_commit() - self.vm.shutdown() - + self.run_commit_test(self.mid_img, self.backing_img) self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', self.backing_img_abs).find("verification failed")) self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed")) @@ -209,10 +199,9 @@ class TestRelativePaths(ImageCommitTestCase): self.assert_qmp(result, 'error/desc', 'Base \'badfile\' not found') def test_top_is_active(self): - self.assert_no_active_commit() - result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.test_img, base='%s' % self.backing_img) - self.assert_qmp(result, 'error/class', 'GenericError') - self.assert_qmp(result, 'error/desc', 'Top image as the active layer is currently unsupported') + self.run_commit_test(self.test_img, self.backing_img) + self.assertEqual(-1, qemu_io('-c', 'read -P 0xab 0 524288', self.backing_img_abs).find("verification failed")) + self.assertEqual(-1, qemu_io('-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed")) def test_top_and_base_reversed(self): self.assert_no_active_commit() @@ -229,6 +218,7 @@ class TestSetSpeed(ImageCommitTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) qemu_io('-c', 'write -P 0x1 0 512', test_img) + qemu_io('-c', 'write -P 0xef 524288 524288', mid_img) self.vm = iotests.VM().add_drive(test_img) self.vm.launch() diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 49e95a20cf..d0c5173626 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -91,7 +91,6 @@ Testing: -drive if=virtio QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty QEMU_PROG: -drive if=virtio: Device initialization failed. -QEMU_PROG: -drive if=virtio: Device initialization failed. QEMU_PROG: -drive if=virtio: Device 'virtio-blk-pci' could not be initialized Testing: -drive if=scsi @@ -223,7 +222,7 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K Testing: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: could not open disk image TEST_DIR/t.qcow2: Can't use 'qcow2' as a block driver for the protocol level +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: could not open disk image TEST_DIR/t.qcow2: Block format 'qcow2' used by device '' doesn't support the option 'filename' === Parsing protocol from file name === diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 index 73941c3e61..2d604d3a91 100755 --- a/tests/qemu-iotests/059 +++ b/tests/qemu-iotests/059 @@ -42,6 +42,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt vmdk _supported_proto generic _supported_os Linux +_unsupported_imgopts "subformat=monolithicFlat" \ + "subformat=twoGbMaxExtentFlat" \ + "subformat=twoGbMaxExtentSparse" capacity_offset=16 granularity_offset=20 @@ -81,10 +84,37 @@ IMGOPTS="subformat=twoGbMaxExtentFlat" _make_test_img 1000G $QEMU_IMG info $TEST_IMG | _filter_testdir | sed -e 's/cid: [0-9]*/cid: XXXXXXXX/' echo +echo "=== Testing malformed VMFS extent description line ===" +cat >"$TEST_IMG" <<EOF +# Disk DescriptorFile +version=1 +CID=58ab4847 +parentCID=ffffffff +createType="vmfs" + +# Extent description +RW 12582912 VMFS "dummy.vmdk" 1 +EOF +_img_info + +echo +echo "=== Testing truncated sparse ===" +IMGOPTS="subformat=monolithicSparse" _make_test_img 100G +truncate -s 10M $TEST_IMG +_img_info + +echo echo "=== Testing version 3 ===" _use_sample_img iotest-version3.vmdk.bz2 _img_info +echo +echo "=== Testing 4TB monolithicFlat creation and IO ===" +IMGOPTS="subformat=monolithicFlat" _make_test_img 4T +_img_info +$QEMU_IO -c "write -P 0xa 900G 512" "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c "read -v 900G 1024" "$TEST_IMG" | _filter_qemu_io + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out index 4ff935c6f4..4ffeb54710 100644 --- a/tests/qemu-iotests/059.out +++ b/tests/qemu-iotests/059.out @@ -2038,8 +2038,92 @@ Format specific information: filename: TEST_DIR/t-f500.vmdk format: FLAT +=== Testing malformed VMFS extent description line === +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Invalid extent lines: +RW 12582912 VMFS "dummy.IMGFMT" 1 + + +=== Testing truncated sparse === +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 +qemu-img: File truncated, expecting at least 13172736 bytes +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Could not open 'TEST_DIR/t.IMGFMT': Wrong medium type + === Testing version 3 === image: TEST_DIR/iotest-version3.IMGFMT file format: IMGFMT virtual size: 1.0G (1073741824 bytes) + +=== Testing 4TB monolithicFlat creation and IO === +Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104 +image: TEST_DIR/iotest-version3.IMGFMT +file format: IMGFMT +virtual size: 4.0T (4398046511104 bytes) +wrote 512/512 bytes at offset 966367641600 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +e100000000: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000010: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000020: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000030: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000040: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000050: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000060: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000070: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000080: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000090: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e1000000a0: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e1000000b0: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e1000000c0: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e1000000d0: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e1000000e0: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e1000000f0: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000100: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000110: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000120: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000130: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000140: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000150: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000160: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000170: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000180: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000190: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e1000001a0: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e1000001b0: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e1000001c0: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e1000001d0: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e1000001e0: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e1000001f0: 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ................ +e100000200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000250: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000270: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e1000002a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e1000002b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e1000002c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e1000002d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e1000002e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e1000002f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e100000390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e1000003a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e1000003b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e1000003c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e1000003d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e1000003e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +e1000003f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +read 1024/1024 bytes at offset 966367641600 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063 index 2ab8f20e02..77503a2984 100755 --- a/tests/qemu-iotests/063 +++ b/tests/qemu-iotests/063 @@ -44,6 +44,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt qcow qcow2 vmdk qed raw _supported_proto generic _supported_os Linux +_unsupported_imgopts "subformat=monolithicFlat" \ + "subformat=twoGbMaxExtentFlat" \ + "subformat=twoGbMaxExtentSparse" _make_test_img 4M diff --git a/tests/qemu-iotests/069 b/tests/qemu-iotests/069 index 3042803a81..50347d91d2 100755 --- a/tests/qemu-iotests/069 +++ b/tests/qemu-iotests/069 @@ -41,6 +41,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt cow qed qcow qcow2 vmdk _supported_proto generic _supported_os Linux +_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" IMG_SIZE=128K diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071 new file mode 100755 index 0000000000..2a22546e1a --- /dev/null +++ b/tests/qemu-iotests/071 @@ -0,0 +1,239 @@ +#!/bin/bash +# +# Test case for the QMP blkdebug and blkverify interfaces +# +# Copyright (C) 2013 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt generic +_supported_proto generic +_supported_os Linux + +function do_run_qemu() +{ + echo Testing: "$@" | _filter_imgfmt + $QEMU -nographic -qmp stdio -serial none "$@" + echo +} + +function run_qemu() +{ + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | _filter_qemu_io +} + +IMG_SIZE=64M + +echo +echo "=== Testing blkverify through filename ===" +echo + +TEST_IMG="$TEST_IMG.base" IMGOPTS="" IMGFMT="raw" _make_test_img $IMG_SIZE |\ + _filter_imgfmt +_make_test_img $IMG_SIZE +$QEMU_IO -c "open -o file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \ + -c 'read 0 512' -c 'write -P 42 0x38000 512' -c 'read -P 42 0x38000 512' | _filter_qemu_io + +$QEMU_IO -c 'write -P 42 0 512' "$TEST_IMG" | _filter_qemu_io + +$QEMU_IO -c "open -o file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \ + -c 'read -P 42 0 512' | _filter_qemu_io + +echo +echo "=== Testing blkverify through file blockref ===" +echo + +TEST_IMG="$TEST_IMG.base" IMGOPTS="" IMGFMT="raw" _make_test_img $IMG_SIZE |\ + _filter_imgfmt +_make_test_img $IMG_SIZE +$QEMU_IO -c "open -o file.driver=blkverify,file.raw.filename=$TEST_IMG.base,file.test.driver=$IMGFMT,file.test.file.filename=$TEST_IMG" \ + -c 'read 0 512' -c 'write -P 42 0x38000 512' -c 'read -P 42 0x38000 512' | _filter_qemu_io + +$QEMU_IO -c 'write -P 42 0 512' "$TEST_IMG" | _filter_qemu_io + +$QEMU_IO -c "open -o file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \ + -c 'read -P 42 0 512' | _filter_qemu_io + +echo +echo "=== Testing blkdebug through filename ===" +echo + +$QEMU_IO -c "open -o file.driver=blkdebug,file.inject-error.event=l2_load $TEST_IMG" \ + -c 'read -P 42 0x38000 512' + +echo +echo "=== Testing blkdebug through file blockref ===" +echo + +$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.inject-error.event=l2_load,file.image.filename=$TEST_IMG" \ + -c 'read -P 42 0x38000 512' + +echo +echo "=== Testing blkdebug on existing block device ===" +echo + +run_qemu -drive "file=$TEST_IMG,format=raw,if=none,id=drive0" <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "drive0-debug", + "file": { + "driver": "blkdebug", + "image": "drive0", + "inject-error": [{ + "event": "l2_load" + }] + } + } + } +} +{ "execute": "human-monitor-command", + "arguments": { + "command-line": 'qemu-io drive0-debug "read 0 512"' + } +} +{ "execute": "quit" } +EOF + +echo +echo "=== Testing blkverify on existing block device ===" +echo + +run_qemu -drive "file=$TEST_IMG,format=$IMGFMT,if=none,id=drive0" <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "blkverify", + "id": "drive0-verify", + "test": "drive0", + "raw": { + "driver": "raw", + "file": { + "driver": "file", + "filename": "$TEST_IMG.base" + } + } + } + } +} +{ "execute": "human-monitor-command", + "arguments": { + "command-line": 'qemu-io drive0-verify "read 0 512"' + } +} +{ "execute": "quit" } +EOF + +echo +echo "=== Testing blkverify on existing raw block device ===" +echo + +run_qemu -drive "file=$TEST_IMG.base,if=none,id=drive0" <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "blkverify", + "id": "drive0-verify", + "test": { + "driver": "$IMGFMT", + "file": { + "driver": "file", + "filename": "$TEST_IMG" + } + }, + "raw": "drive0" + } + } +} +{ "execute": "human-monitor-command", + "arguments": { + "command-line": 'qemu-io drive0-verify "read 0 512"' + } +} +{ "execute": "quit" } +EOF + +echo +echo "=== Testing blkdebug's set-state through QMP ===" +echo + +run_qemu -drive "file=$TEST_IMG,format=raw,if=none,id=drive0" <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "blockdev-add", + "arguments": { + "options": { + "driver": "$IMGFMT", + "id": "drive0-debug", + "file": { + "driver": "blkdebug", + "image": "drive0", + "inject-error": [{ + "event": "read_aio", + "state": 42 + }], + "set-state": [{ + "event": "write_aio", + "new_state": 42 + }] + } + } + } +} +{ "execute": "human-monitor-command", + "arguments": { + "command-line": 'qemu-io drive0-debug "read 0 512"' + } +} +{ "execute": "human-monitor-command", + "arguments": { + "command-line": 'qemu-io drive0-debug "write 0 512"' + } +} +{ "execute": "human-monitor-command", + "arguments": { + "command-line": 'qemu-io drive0-debug "read 0 512"' + } +} +{ "execute": "quit" } +EOF + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out new file mode 100644 index 0000000000..5f840a9980 --- /dev/null +++ b/tests/qemu-iotests/071.out @@ -0,0 +1,90 @@ +QA output created by 071 + +=== Testing blkverify through filename === + +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 512/512 bytes at offset 229376 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 229376 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkverify: read sector_num=0 nb_sectors=4 contents mismatch in sector 0 + +=== Testing blkverify through file blockref === + +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 512/512 bytes at offset 229376 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 229376 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkverify: read sector_num=0 nb_sectors=4 contents mismatch in sector 0 + +=== Testing blkdebug through filename === + +read failed: Input/output error + +=== Testing blkdebug through file blockref === + +read failed: Input/output error + +=== Testing blkdebug on existing block device === + +Testing: -drive file=TEST_DIR/t.IMGFMT,format=raw,if=none,id=drive0 +QMP_VERSION +{"return": {}} +{"return": {}} +read failed: Input/output error +{"return": ""} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}} + + +=== Testing blkverify on existing block device === + +Testing: -drive file=TEST_DIR/t.IMGFMT,format=IMGFMT,if=none,id=drive0 +QMP_VERSION +{"return": {}} +{"return": {}} +blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 + + +=== Testing blkverify on existing raw block device === + +Testing: -drive file=TEST_DIR/t.IMGFMT.base,if=none,id=drive0 +QMP_VERSION +{"return": {}} +{"return": {}} +blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0 + + +=== Testing blkdebug's set-state through QMP === + +Testing: -drive file=TEST_DIR/t.IMGFMT,format=raw,if=none,id=drive0 +QMP_VERSION +{"return": {}} +{"return": {}} +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +wrote 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +read failed: Input/output error +{"return": ""} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}} + +*** done diff --git a/tests/qemu-iotests/072 b/tests/qemu-iotests/072 new file mode 100755 index 0000000000..a3876c2161 --- /dev/null +++ b/tests/qemu-iotests/072 @@ -0,0 +1,69 @@ +#!/bin/bash +# +# Test case for nested image formats +# +# Copyright (C) 2013 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt vpc vmdk vhdx vdi qed qcow2 qcow cow +_supported_proto generic +_supported_os Linux + +IMG_SIZE=64M + +echo +echo "=== Testing nested image formats ===" +echo + +TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE + +$QEMU_IO -c 'write -P 42 0 512' -c 'write -P 23 512 512' \ + -c 'write -P 66 1024 512' "$TEST_IMG.base" | _filter_qemu_io + +$QEMU_IMG convert -f raw -O $IMGFMT "$TEST_IMG.base" "$TEST_IMG" + +$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=$IMGFMT,file.file.filename=$TEST_IMG" \ + -c 'read -P 42 0 512' -c 'read -P 23 512 512' \ + -c 'read -P 66 1024 512' | _filter_qemu_io + +# When not giving any format, qemu should open only one "layer". Therefore, this +# should not work for any image formats with a header. +$QEMU_IO -c 'read -P 42 0 512' "$TEST_IMG" | _filter_qemu_io + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/072.out b/tests/qemu-iotests/072.out new file mode 100644 index 0000000000..efe577c1c0 --- /dev/null +++ b/tests/qemu-iotests/072.out @@ -0,0 +1,21 @@ +QA output created by 072 + +=== Testing nested image formats === + +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 +wrote 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 512/512 bytes at offset 1024 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 1024 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Pattern verification failed at offset 0, 512 bytes +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +*** done diff --git a/tests/qemu-iotests/077 b/tests/qemu-iotests/077 new file mode 100755 index 0000000000..bbf7b5145a --- /dev/null +++ b/tests/qemu-iotests/077 @@ -0,0 +1,278 @@ +#!/bin/bash +# +# Test concurrent pread/pwrite +# +# Copyright (C) 2014 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=kwolf@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt generic +_supported_proto generic +_supported_os Linux + +CLUSTER_SIZE=4k +size=128M + +_make_test_img $size + +echo +echo "== Some concurrent requests involving RMW ==" + +function test_io() +{ +echo "open -o file.align=4k blkdebug::$TEST_IMG" +# A simple RMW request +cat <<EOF +aio_write -P 10 0x200 0x200 +aio_flush +EOF + +# Sequential RMW requests on the same physical sector +off=0x1000 +for ev in "head" "after_head" "tail" "after_tail"; do +cat <<EOF +break pwritev_rmw.$ev A +aio_write -P 10 $((off + 0x200)) 0x200 +wait_break A +aio_write -P 11 $((off + 0x400)) 0x200 +sleep 100 +resume A +aio_flush +EOF +off=$((off + 0x1000)) +done + +# Chained dependencies +cat <<EOF +break pwritev_rmw.after_tail A +aio_write -P 10 0x5000 0x200 +wait_break A +aio_write -P 11 0x5200 0x200 +aio_write -P 12 0x5400 0x200 +aio_write -P 13 0x5600 0x200 +aio_write -P 14 0x5800 0x200 +aio_write -P 15 0x5a00 0x200 +aio_write -P 16 0x5c00 0x200 +aio_write -P 17 0x5e00 0x200 +sleep 100 +resume A +aio_flush +EOF + +# Overlapping multiple requests +cat <<EOF +break pwritev_rmw.after_tail A +aio_write -P 10 0x6000 0x200 +wait_break A +break pwritev_rmw.after_head B +aio_write -P 10 0x7e00 0x200 +wait_break B +aio_write -P 11 0x6800 0x1000 +resume A +sleep 100 +resume B +aio_flush +EOF + +cat <<EOF +break pwritev_rmw.after_tail A +aio_write -P 10 0x8000 0x200 +wait_break A +break pwritev_rmw.after_head B +aio_write -P 10 0x9e00 0x200 +wait_break B +aio_write -P 11 0x8800 0x1000 +resume B +sleep 100 +resume A +aio_flush +EOF + +cat <<EOF +break pwritev_rmw.after_tail A +aio_write -P 10 0xa000 0x200 +wait_break A +aio_write -P 11 0xa800 0x1000 +break pwritev_rmw.after_head B +aio_write -P 10 0xbe00 0x200 +wait_break B +resume A +sleep 100 +resume B +aio_flush +EOF + +cat <<EOF +break pwritev_rmw.after_tail A +aio_write -P 10 0xc000 0x200 +wait_break A +aio_write -P 11 0xc800 0x1000 +break pwritev_rmw.after_head B +aio_write -P 10 0xde00 0x200 +wait_break B +resume B +sleep 100 +resume A +aio_flush +EOF + +# Only RMW for the tail part +cat <<EOF +break pwritev_rmw.after_tail A +aio_write -P 10 0xe000 0x1800 +wait_break A +aio_write -P 11 0xf000 0xc00 +sleep 100 +resume A +aio_flush +EOF + +cat <<EOF +break pwritev A +aio_write -P 10 0x10000 0x800 +wait_break A +break pwritev_rmw.after_tail B +aio_write -P 11 0x10000 0x400 +break pwritev_done C +resume A +wait_break C +resume C +sleep 100 +wait_break B +resume B +aio_flush +EOF + +cat <<EOF +break pwritev A +aio_write -P 10 0x11000 0x800 +wait_break A +aio_write -P 11 0x11000 0x1000 +sleep 100 +resume A +aio_flush +EOF +} + +test_io | $QEMU_IO | _filter_qemu_io | \ + sed -e 's,[0-9/]* bytes at offset [0-9]*,XXX/XXX bytes at offset XXX,g' \ + -e 's/^[0-9]* \(bytes\|KiB\)/XXX bytes/' \ + -e '/Suspended/d' + +echo +echo "== Verify image content ==" + +function verify_io() +{ + # A simple RMW request + echo read -P 0 0 0x200 + echo read -P 10 0x200 0x200 + echo read -P 0 0x400 0xc00 + + # Sequential RMW requests on the same physical sector + echo read -P 0 0x1000 0x200 + echo read -P 10 0x1200 0x200 + echo read -P 11 0x1400 0x200 + echo read -P 0 0x1600 0xa00 + + echo read -P 0 0x2000 0x200 + echo read -P 10 0x2200 0x200 + echo read -P 11 0x2400 0x200 + echo read -P 0 0x2600 0xa00 + + echo read -P 0 0x3000 0x200 + echo read -P 10 0x3200 0x200 + echo read -P 11 0x3400 0x200 + echo read -P 0 0x3600 0xa00 + + echo read -P 0 0x4000 0x200 + echo read -P 10 0x4200 0x200 + echo read -P 11 0x4400 0x200 + echo read -P 0 0x4600 0xa00 + + # Chained dependencies + echo read -P 10 0x5000 0x200 + echo read -P 11 0x5200 0x200 + echo read -P 12 0x5400 0x200 + echo read -P 13 0x5600 0x200 + echo read -P 14 0x5800 0x200 + echo read -P 15 0x5a00 0x200 + echo read -P 16 0x5c00 0x200 + echo read -P 17 0x5e00 0x200 + + # Overlapping multiple requests + echo read -P 10 0x6000 0x200 + echo read -P 0 0x6200 0x600 + echo read -P 11 0x6800 0x1000 + echo read -P 0 0x7800 0x600 + echo read -P 10 0x7e00 0x200 + + echo read -P 10 0x8000 0x200 + echo read -P 0 0x8200 0x600 + echo read -P 11 0x8800 0x1000 + echo read -P 0 0x9800 0x600 + echo read -P 10 0x9e00 0x200 + + echo read -P 10 0xa000 0x200 + echo read -P 0 0xa200 0x600 + echo read -P 11 0xa800 0x1000 + echo read -P 0 0xb800 0x600 + echo read -P 10 0xbe00 0x200 + + echo read -P 10 0xc000 0x200 + echo read -P 0 0xc200 0x600 + echo read -P 11 0xc800 0x1000 + echo read -P 0 0xd800 0x600 + echo read -P 10 0xde00 0x200 + + # Only RMW for the tail part + echo read -P 10 0xe000 0x1000 + echo read -P 11 0xf800 0x400 + echo read -P 0 0xfc00 0x400 + + echo read -P 11 0x10000 0x400 + echo read -P 10 0x10400 0x400 + + echo read -P 11 0x11800 0x800 +} + +verify_io | $QEMU_IO "$TEST_IMG" | _filter_qemu_io + +_check_test_img + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/077.out b/tests/qemu-iotests/077.out new file mode 100644 index 0000000000..ab612344d6 --- /dev/null +++ b/tests/qemu-iotests/077.out @@ -0,0 +1,202 @@ +QA output created by 077 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 + +== Some concurrent requests involving RMW == +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'A' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'A' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'A' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'A' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'A' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'A' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'B' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'B' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'A' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'A' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'B' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'B' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'A' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'A' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'A' +blkdebug: Resuming request 'C' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'B' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +blkdebug: Resuming request 'A' +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== Verify image content == +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 3072/3072 bytes at offset 1024 +3 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 4096 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 4608 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 5120 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 2560/2560 bytes at offset 5632 +2.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 8192 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 8704 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 9216 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 2560/2560 bytes at offset 9728 +2.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 12288 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 12800 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 13312 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 2560/2560 bytes at offset 13824 +2.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 16384 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 16896 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 17408 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 2560/2560 bytes at offset 17920 +2.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 20480 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 20992 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 21504 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 22016 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 22528 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 23040 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 23552 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 24064 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 24576 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1536/1536 bytes at offset 25088 +1.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 26624 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1536/1536 bytes at offset 30720 +1.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 32256 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 32768 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1536/1536 bytes at offset 33280 +1.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 34816 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1536/1536 bytes at offset 38912 +1.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 40448 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 40960 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1536/1536 bytes at offset 41472 +1.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 43008 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1536/1536 bytes at offset 47104 +1.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 48640 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 49152 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1536/1536 bytes at offset 49664 +1.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 51200 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1536/1536 bytes at offset 55296 +1.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 56832 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 57344 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1024/1024 bytes at offset 63488 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1024/1024 bytes at offset 64512 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1024/1024 bytes at offset 65536 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1024/1024 bytes at offset 66560 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 2048/2048 bytes at offset 71680 +2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +No errors were found on the image. +*** done diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 28ba0d9ad5..0f68156400 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -170,6 +170,17 @@ _make_test_img() fi } +_rm_test_img() +{ + local img=$1 + if [ "$IMGFMT" = "vmdk" ]; then + # Remove all the extents for vmdk + $QEMU_IMG info $img 2>/dev/null | grep 'filename:' | cut -f 2 -d: \ + | xargs -I {} rm -f "{}" + fi + rm -f $img +} + _cleanup_test_img() { case "$IMGPROTO" in @@ -179,9 +190,9 @@ _cleanup_test_img() rm -f "$TEST_IMG_FILE" ;; file) - rm -f "$TEST_DIR/t.$IMGFMT" - rm -f "$TEST_DIR/t.$IMGFMT.orig" - rm -f "$TEST_DIR/t.$IMGFMT.base" + _rm_test_img "$TEST_DIR/t.$IMGFMT" + _rm_test_img "$TEST_DIR/t.$IMGFMT.orig" + _rm_test_img "$TEST_DIR/t.$IMGFMT.base" if [ -n "$SAMPLE_IMG_FILE" ] then rm -f "$TEST_DIR/$SAMPLE_IMG_FILE" @@ -406,6 +417,17 @@ _default_cache_mode() fi } +_unsupported_imgopts() +{ + for bad_opt + do + if echo "$IMGOPTS" | grep -q 2>/dev/null "$bad_opt" + then + _notrun "not suitable for image option: $bad_opt" + fi + done +} + # this test requires that a specified command (executable) exists # _require_command() diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index cc750c986e..03c762fb4f 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -77,5 +77,8 @@ 068 rw auto 069 rw auto 070 rw auto +071 rw auto +072 rw auto 073 rw auto 074 rw auto +077 rw auto diff --git a/tests/qom-test.c b/tests/qom-test.c index 499be40261..5e5af7a50f 100644 --- a/tests/qom-test.c +++ b/tests/qom-test.c @@ -70,6 +70,8 @@ static const char *arm_machines[] = { "xilinx-zynq-a9", "highbank", "midway", + "canon-a1100", + "cubieboard", }; static const char *cris_machines[] = { diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c new file mode 100644 index 0000000000..75cd1a1fd4 --- /dev/null +++ b/tests/test-vmstate.c @@ -0,0 +1,357 @@ +/* + * Test code for VMState + * + * Copyright (c) 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <glib.h> + +#include "qemu-common.h" +#include "migration/migration.h" +#include "migration/vmstate.h" +#include "block/coroutine.h" + +char temp_file[] = "/tmp/vmst.test.XXXXXX"; +int temp_fd; + +/* Fake yield_until_fd_readable() implementation so we don't have to pull the + * coroutine code as dependency. + */ +void yield_until_fd_readable(int fd) +{ + fd_set fds; + FD_ZERO(&fds); + FD_SET(fd, &fds); + select(fd + 1, &fds, NULL, NULL, NULL); +} + +/* Duplicate temp_fd and seek to the beginning of the file */ +static int dup_temp_fd(bool truncate) +{ + int fd = dup(temp_fd); + lseek(fd, 0, SEEK_SET); + if (truncate) { + g_assert_cmpint(ftruncate(fd, 0), ==, 0); + } + return fd; +} + +typedef struct TestSruct { + uint32_t a, b, c, e; + uint64_t d, f; + bool skip_c_e; +} TestStruct; + + +static const VMStateDescription vmstate_simple = { + .name = "test", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(a, TestStruct), + VMSTATE_UINT32(b, TestStruct), + VMSTATE_UINT32(c, TestStruct), + VMSTATE_UINT64(d, TestStruct), + VMSTATE_END_OF_LIST() + } +}; + +static void test_simple_save(void) +{ + QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4 }; + vmstate_save_state(fsave, &vmstate_simple, &obj); + g_assert(!qemu_file_get_error(fsave)); + qemu_fclose(fsave); + + QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + uint8_t expected[] = { + 0, 0, 0, 1, /* a */ + 0, 0, 0, 2, /* b */ + 0, 0, 0, 3, /* c */ + 0, 0, 0, 0, 0, 0, 0, 4, /* d */ + }; + uint8_t result[sizeof(expected)]; + g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==, + sizeof(result)); + g_assert(!qemu_file_get_error(loading)); + g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0); + + /* Must reach EOF */ + qemu_get_byte(loading); + g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO); + + qemu_fclose(loading); +} + +static void test_simple_load(void) +{ + QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + uint8_t buf[] = { + 0, 0, 0, 10, /* a */ + 0, 0, 0, 20, /* b */ + 0, 0, 0, 30, /* c */ + 0, 0, 0, 0, 0, 0, 0, 40, /* d */ + QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ + }; + qemu_put_buffer(fsave, buf, sizeof(buf)); + qemu_fclose(fsave); + + QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + TestStruct obj; + vmstate_load_state(loading, &vmstate_simple, &obj, 1); + g_assert(!qemu_file_get_error(loading)); + g_assert_cmpint(obj.a, ==, 10); + g_assert_cmpint(obj.b, ==, 20); + g_assert_cmpint(obj.c, ==, 30); + g_assert_cmpint(obj.d, ==, 40); + qemu_fclose(loading); +} + +static const VMStateDescription vmstate_versioned = { + .name = "test", + .version_id = 2, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(a, TestStruct), + VMSTATE_UINT32_V(b, TestStruct, 2), /* Versioned field in the middle, so + * we catch bugs more easily. + */ + VMSTATE_UINT32(c, TestStruct), + VMSTATE_UINT64(d, TestStruct), + VMSTATE_UINT32_V(e, TestStruct, 2), + VMSTATE_UINT64_V(f, TestStruct, 2), + VMSTATE_END_OF_LIST() + } +}; + +static void test_load_v1(void) +{ + QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + uint8_t buf[] = { + 0, 0, 0, 10, /* a */ + 0, 0, 0, 30, /* c */ + 0, 0, 0, 0, 0, 0, 0, 40, /* d */ + QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ + }; + qemu_put_buffer(fsave, buf, sizeof(buf)); + qemu_fclose(fsave); + + QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + TestStruct obj = { .b = 200, .e = 500, .f = 600 }; + vmstate_load_state(loading, &vmstate_versioned, &obj, 1); + g_assert(!qemu_file_get_error(loading)); + g_assert_cmpint(obj.a, ==, 10); + g_assert_cmpint(obj.b, ==, 200); + g_assert_cmpint(obj.c, ==, 30); + g_assert_cmpint(obj.d, ==, 40); + g_assert_cmpint(obj.e, ==, 500); + g_assert_cmpint(obj.f, ==, 600); + qemu_fclose(loading); +} + +static void test_load_v2(void) +{ + QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + uint8_t buf[] = { + 0, 0, 0, 10, /* a */ + 0, 0, 0, 20, /* b */ + 0, 0, 0, 30, /* c */ + 0, 0, 0, 0, 0, 0, 0, 40, /* d */ + 0, 0, 0, 50, /* e */ + 0, 0, 0, 0, 0, 0, 0, 60, /* f */ + QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ + }; + qemu_put_buffer(fsave, buf, sizeof(buf)); + qemu_fclose(fsave); + + QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + TestStruct obj; + vmstate_load_state(loading, &vmstate_versioned, &obj, 2); + g_assert_cmpint(obj.a, ==, 10); + g_assert_cmpint(obj.b, ==, 20); + g_assert_cmpint(obj.c, ==, 30); + g_assert_cmpint(obj.d, ==, 40); + g_assert_cmpint(obj.e, ==, 50); + g_assert_cmpint(obj.f, ==, 60); + qemu_fclose(loading); +} + +static bool test_skip(void *opaque, int version_id) +{ + TestStruct *t = (TestStruct *)opaque; + return !t->skip_c_e; +} + +static const VMStateDescription vmstate_skipping = { + .name = "test", + .version_id = 2, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(a, TestStruct), + VMSTATE_UINT32(b, TestStruct), + VMSTATE_UINT32_TEST(c, TestStruct, test_skip), + VMSTATE_UINT64(d, TestStruct), + VMSTATE_UINT32_TEST(e, TestStruct, test_skip), + VMSTATE_UINT64_V(f, TestStruct, 2), + VMSTATE_END_OF_LIST() + } +}; + + +static void test_save_noskip(void) +{ + QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, + .skip_c_e = false }; + vmstate_save_state(fsave, &vmstate_skipping, &obj); + g_assert(!qemu_file_get_error(fsave)); + qemu_fclose(fsave); + + QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + uint8_t expected[] = { + 0, 0, 0, 1, /* a */ + 0, 0, 0, 2, /* b */ + 0, 0, 0, 3, /* c */ + 0, 0, 0, 0, 0, 0, 0, 4, /* d */ + 0, 0, 0, 5, /* e */ + 0, 0, 0, 0, 0, 0, 0, 6, /* f */ + }; + uint8_t result[sizeof(expected)]; + g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==, + sizeof(result)); + g_assert(!qemu_file_get_error(loading)); + g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0); + + /* Must reach EOF */ + qemu_get_byte(loading); + g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO); + + qemu_fclose(loading); +} + +static void test_save_skip(void) +{ + QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + TestStruct obj = { .a = 1, .b = 2, .c = 3, .d = 4, .e = 5, .f = 6, + .skip_c_e = true }; + vmstate_save_state(fsave, &vmstate_skipping, &obj); + g_assert(!qemu_file_get_error(fsave)); + qemu_fclose(fsave); + + QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + uint8_t expected[] = { + 0, 0, 0, 1, /* a */ + 0, 0, 0, 2, /* b */ + 0, 0, 0, 0, 0, 0, 0, 4, /* d */ + 0, 0, 0, 0, 0, 0, 0, 6, /* f */ + }; + uint8_t result[sizeof(expected)]; + g_assert_cmpint(qemu_get_buffer(loading, result, sizeof(result)), ==, + sizeof(result)); + g_assert(!qemu_file_get_error(loading)); + g_assert_cmpint(memcmp(result, expected, sizeof(result)), ==, 0); + + + /* Must reach EOF */ + qemu_get_byte(loading); + g_assert_cmpint(qemu_file_get_error(loading), ==, -EIO); + + qemu_fclose(loading); +} + +static void test_load_noskip(void) +{ + QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + uint8_t buf[] = { + 0, 0, 0, 10, /* a */ + 0, 0, 0, 20, /* b */ + 0, 0, 0, 30, /* c */ + 0, 0, 0, 0, 0, 0, 0, 40, /* d */ + 0, 0, 0, 50, /* e */ + 0, 0, 0, 0, 0, 0, 0, 60, /* f */ + QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ + }; + qemu_put_buffer(fsave, buf, sizeof(buf)); + qemu_fclose(fsave); + + QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + TestStruct obj = { .skip_c_e = false }; + vmstate_load_state(loading, &vmstate_skipping, &obj, 2); + g_assert(!qemu_file_get_error(loading)); + g_assert_cmpint(obj.a, ==, 10); + g_assert_cmpint(obj.b, ==, 20); + g_assert_cmpint(obj.c, ==, 30); + g_assert_cmpint(obj.d, ==, 40); + g_assert_cmpint(obj.e, ==, 50); + g_assert_cmpint(obj.f, ==, 60); + qemu_fclose(loading); +} + +static void test_load_skip(void) +{ + QEMUFile *fsave = qemu_fdopen(dup_temp_fd(true), "wb"); + uint8_t buf[] = { + 0, 0, 0, 10, /* a */ + 0, 0, 0, 20, /* b */ + 0, 0, 0, 0, 0, 0, 0, 40, /* d */ + 0, 0, 0, 0, 0, 0, 0, 60, /* f */ + QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */ + }; + qemu_put_buffer(fsave, buf, sizeof(buf)); + qemu_fclose(fsave); + + QEMUFile *loading = qemu_fdopen(dup_temp_fd(false), "rb"); + TestStruct obj = { .skip_c_e = true, .c = 300, .e = 500 }; + vmstate_load_state(loading, &vmstate_skipping, &obj, 2); + g_assert(!qemu_file_get_error(loading)); + g_assert_cmpint(obj.a, ==, 10); + g_assert_cmpint(obj.b, ==, 20); + g_assert_cmpint(obj.c, ==, 300); + g_assert_cmpint(obj.d, ==, 40); + g_assert_cmpint(obj.e, ==, 500); + g_assert_cmpint(obj.f, ==, 60); + qemu_fclose(loading); +} + +int main(int argc, char **argv) +{ + temp_fd = mkstemp(temp_file); + + g_test_init(&argc, &argv, NULL); + g_test_add_func("/vmstate/simple/save", test_simple_save); + g_test_add_func("/vmstate/simple/load", test_simple_load); + g_test_add_func("/vmstate/versioned/load/v1", test_load_v1); + g_test_add_func("/vmstate/versioned/load/v2", test_load_v2); + g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip); + g_test_add_func("/vmstate/field_exists/load/skip", test_load_skip); + g_test_add_func("/vmstate/field_exists/save/noskip", test_save_noskip); + g_test_add_func("/vmstate/field_exists/save/skip", test_save_skip); + g_test_run(); + + close(temp_fd); + unlink(temp_file); + + return 0; +} |