aboutsummaryrefslogtreecommitdiff
path: root/block/block-backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/block-backend.c')
-rw-r--r--block/block-backend.c151
1 files changed, 140 insertions, 11 deletions
diff --git a/block/block-backend.c b/block/block-backend.c
index ae30873df1..bdcbac674a 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -13,6 +13,10 @@
#include "sysemu/block-backend.h"
#include "block/block_int.h"
#include "sysemu/blockdev.h"
+#include "qapi-event.h"
+
+/* Number of coroutines to reserve per attached device model */
+#define COROUTINE_POOL_RESERVATION 64
struct BlockBackend {
char *name;
@@ -20,6 +24,11 @@ struct BlockBackend {
BlockDriverState *bs;
DriveInfo *legacy_dinfo; /* null unless created by drive_new() */
QTAILQ_ENTRY(BlockBackend) link; /* for blk_backends */
+
+ void *dev; /* attached device model, if any */
+ /* TODO change to DeviceState when all users are qdevified */
+ const BlockDevOps *dev_ops;
+ void *dev_opaque;
};
static void drive_info_del(DriveInfo *dinfo);
@@ -85,6 +94,7 @@ BlockBackend *blk_new_with_bs(const char *name, Error **errp)
static void blk_delete(BlockBackend *blk)
{
assert(!blk->refcnt);
+ assert(!blk->dev);
if (blk->bs) {
assert(blk->bs->blk == blk);
blk->bs->blk = NULL;
@@ -237,34 +247,153 @@ void blk_hide_on_behalf_of_do_drive_del(BlockBackend *blk)
}
}
-void blk_iostatus_enable(BlockBackend *blk)
-{
- bdrv_iostatus_enable(blk->bs);
-}
-
+/*
+ * Attach device model @dev to @blk.
+ * Return 0 on success, -EBUSY when a device model is attached already.
+ */
int blk_attach_dev(BlockBackend *blk, void *dev)
+/* TODO change to DeviceState *dev when all users are qdevified */
{
- return bdrv_attach_dev(blk->bs, dev);
+ if (blk->dev) {
+ return -EBUSY;
+ }
+ blk->dev = dev;
+ bdrv_iostatus_reset(blk->bs);
+
+ /* We're expecting I/O from the device so bump up coroutine pool size */
+ qemu_coroutine_adjust_pool_size(COROUTINE_POOL_RESERVATION);
+ return 0;
}
+/*
+ * Attach device model @dev to @blk.
+ * @blk must not have a device model attached already.
+ * TODO qdevified devices don't use this, remove when devices are qdevified
+ */
void blk_attach_dev_nofail(BlockBackend *blk, void *dev)
{
- bdrv_attach_dev_nofail(blk->bs, dev);
+ if (blk_attach_dev(blk, dev) < 0) {
+ abort();
+ }
}
+/*
+ * Detach device model @dev from @blk.
+ * @dev must be currently attached to @blk.
+ */
void blk_detach_dev(BlockBackend *blk, void *dev)
+/* TODO change to DeviceState *dev when all users are qdevified */
{
- bdrv_detach_dev(blk->bs, dev);
+ assert(blk->dev == dev);
+ blk->dev = NULL;
+ blk->dev_ops = NULL;
+ blk->dev_opaque = NULL;
+ bdrv_set_guest_block_size(blk->bs, 512);
+ qemu_coroutine_adjust_pool_size(-COROUTINE_POOL_RESERVATION);
}
+/*
+ * Return the device model attached to @blk if any, else null.
+ */
void *blk_get_attached_dev(BlockBackend *blk)
+/* TODO change to return DeviceState * when all users are qdevified */
+{
+ return blk->dev;
+}
+
+/*
+ * Set @blk's device model callbacks to @ops.
+ * @opaque is the opaque argument to pass to the callbacks.
+ * This is for use by device models.
+ */
+void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
+ void *opaque)
{
- return bdrv_get_attached_dev(blk->bs);
+ blk->dev_ops = ops;
+ blk->dev_opaque = opaque;
}
-void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque)
+/*
+ * Notify @blk's attached device model of media change.
+ * If @load is true, notify of media load.
+ * Else, notify of media eject.
+ * Also send DEVICE_TRAY_MOVED events as appropriate.
+ */
+void blk_dev_change_media_cb(BlockBackend *blk, bool load)
{
- bdrv_set_dev_ops(blk->bs, ops, opaque);
+ if (blk->dev_ops && blk->dev_ops->change_media_cb) {
+ bool tray_was_closed = !blk_dev_is_tray_open(blk);
+
+ blk->dev_ops->change_media_cb(blk->dev_opaque, load);
+ if (tray_was_closed) {
+ /* tray open */
+ qapi_event_send_device_tray_moved(blk_name(blk),
+ true, &error_abort);
+ }
+ if (load) {
+ /* tray close */
+ qapi_event_send_device_tray_moved(blk_name(blk),
+ false, &error_abort);
+ }
+ }
+}
+
+/*
+ * Does @blk's attached device model have removable media?
+ * %true if no device model is attached.
+ */
+bool blk_dev_has_removable_media(BlockBackend *blk)
+{
+ return !blk->dev || (blk->dev_ops && blk->dev_ops->change_media_cb);
+}
+
+/*
+ * Notify @blk's attached device model of a media eject request.
+ * If @force is true, the medium is about to be yanked out forcefully.
+ */
+void blk_dev_eject_request(BlockBackend *blk, bool force)
+{
+ if (blk->dev_ops && blk->dev_ops->eject_request_cb) {
+ blk->dev_ops->eject_request_cb(blk->dev_opaque, force);
+ }
+}
+
+/*
+ * Does @blk's attached device model have a tray, and is it open?
+ */
+bool blk_dev_is_tray_open(BlockBackend *blk)
+{
+ if (blk->dev_ops && blk->dev_ops->is_tray_open) {
+ return blk->dev_ops->is_tray_open(blk->dev_opaque);
+ }
+ return false;
+}
+
+/*
+ * Does @blk's attached device model have the medium locked?
+ * %false if the device model has no such lock.
+ */
+bool blk_dev_is_medium_locked(BlockBackend *blk)
+{
+ if (blk->dev_ops && blk->dev_ops->is_medium_locked) {
+ return blk->dev_ops->is_medium_locked(blk->dev_opaque);
+ }
+ return false;
+}
+
+/*
+ * Notify @blk's attached device model of a backend size change.
+ */
+void blk_dev_resize_cb(BlockBackend *blk)
+{
+ if (blk->dev_ops && blk->dev_ops->resize_cb) {
+ blk->dev_ops->resize_cb(blk->dev_opaque);
+ }
+}
+
+void blk_iostatus_enable(BlockBackend *blk)
+{
+ bdrv_iostatus_enable(blk->bs);
}
int blk_read(BlockBackend *blk, int64_t sector_num, uint8_t *buf,