From: Markus Armbruster <armbru@redhat.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com, kraxel@redhat.com, hch@lst.de
Subject: [Qemu-devel] [PATCH 08/12] block: Catch attempt to attach multiple devices to a blockdev
Date: Fri, 25 Jun 2010 18:53:28 +0200 [thread overview]
Message-ID: <1277484812-22012-9-git-send-email-armbru@redhat.com> (raw)
In-Reply-To: <1277484812-22012-1-git-send-email-armbru@redhat.com>
For instance, -device scsi-disk,drive=foo -device scsi-disk,drive=foo
happily creates two SCSI disks connected to the same block device.
It's all downhill from there.
Device usb-storage deliberately attaches twice to the same blockdev,
which fails with the fix in place. Detach before the second attach
there.
Also catch attempt to delete while a guest device model is attached.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
block.c | 22 ++++++++++++++++++++++
block.h | 3 +++
block_int.h | 2 ++
hw/fdc.c | 10 +++++-----
hw/ide/qdev.c | 2 +-
hw/pci-hotplug.c | 5 ++++-
hw/qdev-properties.c | 21 ++++++++++++++++++++-
hw/qdev.h | 3 ++-
hw/s390-virtio.c | 2 +-
hw/scsi-bus.c | 4 +++-
hw/usb-msd.c | 11 +++++++----
11 files changed, 70 insertions(+), 15 deletions(-)
diff --git a/block.c b/block.c
index e71a771..5e0ffa0 100644
--- a/block.c
+++ b/block.c
@@ -659,6 +659,8 @@ void bdrv_close_all(void)
void bdrv_delete(BlockDriverState *bs)
{
+ assert(!bs->peer);
+
/* remove from list, if necessary */
if (bs->device_name[0] != '\0') {
QTAILQ_REMOVE(&bdrv_states, bs, list);
@@ -672,6 +674,26 @@ void bdrv_delete(BlockDriverState *bs)
qemu_free(bs);
}
+int bdrv_attach(BlockDriverState *bs, DeviceState *qdev)
+{
+ if (bs->peer) {
+ return -EBUSY;
+ }
+ bs->peer = qdev;
+ return 0;
+}
+
+void bdrv_detach(BlockDriverState *bs, DeviceState *qdev)
+{
+ assert(bs->peer == qdev);
+ bs->peer = NULL;
+}
+
+DeviceState *bdrv_get_attached(BlockDriverState *bs)
+{
+ return bs->peer;
+}
+
/*
* Run consistency checks on an image
*
diff --git a/block.h b/block.h
index 6a157f4..88ac06e 100644
--- a/block.h
+++ b/block.h
@@ -71,6 +71,9 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
BlockDriver *drv);
void bdrv_close(BlockDriverState *bs);
+int bdrv_attach(BlockDriverState *bs, DeviceState *qdev);
+void bdrv_detach(BlockDriverState *bs, DeviceState *qdev);
+DeviceState *bdrv_get_attached(BlockDriverState *bs);
int bdrv_check(BlockDriverState *bs);
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
diff --git a/block_int.h b/block_int.h
index e60aed4..a94b801 100644
--- a/block_int.h
+++ b/block_int.h
@@ -148,6 +148,8 @@ struct BlockDriverState {
BlockDriver *drv; /* NULL means no media */
void *opaque;
+ DeviceState *peer;
+
char filename[1024];
char backing_file[1024]; /* if non zero, the image is a diff of
this file image */
diff --git a/hw/fdc.c b/hw/fdc.c
index 08712bc..1496cfa 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1860,10 +1860,10 @@ FDCtrl *fdctrl_init_isa(DriveInfo **fds)
dev = isa_create("isa-fdc");
if (fds[0]) {
- qdev_prop_set_drive(&dev->qdev, "driveA", fds[0]->bdrv);
+ qdev_prop_set_drive_nofail(&dev->qdev, "driveA", fds[0]->bdrv);
}
if (fds[1]) {
- qdev_prop_set_drive(&dev->qdev, "driveB", fds[1]->bdrv);
+ qdev_prop_set_drive_nofail(&dev->qdev, "driveB", fds[1]->bdrv);
}
if (qdev_init(&dev->qdev) < 0)
return NULL;
@@ -1882,10 +1882,10 @@ FDCtrl *fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
fdctrl = &sys->state;
fdctrl->dma_chann = dma_chann; /* FIXME */
if (fds[0]) {
- qdev_prop_set_drive(dev, "driveA", fds[0]->bdrv);
+ qdev_prop_set_drive_nofail(dev, "driveA", fds[0]->bdrv);
}
if (fds[1]) {
- qdev_prop_set_drive(dev, "driveB", fds[1]->bdrv);
+ qdev_prop_set_drive_nofail(dev, "driveB", fds[1]->bdrv);
}
qdev_init_nofail(dev);
sysbus_connect_irq(&sys->busdev, 0, irq);
@@ -1903,7 +1903,7 @@ FDCtrl *sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
dev = qdev_create(NULL, "SUNW,fdtwo");
if (fds[0]) {
- qdev_prop_set_drive(dev, "drive", fds[0]->bdrv);
+ qdev_prop_set_drive_nofail(dev, "drive", fds[0]->bdrv);
}
qdev_init_nofail(dev);
sys = DO_UPCAST(FDCtrlSysBus, busdev.qdev, dev);
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 3bb94c6..b4bc5ac 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -83,7 +83,7 @@ IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
dev = qdev_create(&bus->qbus, "ide-drive");
qdev_prop_set_uint32(dev, "unit", unit);
- qdev_prop_set_drive(dev, "drive", drive->bdrv);
+ qdev_prop_set_drive_nofail(dev, "drive", drive->bdrv);
qdev_init_nofail(dev);
return DO_UPCAST(IDEDevice, qdev, dev);
}
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index d743192..b47e01e 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -214,7 +214,10 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
return NULL;
}
dev = pci_create(bus, devfn, "virtio-blk-pci");
- qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv);
+ if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) {
+ dev = NULL;
+ break;
+ }
if (qdev_init(&dev->qdev) < 0)
dev = NULL;
break;
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 257233e..caf6798 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -291,6 +291,8 @@ static int parse_drive(DeviceState *dev, Property *prop, const char *str)
bs = bdrv_find(str);
if (bs == NULL)
return -ENOENT;
+ if (bdrv_attach(bs, dev) < 0)
+ return -EEXIST;
*ptr = bs;
return 0;
}
@@ -300,6 +302,7 @@ static void free_drive(DeviceState *dev, Property *prop)
BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop);
if (*ptr) {
+ bdrv_detach(*ptr, dev);
blockdev_auto_del(*ptr);
}
}
@@ -640,11 +643,27 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, char *value)
qdev_prop_set(dev, name, &value, PROP_TYPE_STRING);
}
-void qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value)
+int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value)
{
+ int res;
+
qdev_prop_set(dev, name, &value, PROP_TYPE_DRIVE);
+ res = bdrv_attach(value, dev);
+ if (res < 0) {
+ error_report("Can't attach drive %s to %s.%s: %s",
+ bdrv_get_device_name(value),
+ dev->id ? dev->id : dev->info->name,
+ name, strerror(-res));
+ }
+ return res;
}
+void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value)
+{
+ if (qdev_prop_set_drive(dev, name, value) < 0) {
+ exit(1);
+ }
+}
void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value)
{
qdev_prop_set(dev, name, &value, PROP_TYPE_CHR);
diff --git a/hw/qdev.h b/hw/qdev.h
index 7a01a81..cbc89f2 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -275,7 +275,8 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, char *value);
void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value);
void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value);
void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value);
-void qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value);
+int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT;
+void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value);
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value);
/* FIXME: Remove opaque pointer properties. */
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
index c7c3fc9..6af58e2 100644
--- a/hw/s390-virtio.c
+++ b/hw/s390-virtio.c
@@ -262,7 +262,7 @@ static void s390_init(ram_addr_t ram_size,
}
dev = qdev_create((BusState *)s390_bus, "virtio-blk-s390");
- qdev_prop_set_drive(dev, "drive", dinfo->bdrv);
+ qdev_prop_set_drive_nofail(dev, "drive", dinfo->bdrv);
qdev_init_nofail(dev);
}
}
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 2c58aca..9678328 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -91,7 +91,9 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, int
driver = bdrv_is_sg(bdrv) ? "scsi-generic" : "scsi-disk";
dev = qdev_create(&bus->qbus, driver);
qdev_prop_set_uint32(dev, "scsi-id", unit);
- qdev_prop_set_drive(dev, "drive", bdrv);
+ if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) {
+ return NULL;
+ }
if (qdev_init(dev) < 0)
return NULL;
return DO_UPCAST(SCSIDevice, qdev, dev);
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 19a14b4..008cc0f 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -532,12 +532,13 @@ static int usb_msd_initfn(USBDevice *dev)
/*
* Hack alert: this pretends to be a block device, but it's really
* a SCSI bus that can serve only a single device, which it
- * creates automatically. Two drive properties pointing to the
- * same drive is not good: free_drive() dies for the second one.
- * Zap the one we're not going to use.
+ * creates automatically. But first it needs to detach from its
+ * blockdev, or else scsi_bus_legacy_add_drive() dies when it
+ * attaches again.
*
* The hack is probably a bad idea.
*/
+ bdrv_detach(bs, &s->dev.qdev);
s->conf.bs = NULL;
s->dev.speed = USB_SPEED_FULL;
@@ -609,7 +610,9 @@ static USBDevice *usb_msd_init(const char *filename)
if (!dev) {
return NULL;
}
- qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv);
+ if (qdev_prop_set_drive(&dev->qdev, "drive", dinfo->bdrv) < 0) {
+ return NULL;
+ }
if (qdev_init(&dev->qdev) < 0)
return NULL;
--
1.6.6.1
next prev parent reply other threads:[~2010-06-25 17:42 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-06-25 16:53 [Qemu-devel] [PATCH 00/12] More block-related fixes and cleanups Markus Armbruster
2010-06-25 16:53 ` [Qemu-devel] [PATCH 01/12] scsi: scsi_bus_legacy_handle_cmdline() can fail, fix callers Markus Armbruster
2010-06-25 19:39 ` [Qemu-devel] " Christoph Hellwig
2010-06-25 16:53 ` [Qemu-devel] [PATCH 02/12] ide: Make it explicit that ide_create_drive() can't fail Markus Armbruster
2010-06-25 19:40 ` [Qemu-devel] " Christoph Hellwig
2010-06-25 16:53 ` [Qemu-devel] [PATCH 03/12] blockdev: Remove drive_get_serial() Markus Armbruster
2010-06-25 19:41 ` [Qemu-devel] " Christoph Hellwig
2010-06-25 16:53 ` [Qemu-devel] [PATCH 04/12] blockdev: New drive_of_blockdev() Markus Armbruster
2010-06-25 19:42 ` [Qemu-devel] " Christoph Hellwig
2010-06-26 5:32 ` Markus Armbruster
2010-06-26 9:46 ` Christoph Hellwig
2010-06-26 14:46 ` Markus Armbruster
2010-06-27 9:36 ` Christoph Hellwig
2010-06-28 9:58 ` Paolo Bonzini
2010-06-29 8:57 ` Markus Armbruster
2010-06-25 16:53 ` [Qemu-devel] [PATCH 05/12] blockdev: Clean up automatic drive deletion Markus Armbruster
2010-06-26 9:48 ` [Qemu-devel] " Christoph Hellwig
2010-06-25 16:53 ` [Qemu-devel] [PATCH 06/12] qdev: Decouple qdev_prop_drive from DriveInfo Markus Armbruster
2010-06-26 10:09 ` [Qemu-devel] " Christoph Hellwig
2010-06-25 16:53 ` [Qemu-devel] [PATCH 07/12] blockdev: drive_get_by_id() is no longer used, remove Markus Armbruster
2010-06-26 10:09 ` [Qemu-devel] " Christoph Hellwig
2010-06-25 16:53 ` Markus Armbruster [this message]
2010-06-26 10:11 ` [Qemu-devel] Re: [PATCH 08/12] block: Catch attempt to attach multiple devices to a blockdev Christoph Hellwig
2010-06-26 14:44 ` Markus Armbruster
2010-06-27 9:36 ` Christoph Hellwig
2010-06-28 8:24 ` Kevin Wolf
2010-06-28 10:16 ` Christoph Hellwig
2010-06-28 10:26 ` Kevin Wolf
2010-06-30 11:52 ` Markus Armbruster
2010-06-30 12:13 ` Kevin Wolf
2010-06-29 8:06 ` Gerd Hoffmann
2010-06-30 11:33 ` Markus Armbruster
2010-06-29 13:32 ` Kevin Wolf
2010-06-29 14:29 ` Markus Armbruster
2010-06-29 14:58 ` [Qemu-devel] [PATCH v2 " Markus Armbruster
2010-06-25 16:53 ` [Qemu-devel] [PATCH 09/12] savevm: Survive hot-unplug of snapshot device Markus Armbruster
2010-06-26 10:12 ` [Qemu-devel] " Christoph Hellwig
2010-06-30 11:28 ` Markus Armbruster
2010-06-30 13:37 ` Kevin Wolf
2010-06-30 16:34 ` Markus Armbruster
2010-06-25 16:53 ` [Qemu-devel] [PATCH 10/12] block: Fix virtual media change for if=none Markus Armbruster
2010-06-26 10:14 ` [Qemu-devel] " Christoph Hellwig
2010-06-25 16:53 ` [Qemu-devel] [PATCH 11/12] ide: Make PIIX and ISA IDE init functions return the qdev Markus Armbruster
2010-06-26 10:14 ` [Qemu-devel] " Christoph Hellwig
2010-06-25 16:53 ` [Qemu-devel] [PATCH 12/12] pc: Fix CMOS info for drives defined with -device Markus Armbruster
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1277484812-22012-9-git-send-email-armbru@redhat.com \
--to=armbru@redhat.com \
--cc=hch@lst.de \
--cc=kraxel@redhat.com \
--cc=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.