qemu/tests/hd-geo-test.c
Thomas Huth a0d6d7454a tests/hd-geo-test: Skip test when images can not be created
In certain environments like restricted containers, we can not create
huge test images. To be able to use "make check" in such container
environments, too, let's skip the hd-geo-test instead of failing when
the test images could not be created.

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20191204154618.23560-5-thuth@redhat.com>
2019-12-18 20:17:45 +00:00

989 lines
27 KiB
C

/*
* Hard disk geometry test cases.
*
* Copyright (c) 2012 Red Hat Inc.
*
* Authors:
* Markus Armbruster <armbru@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.
*/
/*
* Covers only IDE and tests only CMOS contents. Better than nothing.
* Improvements welcome.
*/
#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
static char *create_test_img(int secs)
{
char *template = strdup("/tmp/qtest.XXXXXX");
int fd, ret;
fd = mkstemp(template);
g_assert(fd >= 0);
ret = ftruncate(fd, (off_t)secs * 512);
close(fd);
if (ret) {
free(template);
template = NULL;
}
return template;
}
typedef struct {
int cyls, heads, secs, trans;
} CHST;
typedef enum {
mbr_blank, mbr_lba, mbr_chs,
mbr_last
} MBRcontents;
typedef enum {
/* order is relevant */
backend_small, backend_large, backend_empty,
backend_last
} Backend;
static const int img_secs[backend_last] = {
[backend_small] = 61440,
[backend_large] = 8388608,
[backend_empty] = -1,
};
static const CHST hd_chst[backend_last][mbr_last] = {
[backend_small] = {
[mbr_blank] = { 60, 16, 63, 0 },
[mbr_lba] = { 60, 16, 63, 2 },
[mbr_chs] = { 60, 16, 63, 0 }
},
[backend_large] = {
[mbr_blank] = { 8322, 16, 63, 1 },
[mbr_lba] = { 8322, 16, 63, 1 },
[mbr_chs] = { 8322, 16, 63, 0 }
},
};
static char *img_file_name[backend_last];
static const CHST *cur_ide[4];
static bool is_hd(const CHST *expected_chst)
{
return expected_chst && expected_chst->cyls;
}
static void test_cmos_byte(QTestState *qts, int reg, int expected)
{
enum { cmos_base = 0x70 };
int actual;
qtest_outb(qts, cmos_base + 0, reg);
actual = qtest_inb(qts, cmos_base + 1);
g_assert(actual == expected);
}
static void test_cmos_bytes(QTestState *qts, int reg0, int n,
uint8_t expected[])
{
int i;
for (i = 0; i < 9; i++) {
test_cmos_byte(qts, reg0 + i, expected[i]);
}
}
static void test_cmos_disk_data(QTestState *qts)
{
test_cmos_byte(qts, 0x12,
(is_hd(cur_ide[0]) ? 0xf0 : 0) |
(is_hd(cur_ide[1]) ? 0x0f : 0));
}
static void test_cmos_drive_cyl(QTestState *qts, int reg0,
const CHST *expected_chst)
{
if (is_hd(expected_chst)) {
int c = expected_chst->cyls;
int h = expected_chst->heads;
int s = expected_chst->secs;
uint8_t expected_bytes[9] = {
c & 0xff, c >> 8, h, 0xff, 0xff, 0xc0 | ((h > 8) << 3),
c & 0xff, c >> 8, s
};
test_cmos_bytes(qts, reg0, 9, expected_bytes);
} else {
int i;
for (i = 0; i < 9; i++) {
test_cmos_byte(qts, reg0 + i, 0);
}
}
}
static void test_cmos_drive1(QTestState *qts)
{
test_cmos_byte(qts, 0x19, is_hd(cur_ide[0]) ? 47 : 0);
test_cmos_drive_cyl(qts, 0x1b, cur_ide[0]);
}
static void test_cmos_drive2(QTestState *qts)
{
test_cmos_byte(qts, 0x1a, is_hd(cur_ide[1]) ? 47 : 0);
test_cmos_drive_cyl(qts, 0x24, cur_ide[1]);
}
static void test_cmos_disktransflag(QTestState *qts)
{
int val, i;
val = 0;
for (i = 0; i < ARRAY_SIZE(cur_ide); i++) {
if (is_hd(cur_ide[i])) {
val |= cur_ide[i]->trans << (2 * i);
}
}
test_cmos_byte(qts, 0x39, val);
}
static void test_cmos(QTestState *qts)
{
test_cmos_disk_data(qts);
test_cmos_drive1(qts);
test_cmos_drive2(qts);
test_cmos_disktransflag(qts);
}
static int append_arg(int argc, char *argv[], int argv_sz, char *arg)
{
g_assert(argc + 1 < argv_sz);
argv[argc++] = arg;
argv[argc] = NULL;
return argc;
}
static int setup_common(char *argv[], int argv_sz)
{
memset(cur_ide, 0, sizeof(cur_ide));
return append_arg(0, argv, argv_sz,
g_strdup("-nodefaults"));
}
static void setup_mbr(int img_idx, MBRcontents mbr)
{
static const uint8_t part_lba[16] = {
/* chs 0,1,1 (lba 63) to chs 0,127,63 (8001 sectors) */
0x80, 1, 1, 0, 6, 127, 63, 0, 63, 0, 0, 0, 0x41, 0x1F, 0, 0,
};
static const uint8_t part_chs[16] = {
/* chs 0,1,1 (lba 63) to chs 7,15,63 (8001 sectors) */
0x80, 1, 1, 0, 6, 15, 63, 7, 63, 0, 0, 0, 0x41, 0x1F, 0, 0,
};
uint8_t buf[512];
int fd, ret;
memset(buf, 0, sizeof(buf));
if (mbr != mbr_blank) {
buf[0x1fe] = 0x55;
buf[0x1ff] = 0xAA;
memcpy(buf + 0x1BE, mbr == mbr_lba ? part_lba : part_chs, 16);
}
fd = open(img_file_name[img_idx], O_WRONLY);
g_assert(fd >= 0);
ret = write(fd, buf, sizeof(buf));
g_assert(ret == sizeof(buf));
close(fd);
}
static int setup_ide(int argc, char *argv[], int argv_sz,
int ide_idx, const char *dev, int img_idx,
MBRcontents mbr)
{
char *s1, *s2, *s3;
s1 = g_strdup_printf("-drive id=drive%d,if=%s",
ide_idx, dev ? "none" : "ide");
s2 = dev ? g_strdup("") : g_strdup_printf(",index=%d", ide_idx);
if (img_secs[img_idx] >= 0) {
setup_mbr(img_idx, mbr);
s3 = g_strdup_printf(",format=raw,file=%s", img_file_name[img_idx]);
} else {
s3 = g_strdup(",media=cdrom");
}
argc = append_arg(argc, argv, argv_sz,
g_strdup_printf("%s%s%s", s1, s2, s3));
g_free(s1);
g_free(s2);
g_free(s3);
if (dev) {
argc = append_arg(argc, argv, argv_sz,
g_strdup_printf("-device %s,drive=drive%d,"
"bus=ide.%d,unit=%d",
dev, ide_idx,
ide_idx / 2, ide_idx % 2));
}
return argc;
}
/*
* Test case: no IDE devices
*/
static void test_ide_none(void)
{
char **argv = g_new0(char *, ARGV_SIZE);
char *args;
QTestState *qts;
setup_common(argv, ARGV_SIZE);
args = g_strjoinv(" ", argv);
qts = qtest_init(args);
g_strfreev(argv);
g_free(args);
test_cmos(qts);
qtest_quit(qts);
}
static void test_ide_mbr(bool use_device, MBRcontents mbr)
{
char **argv = g_new0(char *, ARGV_SIZE);
char *args;
int argc;
Backend i;
const char *dev;
QTestState *qts;
argc = setup_common(argv, ARGV_SIZE);
for (i = 0; i < backend_last; i++) {
cur_ide[i] = &hd_chst[i][mbr];
dev = use_device ? (is_hd(cur_ide[i]) ? "ide-hd" : "ide-cd") : NULL;
argc = setup_ide(argc, argv, ARGV_SIZE, i, dev, i, mbr);
}
args = g_strjoinv(" ", argv);
qts = qtest_init(args);
g_strfreev(argv);
g_free(args);
test_cmos(qts);
qtest_quit(qts);
}
/*
* Test case: IDE devices (if=ide) with blank MBRs
*/
static void test_ide_drive_mbr_blank(void)
{
test_ide_mbr(false, mbr_blank);
}
/*
* Test case: IDE devices (if=ide) with MBRs indicating LBA is in use
*/
static void test_ide_drive_mbr_lba(void)
{
test_ide_mbr(false, mbr_lba);
}
/*
* Test case: IDE devices (if=ide) with MBRs indicating CHS is in use
*/
static void test_ide_drive_mbr_chs(void)
{
test_ide_mbr(false, mbr_chs);
}
/*
* Test case: IDE devices (if=none) with blank MBRs
*/
static void test_ide_device_mbr_blank(void)
{
test_ide_mbr(true, mbr_blank);
}
/*
* Test case: IDE devices (if=none) with MBRs indicating LBA is in use
*/
static void test_ide_device_mbr_lba(void)
{
test_ide_mbr(true, mbr_lba);
}
/*
* Test case: IDE devices (if=none) with MBRs indicating CHS is in use
*/
static void test_ide_device_mbr_chs(void)
{
test_ide_mbr(true, mbr_chs);
}
static void test_ide_drive_user(const char *dev, bool trans)
{
char **argv = g_new0(char *, ARGV_SIZE);
char *args, *opts;
int argc;
int secs = img_secs[backend_small];
const CHST expected_chst = { secs / (4 * 32) , 4, 32, trans };
QTestState *qts;
argc = setup_common(argv, ARGV_SIZE);
opts = g_strdup_printf("%s,%scyls=%d,heads=%d,secs=%d",
dev, trans ? "bios-chs-trans=lba," : "",
expected_chst.cyls, expected_chst.heads,
expected_chst.secs);
cur_ide[0] = &expected_chst;
argc = setup_ide(argc, argv, ARGV_SIZE, 0, opts, backend_small, mbr_chs);
g_free(opts);
args = g_strjoinv(" ", argv);
qts = qtest_init(args);
g_strfreev(argv);
g_free(args);
test_cmos(qts);
qtest_quit(qts);
}
/*
* Test case: IDE device (if=none) with explicit CHS
*/
static void test_ide_device_user_chs(void)
{
test_ide_drive_user("ide-hd", false);
}
/*
* Test case: IDE device (if=none) with explicit CHS and translation
*/
static void test_ide_device_user_chst(void)
{
test_ide_drive_user("ide-hd", true);
}
/*
* Test case: IDE devices (if=ide), but use index=0 for CD-ROM
*/
static void test_ide_drive_cd_0(void)
{
char **argv = g_new0(char *, ARGV_SIZE);
char *args;
int argc, ide_idx;
Backend i;
QTestState *qts;
argc = setup_common(argv, ARGV_SIZE);
for (i = 0; i <= backend_empty; i++) {
ide_idx = backend_empty - i;
cur_ide[ide_idx] = &hd_chst[i][mbr_blank];
argc = setup_ide(argc, argv, ARGV_SIZE, ide_idx, NULL, i, mbr_blank);
}
args = g_strjoinv(" ", argv);
qts = qtest_init(args);
g_strfreev(argv);
g_free(args);
test_cmos(qts);
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;
int ret;
g_test_init(&argc, &argv, NULL);
for (i = 0; i < backend_last; i++) {
if (img_secs[i] >= 0) {
img_file_name[i] = create_test_img(img_secs[i]);
if (!img_file_name[i]) {
g_test_message("Could not create test images.");
goto test_add_done;
}
} else {
img_file_name[i] = NULL;
}
}
qtest_add_func("hd-geo/ide/none", test_ide_none);
qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank);
qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba);
qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs);
qtest_add_func("hd-geo/ide/drive/cd_0", test_ide_drive_cd_0);
qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank);
qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba);
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");
}
test_add_done:
ret = g_test_run();
for (i = 0; i < backend_last; i++) {
if (img_file_name[i]) {
unlink(img_file_name[i]);
free(img_file_name[i]);
}
}
return ret;
}