Commit 507ef2f9 authored by Peter Maydell's avatar Peter Maydell

Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging

# gpg: Signature made Sat 04 Oct 2014 21:24:46 BST using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>"

* remotes/stefanha/tags/block-pull-request: (23 commits)
  blockdev-test: Test device_del after drive_del
  blockdev-test: Factor out some common code into helpers
  blockdev-test: Simplify by using g_assert_cmpstr()
  blockdev-test: Clean up bogus drive_add argument
  blockdev-test: Use single rather than double quotes in QMP
  drive_del-test: Merge of qdev-monitor-test, blockdev-test
  iotests: qemu-img info output for corrupt image
  qapi: Add corrupt field to ImageInfoSpecificQCow2
  iotests: Use _img_info
  util: Emancipate id_wellformed() from QemuOpts
  q35/ahci: Pick up -cdrom and -hda options
  qtest/bios-tables: Correct Q35 command line
  ide: Update ide_drive_get to be HBA agnostic
  pc/vl: Add units-per-default-bus property
  blockdev: Allow overriding if_max_dev property
  blockdev: Orphaned drive search
  qemu-iotests: Fix supported cache modes for 052
  make check-block: Use default cache modes
  Modify qemu_opt_rename to realize renaming all items in opts
  vmdk: Fix integer overflow in offset calculation
  ...
Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents b00a0ddb 767c86d3
......@@ -335,18 +335,13 @@ void bdrv_register(BlockDriver *bdrv)
QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
}
static bool bdrv_is_valid_name(const char *name)
{
return qemu_opts_id_wellformed(name);
}
/* create a new block device (by default it is empty) */
BlockDriverState *bdrv_new(const char *device_name, Error **errp)
{
BlockDriverState *bs;
int i;
if (*device_name && !bdrv_is_valid_name(device_name)) {
if (*device_name && !id_wellformed(device_name)) {
error_setg(errp, "Invalid device name");
return NULL;
}
......@@ -874,7 +869,7 @@ static void bdrv_assign_node_name(BlockDriverState *bs,
}
/* Check for empty string or invalid characters */
if (!bdrv_is_valid_name(node_name)) {
if (!id_wellformed(node_name)) {
error_setg(errp, "Invalid node name");
return;
}
......
......@@ -2282,6 +2282,9 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
.lazy_refcounts = s->compatible_features &
QCOW2_COMPAT_LAZY_REFCOUNTS,
.has_lazy_refcounts = true,
.corrupt = s->incompatible_features &
QCOW2_INCOMPAT_CORRUPT,
.has_corrupt = true,
};
}
......
......@@ -517,6 +517,11 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
const char *host, *user, *path, *host_key_check;
int port;
if (!qdict_haskey(options, "host")) {
ret = -EINVAL;
error_setg(errp, "No hostname was specified");
goto err;
}
host = qdict_get_str(options, "host");
if (qdict_haskey(options, "port")) {
......@@ -525,6 +530,11 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
port = 22;
}
if (!qdict_haskey(options, "path")) {
ret = -EINVAL;
error_setg(errp, "No path was specified");
goto err;
}
path = qdict_get_str(options, "path");
if (qdict_haskey(options, "user")) {
......
......@@ -1113,7 +1113,7 @@ static int get_cluster_offset(BlockDriverState *bs,
uint32_t min_count, *l2_table;
bool zeroed = false;
int64_t ret;
int32_t cluster_sector;
int64_t cluster_sector;
if (m_data) {
m_data->valid = 0;
......
......@@ -60,7 +60,7 @@ static const char *const if_name[IF_COUNT] = {
[IF_XEN] = "xen",
};
static const int if_max_devs[IF_COUNT] = {
static int if_max_devs[IF_COUNT] = {
/*
* Do not change these numbers! They govern how drive option
* index maps to unit and bus. That mapping is ABI.
......@@ -79,6 +79,30 @@ static const int if_max_devs[IF_COUNT] = {
[IF_SCSI] = 7,
};
/**
* Boards may call this to offer board-by-board overrides
* of the default, global values.
*/
void override_max_devs(BlockInterfaceType type, int max_devs)
{
DriveInfo *dinfo;
if (max_devs <= 0) {
return;
}
QTAILQ_FOREACH(dinfo, &drives, next) {
if (dinfo->type == type) {
fprintf(stderr, "Cannot override units-per-bus property of"
" the %s interface, because a drive of that type has"
" already been added.\n", if_name[type]);
g_assert_not_reached();
}
}
if_max_devs[type] = max_devs;
}
/*
* We automatically delete the drive when a device using it gets
* unplugged. Questionable feature, but we can't just drop it.
......@@ -111,6 +135,23 @@ void blockdev_auto_del(BlockDriverState *bs)
}
}
/**
* Returns the current mapping of how many units per bus
* a particular interface can support.
*
* A positive integer indicates n units per bus.
* 0 implies the mapping has not been established.
* -1 indicates an invalid BlockInterfaceType was given.
*/
int drive_get_max_devs(BlockInterfaceType type)
{
if (type >= IF_IDE && type < IF_COUNT) {
return if_max_devs[type];
}
return -1;
}
static int drive_index_to_bus_id(BlockInterfaceType type, int index)
{
int max_devs = if_max_devs[type];
......@@ -166,6 +207,27 @@ DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
return NULL;
}
bool drive_check_orphaned(void)
{
DriveInfo *dinfo;
bool rs = false;
QTAILQ_FOREACH(dinfo, &drives, next) {
/* If dinfo->bdrv->dev is NULL, it has no device attached. */
/* Unless this is a default drive, this may be an oversight. */
if (!dinfo->bdrv->dev && !dinfo->is_default &&
dinfo->type != IF_NONE) {
fprintf(stderr, "Warning: Orphaned drive without device: "
"id=%s,file=%s,if=%s,bus=%d,unit=%d\n",
dinfo->id, dinfo->bdrv->filename, if_name[dinfo->type],
dinfo->bus, dinfo->unit);
rs = true;
}
}
return rs;
}
DriveInfo *drive_get_by_index(BlockInterfaceType type, int index)
{
return drive_get(type,
......@@ -224,9 +286,7 @@ void drive_info_del(DriveInfo *dinfo)
if (!dinfo) {
return;
}
if (dinfo->opts) {
qemu_opts_del(dinfo->opts);
}
qemu_opts_del(dinfo->opts);
g_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
g_free(dinfo->serial);
......@@ -550,6 +610,10 @@ static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to,
"same time", to, from);
return;
}
}
/* rename all items in opts */
while ((value = qemu_opt_get(opts, from))) {
qemu_opt_set(opts, to, value);
qemu_opt_unset(opts, from);
}
......
......@@ -97,7 +97,7 @@ static void clipper_init(MachineState *machine)
/* IDE disk setup. */
{
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
ide_drive_get(hd, MAX_IDE_BUS);
ide_drive_get(hd, ARRAY_SIZE(hd));
pci_cmd646_ide_init(pci_bus, hd, 0);
}
......
......@@ -1524,6 +1524,7 @@ static void pc_generic_machine_class_init(ObjectClass *oc, void *data)
mc->hot_add_cpu = qm->hot_add_cpu;
mc->kvm_type = qm->kvm_type;
mc->block_default_type = qm->block_default_type;
mc->units_per_default_bus = qm->units_per_default_bus;
mc->max_cpus = qm->max_cpus;
mc->no_serial = qm->no_serial;
mc->no_parallel = qm->no_parallel;
......
......@@ -239,7 +239,7 @@ static void pc_init1(MachineState *machine,
pc_nic_init(isa_bus, pci_bus);
ide_drive_get(hd, MAX_IDE_BUS);
ide_drive_get(hd, ARRAY_SIZE(hd));
if (pci_enabled) {
PCIDevice *dev;
if (xen_enabled()) {
......
......@@ -86,6 +86,7 @@ static void pc_q35_init(MachineState *machine)
DeviceState *icc_bridge;
PcGuestInfo *guest_info;
ram_addr_t lowmem;
DriveInfo *hd[MAX_SATA_PORTS];
/* Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory
* and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping
......@@ -253,6 +254,9 @@ static void pc_q35_init(MachineState *machine)
true, "ich9-ahci");
idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0");
idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1");
g_assert_cmpint(MAX_SATA_PORTS, ==, ICH_AHCI(ahci)->ahci.ports);
ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports);
ahci_ide_create_devs(ahci, hd);
if (usb_enabled(false)) {
/* Should we create 6 UHCI according to ich9 spec? */
......@@ -344,7 +348,8 @@ static void pc_q35_init_1_4(MachineState *machine)
#define PC_Q35_MACHINE_OPTIONS \
PC_DEFAULT_MACHINE_OPTIONS, \
.desc = "Standard PC (Q35 + ICH9, 2009)", \
.hot_add_cpu = pc_hot_add_cpu
.hot_add_cpu = pc_hot_add_cpu, \
.units_per_default_bus = 1
#define PC_Q35_2_2_MACHINE_OPTIONS \
PC_Q35_MACHINE_OPTIONS, \
......
......@@ -1419,3 +1419,18 @@ static void sysbus_ahci_register_types(void)
}
type_init(sysbus_ahci_register_types)
void ahci_ide_create_devs(PCIDevice *dev, DriveInfo **hd)
{
AHCIPCIState *d = ICH_AHCI(dev);
AHCIState *ahci = &d->ahci;
int i;
for (i = 0; i < ahci->ports; i++) {
if (hd[i] == NULL) {
continue;
}
ide_create_drive(&ahci->dev[i].port, 0, hd[i]);
}
}
......@@ -332,4 +332,6 @@ void ahci_uninit(AHCIState *s);
void ahci_reset(AHCIState *s);
void ahci_ide_create_devs(PCIDevice *dev, DriveInfo **hd);
#endif /* HW_IDE_AHCI_H */
......@@ -2558,16 +2558,28 @@ const VMStateDescription vmstate_ide_bus = {
}
};
void ide_drive_get(DriveInfo **hd, int max_bus)
void ide_drive_get(DriveInfo **hd, int n)
{
int i;
int highest_bus = drive_get_max_bus(IF_IDE) + 1;
int max_devs = drive_get_max_devs(IF_IDE);
int n_buses = max_devs ? (n / max_devs) : n;
if (drive_get_max_bus(IF_IDE) >= max_bus) {
fprintf(stderr, "qemu: too many IDE bus: %d\n", max_bus);
/*
* Note: The number of actual buses available is not known.
* We compute this based on the size of the DriveInfo* array, n.
* If it is less than max_devs * <num_real_buses>,
* We will stop looking for drives prematurely instead of overfilling
* the array.
*/
if (highest_bus > n_buses) {
error_report("Too many IDE buses defined (%d > %d)",
highest_bus, n_buses);
exit(1);
}
for(i = 0; i < max_bus * MAX_IDE_DEVS; i++) {
hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
for (i = 0; i < n; i++) {
hd[i] = drive_get_by_index(IF_IDE, i);
}
}
......@@ -350,7 +350,7 @@ static void mips_fulong2e_init(MachineState *machine)
pci_bus = bonito_init((qemu_irq *)&(env->irq[2]));
/* South bridge */
ide_drive_get(hd, MAX_IDE_BUS);
ide_drive_get(hd, ARRAY_SIZE(hd));
isa_bus = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0));
if (!isa_bus) {
......
......@@ -1147,7 +1147,7 @@ void mips_malta_init(MachineState *machine)
pci_bus = gt64120_register(isa_irq);
/* Southbridge */
ide_drive_get(hd, MAX_IDE_BUS);
ide_drive_get(hd, ARRAY_SIZE(hd));
piix4_devfn = piix4_init(pci_bus, &isa_bus, 80);
......
......@@ -294,7 +294,7 @@ void mips_r4k_init(MachineState *machine)
if (nd_table[0].used)
isa_ne2000_init(isa_bus, 0x300, 9, &nd_table[0]);
ide_drive_get(hd, MAX_IDE_BUS);
ide_drive_get(hd, ARRAY_SIZE(hd));
for(i = 0; i < MAX_IDE_BUS; i++)
isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i],
hd[MAX_IDE_DEVS * i],
......
......@@ -400,7 +400,7 @@ static void ppc_core99_init(MachineState *machine)
macio_init(macio, pic_mem, escc_bar);
/* We only emulate 2 out of 3 IDE controllers for now */
ide_drive_get(hd, MAX_IDE_BUS);
ide_drive_get(hd, ARRAY_SIZE(hd));
macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
"ide[0]"));
......
......@@ -278,7 +278,7 @@ static void ppc_heathrow_init(MachineState *machine)
pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
ide_drive_get(hd, MAX_IDE_BUS);
ide_drive_get(hd, ARRAY_SIZE(hd));
macio = pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO);
dev = DEVICE(macio);
......
......@@ -519,7 +519,7 @@ static void ppc_prep_init(MachineState *machine)
}
}
ide_drive_get(hd, MAX_IDE_BUS);
ide_drive_get(hd, ARRAY_SIZE(hd));
for(i = 0; i < MAX_IDE_BUS; i++) {
isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i],
hd[2 * i],
......
......@@ -864,7 +864,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
for(i = 0; i < nb_nics; i++)
pci_nic_init_nofail(&nd_table[i], pci_bus, "ne2k_pci", NULL);
ide_drive_get(hd, MAX_IDE_BUS);
ide_drive_get(hd, ARRAY_SIZE(hd));
pci_cmd646_ide_init(pci_bus, hd, 1);
......
......@@ -28,6 +28,7 @@ struct QEMUMachine {
QEMUMachineHotAddCPUFunc *hot_add_cpu;
QEMUMachineGetKvmtypeFunc *kvm_type;
BlockInterfaceType block_default_type;
int units_per_default_bus;
int max_cpus;
unsigned int no_serial:1,
no_parallel:1,
......@@ -86,6 +87,7 @@ struct MachineClass {
int (*kvm_type)(const char *arg);
BlockInterfaceType block_default_type;
int units_per_default_bus;
int max_cpus;
unsigned int no_serial:1,
no_parallel:1,
......
......@@ -190,6 +190,9 @@ int64_t strtosz_suffix_unit(const char *nptr, char **end,
/* used to print char* safely */
#define STR_OR_NULL(str) ((str) ? (str) : "null")
/* id.c */
bool id_wellformed(const char *id);
/* path.c */
void init_paths(const char *prefix);
const char *path(const char *pathname);
......
......@@ -103,7 +103,6 @@ typedef int (*qemu_opt_loopfunc)(const char *name, const char *value, void *opaq
int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
int abort_on_failure);
int qemu_opts_id_wellformed(const char *id);
QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id);
QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id,
int fail_if_exists, Error **errp);
......
......@@ -38,6 +38,7 @@ struct DriveInfo {
int unit;
int auto_del; /* see blockdev_mark_auto_del() */
bool enable_auto_del; /* Only for legacy drive_new() */
bool is_default; /* Added by default_drive() ? */
int media_cd;
int cyls, heads, secs, trans;
QemuOpts *opts;
......@@ -45,9 +46,13 @@ struct DriveInfo {
QTAILQ_ENTRY(DriveInfo) next;
};
void override_max_devs(BlockInterfaceType type, int max_devs);
DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit);
bool drive_check_orphaned(void);
DriveInfo *drive_get_by_index(BlockInterfaceType type, int index);
int drive_get_max_bus(BlockInterfaceType type);
int drive_get_max_devs(BlockInterfaceType type);
DriveInfo *drive_get_next(BlockInterfaceType type);
DriveInfo *drive_get_by_blockdev(BlockDriverState *bs);
......
......@@ -38,12 +38,16 @@
#
# @lazy-refcounts: #optional on or off; only valid for compat >= 1.1
#
# @corrupt: #optional true if the image has been marked corrupt; only valid for
# compat >= 1.1 (since 2.2)
#
# Since: 1.7
##
{ 'type': 'ImageInfoSpecificQCow2',
'data': {
'compat': 'str',
'*lazy-refcounts': 'bool'
'*lazy-refcounts': 'bool',
'*corrupt': 'bool'
} }
##
......
......@@ -1736,9 +1736,7 @@ out:
qemu_opts_del(opts);
qemu_opts_free(create_opts);
qemu_vfree(buf);
if (sn_opts) {
qemu_opts_del(sn_opts);
}
qemu_opts_del(sn_opts);
if (out_bs) {
bdrv_unref(out_bs);
}
......
......@@ -778,9 +778,7 @@ int main(int argc, char **argv)
unlink(sockpath);
}
if (sn_opts) {
qemu_opts_del(sn_opts);
}
qemu_opts_del(sn_opts);
if (device) {
void *ret;
......
......@@ -1245,19 +1245,18 @@ int load_vmstate(const char *name)
void do_delvm(Monitor *mon, const QDict *qdict)
{
BlockDriverState *bs, *bs1;
BlockDriverState *bs;
Error *err = NULL;
const char *name = qdict_get_str(qdict, "name");
bs = find_vmstate_bs();
if (!bs) {
if (!find_vmstate_bs()) {
monitor_printf(mon, "No block device supports snapshots\n");
return;
}
bs1 = NULL;
while ((bs1 = bdrv_next(bs1))) {
if (bdrv_can_snapshot(bs1)) {
bs = NULL;
while ((bs = bdrv_next(bs))) {
if (bdrv_can_snapshot(bs)) {
bdrv_snapshot_delete_by_id_or_name(bs, name, &err);
if (err) {
monitor_printf(mon,
......
......@@ -140,8 +140,7 @@ check-qtest-i386-y += tests/bios-tables-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)
check-qtest-i386-y += tests/blockdev-test$(EXESUF)
check-qtest-i386-y += tests/qdev-monitor-test$(EXESUF)
check-qtest-i386-y += tests/drive_del-test$(EXESUF)
check-qtest-i386-y += tests/wdt_ib700-test$(EXESUF)
gcov-files-i386-y += hw/watchdog/watchdog.c hw/watchdog/wdt_ib700.c
check-qtest-i386-y += $(check-qtest-pci-y)
......@@ -335,7 +334,7 @@ tests/tpci200-test$(EXESUF): tests/tpci200-test.o
tests/display-vga-test$(EXESUF): tests/display-vga-test.o
tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
tests/qom-test$(EXESUF): tests/qom-test.o
tests/blockdev-test$(EXESUF): tests/blockdev-test.o $(libqos-pc-obj-y)
tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-pc-obj-y)
tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y)
tests/nvme-test$(EXESUF): tests/nvme-test.o
tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o
......
......@@ -714,14 +714,12 @@ static void test_acpi_one(const char *params, test_data *data)
uint8_t signature_high;
uint16_t signature;
int i;
const char *device = "";
if (!g_strcmp0(data->machine, MACHINE_Q35)) {
device = ",id=hd -device ide-hd,drive=hd";
}
args = g_strdup_printf("-net none -display none %s "
"-drive id=hd0,if=none,file=%s "
"-device ide-hd,drive=hd0 ",
params ? params : "", disk);
args = g_strdup_printf("-net none -display none %s -drive file=%s%s,",
params ? params : "", disk, device);
qtest_start(args);
/* Wait at most 1 minute */
......
/*
* blockdev.c test cases
*
* Copyright (C) 2013 Red Hat Inc.
*
* Authors:
* Stefan Hajnoczi <stefanha@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 <string.h>
#include "libqtest.h"
static void test_drive_add_empty(void)
{
QDict *response;
const char *response_return;
/* Start with an empty drive */
qtest_start("-drive if=none,id=drive0");
/* Delete the drive */
response = qmp("{\"execute\": \"human-monitor-command\","
" \"arguments\": {"
" \"command-line\": \"drive_del drive0\""
"}}");
g_assert(response);
response_return = qdict_get_try_str(response, "return");
g_assert(response_return);
g_assert(strcmp(response_return, "") == 0);
QDECREF(response);
/* Ensure re-adding the drive works - there should be no duplicate ID error
* because the old drive must be gone.
*/
response = qmp("{\"execute\": \"human-monitor-command\","
" \"arguments\": {"
" \"command-line\": \"drive_add 0 if=none,id=drive0\""
"}}");
g_assert(response);
response_return = qdict_get_try_str(response, "return");
g_assert(response_return);
g_assert(strcmp(response_return, "OK\r\n") == 0);
QDECREF(response);
qtest_end();
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
qtest_add_func("/qmp/drive_add_empty", test_drive_add_empty);
return g_test_run();
}
/*
* qdev-monitor.c test cases
* blockdev.c test cases
*
* Copyright (C) 2013 Red Hat Inc.
* Copyright (C) 2013-2014 Red Hat Inc.
*
* Authors:
* Stefan Hajnoczi <stefanha@redhat.com>
......@@ -10,12 +10,66 @@
* See the COPYING.LIB file in the top-level directory.
*/
#include <string.h>
#include <glib.h>
#include <string.h>
#include "libqtest.h"
#include "qapi/qmp/qjson.h"
static void test_device_add(void)
static void drive_add(void)
{
QDict *response;
response = qmp("{'execute': 'human-monitor-command',"
" 'arguments': {"
" 'command-line': 'drive_add 0 if=none,id=drive0'"
"}}");
g_assert(response);
g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, "OK\r\n");
QDECREF(response);
}
static void drive_del(void)
{
QDict *response;
response = qmp("{'execute': 'human-monitor-command',"
" 'arguments': {"
" 'command-line': 'drive_del drive0'"
"}}");
g_assert(response);
g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, "");
QDECREF(response);
}
static void device_del(void)
{
QDict *response;
/* Complication: ignore DEVICE_DELETED event */
qmp_discard_response("{'execute': 'device_del',"
" 'arguments': { 'id': 'dev0' } }");
response = qmp_receive();
g_assert(response);
g_assert(qdict_haskey(response, "return"));
QDECREF(response);
}
static void test_drive_without_dev(void)
{
/* Start with an empty drive */
qtest_start("-drive if=none,id=drive0");
/* Delete the drive */
drive_del();
/* Ensure re-adding the drive works - there should be no duplicate ID error
* because the old drive must be gone.
*/
drive_add();
qtest_end();
}
static void test_after_failed_device_add(void)
{
QDict *response;
QDict *error;
......@@ -25,10 +79,10 @@ static void test_device_add(void)
/* Make device_add fail. If this leaks the virtio-blk-pci device then a
* reference to drive0 will also be held (via qdev properties).
*/
response = qmp("{\"execute\": \"device_add\","
" \"arguments\": {"
" \"driver\": \"virtio-blk-pci\","
" \"drive\": \"drive0\""
response = qmp("{'execute': 'device_add',"
" 'arguments': {"
" 'driver': 'virtio-blk-pci',"
" 'drive': 'drive0'"
"}}");
g_assert(response);
error = qdict_get_qdict(response, "error");
......@@ -36,24 +90,29 @@ static void test_device_add(void)
QDECREF(response);
/* Delete the drive */
response = qmp("{\"execute\": \"human-monitor-command\","
" \"arguments\": {"
" \"command-line\": \"drive_del drive0\""
"}}");
g_assert(response);
g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, "");
QDECREF(response);
drive_del();
/* Try to re-add the drive. This fails with duplicate IDs if a leaked
* virtio-blk-pci exists that holds a reference to the old drive0.
*/
response = qmp("{\"execute\": \"human-monitor-command\","
" \"arguments\": {"
" \"command-line\": \"drive_add pci-addr=auto if=none,id=drive0\""
"}}");
g_assert(response);
g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, "OK\r\n");
QDECREF(response);
drive_add();
qtest_end();
}
static void test_drive_del_device_del(void)
{
/* Start with a drive used by a device that unplugs instantaneously */
qtest_start("-drive if=none,id=drive0,file=/dev/null"
" -device virtio-scsi-pci"
" -device scsi-hd,drive=drive0,id=dev0");
/*
* Delete the drive, and then the device
* Doing it in this order takes notoriously tricky special paths
*/