aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-02-02 18:04:04 +0000
committerPeter Maydell <peter.maydell@linaro.org>2016-02-02 18:04:04 +0000
commitc65db7705b7926f4a084b93778e4bd5dd3990aad (patch)
tree760ad7f08ecb9cd1f706c6f000df625a506f1483 /hw
parent3bb1e822ca7c8b48ac80cb7bd53af94c91c949e7 (diff)
parent8983b670f62ab5e5e8dd2690bf8304123651bfe5 (diff)
Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-for-peter-2016-02-02' into staging
Block patches # gpg: Signature made Tue 02 Feb 2016 17:23:44 GMT using RSA key ID E838ACAD # gpg: Good signature from "Max Reitz <mreitz@redhat.com>" * remotes/maxreitz/tags/pull-block-for-peter-2016-02-02: (50 commits) block: qemu-iotests - add test for snapshot, commit, snapshot bug block: set device_list.tqe_prev to NULL on BDS removal iotests: Add "qemu-img map" test for VMDK extents qemu-img: Make MapEntry a QAPI struct qemu-img: In "map", use the returned "file" from bdrv_get_block_status block: Use returned *file in bdrv_co_get_block_status vmdk: Return extent's file in bdrv_get_block_status vmdk: Fix calculation of block status's offset vpc: Assign bs->file->bs to file in vpc_co_get_block_status vdi: Assign bs->file->bs to file in vdi_co_get_block_status sheepdog: Assign bs to file in sd_co_get_block_status qed: Assign bs->file->bs to file in bdrv_qed_co_get_block_status parallels: Assign bs->file->bs to file in parallels_co_get_block_status iscsi: Assign bs to file in iscsi_co_get_block_status raw: Assign bs to file in raw_co_get_block_status qcow2: Assign bs->file->bs to file in qcow2_co_get_block_status qcow: Assign bs->file->bs to file in qcow_co_get_block_status block: Add "file" output parameter to block status query functions block: acquire in bdrv_query_image_info iotests: Add test for block jobs and BDS ejection ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/block/dataplane/virtio-blk.c77
-rw-r--r--hw/block/fdc.c23
-rw-r--r--hw/scsi/virtio-scsi.c55
3 files changed, 121 insertions, 34 deletions
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index bc34046fb5..ee0c4d4070 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -40,6 +40,8 @@ struct VirtIOBlockDataPlane {
EventNotifier *guest_notifier; /* irq */
QEMUBH *bh; /* bh for guest notification */
+ Notifier insert_notifier, remove_notifier;
+
/* Note that these EventNotifiers are assigned by value. This is
* fine as long as you do not call event_notifier_cleanup on them
* (because you don't own the file descriptor or handle; you just
@@ -137,6 +139,54 @@ static void handle_notify(EventNotifier *e)
blk_io_unplug(s->conf->conf.blk);
}
+static void data_plane_set_up_op_blockers(VirtIOBlockDataPlane *s)
+{
+ assert(!s->blocker);
+ error_setg(&s->blocker, "block device is in use by data plane");
+ blk_op_block_all(s->conf->conf.blk, s->blocker);
+ blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker);
+ blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
+ blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker);
+ blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_CHANGE, s->blocker);
+ blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_COMMIT_SOURCE, s->blocker);
+ blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_COMMIT_TARGET, s->blocker);
+ blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_EJECT, s->blocker);
+ blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
+ s->blocker);
+ blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT,
+ s->blocker);
+ blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
+ s->blocker);
+ blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_MIRROR_SOURCE, s->blocker);
+ blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker);
+ blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker);
+}
+
+static void data_plane_remove_op_blockers(VirtIOBlockDataPlane *s)
+{
+ if (s->blocker) {
+ blk_op_unblock_all(s->conf->conf.blk, s->blocker);
+ error_free(s->blocker);
+ s->blocker = NULL;
+ }
+}
+
+static void data_plane_blk_insert_notifier(Notifier *n, void *data)
+{
+ VirtIOBlockDataPlane *s = container_of(n, VirtIOBlockDataPlane,
+ insert_notifier);
+ assert(s->conf->conf.blk == data);
+ data_plane_set_up_op_blockers(s);
+}
+
+static void data_plane_blk_remove_notifier(Notifier *n, void *data)
+{
+ VirtIOBlockDataPlane *s = container_of(n, VirtIOBlockDataPlane,
+ remove_notifier);
+ assert(s->conf->conf.blk == data);
+ data_plane_remove_op_blockers(s);
+}
+
/* Context: QEMU global mutex held */
void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
VirtIOBlockDataPlane **dataplane,
@@ -179,22 +229,12 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
s->ctx = iothread_get_aio_context(s->iothread);
s->bh = aio_bh_new(s->ctx, notify_guest_bh, s);
- error_setg(&s->blocker, "block device is in use by data plane");
- blk_op_block_all(conf->conf.blk, s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_CHANGE, s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT_SOURCE, s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT_TARGET, s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EJECT, s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
- s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_MIRROR_SOURCE, s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker);
- blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker);
+ s->insert_notifier.notify = data_plane_blk_insert_notifier;
+ s->remove_notifier.notify = data_plane_blk_remove_notifier;
+ blk_add_insert_bs_notifier(conf->conf.blk, &s->insert_notifier);
+ blk_add_remove_bs_notifier(conf->conf.blk, &s->remove_notifier);
+
+ data_plane_set_up_op_blockers(s);
*dataplane = s;
}
@@ -207,8 +247,9 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
}
virtio_blk_data_plane_stop(s);
- blk_op_unblock_all(s->conf->conf.blk, s->blocker);
- error_free(s->blocker);
+ data_plane_remove_op_blockers(s);
+ notifier_remove(&s->insert_notifier);
+ notifier_remove(&s->remove_notifier);
qemu_bh_delete(s->bh);
object_unref(OBJECT(s->iothread));
g_free(s);
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
index e3b0e1e60c..818e8a4072 100644
--- a/hw/block/fdc.c
+++ b/hw/block/fdc.c
@@ -173,7 +173,6 @@ typedef struct FDrive {
uint8_t media_changed; /* Is media changed */
uint8_t media_rate; /* Data rate of medium */
- bool media_inserted; /* Is there a medium in the tray */
bool media_validated; /* Have we validated the media? */
} FDrive;
@@ -249,7 +248,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
#endif
drv->head = head;
if (drv->track != track) {
- if (drv->media_inserted) {
+ if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
drv->media_changed = 0;
}
ret = 1;
@@ -258,7 +257,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
drv->sect = sect;
}
- if (!drv->media_inserted) {
+ if (drv->blk == NULL || !blk_is_inserted(drv->blk)) {
ret = 2;
}
@@ -288,7 +287,9 @@ static int pick_geometry(FDrive *drv)
bool magic = drv->drive == FLOPPY_DRIVE_TYPE_AUTO;
/* We can only pick a geometry if we have a diskette. */
- if (!drv->media_inserted || drv->drive == FLOPPY_DRIVE_TYPE_NONE) {
+ if (!drv->blk || !blk_is_inserted(drv->blk) ||
+ drv->drive == FLOPPY_DRIVE_TYPE_NONE)
+ {
return -1;
}
@@ -390,7 +391,7 @@ static void fd_revalidate(FDrive *drv)
FLOPPY_DPRINTF("revalidate\n");
if (drv->blk != NULL) {
drv->ro = blk_is_read_only(drv->blk);
- if (!drv->media_inserted) {
+ if (!blk_is_inserted(drv->blk)) {
FLOPPY_DPRINTF("No disk in drive\n");
drv->disk = FLOPPY_DRIVE_TYPE_NONE;
} else if (!drv->media_validated) {
@@ -793,7 +794,7 @@ static bool fdrive_media_changed_needed(void *opaque)
{
FDrive *drive = opaque;
- return (drive->media_inserted && drive->media_changed != 1);
+ return (drive->blk != NULL && drive->media_changed != 1);
}
static const VMStateDescription vmstate_fdrive_media_changed = {
@@ -2285,22 +2286,13 @@ static void fdctrl_change_cb(void *opaque, bool load)
{
FDrive *drive = opaque;
- drive->media_inserted = load && drive->blk && blk_is_inserted(drive->blk);
-
drive->media_changed = 1;
drive->media_validated = false;
fd_revalidate(drive);
}
-static bool fdctrl_is_tray_open(void *opaque)
-{
- FDrive *drive = opaque;
- return !drive->media_inserted;
-}
-
static const BlockDevOps fdctrl_block_ops = {
.change_media_cb = fdctrl_change_cb,
- .is_tray_open = fdctrl_is_tray_open,
};
/* Init functions */
@@ -2327,7 +2319,6 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, Error **errp)
fd_init(drive);
if (drive->blk) {
blk_set_dev_ops(drive->blk, &fdctrl_block_ops, drive);
- drive->media_inserted = blk_is_inserted(drive->blk);
pick_drive_type(drive);
}
fd_revalidate(drive);
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 5f23ab2f60..1500c42728 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -758,6 +758,22 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
}
}
+static void virtio_scsi_blk_insert_notifier(Notifier *n, void *data)
+{
+ VirtIOSCSIBlkChangeNotifier *cn = DO_UPCAST(VirtIOSCSIBlkChangeNotifier,
+ n, n);
+ assert(cn->sd->conf.blk == data);
+ blk_op_block_all(cn->sd->conf.blk, cn->s->blocker);
+}
+
+static void virtio_scsi_blk_remove_notifier(Notifier *n, void *data)
+{
+ VirtIOSCSIBlkChangeNotifier *cn = DO_UPCAST(VirtIOSCSIBlkChangeNotifier,
+ n, n);
+ assert(cn->sd->conf.blk == data);
+ blk_op_unblock_all(cn->sd->conf.blk, cn->s->blocker);
+}
+
static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
@@ -766,6 +782,8 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
SCSIDevice *sd = SCSI_DEVICE(dev);
if (s->ctx && !s->dataplane_disabled) {
+ VirtIOSCSIBlkChangeNotifier *insert_notifier, *remove_notifier;
+
if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
return;
}
@@ -773,6 +791,20 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
aio_context_acquire(s->ctx);
blk_set_aio_context(sd->conf.blk, s->ctx);
aio_context_release(s->ctx);
+
+ insert_notifier = g_new0(VirtIOSCSIBlkChangeNotifier, 1);
+ insert_notifier->n.notify = virtio_scsi_blk_insert_notifier;
+ insert_notifier->s = s;
+ insert_notifier->sd = sd;
+ blk_add_insert_bs_notifier(sd->conf.blk, &insert_notifier->n);
+ QTAILQ_INSERT_TAIL(&s->insert_notifiers, insert_notifier, next);
+
+ remove_notifier = g_new0(VirtIOSCSIBlkChangeNotifier, 1);
+ remove_notifier->n.notify = virtio_scsi_blk_remove_notifier;
+ remove_notifier->s = s;
+ remove_notifier->sd = sd;
+ blk_add_remove_bs_notifier(sd->conf.blk, &remove_notifier->n);
+ QTAILQ_INSERT_TAIL(&s->remove_notifiers, remove_notifier, next);
}
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
@@ -788,6 +820,7 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
SCSIDevice *sd = SCSI_DEVICE(dev);
+ VirtIOSCSIBlkChangeNotifier *insert_notifier, *remove_notifier;
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
virtio_scsi_push_event(s, sd,
@@ -798,6 +831,25 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
if (s->ctx) {
blk_op_unblock_all(sd->conf.blk, s->blocker);
}
+
+ QTAILQ_FOREACH(insert_notifier, &s->insert_notifiers, next) {
+ if (insert_notifier->sd == sd) {
+ notifier_remove(&insert_notifier->n);
+ QTAILQ_REMOVE(&s->insert_notifiers, insert_notifier, next);
+ g_free(insert_notifier);
+ break;
+ }
+ }
+
+ QTAILQ_FOREACH(remove_notifier, &s->remove_notifiers, next) {
+ if (remove_notifier->sd == sd) {
+ notifier_remove(&remove_notifier->n);
+ QTAILQ_REMOVE(&s->remove_notifiers, remove_notifier, next);
+ g_free(remove_notifier);
+ break;
+ }
+ }
+
qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
}
@@ -912,6 +964,9 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
add_migration_state_change_notifier(&s->migration_state_notifier);
error_setg(&s->blocker, "block device is in use by data plane");
+
+ QTAILQ_INIT(&s->insert_notifiers);
+ QTAILQ_INIT(&s->remove_notifiers);
}
static void virtio_scsi_instance_init(Object *obj)