소스 검색

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: Peter Maydell <peter.maydell@linaro.org>
Peter Maydell 11 년 전
부모
커밋
507ef2f9fa
52개의 변경된 파일500개의 추가작업 그리고 285개의 파일을 삭제
  1. 2 7
      block.c
  2. 3 0
      block/qcow2.c
  3. 10 0
      block/ssh.c
  4. 1 1
      block/vmdk.c
  5. 68 4
      blockdev.c
  6. 1 1
      hw/alpha/dp264.c
  7. 1 0
      hw/i386/pc.c
  8. 1 1
      hw/i386/pc_piix.c
  9. 6 1
      hw/i386/pc_q35.c
  10. 15 0
      hw/ide/ahci.c
  11. 2 0
      hw/ide/ahci.h
  12. 17 5
      hw/ide/core.c
  13. 1 1
      hw/mips/mips_fulong2e.c
  14. 1 1
      hw/mips/mips_malta.c
  15. 1 1
      hw/mips/mips_r4k.c
  16. 1 1
      hw/ppc/mac_newworld.c
  17. 1 1
      hw/ppc/mac_oldworld.c
  18. 1 1
      hw/ppc/prep.c
  19. 1 1
      hw/sparc64/sun4u.c
  20. 2 0
      include/hw/boards.h
  21. 3 0
      include/qemu-common.h
  22. 0 1
      include/qemu/option.h
  23. 5 0
      include/sysemu/blockdev.h
  24. 5 1
      qapi/block-core.json
  25. 1 3
      qemu-img.c
  26. 1 3
      qemu-nbd.c
  27. 5 6
      savevm.c
  28. 2 3
      tests/Makefile
  29. 4 6
      tests/bios-tables-test.c
  30. 0 59
      tests/blockdev-test.c
  31. 137 0
      tests/drive_del-test.c
  32. 0 77
      tests/qdev-monitor-test.c
  33. 1 1
      tests/qemu-iotests-quick.sh
  34. 3 2
      tests/qemu-iotests/052
  35. 3 0
      tests/qemu-iotests/060
  36. 9 0
      tests/qemu-iotests/060.out
  37. 6 6
      tests/qemu-iotests/065
  38. 5 5
      tests/qemu-iotests/067.out
  39. 1 1
      tests/qemu-iotests/070
  40. 2 3
      tests/qemu-iotests/070.out
  41. 6 6
      tests/qemu-iotests/082
  42. 18 44
      tests/qemu-iotests/082.out
  43. 2 0
      tests/qemu-iotests/089.out
  44. 2 2
      tests/qemu-iotests/095
  45. 4 12
      tests/qemu-iotests/095.out
  46. 70 0
      tests/qemu-iotests/105
  47. 21 0
      tests/qemu-iotests/105.out
  48. 1 0
      tests/qemu-iotests/group
  49. 1 0
      util/Makefile.objs
  50. 28 0
      util/id.c
  51. 1 16
      util/qemu-option.c
  52. 17 1
      vl.c

+ 2 - 7
block.c

@@ -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;
     }

+ 3 - 0
block/qcow2.c

@@ -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,
         };
     }
 

+ 10 - 0
block/ssh.c

@@ -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")) {

+ 1 - 1
block/vmdk.c

@@ -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;

+ 68 - 4
blockdev.c

@@ -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);
     }

+ 1 - 1
hw/alpha/dp264.c

@@ -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);
     }

+ 1 - 0
hw/i386/pc.c

@@ -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;

+ 1 - 1
hw/i386/pc_piix.c

@@ -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()) {

+ 6 - 1
hw/i386/pc_q35.c

@@ -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,                             \

+ 15 - 0
hw/ide/ahci.c

@@ -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]);
+    }
+
+}

+ 2 - 0
hw/ide/ahci.h

@@ -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 */

+ 17 - 5
hw/ide/core.c

@@ -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);
     }
 }

+ 1 - 1
hw/mips/mips_fulong2e.c

@@ -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) {

+ 1 - 1
hw/mips/mips_malta.c

@@ -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);
 

+ 1 - 1
hw/mips/mips_r4k.c

@@ -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],

+ 1 - 1
hw/ppc/mac_newworld.c

@@ -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]"));

+ 1 - 1
hw/ppc/mac_oldworld.c

@@ -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);

+ 1 - 1
hw/ppc/prep.c

@@ -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],

+ 1 - 1
hw/sparc64/sun4u.c

@@ -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);
 

+ 2 - 0
include/hw/boards.h

@@ -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,

+ 3 - 0
include/qemu-common.h

@@ -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);

+ 0 - 1
include/qemu/option.h

@@ -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);

+ 5 - 0
include/sysemu/blockdev.h

@@ -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);
 

+ 5 - 1
qapi/block-core.json

@@ -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'
   } }
 
 ##

+ 1 - 3
qemu-img.c

@@ -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);
     }

+ 1 - 3
qemu-nbd.c

@@ -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;

+ 5 - 6
savevm.c

@@ -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,

+ 2 - 3
tests/Makefile

@@ -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

+ 4 - 6
tests/bios-tables-test.c

@@ -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 */

+ 0 - 59
tests/blockdev-test.c

@@ -1,59 +0,0 @@
-/*
- * 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();
-}

+ 137 - 0
tests/drive_del-test.c

@@ -0,0 +1,137 @@
+/*
+ * blockdev.c test cases
+ *
+ * Copyright (C) 2013-2014 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 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;
+
+    qtest_start("-drive if=none,id=drive0");
+
+    /* 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'"
+                   "}}");
+    g_assert(response);
+    error = qdict_get_qdict(response, "error");
+    g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, "GenericError");
+    QDECREF(response);
+
+    /* Delete the drive */
+    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.
+     */
+    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
+     */
+    drive_del();
+    device_del();
+
+    qtest_end();
+}
+
+int main(int argc, char **argv)
+{
+    const char *arch = qtest_get_arch();
+
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/drive_del/without-dev", test_drive_without_dev);
+
+    /* TODO I guess any arch with PCI would do */
+    if (!strcmp(arch, "i386") || !strcmp(arch, "x86_64")) {
+        qtest_add_func("/drive_del/after_failed_device_add",
+                       test_after_failed_device_add);
+        qtest_add_func("/blockdev/drive_del_device_del",
+                       test_drive_del_device_del);
+    }
+
+    return g_test_run();
+}

+ 0 - 77
tests/qdev-monitor-test.c

@@ -1,77 +0,0 @@
-/*
- * qdev-monitor.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 <string.h>
-#include <glib.h>
-#include "libqtest.h"
-#include "qapi/qmp/qjson.h"
-
-static void test_device_add(void)
-{
-    QDict *response;
-    QDict *error;
-
-    qtest_start("-drive if=none,id=drive0");
-
-    /* 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\""
-                   "}}");
-    g_assert(response);
-    error = qdict_get_qdict(response, "error");
-    g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, "GenericError");
-    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);
-
-    /* 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);
-
-    qtest_end();
-}
-
-int main(int argc, char **argv)
-{
-    const char *arch = qtest_get_arch();
-
-    /* Check architecture */
-    if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) {
-        g_test_message("Skipping test for non-x86\n");
-        return 0;
-    }
-
-    /* Run the tests */
-    g_test_init(&argc, &argv, NULL);
-
-    qtest_add_func("/qmp/device_add", test_device_add);
-
-    return g_test_run();
-}

+ 1 - 1
tests/qemu-iotests-quick.sh

@@ -3,6 +3,6 @@
 cd tests/qemu-iotests
 
 ret=0
-./check -T -nocache -qcow2 -g quick || ret=1
+./check -T -qcow2 -g quick || ret=1
 
 exit $ret

+ 3 - 2
tests/qemu-iotests/052

@@ -41,8 +41,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt generic
 _supported_proto file
 _supported_os Linux
-_default_cache_mode "writethrough"
-_supported_cache_modes "writethrough"
+
+# Don't do O_DIRECT on tmpfs
+_supported_cache_modes "writeback" "writethrough" "unsafe"
 
 size=128M
 _make_test_img $size

+ 3 - 0
tests/qemu-iotests/060

@@ -76,6 +76,9 @@ $QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
 # The corrupt bit must now be set
 $PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
 
+# This information should be available through qemu-img info
+$QEMU_IMG info "$TEST_IMG" | _filter_testdir
+
 # Try to open the image R/W (which should fail)
 $QEMU_IO -c "$OPEN_RW" -c "read 0 512" 2>&1 | _filter_qemu_io \
                                             | _filter_testdir \

+ 9 - 0
tests/qemu-iotests/060.out

@@ -11,6 +11,15 @@ incompatible_features     0x0
 qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with active L1 table); further corruption events will be suppressed
 write failed: Input/output error
 incompatible_features     0x2
+image: TEST_DIR/t.qcow2
+file format: qcow2
+virtual size: 64M (67108864 bytes)
+disk size: 196K
+cluster_size: 65536
+Format specific information:
+    compat: 1.1
+    lazy refcounts: false
+    corrupt: true
 qemu-io: can't open device TEST_DIR/t.IMGFMT: IMGFMT: Image is corrupt; cannot be opened read/write
 read 512/512 bytes at offset 0
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)

+ 6 - 6
tests/qemu-iotests/065

@@ -94,28 +94,28 @@ class TestQCow2(TestQemuImgInfo):
 class TestQCow3NotLazy(TestQemuImgInfo):
     '''Testing a qcow2 version 3 image with lazy refcounts disabled'''
     img_options = 'compat=1.1,lazy_refcounts=off'
-    json_compare = { 'compat': '1.1', 'lazy-refcounts': False }
-    human_compare = [ 'compat: 1.1', 'lazy refcounts: false' ]
+    json_compare = { 'compat': '1.1', 'lazy-refcounts': False, 'corrupt': False }
+    human_compare = [ 'compat: 1.1', 'lazy refcounts: false', 'corrupt: false' ]
 
 class TestQCow3Lazy(TestQemuImgInfo):
     '''Testing a qcow2 version 3 image with lazy refcounts enabled'''
     img_options = 'compat=1.1,lazy_refcounts=on'
-    json_compare = { 'compat': '1.1', 'lazy-refcounts': True }
-    human_compare = [ 'compat: 1.1', 'lazy refcounts: true' ]
+    json_compare = { 'compat': '1.1', 'lazy-refcounts': True, 'corrupt': False }
+    human_compare = [ 'compat: 1.1', 'lazy refcounts: true', 'corrupt: false' ]
 
 class TestQCow3NotLazyQMP(TestQMP):
     '''Testing a qcow2 version 3 image with lazy refcounts disabled, opening
        with lazy refcounts enabled'''
     img_options = 'compat=1.1,lazy_refcounts=off'
     qemu_options = 'lazy-refcounts=on'
-    compare = { 'compat': '1.1', 'lazy-refcounts': False }
+    compare = { 'compat': '1.1', 'lazy-refcounts': False, 'corrupt': False }
 
 class TestQCow3LazyQMP(TestQMP):
     '''Testing a qcow2 version 3 image with lazy refcounts enabled, opening
        with lazy refcounts disabled'''
     img_options = 'compat=1.1,lazy_refcounts=on'
     qemu_options = 'lazy-refcounts=off'
-    compare = { 'compat': '1.1', 'lazy-refcounts': True }
+    compare = { 'compat': '1.1', 'lazy-refcounts': True, 'corrupt': False }
 
 TestImageInfoSpecific = None
 TestQemuImgInfo = None

+ 5 - 5
tests/qemu-iotests/067.out

@@ -6,7 +6,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virtio-blk-pci,drive=disk,id=virtio0
 QMP_VERSION
 {"return": {}}
-{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
+{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false, "corrupt": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
@@ -24,7 +24,7 @@ QMP_VERSION
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
 QMP_VERSION
 {"return": {}}
-{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
+{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false, "corrupt": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"return": {}}
 {"return": {}}
@@ -44,7 +44,7 @@ Testing:
 QMP_VERSION
 {"return": {}}
 {"return": "OK\r\n"}
-{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false, "corrupt": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"return": {}}
 {"return": {}}
@@ -64,14 +64,14 @@ Testing:
 QMP_VERSION
 {"return": {}}
 {"return": {}}
-{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false, "corrupt": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"return": {}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "RESET"}
-{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false, "corrupt": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}

+ 1 - 1
tests/qemu-iotests/070

@@ -77,7 +77,7 @@ _use_sample_img test-disk2vhd.vhdx.bz2
 
 echo
 echo "=== Verify image created by Disk2VHD can be opened ==="
-$QEMU_IMG info "$TEST_IMG" 2>&1 | _filter_testdir | _filter_qemu
+_img_info
 
 # success, all done
 echo "*** done"

+ 2 - 3
tests/qemu-iotests/070.out

@@ -20,9 +20,8 @@ read 18874368/18874368 bytes at offset 0
 18 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
 
 === Verify image created by Disk2VHD can be opened ===
-image: TEST_DIR/test-disk2vhd.vhdx
-file format: vhdx
+image: TEST_DIR/test-disk2vhd.IMGFMT
+file format: IMGFMT
 virtual size: 256M (268435456 bytes)
-disk size: 260M
 cluster_size: 2097152
 *** done

+ 6 - 6
tests/qemu-iotests/082

@@ -56,7 +56,7 @@ echo === create: Options specified more than once ===
 
 # Last -f should win
 run_qemu_img create -f foo -f $IMGFMT "$TEST_IMG" $size
-run_qemu_img info "$TEST_IMG"
+_img_info
 
 # Multiple -o should be merged
 run_qemu_img create -f $IMGFMT -o cluster_size=4k -o lazy_refcounts=on "$TEST_IMG" $size
@@ -66,7 +66,7 @@ run_qemu_img info "$TEST_IMG"
 run_qemu_img create -f $IMGFMT -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k "$TEST_IMG" $size
 run_qemu_img info "$TEST_IMG"
 run_qemu_img create -f $IMGFMT -o cluster_size=4k,cluster_size=8k "$TEST_IMG" $size
-run_qemu_img info "$TEST_IMG"
+_img_info
 
 echo
 echo === create: help for -o ===
@@ -106,11 +106,11 @@ run_qemu_img create -f $IMGFMT "$TEST_IMG" $size
 
 # Last -f should win
 run_qemu_img convert -f foo -f $IMGFMT "$TEST_IMG" "$TEST_IMG".base
-run_qemu_img info "$TEST_IMG".base
+TEST_IMG="${TEST_IMG}.base" _img_info
 
 # Last -O should win
 run_qemu_img convert -O foo -O $IMGFMT "$TEST_IMG" "$TEST_IMG".base
-run_qemu_img info "$TEST_IMG".base
+TEST_IMG="${TEST_IMG}.base" _img_info
 
 # Multiple -o should be merged
 run_qemu_img convert -O $IMGFMT -o cluster_size=4k -o lazy_refcounts=on "$TEST_IMG" "$TEST_IMG".base
@@ -120,7 +120,7 @@ run_qemu_img info "$TEST_IMG".base
 run_qemu_img convert -O $IMGFMT -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k "$TEST_IMG" "$TEST_IMG".base
 run_qemu_img info "$TEST_IMG".base
 run_qemu_img convert -O $IMGFMT -o cluster_size=4k,cluster_size=8k "$TEST_IMG" "$TEST_IMG".base
-run_qemu_img info "$TEST_IMG".base
+TEST_IMG="${TEST_IMG}.base" _img_info
 
 echo
 echo === convert: help for -o ===
@@ -167,7 +167,7 @@ run_qemu_img info "$TEST_IMG"
 run_qemu_img amend -f $IMGFMT -o size=8M -o lazy_refcounts=on -o size=132M "$TEST_IMG"
 run_qemu_img info "$TEST_IMG"
 run_qemu_img amend -f $IMGFMT -o size=4M,size=148M "$TEST_IMG"
-run_qemu_img info "$TEST_IMG"
+_img_info
 
 echo
 echo === amend: help for -o ===

+ 18 - 44
tests/qemu-iotests/082.out

@@ -4,16 +4,10 @@ QA output created by 082
 
 Testing: create -f foo -f qcow2 TEST_DIR/t.qcow2 128M
 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=65536 lazy_refcounts=off 
-
-Testing: info TEST_DIR/t.qcow2
-image: TEST_DIR/t.qcow2
-file format: qcow2
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
 virtual size: 128M (134217728 bytes)
-disk size: 196K
 cluster_size: 65536
-Format specific information:
-    compat: 1.1
-    lazy refcounts: false
 
 Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on TEST_DIR/t.qcow2 128M
 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=4096 lazy_refcounts=on 
@@ -27,6 +21,7 @@ cluster_size: 4096
 Format specific information:
     compat: 1.1
     lazy refcounts: true
+    corrupt: false
 
 Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 128M
 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=8192 lazy_refcounts=on 
@@ -40,19 +35,14 @@ cluster_size: 8192
 Format specific information:
     compat: 1.1
     lazy refcounts: true
+    corrupt: false
 
 Testing: create -f qcow2 -o cluster_size=4k,cluster_size=8k TEST_DIR/t.qcow2 128M
 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=8192 lazy_refcounts=off 
-
-Testing: info TEST_DIR/t.qcow2
-image: TEST_DIR/t.qcow2
-file format: qcow2
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
 virtual size: 128M (134217728 bytes)
-disk size: 28K
 cluster_size: 8192
-Format specific information:
-    compat: 1.1
-    lazy refcounts: false
 
 === create: help for -o ===
 
@@ -188,24 +178,15 @@ Testing: create -f qcow2 TEST_DIR/t.qcow2 128M
 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=65536 lazy_refcounts=off 
 
 Testing: convert -f foo -f qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
-
-Testing: info TEST_DIR/t.qcow2.base
-image: TEST_DIR/t.qcow2.base
+image: TEST_DIR/t.IMGFMT.base
 file format: raw
 virtual size: 128M (134217728 bytes)
-disk size: 0
 
 Testing: convert -O foo -O qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
-
-Testing: info TEST_DIR/t.qcow2.base
-image: TEST_DIR/t.qcow2.base
-file format: qcow2
+image: TEST_DIR/t.IMGFMT.base
+file format: IMGFMT
 virtual size: 128M (134217728 bytes)
-disk size: 196K
 cluster_size: 65536
-Format specific information:
-    compat: 1.1
-    lazy refcounts: false
 
 Testing: convert -O qcow2 -o cluster_size=4k -o lazy_refcounts=on TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
 
@@ -218,6 +199,7 @@ cluster_size: 4096
 Format specific information:
     compat: 1.1
     lazy refcounts: true
+    corrupt: false
 
 Testing: convert -O qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
 
@@ -230,18 +212,13 @@ cluster_size: 8192
 Format specific information:
     compat: 1.1
     lazy refcounts: true
+    corrupt: false
 
 Testing: convert -O qcow2 -o cluster_size=4k,cluster_size=8k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
-
-Testing: info TEST_DIR/t.qcow2.base
-image: TEST_DIR/t.qcow2.base
-file format: qcow2
+image: TEST_DIR/t.IMGFMT.base
+file format: IMGFMT
 virtual size: 128M (134217728 bytes)
-disk size: 28K
 cluster_size: 8192
-Format specific information:
-    compat: 1.1
-    lazy refcounts: false
 
 === convert: help for -o ===
 
@@ -384,6 +361,7 @@ cluster_size: 65536
 Format specific information:
     compat: 1.1
     lazy refcounts: true
+    corrupt: false
 
 Testing: amend -f qcow2 -o size=130M -o lazy_refcounts=off TEST_DIR/t.qcow2
 
@@ -396,6 +374,7 @@ cluster_size: 65536
 Format specific information:
     compat: 1.1
     lazy refcounts: false
+    corrupt: false
 
 Testing: amend -f qcow2 -o size=8M -o lazy_refcounts=on -o size=132M TEST_DIR/t.qcow2
 
@@ -408,18 +387,13 @@ cluster_size: 65536
 Format specific information:
     compat: 1.1
     lazy refcounts: true
+    corrupt: false
 
 Testing: amend -f qcow2 -o size=4M,size=148M TEST_DIR/t.qcow2
-
-Testing: info TEST_DIR/t.qcow2
-image: TEST_DIR/t.qcow2
-file format: qcow2
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
 virtual size: 148M (155189248 bytes)
-disk size: 196K
 cluster_size: 65536
-Format specific information:
-    compat: 1.1
-    lazy refcounts: true
 
 === amend: help for -o ===
 

+ 2 - 0
tests/qemu-iotests/089.out

@@ -41,10 +41,12 @@ vm state offset: 512 MiB
 Format specific information:
     compat: 1.1
     lazy refcounts: false
+    corrupt: false
 format name: IMGFMT
 cluster size: 64 KiB
 vm state offset: 512 MiB
 Format specific information:
     compat: 1.1
     lazy refcounts: false
+    corrupt: false
 *** done

+ 2 - 2
tests/qemu-iotests/095

@@ -60,7 +60,7 @@ _make_test_img -b "${TEST_IMG}.snp1" $size_larger
 
 echo
 echo "=== Base image info before commit and resize ==="
-$QEMU_IMG info "${TEST_IMG}.base" | _filter_testdir
+TEST_IMG="${TEST_IMG}.base" _img_info
 
 echo
 echo === Running QEMU Live Commit Test ===
@@ -78,7 +78,7 @@ _send_qemu_cmd $h "{ 'execute': 'block-commit',
 
 echo
 echo "=== Base image info after commit and resize ==="
-$QEMU_IMG info "${TEST_IMG}.base" | _filter_testdir
+TEST_IMG="${TEST_IMG}.base" _img_info
 
 # success, all done
 echo "*** done"

+ 4 - 12
tests/qemu-iotests/095.out

@@ -4,14 +4,10 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=104857600 backing_file='TEST_DIR
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=104857600 backing_file='TEST_DIR/t.IMGFMT.snp1' 
 
 === Base image info before commit and resize ===
-image: TEST_DIR/t.qcow2.base
-file format: qcow2
+image: TEST_DIR/t.IMGFMT.base
+file format: IMGFMT
 virtual size: 5.0M (5242880 bytes)
-disk size: 196K
 cluster_size: 65536
-Format specific information:
-    compat: 1.1
-    lazy refcounts: false
 
 === Running QEMU Live Commit Test ===
 
@@ -20,12 +16,8 @@ Format specific information:
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "test", "len": 104857600, "offset": 104857600, "speed": 0, "type": "commit"}}
 
 === Base image info after commit and resize ===
-image: TEST_DIR/t.qcow2.base
-file format: qcow2
+image: TEST_DIR/t.IMGFMT.base
+file format: IMGFMT
 virtual size: 100M (104857600 bytes)
-disk size: 196K
 cluster_size: 65536
-Format specific information:
-    compat: 1.1
-    lazy refcounts: false
 *** done

+ 70 - 0
tests/qemu-iotests/105

@@ -0,0 +1,70 @@
+#!/bin/bash
+#
+# Create, read, write big image
+#
+# 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=famz@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 qcow2 vmdk vhdx qed
+_supported_proto generic
+_supported_os Linux
+_unsupported_imgopts "subformat=twoGbMaxExtentFlat" \
+                     "subformat=twoGbMaxExtentSparse"
+
+echo
+echo "creating large image"
+_make_test_img 16T
+
+echo
+echo "small read"
+$QEMU_IO -c "read 1024 4096" "$TEST_IMG" | _filter_qemu_io
+
+echo
+echo "small write"
+$QEMU_IO -c "write 8192 4096" "$TEST_IMG" | _filter_qemu_io
+
+echo
+echo "small read at high offset"
+$QEMU_IO -c "read 14T 4096" "$TEST_IMG" | _filter_qemu_io
+
+echo
+echo "small write at high offset"
+$QEMU_IO -c "write 14T 4096" "$TEST_IMG" | _filter_qemu_io
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0

+ 21 - 0
tests/qemu-iotests/105.out

@@ -0,0 +1,21 @@
+QA output created by 105
+
+creating large image
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=17592186044416
+
+small read
+read 4096/4096 bytes at offset 1024
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+small write
+wrote 4096/4096 bytes at offset 8192
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+small read at high offset
+read 4096/4096 bytes at offset 15393162788864
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+small write at high offset
+wrote 4096/4096 bytes at offset 15393162788864
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done

+ 1 - 0
tests/qemu-iotests/group

@@ -105,3 +105,4 @@
 101 rw auto quick
 103 rw auto quick
 104 rw auto
+105 rw auto quick

+ 1 - 0
util/Makefile.objs

@@ -8,6 +8,7 @@ util-obj-y += fifo8.o
 util-obj-y += acl.o
 util-obj-y += error.o qemu-error.o
 util-obj-$(CONFIG_POSIX) += compatfd.o
+util-obj-y += id.o
 util-obj-y += iov.o aes.o qemu-config.o qemu-sockets.o uri.o notify.o
 util-obj-y += qemu-option.o qemu-progress.o
 util-obj-y += hexdump.o

+ 28 - 0
util/id.c

@@ -0,0 +1,28 @@
+/*
+ * Dealing with identifiers
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * Authors:
+ *  Markus Armbruster <armbru@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 "qemu-common.h"
+
+bool id_wellformed(const char *id)
+{
+    int i;
+
+    if (!qemu_isalpha(id[0])) {
+        return false;
+    }
+    for (i = 1; id[i]; i++) {
+        if (!qemu_isalnum(id[i]) && !strchr("-._", id[i])) {
+            return false;
+        }
+    }
+    return true;
+}

+ 1 - 16
util/qemu-option.c

@@ -641,28 +641,13 @@ QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id)
     return NULL;
 }
 
-int qemu_opts_id_wellformed(const char *id)
-{
-    int i;
-
-    if (!qemu_isalpha(id[0])) {
-        return 0;
-    }
-    for (i = 1; id[i]; i++) {
-        if (!qemu_isalnum(id[i]) && !strchr("-._", id[i])) {
-            return 0;
-        }
-    }
-    return 1;
-}
-
 QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id,
                            int fail_if_exists, Error **errp)
 {
     QemuOpts *opts = NULL;
 
     if (id) {
-        if (!qemu_opts_id_wellformed(id)) {
+        if (!id_wellformed(id)) {
             error_set(errp,QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
 #if 0 /* conversion from qerror_report() to error_set() broke this: */
             error_printf_unless_qmp("Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.\n");

+ 17 - 1
vl.c

@@ -1169,6 +1169,7 @@ static void default_drive(int enable, int snapshot, BlockInterfaceType type,
                           int index, const char *optstr)
 {
     QemuOpts *opts;
+    DriveInfo *dinfo;
 
     if (!enable || drive_get_by_index(type, index)) {
         return;
@@ -1178,9 +1179,13 @@ static void default_drive(int enable, int snapshot, BlockInterfaceType type,
     if (snapshot) {
         drive_enable_snapshot(opts, NULL);
     }
-    if (!drive_new(opts, type)) {
+
+    dinfo = drive_new(opts, type);
+    if (!dinfo) {
         exit(1);
     }
+    dinfo->is_default = true;
+
 }
 
 void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque)
@@ -1580,6 +1585,7 @@ static void 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;
@@ -4370,6 +4376,13 @@ int main(int argc, char **argv, char **envp)
     blk_mig_init();
     ram_mig_init();
 
+    /* If the currently selected machine wishes to override the units-per-bus
+     * property of its default HBA interface type, do so now. */
+    if (machine_class->units_per_default_bus) {
+        override_max_devs(machine_class->block_default_type,
+                          machine_class->units_per_default_bus);
+    }
+
     /* open the virtual block devices */
     if (snapshot)
         qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, NULL, 0);
@@ -4457,6 +4470,9 @@ int main(int argc, char **argv, char **envp)
     if (qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, 1) != 0)
         exit(1);
 
+    /* Did we create any drives that we failed to create a device for? */
+    drive_check_orphaned();
+
     net_check_clients();
 
     ds = init_displaystate();