|
@@ -17,7 +17,12 @@
|
|
|
|
|
|
#include "qemu/osdep.h"
|
|
|
#include "qemu-common.h"
|
|
|
+#include "qemu/bswap.h"
|
|
|
+#include "qapi/qmp/qlist.h"
|
|
|
#include "libqtest.h"
|
|
|
+#include "libqos/fw_cfg.h"
|
|
|
+#include "libqos/libqos.h"
|
|
|
+#include "standard-headers/linux/qemu_fw_cfg.h"
|
|
|
|
|
|
#define ARGV_SIZE 256
|
|
|
|
|
@@ -388,6 +393,537 @@ static void test_ide_drive_cd_0(void)
|
|
|
qtest_quit(qts);
|
|
|
}
|
|
|
|
|
|
+typedef struct {
|
|
|
+ bool active;
|
|
|
+ uint32_t head;
|
|
|
+ uint32_t sector;
|
|
|
+ uint32_t cyl;
|
|
|
+ uint32_t end_head;
|
|
|
+ uint32_t end_sector;
|
|
|
+ uint32_t end_cyl;
|
|
|
+ uint32_t start_sect;
|
|
|
+ uint32_t nr_sects;
|
|
|
+} MBRpartitions[4];
|
|
|
+
|
|
|
+static MBRpartitions empty_mbr = { {false, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
+ {false, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
+ {false, 0, 0, 0, 0, 0, 0, 0, 0},
|
|
|
+ {false, 0, 0, 0, 0, 0, 0, 0, 0} };
|
|
|
+
|
|
|
+static char *create_qcow2_with_mbr(MBRpartitions mbr, uint64_t sectors)
|
|
|
+{
|
|
|
+ const char *template = "/tmp/qtest.XXXXXX";
|
|
|
+ char *raw_path = strdup(template);
|
|
|
+ char *qcow2_path = strdup(template);
|
|
|
+ char cmd[100 + 2 * PATH_MAX];
|
|
|
+ uint8_t buf[512];
|
|
|
+ int i, ret, fd, offset;
|
|
|
+ uint64_t qcow2_size = sectors * 512;
|
|
|
+ uint8_t status, parttype, head, sector, cyl;
|
|
|
+ char *qemu_img_path;
|
|
|
+ char *qemu_img_abs_path;
|
|
|
+
|
|
|
+ offset = 0xbe;
|
|
|
+
|
|
|
+ for (i = 0; i < 4; i++) {
|
|
|
+ status = mbr[i].active ? 0x80 : 0x00;
|
|
|
+ g_assert(mbr[i].head < 256);
|
|
|
+ g_assert(mbr[i].sector < 64);
|
|
|
+ g_assert(mbr[i].cyl < 1024);
|
|
|
+ head = mbr[i].head;
|
|
|
+ sector = mbr[i].sector + ((mbr[i].cyl & 0x300) >> 2);
|
|
|
+ cyl = mbr[i].cyl & 0xff;
|
|
|
+
|
|
|
+ buf[offset + 0x0] = status;
|
|
|
+ buf[offset + 0x1] = head;
|
|
|
+ buf[offset + 0x2] = sector;
|
|
|
+ buf[offset + 0x3] = cyl;
|
|
|
+
|
|
|
+ parttype = 0;
|
|
|
+ g_assert(mbr[i].end_head < 256);
|
|
|
+ g_assert(mbr[i].end_sector < 64);
|
|
|
+ g_assert(mbr[i].end_cyl < 1024);
|
|
|
+ head = mbr[i].end_head;
|
|
|
+ sector = mbr[i].end_sector + ((mbr[i].end_cyl & 0x300) >> 2);
|
|
|
+ cyl = mbr[i].end_cyl & 0xff;
|
|
|
+
|
|
|
+ buf[offset + 0x4] = parttype;
|
|
|
+ buf[offset + 0x5] = head;
|
|
|
+ buf[offset + 0x6] = sector;
|
|
|
+ buf[offset + 0x7] = cyl;
|
|
|
+
|
|
|
+ (*(uint32_t *)&buf[offset + 0x8]) = cpu_to_le32(mbr[i].start_sect);
|
|
|
+ (*(uint32_t *)&buf[offset + 0xc]) = cpu_to_le32(mbr[i].nr_sects);
|
|
|
+
|
|
|
+ offset += 0x10;
|
|
|
+ }
|
|
|
+
|
|
|
+ fd = mkstemp(raw_path);
|
|
|
+ g_assert(fd);
|
|
|
+ close(fd);
|
|
|
+
|
|
|
+ fd = open(raw_path, O_WRONLY);
|
|
|
+ g_assert(fd >= 0);
|
|
|
+ ret = write(fd, buf, sizeof(buf));
|
|
|
+ g_assert(ret == sizeof(buf));
|
|
|
+ close(fd);
|
|
|
+
|
|
|
+ fd = mkstemp(qcow2_path);
|
|
|
+ g_assert(fd);
|
|
|
+ close(fd);
|
|
|
+
|
|
|
+ qemu_img_path = getenv("QTEST_QEMU_IMG");
|
|
|
+ g_assert(qemu_img_path);
|
|
|
+ qemu_img_abs_path = realpath(qemu_img_path, NULL);
|
|
|
+ g_assert(qemu_img_abs_path);
|
|
|
+
|
|
|
+ ret = snprintf(cmd, sizeof(cmd),
|
|
|
+ "%s convert -f raw -O qcow2 %s %s > /dev/null",
|
|
|
+ qemu_img_abs_path,
|
|
|
+ raw_path, qcow2_path);
|
|
|
+ g_assert((0 < ret) && (ret <= sizeof(cmd)));
|
|
|
+ ret = system(cmd);
|
|
|
+ g_assert(ret == 0);
|
|
|
+
|
|
|
+ ret = snprintf(cmd, sizeof(cmd),
|
|
|
+ "%s resize %s %" PRIu64 " > /dev/null",
|
|
|
+ qemu_img_abs_path,
|
|
|
+ qcow2_path, qcow2_size);
|
|
|
+ g_assert((0 < ret) && (ret <= sizeof(cmd)));
|
|
|
+ ret = system(cmd);
|
|
|
+ g_assert(ret == 0);
|
|
|
+
|
|
|
+ free(qemu_img_abs_path);
|
|
|
+
|
|
|
+ unlink(raw_path);
|
|
|
+ free(raw_path);
|
|
|
+
|
|
|
+ return qcow2_path;
|
|
|
+}
|
|
|
+
|
|
|
+#define BIOS_GEOMETRY_MAX_SIZE 10000
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ uint32_t c;
|
|
|
+ uint32_t h;
|
|
|
+ uint32_t s;
|
|
|
+} CHS;
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ const char *dev_path;
|
|
|
+ CHS chs;
|
|
|
+} CHSResult;
|
|
|
+
|
|
|
+static void read_bootdevices(QFWCFG *fw_cfg, CHSResult expected[])
|
|
|
+{
|
|
|
+ char *buf = g_malloc0(BIOS_GEOMETRY_MAX_SIZE);
|
|
|
+ char *cur;
|
|
|
+ GList *results = NULL, *cur_result;
|
|
|
+ CHSResult *r;
|
|
|
+ int i;
|
|
|
+ int res;
|
|
|
+ bool found;
|
|
|
+
|
|
|
+ qfw_cfg_get_file(fw_cfg, "bios-geometry", buf, BIOS_GEOMETRY_MAX_SIZE);
|
|
|
+
|
|
|
+ for (cur = buf; *cur; cur++) {
|
|
|
+ if (*cur == '\n') {
|
|
|
+ *cur = '\0';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ cur = buf;
|
|
|
+
|
|
|
+ while (strlen(cur)) {
|
|
|
+
|
|
|
+ r = g_malloc0(sizeof(*r));
|
|
|
+ r->dev_path = g_malloc0(strlen(cur) + 1);
|
|
|
+ res = sscanf(cur, "%s %" PRIu32 " %" PRIu32 " %" PRIu32,
|
|
|
+ (char *)r->dev_path,
|
|
|
+ &(r->chs.c), &(r->chs.h), &(r->chs.s));
|
|
|
+
|
|
|
+ g_assert(res == 4);
|
|
|
+
|
|
|
+ results = g_list_prepend(results, r);
|
|
|
+
|
|
|
+ cur += strlen(cur) + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ i = 0;
|
|
|
+
|
|
|
+ while (expected[i].dev_path) {
|
|
|
+ found = false;
|
|
|
+ cur_result = results;
|
|
|
+ while (cur_result) {
|
|
|
+ r = cur_result->data;
|
|
|
+ if (!strcmp(r->dev_path, expected[i].dev_path) &&
|
|
|
+ !memcmp(&(r->chs), &(expected[i].chs), sizeof(r->chs))) {
|
|
|
+ found = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ cur_result = g_list_next(cur_result);
|
|
|
+ }
|
|
|
+ g_assert(found);
|
|
|
+ g_free((char *)((CHSResult *)cur_result->data)->dev_path);
|
|
|
+ g_free(cur_result->data);
|
|
|
+ results = g_list_delete_link(results, cur_result);
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+
|
|
|
+ g_assert(results == NULL);
|
|
|
+
|
|
|
+ g_free(buf);
|
|
|
+}
|
|
|
+
|
|
|
+#define MAX_DRIVES 30
|
|
|
+
|
|
|
+typedef struct {
|
|
|
+ char **argv;
|
|
|
+ int argc;
|
|
|
+ char **drives;
|
|
|
+ int n_drives;
|
|
|
+ int n_scsi_disks;
|
|
|
+ int n_scsi_controllers;
|
|
|
+ int n_virtio_disks;
|
|
|
+} TestArgs;
|
|
|
+
|
|
|
+static TestArgs *create_args(void)
|
|
|
+{
|
|
|
+ TestArgs *args = g_malloc0(sizeof(*args));
|
|
|
+ args->argv = g_new0(char *, ARGV_SIZE);
|
|
|
+ args->argc = append_arg(args->argc, args->argv,
|
|
|
+ ARGV_SIZE, g_strdup("-nodefaults"));
|
|
|
+ args->drives = g_new0(char *, MAX_DRIVES);
|
|
|
+ return args;
|
|
|
+}
|
|
|
+
|
|
|
+static void add_drive_with_mbr(TestArgs *args,
|
|
|
+ MBRpartitions mbr, uint64_t sectors)
|
|
|
+{
|
|
|
+ char *img_file_name;
|
|
|
+ char part[300];
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ g_assert(args->n_drives < MAX_DRIVES);
|
|
|
+
|
|
|
+ img_file_name = create_qcow2_with_mbr(mbr, sectors);
|
|
|
+
|
|
|
+ args->drives[args->n_drives] = img_file_name;
|
|
|
+ ret = snprintf(part, sizeof(part),
|
|
|
+ "-drive file=%s,if=none,format=qcow2,id=disk%d",
|
|
|
+ img_file_name, args->n_drives);
|
|
|
+ g_assert((0 < ret) && (ret <= sizeof(part)));
|
|
|
+ args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
|
|
|
+ args->n_drives++;
|
|
|
+}
|
|
|
+
|
|
|
+static void add_ide_disk(TestArgs *args,
|
|
|
+ int drive_idx, int bus, int unit, int c, int h, int s)
|
|
|
+{
|
|
|
+ char part[300];
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = snprintf(part, sizeof(part),
|
|
|
+ "-device ide-hd,drive=disk%d,bus=ide.%d,unit=%d,"
|
|
|
+ "lcyls=%d,lheads=%d,lsecs=%d",
|
|
|
+ drive_idx, bus, unit, c, h, s);
|
|
|
+ g_assert((0 < ret) && (ret <= sizeof(part)));
|
|
|
+ args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
|
|
|
+}
|
|
|
+
|
|
|
+static void add_scsi_controller(TestArgs *args,
|
|
|
+ const char *type,
|
|
|
+ const char *bus,
|
|
|
+ int addr)
|
|
|
+{
|
|
|
+ char part[300];
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = snprintf(part, sizeof(part),
|
|
|
+ "-device %s,id=scsi%d,bus=%s,addr=%d",
|
|
|
+ type, args->n_scsi_controllers, bus, addr);
|
|
|
+ g_assert((0 < ret) && (ret <= sizeof(part)));
|
|
|
+ args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
|
|
|
+ args->n_scsi_controllers++;
|
|
|
+}
|
|
|
+
|
|
|
+static void add_scsi_disk(TestArgs *args,
|
|
|
+ int drive_idx, int bus,
|
|
|
+ int channel, int scsi_id, int lun,
|
|
|
+ int c, int h, int s)
|
|
|
+{
|
|
|
+ char part[300];
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = snprintf(part, sizeof(part),
|
|
|
+ "-device scsi-hd,id=scsi-disk%d,drive=disk%d,"
|
|
|
+ "bus=scsi%d.0,"
|
|
|
+ "channel=%d,scsi-id=%d,lun=%d,"
|
|
|
+ "lcyls=%d,lheads=%d,lsecs=%d",
|
|
|
+ args->n_scsi_disks, drive_idx, bus, channel, scsi_id, lun,
|
|
|
+ c, h, s);
|
|
|
+ g_assert((0 < ret) && (ret <= sizeof(part)));
|
|
|
+ args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
|
|
|
+ args->n_scsi_disks++;
|
|
|
+}
|
|
|
+
|
|
|
+static void add_virtio_disk(TestArgs *args,
|
|
|
+ int drive_idx, const char *bus, int addr,
|
|
|
+ int c, int h, int s)
|
|
|
+{
|
|
|
+ char part[300];
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = snprintf(part, sizeof(part),
|
|
|
+ "-device virtio-blk-pci,id=virtio-disk%d,"
|
|
|
+ "drive=disk%d,bus=%s,addr=%d,"
|
|
|
+ "lcyls=%d,lheads=%d,lsecs=%d",
|
|
|
+ args->n_virtio_disks, drive_idx, bus, addr, c, h, s);
|
|
|
+ g_assert((0 < ret) && (ret <= sizeof(part)));
|
|
|
+ args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, g_strdup(part));
|
|
|
+ args->n_virtio_disks++;
|
|
|
+}
|
|
|
+
|
|
|
+static void test_override(TestArgs *args, CHSResult expected[])
|
|
|
+{
|
|
|
+ QTestState *qts;
|
|
|
+ char *joined_args;
|
|
|
+ QFWCFG *fw_cfg;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ joined_args = g_strjoinv(" ", args->argv);
|
|
|
+
|
|
|
+ qts = qtest_init(joined_args);
|
|
|
+ fw_cfg = pc_fw_cfg_init(qts);
|
|
|
+
|
|
|
+ read_bootdevices(fw_cfg, expected);
|
|
|
+
|
|
|
+ g_free(joined_args);
|
|
|
+ qtest_quit(qts);
|
|
|
+
|
|
|
+ g_free(fw_cfg);
|
|
|
+
|
|
|
+ for (i = 0; i < args->n_drives; i++) {
|
|
|
+ unlink(args->drives[i]);
|
|
|
+ free(args->drives[i]);
|
|
|
+ }
|
|
|
+ g_free(args->drives);
|
|
|
+ g_strfreev(args->argv);
|
|
|
+ g_free(args);
|
|
|
+}
|
|
|
+
|
|
|
+static void test_override_ide(void)
|
|
|
+{
|
|
|
+ TestArgs *args = create_args();
|
|
|
+ CHSResult expected[] = {
|
|
|
+ {"/pci@i0cf8/ide@1,1/drive@0/disk@0", {10000, 120, 30} },
|
|
|
+ {"/pci@i0cf8/ide@1,1/drive@0/disk@1", {9000, 120, 30} },
|
|
|
+ {"/pci@i0cf8/ide@1,1/drive@1/disk@0", {0, 1, 1} },
|
|
|
+ {"/pci@i0cf8/ide@1,1/drive@1/disk@1", {1, 0, 0} },
|
|
|
+ {NULL, {0, 0, 0} }
|
|
|
+ };
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_ide_disk(args, 0, 0, 0, 10000, 120, 30);
|
|
|
+ add_ide_disk(args, 1, 0, 1, 9000, 120, 30);
|
|
|
+ add_ide_disk(args, 2, 1, 0, 0, 1, 1);
|
|
|
+ add_ide_disk(args, 3, 1, 1, 1, 0, 0);
|
|
|
+ test_override(args, expected);
|
|
|
+}
|
|
|
+
|
|
|
+static void test_override_scsi(void)
|
|
|
+{
|
|
|
+ TestArgs *args = create_args();
|
|
|
+ CHSResult expected[] = {
|
|
|
+ {"/pci@i0cf8/scsi@3/channel@0/disk@0,0", {10000, 120, 30} },
|
|
|
+ {"/pci@i0cf8/scsi@3/channel@0/disk@1,0", {9000, 120, 30} },
|
|
|
+ {"/pci@i0cf8/scsi@3/channel@0/disk@2,0", {1, 0, 0} },
|
|
|
+ {"/pci@i0cf8/scsi@3/channel@0/disk@3,0", {0, 1, 0} },
|
|
|
+ {NULL, {0, 0, 0} }
|
|
|
+ };
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_scsi_controller(args, "lsi53c895a", "pci.0", 3);
|
|
|
+ add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
|
|
|
+ add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30);
|
|
|
+ add_scsi_disk(args, 2, 0, 0, 2, 0, 1, 0, 0);
|
|
|
+ add_scsi_disk(args, 3, 0, 0, 3, 0, 0, 1, 0);
|
|
|
+ test_override(args, expected);
|
|
|
+}
|
|
|
+
|
|
|
+static void test_override_scsi_2_controllers(void)
|
|
|
+{
|
|
|
+ TestArgs *args = create_args();
|
|
|
+ CHSResult expected[] = {
|
|
|
+ {"/pci@i0cf8/scsi@3/channel@0/disk@0,0", {10000, 120, 30} },
|
|
|
+ {"/pci@i0cf8/scsi@3/channel@0/disk@1,0", {9000, 120, 30} },
|
|
|
+ {"/pci@i0cf8/scsi@4/channel@0/disk@0,1", {1, 0, 0} },
|
|
|
+ {"/pci@i0cf8/scsi@4/channel@0/disk@1,2", {0, 1, 0} },
|
|
|
+ {NULL, {0, 0, 0} }
|
|
|
+ };
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_scsi_controller(args, "lsi53c895a", "pci.0", 3);
|
|
|
+ add_scsi_controller(args, "virtio-scsi-pci", "pci.0", 4);
|
|
|
+ add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
|
|
|
+ add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30);
|
|
|
+ add_scsi_disk(args, 2, 1, 0, 0, 1, 1, 0, 0);
|
|
|
+ add_scsi_disk(args, 3, 1, 0, 1, 2, 0, 1, 0);
|
|
|
+ test_override(args, expected);
|
|
|
+}
|
|
|
+
|
|
|
+static void test_override_virtio_blk(void)
|
|
|
+{
|
|
|
+ TestArgs *args = create_args();
|
|
|
+ CHSResult expected[] = {
|
|
|
+ {"/pci@i0cf8/scsi@3/disk@0,0", {10000, 120, 30} },
|
|
|
+ {"/pci@i0cf8/scsi@4/disk@0,0", {9000, 120, 30} },
|
|
|
+ {NULL, {0, 0, 0} }
|
|
|
+ };
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_virtio_disk(args, 0, "pci.0", 3, 10000, 120, 30);
|
|
|
+ add_virtio_disk(args, 1, "pci.0", 4, 9000, 120, 30);
|
|
|
+ test_override(args, expected);
|
|
|
+}
|
|
|
+
|
|
|
+static void test_override_zero_chs(void)
|
|
|
+{
|
|
|
+ TestArgs *args = create_args();
|
|
|
+ CHSResult expected[] = {
|
|
|
+ {NULL, {0, 0, 0} }
|
|
|
+ };
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_ide_disk(args, 0, 1, 1, 0, 0, 0);
|
|
|
+ test_override(args, expected);
|
|
|
+}
|
|
|
+
|
|
|
+static void test_override_scsi_hot_unplug(void)
|
|
|
+{
|
|
|
+ QTestState *qts;
|
|
|
+ char *joined_args;
|
|
|
+ QFWCFG *fw_cfg;
|
|
|
+ QDict *response;
|
|
|
+ int i;
|
|
|
+ TestArgs *args = create_args();
|
|
|
+ CHSResult expected[] = {
|
|
|
+ {"/pci@i0cf8/scsi@2/channel@0/disk@0,0", {10000, 120, 30} },
|
|
|
+ {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} },
|
|
|
+ {NULL, {0, 0, 0} }
|
|
|
+ };
|
|
|
+ CHSResult expected2[] = {
|
|
|
+ {"/pci@i0cf8/scsi@2/channel@0/disk@1,0", {20, 20, 20} },
|
|
|
+ {NULL, {0, 0, 0} }
|
|
|
+ };
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_scsi_controller(args, "virtio-scsi-pci", "pci.0", 2);
|
|
|
+ add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
|
|
|
+ add_scsi_disk(args, 1, 0, 0, 1, 0, 20, 20, 20);
|
|
|
+
|
|
|
+ joined_args = g_strjoinv(" ", args->argv);
|
|
|
+
|
|
|
+ qts = qtest_init(joined_args);
|
|
|
+ fw_cfg = pc_fw_cfg_init(qts);
|
|
|
+
|
|
|
+ read_bootdevices(fw_cfg, expected);
|
|
|
+
|
|
|
+ /* unplug device an restart */
|
|
|
+ response = qtest_qmp(qts,
|
|
|
+ "{ 'execute': 'device_del',"
|
|
|
+ " 'arguments': {'id': 'scsi-disk0' }}");
|
|
|
+ g_assert(response);
|
|
|
+ g_assert(!qdict_haskey(response, "error"));
|
|
|
+ qobject_unref(response);
|
|
|
+ response = qtest_qmp(qts,
|
|
|
+ "{ 'execute': 'system_reset', 'arguments': { }}");
|
|
|
+ g_assert(response);
|
|
|
+ g_assert(!qdict_haskey(response, "error"));
|
|
|
+ qobject_unref(response);
|
|
|
+
|
|
|
+ qtest_qmp_eventwait(qts, "RESET");
|
|
|
+
|
|
|
+ read_bootdevices(fw_cfg, expected2);
|
|
|
+
|
|
|
+ g_free(joined_args);
|
|
|
+ qtest_quit(qts);
|
|
|
+
|
|
|
+ g_free(fw_cfg);
|
|
|
+
|
|
|
+ for (i = 0; i < args->n_drives; i++) {
|
|
|
+ unlink(args->drives[i]);
|
|
|
+ free(args->drives[i]);
|
|
|
+ }
|
|
|
+ g_free(args->drives);
|
|
|
+ g_strfreev(args->argv);
|
|
|
+ g_free(args);
|
|
|
+}
|
|
|
+
|
|
|
+static void test_override_virtio_hot_unplug(void)
|
|
|
+{
|
|
|
+ QTestState *qts;
|
|
|
+ char *joined_args;
|
|
|
+ QFWCFG *fw_cfg;
|
|
|
+ QDict *response;
|
|
|
+ int i;
|
|
|
+ TestArgs *args = create_args();
|
|
|
+ CHSResult expected[] = {
|
|
|
+ {"/pci@i0cf8/scsi@2/disk@0,0", {10000, 120, 30} },
|
|
|
+ {"/pci@i0cf8/scsi@3/disk@0,0", {20, 20, 20} },
|
|
|
+ {NULL, {0, 0, 0} }
|
|
|
+ };
|
|
|
+ CHSResult expected2[] = {
|
|
|
+ {"/pci@i0cf8/scsi@3/disk@0,0", {20, 20, 20} },
|
|
|
+ {NULL, {0, 0, 0} }
|
|
|
+ };
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_drive_with_mbr(args, empty_mbr, 1);
|
|
|
+ add_virtio_disk(args, 0, "pci.0", 2, 10000, 120, 30);
|
|
|
+ add_virtio_disk(args, 1, "pci.0", 3, 20, 20, 20);
|
|
|
+
|
|
|
+ joined_args = g_strjoinv(" ", args->argv);
|
|
|
+
|
|
|
+ qts = qtest_init(joined_args);
|
|
|
+ fw_cfg = pc_fw_cfg_init(qts);
|
|
|
+
|
|
|
+ read_bootdevices(fw_cfg, expected);
|
|
|
+
|
|
|
+ /* unplug device an restart */
|
|
|
+ response = qtest_qmp(qts,
|
|
|
+ "{ 'execute': 'device_del',"
|
|
|
+ " 'arguments': {'id': 'virtio-disk0' }}");
|
|
|
+ g_assert(response);
|
|
|
+ g_assert(!qdict_haskey(response, "error"));
|
|
|
+ qobject_unref(response);
|
|
|
+ response = qtest_qmp(qts,
|
|
|
+ "{ 'execute': 'system_reset', 'arguments': { }}");
|
|
|
+ g_assert(response);
|
|
|
+ g_assert(!qdict_haskey(response, "error"));
|
|
|
+ qobject_unref(response);
|
|
|
+
|
|
|
+ qtest_qmp_eventwait(qts, "RESET");
|
|
|
+
|
|
|
+ read_bootdevices(fw_cfg, expected2);
|
|
|
+
|
|
|
+ g_free(joined_args);
|
|
|
+ qtest_quit(qts);
|
|
|
+
|
|
|
+ g_free(fw_cfg);
|
|
|
+
|
|
|
+ for (i = 0; i < args->n_drives; i++) {
|
|
|
+ unlink(args->drives[i]);
|
|
|
+ free(args->drives[i]);
|
|
|
+ }
|
|
|
+ g_free(args->drives);
|
|
|
+ g_strfreev(args->argv);
|
|
|
+ g_free(args);
|
|
|
+}
|
|
|
+
|
|
|
int main(int argc, char **argv)
|
|
|
{
|
|
|
Backend i;
|
|
@@ -413,6 +949,21 @@ int main(int argc, char **argv)
|
|
|
qtest_add_func("hd-geo/ide/device/mbr/chs", test_ide_device_mbr_chs);
|
|
|
qtest_add_func("hd-geo/ide/device/user/chs", test_ide_device_user_chs);
|
|
|
qtest_add_func("hd-geo/ide/device/user/chst", test_ide_device_user_chst);
|
|
|
+ if (have_qemu_img()) {
|
|
|
+ qtest_add_func("hd-geo/override/ide", test_override_ide);
|
|
|
+ qtest_add_func("hd-geo/override/scsi", test_override_scsi);
|
|
|
+ qtest_add_func("hd-geo/override/scsi_2_controllers",
|
|
|
+ test_override_scsi_2_controllers);
|
|
|
+ qtest_add_func("hd-geo/override/virtio_blk", test_override_virtio_blk);
|
|
|
+ qtest_add_func("hd-geo/override/zero_chs", test_override_zero_chs);
|
|
|
+ qtest_add_func("hd-geo/override/scsi_hot_unplug",
|
|
|
+ test_override_scsi_hot_unplug);
|
|
|
+ qtest_add_func("hd-geo/override/virtio_hot_unplug",
|
|
|
+ test_override_virtio_hot_unplug);
|
|
|
+ } else {
|
|
|
+ g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
|
|
|
+ "skipping hd-geo/override/* tests");
|
|
|
+ }
|
|
|
|
|
|
ret = g_test_run();
|
|
|
|