diff mbox

[v3,22/23] block: Lift device model API into BlockBackend

Message ID 1410891148-28849-23-git-send-email-armbru@redhat.com
State New
Headers show

Commit Message

Markus Armbruster Sept. 16, 2014, 6:12 p.m. UTC
Move device model attachment / detachment and the BlockDevOps device
model callbacks and their wrappers from BlockDriverState to
BlockBackend.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 block.c                        | 126 ++++------------------------------
 block/block-backend.c          | 151 ++++++++++++++++++++++++++++++++++++++---
 block/qapi.c                   |   8 +--
 blockdev.c                     |   8 +--
 include/block/block.h          |  45 ------------
 include/block/block_int.h      |  12 ++--
 include/sysemu/block-backend.h |  35 ++++++++++
 7 files changed, 203 insertions(+), 182 deletions(-)

Comments

Benoît Canet Sept. 22, 2014, 12:13 p.m. UTC | #1
On Tue, Sep 16, 2014 at 08:12:27PM +0200, Markus Armbruster wrote:
> Move device model attachment / detachment and the BlockDevOps device
> model callbacks and their wrappers from BlockDriverState to
> BlockBackend.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  block.c                        | 126 ++++------------------------------
>  block/block-backend.c          | 151 ++++++++++++++++++++++++++++++++++++++---
>  block/qapi.c                   |   8 +--
>  blockdev.c                     |   8 +--
>  include/block/block.h          |  45 ------------
>  include/block/block_int.h      |  12 ++--
>  include/sysemu/block-backend.h |  35 ++++++++++
>  7 files changed, 203 insertions(+), 182 deletions(-)
> 
> diff --git a/block.c b/block.c
> index 1d9a680..fac1211 100644
> --- a/block.c
> +++ b/block.c
> @@ -58,9 +58,6 @@ struct BdrvDirtyBitmap {
>  
>  #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
>  
> -#define COROUTINE_POOL_RESERVATION 64 /* number of coroutines to reserve */
> -
> -static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
>  static BlockAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
>          int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
>          BlockCompletionFunc *cb, void *opaque);
> @@ -1527,7 +1524,9 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
>      }
>  
>      if (!bdrv_key_required(bs)) {
> -        bdrv_dev_change_media_cb(bs, true);
> +        if (bs->blk) {
> +            blk_dev_change_media_cb(bs->blk, true);
> +        }
>      } else if (!runstate_check(RUN_STATE_PRELAUNCH)
>                 && !runstate_check(RUN_STATE_INMIGRATE)
>                 && !runstate_check(RUN_STATE_PAUSED)) { /* HACK */
> @@ -1852,7 +1851,9 @@ void bdrv_close(BlockDriverState *bs)
>          }
>      }
>  
> -    bdrv_dev_change_media_cb(bs, false);
> +    if (bs->blk) {
> +        blk_dev_change_media_cb(bs->blk, false);
> +    }
>  
>      /*throttling disk I/O limits*/
>      if (bs->io_limits_enabled) {
> @@ -1971,9 +1972,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
>      /* move some fields that need to stay attached to the device */
>  
>      /* dev info */
> -    bs_dest->dev_ops            = bs_src->dev_ops;
> -    bs_dest->dev_opaque         = bs_src->dev_opaque;
> -    bs_dest->dev                = bs_src->dev;
>      bs_dest->guest_block_size   = bs_src->guest_block_size;
>      bs_dest->copy_on_read       = bs_src->copy_on_read;
>  
> @@ -2041,7 +2039,6 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
>      assert(!bs_new->blk);
>      assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
>      assert(bs_new->job == NULL);
> -    assert(bs_new->dev == NULL);
>      assert(bs_new->io_limits_enabled == false);
>      assert(!throttle_have_timer(&bs_new->throttle_state));
>  
> @@ -2058,7 +2055,6 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
>      assert(!bs_new->blk);
>  
>      /* Check a few fields that should remain attached to the device */
> -    assert(bs_new->dev == NULL);
>      assert(bs_new->job == NULL);
>      assert(bs_new->io_limits_enabled == false);
>      assert(!throttle_have_timer(&bs_new->throttle_state));
> @@ -2097,7 +2093,6 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
>  
>  static void bdrv_delete(BlockDriverState *bs)
>  {
> -    assert(!bs->dev);
>      assert(!bs->job);
>      assert(bdrv_op_blocker_is_empty(bs));
>      assert(!bs->refcnt);
> @@ -2111,105 +2106,6 @@ static void bdrv_delete(BlockDriverState *bs)
>      g_free(bs);
>  }
>  
> -int bdrv_attach_dev(BlockDriverState *bs, void *dev)
> -/* TODO change to DeviceState *dev when all users are qdevified */
> -{
> -    if (bs->dev) {
> -        return -EBUSY;
> -    }
> -    bs->dev = dev;
> -    bdrv_iostatus_reset(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;
> -}
> -
> -/* TODO qdevified devices don't use this, remove when devices are qdevified */
> -void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev)
> -{
> -    if (bdrv_attach_dev(bs, dev) < 0) {
> -        abort();
> -    }
> -}
> -
> -void bdrv_detach_dev(BlockDriverState *bs, void *dev)
> -/* TODO change to DeviceState *dev when all users are qdevified */
> -{
> -    assert(bs->dev == dev);
> -    bs->dev = NULL;
> -    bs->dev_ops = NULL;
> -    bs->dev_opaque = NULL;
> -    bs->guest_block_size = 512;
> -    qemu_coroutine_adjust_pool_size(-COROUTINE_POOL_RESERVATION);
> -}
> -
> -/* TODO change to return DeviceState * when all users are qdevified */
> -void *bdrv_get_attached_dev(BlockDriverState *bs)
> -{
> -    return bs->dev;
> -}
> -
> -void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
> -                      void *opaque)
> -{
> -    bs->dev_ops = ops;
> -    bs->dev_opaque = opaque;
> -}
> -
> -static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load)
> -{
> -    if (bs->dev_ops && bs->dev_ops->change_media_cb) {
> -        bool tray_was_closed = !bdrv_dev_is_tray_open(bs);
> -        bs->dev_ops->change_media_cb(bs->dev_opaque, load);
> -        if (tray_was_closed) {
> -            /* tray open */
> -            qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
> -                                              true, &error_abort);
> -        }
> -        if (load) {
> -            /* tray close */
> -            qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
> -                                              false, &error_abort);
> -        }
> -    }
> -}
> -
> -bool bdrv_dev_has_removable_media(BlockDriverState *bs)
> -{
> -    return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
> -}
> -
> -void bdrv_dev_eject_request(BlockDriverState *bs, bool force)
> -{
> -    if (bs->dev_ops && bs->dev_ops->eject_request_cb) {
> -        bs->dev_ops->eject_request_cb(bs->dev_opaque, force);
> -    }
> -}
> -
> -bool bdrv_dev_is_tray_open(BlockDriverState *bs)
> -{
> -    if (bs->dev_ops && bs->dev_ops->is_tray_open) {
> -        return bs->dev_ops->is_tray_open(bs->dev_opaque);
> -    }
> -    return false;
> -}
> -
> -static void bdrv_dev_resize_cb(BlockDriverState *bs)
> -{
> -    if (bs->dev_ops && bs->dev_ops->resize_cb) {
> -        bs->dev_ops->resize_cb(bs->dev_opaque);
> -    }
> -}
> -
> -bool bdrv_dev_is_medium_locked(BlockDriverState *bs)
> -{
> -    if (bs->dev_ops && bs->dev_ops->is_medium_locked) {
> -        return bs->dev_ops->is_medium_locked(bs->dev_opaque);
> -    }
> -    return false;
> -}
> -
>  /*
>   * Run consistency checks on an image
>   *
> @@ -3543,7 +3439,9 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
>      ret = drv->bdrv_truncate(bs, offset);
>      if (ret == 0) {
>          ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
> -        bdrv_dev_resize_cb(bs);
> +        if (bs->blk) {
> +            blk_dev_resize_cb(bs->blk);
> +        }
>      }
>      return ret;
>  }
> @@ -3744,8 +3642,10 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
>          bs->valid_key = 0;
>      } else if (!bs->valid_key) {
>          bs->valid_key = 1;
> -        /* call the change callback now, we skipped it on open */
> -        bdrv_dev_change_media_cb(bs, true);
> +        if (bs->blk) {
> +            /* call the change callback now, we skipped it on open */
> +            blk_dev_change_media_cb(bs->blk, true);
> +        }
>      }
>      return ret;
>  }
> diff --git a/block/block-backend.c b/block/block-backend.c
> index b55f0b4..d49c988 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;
>      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);
> @@ -81,6 +90,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;
> @@ -233,34 +243,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 bdrv_get_attached_dev(blk->bs);
> +    return blk->dev;
>  }
>  
> -void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque)
> +/*
> + * 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)
>  {
> -    bdrv_set_dev_ops(blk->bs, ops, opaque);
> +    blk->dev_ops = ops;
> +    blk->dev_opaque = 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)
> +{
> +    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,
> diff --git a/block/qapi.c b/block/qapi.c
> index fca981d..1301144 100644
> --- a/block/qapi.c
> +++ b/block/qapi.c
> @@ -275,12 +275,12 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
>      Error *local_err = NULL;
>      info->device = g_strdup(blk_name(blk));
>      info->type = g_strdup("unknown");
> -    info->locked = bdrv_dev_is_medium_locked(bs);
> -    info->removable = bdrv_dev_has_removable_media(bs);
> +    info->locked = blk_dev_is_medium_locked(blk);
> +    info->removable = blk_dev_has_removable_media(blk);
>  
> -    if (bdrv_dev_has_removable_media(bs)) {
> +    if (blk_dev_has_removable_media(blk)) {
>          info->has_tray_open = true;
> -        info->tray_open = bdrv_dev_is_tray_open(bs);
> +        info->tray_open = blk_dev_is_tray_open(blk);
>      }
>  
>      if (bdrv_iostatus_is_enabled(bs)) {
> diff --git a/blockdev.c b/blockdev.c
> index e115bde..d3dccb9 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -1509,14 +1509,14 @@ static void eject_device(BlockBackend *blk, int force, Error **errp)
>      if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
>          return;
>      }
> -    if (!bdrv_dev_has_removable_media(bs)) {
> +    if (!blk_dev_has_removable_media(blk)) {
>          error_setg(errp, "Device '%s' is not removable",
>                     bdrv_get_device_name(bs));
>          return;
>      }
>  
> -    if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
> -        bdrv_dev_eject_request(bs, force);
> +    if (blk_dev_is_medium_locked(blk) && !blk_dev_is_tray_open(blk)) {
> +        blk_dev_eject_request(blk, force);
>          if (!force) {
>              error_setg(errp, "Device '%s' is locked",
>                         bdrv_get_device_name(bs));
> @@ -1753,7 +1753,7 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
>       * can be removed.  If this is a drive with no device backing
>       * then we can just get rid of the block driver state right here.
>       */
> -    if (bdrv_get_attached_dev(bs)) {
> +    if (blk_get_attached_dev(blk)) {
>          blk_hide_on_behalf_of_do_drive_del(blk);
>          /* Further I/O must not pause the guest */
>          bdrv_set_on_error(bs, BLOCKDEV_ON_ERROR_REPORT,
> diff --git a/include/block/block.h b/include/block/block.h
> index 5b45743..bc9ec50 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -48,41 +48,6 @@ typedef struct BlockFragInfo {
>      uint64_t compressed_clusters;
>  } BlockFragInfo;
>  
> -/* Callbacks for block device models */
> -typedef struct BlockDevOps {
> -    /*
> -     * Runs when virtual media changed (monitor commands eject, change)
> -     * Argument load is true on load and false on eject.
> -     * Beware: doesn't run when a host device's physical media
> -     * changes.  Sure would be useful if it did.
> -     * Device models with removable media must implement this callback.
> -     */
> -    void (*change_media_cb)(void *opaque, bool load);
> -    /*
> -     * Runs when an eject request is issued from the monitor, the tray
> -     * is closed, and the medium is locked.
> -     * Device models that do not implement is_medium_locked will not need
> -     * this callback.  Device models that can lock the medium or tray might
> -     * want to implement the callback and unlock the tray when "force" is
> -     * true, even if they do not support eject requests.
> -     */
> -    void (*eject_request_cb)(void *opaque, bool force);
> -    /*
> -     * Is the virtual tray open?
> -     * Device models implement this only when the device has a tray.
> -     */
> -    bool (*is_tray_open)(void *opaque);
> -    /*
> -     * Is the virtual medium locked into the device?
> -     * Device models implement this only when device has such a lock.
> -     */
> -    bool (*is_medium_locked)(void *opaque);
> -    /*
> -     * Runs when the size changed (e.g. monitor command block_resize)
> -     */
> -    void (*resize_cb)(void *opaque);
> -} BlockDevOps;
> -
>  typedef enum {
>      BDRV_REQ_COPY_ON_READ = 0x1,
>      BDRV_REQ_ZERO_WRITE   = 0x2,
> @@ -230,16 +195,6 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state);
>  void bdrv_reopen_abort(BDRVReopenState *reopen_state);
>  void bdrv_close(BlockDriverState *bs);
>  void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify);
> -int bdrv_attach_dev(BlockDriverState *bs, void *dev);
> -void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev);
> -void bdrv_detach_dev(BlockDriverState *bs, void *dev);
> -void *bdrv_get_attached_dev(BlockDriverState *bs);
> -void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
> -                      void *opaque);
> -void bdrv_dev_eject_request(BlockDriverState *bs, bool force);
> -bool bdrv_dev_has_removable_media(BlockDriverState *bs);
> -bool bdrv_dev_is_tray_open(BlockDriverState *bs);
> -bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
>  int bdrv_read(BlockDriverState *bs, int64_t sector_num,
>                uint8_t *buf, int nb_sectors);
>  int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num,
> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index e8e33a8..8898c6c 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -326,11 +326,6 @@ struct BlockDriverState {
>  
>      BlockBackend *blk;          /* owning backend, if any */
>  
> -    void *dev;                  /* attached device model, if any */
> -    /* TODO change to DeviceState when all users are qdevified */
> -    const BlockDevOps *dev_ops;
> -    void *dev_opaque;
> -
>      AioContext *aio_context; /* event loop used for fd handlers, timers, etc */
>      /* long-running tasks intended to always use the same AioContext as this
>       * BDS may register themselves in this list to be notified of changes
> @@ -587,4 +582,11 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
>                    BlockCompletionFunc *cb, void *opaque,
>                    Error **errp);
>  
> +void blk_dev_change_media_cb(BlockBackend *blk, bool load);
> +bool blk_dev_has_removable_media(BlockBackend *blk);
> +void blk_dev_eject_request(BlockBackend *blk, bool force);
> +bool blk_dev_is_tray_open(BlockBackend *blk);
> +bool blk_dev_is_medium_locked(BlockBackend *blk);
> +void blk_dev_resize_cb(BlockBackend *blk);
> +
>  #endif /* BLOCK_INT_H */
> diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
> index e4bfea5..02305a1 100644
> --- a/include/sysemu/block-backend.h
> +++ b/include/sysemu/block-backend.h
> @@ -25,6 +25,41 @@
>   */
>  #include "block/block.h"
>  
> +/* Callbacks for block device models */
> +typedef struct BlockDevOps {
> +    /*
> +     * Runs when virtual media changed (monitor commands eject, change)
> +     * Argument load is true on load and false on eject.
> +     * Beware: doesn't run when a host device's physical media
> +     * changes.  Sure would be useful if it did.
> +     * Device models with removable media must implement this callback.
> +     */
> +    void (*change_media_cb)(void *opaque, bool load);
> +    /*
> +     * Runs when an eject request is issued from the monitor, the tray
> +     * is closed, and the medium is locked.
> +     * Device models that do not implement is_medium_locked will not need
> +     * this callback.  Device models that can lock the medium or tray might
> +     * want to implement the callback and unlock the tray when "force" is
> +     * true, even if they do not support eject requests.
> +     */
> +    void (*eject_request_cb)(void *opaque, bool force);
> +    /*
> +     * Is the virtual tray open?
> +     * Device models implement this only when the device has a tray.
> +     */
> +    bool (*is_tray_open)(void *opaque);
> +    /*
> +     * Is the virtual medium locked into the device?
> +     * Device models implement this only when device has such a lock.
> +     */
> +    bool (*is_medium_locked)(void *opaque);
> +    /*
> +     * Runs when the size changed (e.g. monitor command block_resize)
> +     */
> +    void (*resize_cb)(void *opaque);
> +} BlockDevOps;
> +
>  BlockBackend *blk_new(const char *name, Error **errp);
>  BlockBackend *blk_new_with_bs(const char *name, Error **errp);
>  void blk_ref(BlockBackend *blk);
> -- 
> 1.9.3
> 

This one is difficult to review.
Could it be splitted in multiple baby steps ?

Best regards

Benoît
Markus Armbruster Sept. 22, 2014, 12:54 p.m. UTC | #2
Benoît Canet <benoit.canet@nodalink.com> writes:

> On Tue, Sep 16, 2014 at 08:12:27PM +0200, Markus Armbruster wrote:
>> Move device model attachment / detachment and the BlockDevOps device
>> model callbacks and their wrappers from BlockDriverState to
>> BlockBackend.
>> 
>> Signed-off-by: Markus Armbruster <armbru@redhat.com>
>> ---
>>  block.c                        | 126 ++++------------------------------
>>  block/block-backend.c          | 151 ++++++++++++++++++++++++++++++++++++++---
>>  block/qapi.c                   |   8 +--
>>  blockdev.c                     |   8 +--
>>  include/block/block.h          |  45 ------------
>>  include/block/block_int.h      |  12 ++--
>>  include/sysemu/block-backend.h |  35 ++++++++++
>>  7 files changed, 203 insertions(+), 182 deletions(-)
>> 
>> diff --git a/block.c b/block.c
>> index 1d9a680..fac1211 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -58,9 +58,6 @@ struct BdrvDirtyBitmap {
>>  
>>  #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
>>  
>> -#define COROUTINE_POOL_RESERVATION 64 /* number of coroutines to reserve */
>> -
>> -static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
>>  static BlockAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
>>          int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
>>          BlockCompletionFunc *cb, void *opaque);
>> @@ -1527,7 +1524,9 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
>>      }
>>  
>>      if (!bdrv_key_required(bs)) {
>> -        bdrv_dev_change_media_cb(bs, true);
>> +        if (bs->blk) {
>> +            blk_dev_change_media_cb(bs->blk, true);
>> +        }
>>      } else if (!runstate_check(RUN_STATE_PRELAUNCH)
>>                 && !runstate_check(RUN_STATE_INMIGRATE)
>>                 && !runstate_check(RUN_STATE_PAUSED)) { /* HACK */
>> @@ -1852,7 +1851,9 @@ void bdrv_close(BlockDriverState *bs)
>>          }
>>      }
>>  
>> -    bdrv_dev_change_media_cb(bs, false);
>> +    if (bs->blk) {
>> +        blk_dev_change_media_cb(bs->blk, false);
>> +    }
>>  
>>      /*throttling disk I/O limits*/
>>      if (bs->io_limits_enabled) {
>> @@ -1971,9 +1972,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
>>      /* move some fields that need to stay attached to the device */
>>  
>>      /* dev info */
>> -    bs_dest->dev_ops            = bs_src->dev_ops;
>> -    bs_dest->dev_opaque         = bs_src->dev_opaque;
>> -    bs_dest->dev                = bs_src->dev;
>>      bs_dest->guest_block_size   = bs_src->guest_block_size;
>>      bs_dest->copy_on_read       = bs_src->copy_on_read;
>>  
>> @@ -2041,7 +2039,6 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
>>      assert(!bs_new->blk);
>>      assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
>>      assert(bs_new->job == NULL);
>> -    assert(bs_new->dev == NULL);
>>      assert(bs_new->io_limits_enabled == false);
>>      assert(!throttle_have_timer(&bs_new->throttle_state));
>>  
>> @@ -2058,7 +2055,6 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
>>      assert(!bs_new->blk);
>>  
>>      /* Check a few fields that should remain attached to the device */
>> -    assert(bs_new->dev == NULL);
>>      assert(bs_new->job == NULL);
>>      assert(bs_new->io_limits_enabled == false);
>>      assert(!throttle_have_timer(&bs_new->throttle_state));
>> @@ -2097,7 +2093,6 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
>>  
>>  static void bdrv_delete(BlockDriverState *bs)
>>  {
>> -    assert(!bs->dev);
>>      assert(!bs->job);
>>      assert(bdrv_op_blocker_is_empty(bs));
>>      assert(!bs->refcnt);
>> @@ -2111,105 +2106,6 @@ static void bdrv_delete(BlockDriverState *bs)
>>      g_free(bs);
>>  }
>>  
>> -int bdrv_attach_dev(BlockDriverState *bs, void *dev)
>> -/* TODO change to DeviceState *dev when all users are qdevified */
>> -{
>> -    if (bs->dev) {
>> -        return -EBUSY;
>> -    }
>> -    bs->dev = dev;
>> -    bdrv_iostatus_reset(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;
>> -}
>> -
>> -/* TODO qdevified devices don't use this, remove when devices are qdevified */
>> -void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev)
>> -{
>> -    if (bdrv_attach_dev(bs, dev) < 0) {
>> -        abort();
>> -    }
>> -}
>> -
>> -void bdrv_detach_dev(BlockDriverState *bs, void *dev)
>> -/* TODO change to DeviceState *dev when all users are qdevified */
>> -{
>> -    assert(bs->dev == dev);
>> -    bs->dev = NULL;
>> -    bs->dev_ops = NULL;
>> -    bs->dev_opaque = NULL;
>> -    bs->guest_block_size = 512;
>> -    qemu_coroutine_adjust_pool_size(-COROUTINE_POOL_RESERVATION);
>> -}
>> -
>> -/* TODO change to return DeviceState * when all users are qdevified */
>> -void *bdrv_get_attached_dev(BlockDriverState *bs)
>> -{
>> -    return bs->dev;
>> -}
>> -
>> -void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
>> -                      void *opaque)
>> -{
>> -    bs->dev_ops = ops;
>> -    bs->dev_opaque = opaque;
>> -}
>> -
>> -static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load)
>> -{
>> -    if (bs->dev_ops && bs->dev_ops->change_media_cb) {
>> -        bool tray_was_closed = !bdrv_dev_is_tray_open(bs);
>> -        bs->dev_ops->change_media_cb(bs->dev_opaque, load);
>> -        if (tray_was_closed) {
>> -            /* tray open */
>> -            qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
>> -                                              true, &error_abort);
>> -        }
>> -        if (load) {
>> -            /* tray close */
>> -            qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
>> -                                              false, &error_abort);
>> -        }
>> -    }
>> -}
>> -
>> -bool bdrv_dev_has_removable_media(BlockDriverState *bs)
>> -{
>> -    return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
>> -}
>> -
>> -void bdrv_dev_eject_request(BlockDriverState *bs, bool force)
>> -{
>> -    if (bs->dev_ops && bs->dev_ops->eject_request_cb) {
>> -        bs->dev_ops->eject_request_cb(bs->dev_opaque, force);
>> -    }
>> -}
>> -
>> -bool bdrv_dev_is_tray_open(BlockDriverState *bs)
>> -{
>> -    if (bs->dev_ops && bs->dev_ops->is_tray_open) {
>> -        return bs->dev_ops->is_tray_open(bs->dev_opaque);
>> -    }
>> -    return false;
>> -}
>> -
>> -static void bdrv_dev_resize_cb(BlockDriverState *bs)
>> -{
>> -    if (bs->dev_ops && bs->dev_ops->resize_cb) {
>> -        bs->dev_ops->resize_cb(bs->dev_opaque);
>> -    }
>> -}
>> -
>> -bool bdrv_dev_is_medium_locked(BlockDriverState *bs)
>> -{
>> -    if (bs->dev_ops && bs->dev_ops->is_medium_locked) {
>> -        return bs->dev_ops->is_medium_locked(bs->dev_opaque);
>> -    }
>> -    return false;
>> -}
>> -
>>  /*
>>   * Run consistency checks on an image
>>   *
>> @@ -3543,7 +3439,9 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
>>      ret = drv->bdrv_truncate(bs, offset);
>>      if (ret == 0) {
>>          ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
>> -        bdrv_dev_resize_cb(bs);
>> +        if (bs->blk) {
>> +            blk_dev_resize_cb(bs->blk);
>> +        }
>>      }
>>      return ret;
>>  }
>> @@ -3744,8 +3642,10 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
>>          bs->valid_key = 0;
>>      } else if (!bs->valid_key) {
>>          bs->valid_key = 1;
>> -        /* call the change callback now, we skipped it on open */
>> -        bdrv_dev_change_media_cb(bs, true);
>> +        if (bs->blk) {
>> +            /* call the change callback now, we skipped it on open */
>> +            blk_dev_change_media_cb(bs->blk, true);
>> +        }
>>      }
>>      return ret;
>>  }
>> diff --git a/block/block-backend.c b/block/block-backend.c
>> index b55f0b4..d49c988 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;
>>      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);
>> @@ -81,6 +90,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;
>> @@ -233,34 +243,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 bdrv_get_attached_dev(blk->bs);
>> +    return blk->dev;
>>  }
>>  
>> -void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque)
>> +/*
>> + * 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)
>>  {
>> -    bdrv_set_dev_ops(blk->bs, ops, opaque);
>> +    blk->dev_ops = ops;
>> +    blk->dev_opaque = 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)
>> +{
>> +    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,
>> diff --git a/block/qapi.c b/block/qapi.c
>> index fca981d..1301144 100644
>> --- a/block/qapi.c
>> +++ b/block/qapi.c
>> @@ -275,12 +275,12 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
>>      Error *local_err = NULL;
>>      info->device = g_strdup(blk_name(blk));
>>      info->type = g_strdup("unknown");
>> -    info->locked = bdrv_dev_is_medium_locked(bs);
>> -    info->removable = bdrv_dev_has_removable_media(bs);
>> +    info->locked = blk_dev_is_medium_locked(blk);
>> +    info->removable = blk_dev_has_removable_media(blk);
>>  
>> -    if (bdrv_dev_has_removable_media(bs)) {
>> +    if (blk_dev_has_removable_media(blk)) {
>>          info->has_tray_open = true;
>> -        info->tray_open = bdrv_dev_is_tray_open(bs);
>> +        info->tray_open = blk_dev_is_tray_open(blk);
>>      }
>>  
>>      if (bdrv_iostatus_is_enabled(bs)) {
>> diff --git a/blockdev.c b/blockdev.c
>> index e115bde..d3dccb9 100644
>> --- a/blockdev.c
>> +++ b/blockdev.c
>> @@ -1509,14 +1509,14 @@ static void eject_device(BlockBackend *blk, int force, Error **errp)
>>      if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
>>          return;
>>      }
>> -    if (!bdrv_dev_has_removable_media(bs)) {
>> +    if (!blk_dev_has_removable_media(blk)) {
>>          error_setg(errp, "Device '%s' is not removable",
>>                     bdrv_get_device_name(bs));
>>          return;
>>      }
>>  
>> -    if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
>> -        bdrv_dev_eject_request(bs, force);
>> +    if (blk_dev_is_medium_locked(blk) && !blk_dev_is_tray_open(blk)) {
>> +        blk_dev_eject_request(blk, force);
>>          if (!force) {
>>              error_setg(errp, "Device '%s' is locked",
>>                         bdrv_get_device_name(bs));
>> @@ -1753,7 +1753,7 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
>>       * can be removed.  If this is a drive with no device backing
>>       * then we can just get rid of the block driver state right here.
>>       */
>> -    if (bdrv_get_attached_dev(bs)) {
>> +    if (blk_get_attached_dev(blk)) {
>>          blk_hide_on_behalf_of_do_drive_del(blk);
>>          /* Further I/O must not pause the guest */
>>          bdrv_set_on_error(bs, BLOCKDEV_ON_ERROR_REPORT,
>> diff --git a/include/block/block.h b/include/block/block.h
>> index 5b45743..bc9ec50 100644
>> --- a/include/block/block.h
>> +++ b/include/block/block.h
>> @@ -48,41 +48,6 @@ typedef struct BlockFragInfo {
>>      uint64_t compressed_clusters;
>>  } BlockFragInfo;
>>  
>> -/* Callbacks for block device models */
>> -typedef struct BlockDevOps {
>> -    /*
>> -     * Runs when virtual media changed (monitor commands eject, change)
>> -     * Argument load is true on load and false on eject.
>> -     * Beware: doesn't run when a host device's physical media
>> -     * changes.  Sure would be useful if it did.
>> -     * Device models with removable media must implement this callback.
>> -     */
>> -    void (*change_media_cb)(void *opaque, bool load);
>> -    /*
>> -     * Runs when an eject request is issued from the monitor, the tray
>> -     * is closed, and the medium is locked.
>> -     * Device models that do not implement is_medium_locked will not need
>> -     * this callback.  Device models that can lock the medium or tray might
>> -     * want to implement the callback and unlock the tray when "force" is
>> -     * true, even if they do not support eject requests.
>> -     */
>> -    void (*eject_request_cb)(void *opaque, bool force);
>> -    /*
>> -     * Is the virtual tray open?
>> -     * Device models implement this only when the device has a tray.
>> -     */
>> -    bool (*is_tray_open)(void *opaque);
>> -    /*
>> -     * Is the virtual medium locked into the device?
>> -     * Device models implement this only when device has such a lock.
>> -     */
>> -    bool (*is_medium_locked)(void *opaque);
>> -    /*
>> -     * Runs when the size changed (e.g. monitor command block_resize)
>> -     */
>> -    void (*resize_cb)(void *opaque);
>> -} BlockDevOps;
>> -
>>  typedef enum {
>>      BDRV_REQ_COPY_ON_READ = 0x1,
>>      BDRV_REQ_ZERO_WRITE   = 0x2,
>> @@ -230,16 +195,6 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state);
>>  void bdrv_reopen_abort(BDRVReopenState *reopen_state);
>>  void bdrv_close(BlockDriverState *bs);
>>  void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify);
>> -int bdrv_attach_dev(BlockDriverState *bs, void *dev);
>> -void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev);
>> -void bdrv_detach_dev(BlockDriverState *bs, void *dev);
>> -void *bdrv_get_attached_dev(BlockDriverState *bs);
>> -void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
>> -                      void *opaque);
>> -void bdrv_dev_eject_request(BlockDriverState *bs, bool force);
>> -bool bdrv_dev_has_removable_media(BlockDriverState *bs);
>> -bool bdrv_dev_is_tray_open(BlockDriverState *bs);
>> -bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
>>  int bdrv_read(BlockDriverState *bs, int64_t sector_num,
>>                uint8_t *buf, int nb_sectors);
>>  int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num,
>> diff --git a/include/block/block_int.h b/include/block/block_int.h
>> index e8e33a8..8898c6c 100644
>> --- a/include/block/block_int.h
>> +++ b/include/block/block_int.h
>> @@ -326,11 +326,6 @@ struct BlockDriverState {
>>  
>>      BlockBackend *blk;          /* owning backend, if any */
>>  
>> -    void *dev;                  /* attached device model, if any */
>> -    /* TODO change to DeviceState when all users are qdevified */
>> -    const BlockDevOps *dev_ops;
>> -    void *dev_opaque;
>> -
>>      AioContext *aio_context; /* event loop used for fd handlers, timers, etc */
>>      /* long-running tasks intended to always use the same AioContext as this
>>       * BDS may register themselves in this list to be notified of changes
>> @@ -587,4 +582,11 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
>>                    BlockCompletionFunc *cb, void *opaque,
>>                    Error **errp);
>>  
>> +void blk_dev_change_media_cb(BlockBackend *blk, bool load);
>> +bool blk_dev_has_removable_media(BlockBackend *blk);
>> +void blk_dev_eject_request(BlockBackend *blk, bool force);
>> +bool blk_dev_is_tray_open(BlockBackend *blk);
>> +bool blk_dev_is_medium_locked(BlockBackend *blk);
>> +void blk_dev_resize_cb(BlockBackend *blk);
>> +
>>  #endif /* BLOCK_INT_H */
>> diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
>> index e4bfea5..02305a1 100644
>> --- a/include/sysemu/block-backend.h
>> +++ b/include/sysemu/block-backend.h
>> @@ -25,6 +25,41 @@
>>   */
>>  #include "block/block.h"
>>  
>> +/* Callbacks for block device models */
>> +typedef struct BlockDevOps {
>> +    /*
>> +     * Runs when virtual media changed (monitor commands eject, change)
>> +     * Argument load is true on load and false on eject.
>> +     * Beware: doesn't run when a host device's physical media
>> +     * changes.  Sure would be useful if it did.
>> +     * Device models with removable media must implement this callback.
>> +     */
>> +    void (*change_media_cb)(void *opaque, bool load);
>> +    /*
>> +     * Runs when an eject request is issued from the monitor, the tray
>> +     * is closed, and the medium is locked.
>> +     * Device models that do not implement is_medium_locked will not need
>> +     * this callback.  Device models that can lock the medium or tray might
>> +     * want to implement the callback and unlock the tray when "force" is
>> +     * true, even if they do not support eject requests.
>> +     */
>> +    void (*eject_request_cb)(void *opaque, bool force);
>> +    /*
>> +     * Is the virtual tray open?
>> +     * Device models implement this only when the device has a tray.
>> +     */
>> +    bool (*is_tray_open)(void *opaque);
>> +    /*
>> +     * Is the virtual medium locked into the device?
>> +     * Device models implement this only when device has such a lock.
>> +     */
>> +    bool (*is_medium_locked)(void *opaque);
>> +    /*
>> +     * Runs when the size changed (e.g. monitor command block_resize)
>> +     */
>> +    void (*resize_cb)(void *opaque);
>> +} BlockDevOps;
>> +
>>  BlockBackend *blk_new(const char *name, Error **errp);
>>  BlockBackend *blk_new_with_bs(const char *name, Error **errp);
>>  void blk_ref(BlockBackend *blk);
>> -- 
>> 1.9.3
>> 
>
> This one is difficult to review.
> Could it be splitted in multiple baby steps ?

Not sure, but I'll think about it.

I certainly can try harder in the commit message.
Max Reitz Sept. 22, 2014, 1:58 p.m. UTC | #3
On 16.09.2014 20:12, Markus Armbruster wrote:
> Move device model attachment / detachment and the BlockDevOps device
> model callbacks and their wrappers from BlockDriverState to
> BlockBackend.
>
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>   block.c                        | 126 ++++------------------------------
>   block/block-backend.c          | 151 ++++++++++++++++++++++++++++++++++++++---
>   block/qapi.c                   |   8 +--
>   blockdev.c                     |   8 +--
>   include/block/block.h          |  45 ------------
>   include/block/block_int.h      |  12 ++--
>   include/sysemu/block-backend.h |  35 ++++++++++
>   7 files changed, 203 insertions(+), 182 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>
Kevin Wolf Sept. 30, 2014, 10:49 a.m. UTC | #4
Am 16.09.2014 um 20:12 hat Markus Armbruster geschrieben:
> Move device model attachment / detachment and the BlockDevOps device
> model callbacks and their wrappers from BlockDriverState to
> BlockBackend.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>

Reviewed-by: Kevin Wolf <kwolf@redhat.com>
diff mbox

Patch

diff --git a/block.c b/block.c
index 1d9a680..fac1211 100644
--- a/block.c
+++ b/block.c
@@ -58,9 +58,6 @@  struct BdrvDirtyBitmap {
 
 #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
 
-#define COROUTINE_POOL_RESERVATION 64 /* number of coroutines to reserve */
-
-static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
 static BlockAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockCompletionFunc *cb, void *opaque);
@@ -1527,7 +1524,9 @@  int bdrv_open(BlockDriverState **pbs, const char *filename,
     }
 
     if (!bdrv_key_required(bs)) {
-        bdrv_dev_change_media_cb(bs, true);
+        if (bs->blk) {
+            blk_dev_change_media_cb(bs->blk, true);
+        }
     } else if (!runstate_check(RUN_STATE_PRELAUNCH)
                && !runstate_check(RUN_STATE_INMIGRATE)
                && !runstate_check(RUN_STATE_PAUSED)) { /* HACK */
@@ -1852,7 +1851,9 @@  void bdrv_close(BlockDriverState *bs)
         }
     }
 
-    bdrv_dev_change_media_cb(bs, false);
+    if (bs->blk) {
+        blk_dev_change_media_cb(bs->blk, false);
+    }
 
     /*throttling disk I/O limits*/
     if (bs->io_limits_enabled) {
@@ -1971,9 +1972,6 @@  static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
     /* move some fields that need to stay attached to the device */
 
     /* dev info */
-    bs_dest->dev_ops            = bs_src->dev_ops;
-    bs_dest->dev_opaque         = bs_src->dev_opaque;
-    bs_dest->dev                = bs_src->dev;
     bs_dest->guest_block_size   = bs_src->guest_block_size;
     bs_dest->copy_on_read       = bs_src->copy_on_read;
 
@@ -2041,7 +2039,6 @@  void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
     assert(!bs_new->blk);
     assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
     assert(bs_new->job == NULL);
-    assert(bs_new->dev == NULL);
     assert(bs_new->io_limits_enabled == false);
     assert(!throttle_have_timer(&bs_new->throttle_state));
 
@@ -2058,7 +2055,6 @@  void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
     assert(!bs_new->blk);
 
     /* Check a few fields that should remain attached to the device */
-    assert(bs_new->dev == NULL);
     assert(bs_new->job == NULL);
     assert(bs_new->io_limits_enabled == false);
     assert(!throttle_have_timer(&bs_new->throttle_state));
@@ -2097,7 +2093,6 @@  void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
 
 static void bdrv_delete(BlockDriverState *bs)
 {
-    assert(!bs->dev);
     assert(!bs->job);
     assert(bdrv_op_blocker_is_empty(bs));
     assert(!bs->refcnt);
@@ -2111,105 +2106,6 @@  static void bdrv_delete(BlockDriverState *bs)
     g_free(bs);
 }
 
-int bdrv_attach_dev(BlockDriverState *bs, void *dev)
-/* TODO change to DeviceState *dev when all users are qdevified */
-{
-    if (bs->dev) {
-        return -EBUSY;
-    }
-    bs->dev = dev;
-    bdrv_iostatus_reset(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;
-}
-
-/* TODO qdevified devices don't use this, remove when devices are qdevified */
-void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev)
-{
-    if (bdrv_attach_dev(bs, dev) < 0) {
-        abort();
-    }
-}
-
-void bdrv_detach_dev(BlockDriverState *bs, void *dev)
-/* TODO change to DeviceState *dev when all users are qdevified */
-{
-    assert(bs->dev == dev);
-    bs->dev = NULL;
-    bs->dev_ops = NULL;
-    bs->dev_opaque = NULL;
-    bs->guest_block_size = 512;
-    qemu_coroutine_adjust_pool_size(-COROUTINE_POOL_RESERVATION);
-}
-
-/* TODO change to return DeviceState * when all users are qdevified */
-void *bdrv_get_attached_dev(BlockDriverState *bs)
-{
-    return bs->dev;
-}
-
-void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
-                      void *opaque)
-{
-    bs->dev_ops = ops;
-    bs->dev_opaque = opaque;
-}
-
-static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load)
-{
-    if (bs->dev_ops && bs->dev_ops->change_media_cb) {
-        bool tray_was_closed = !bdrv_dev_is_tray_open(bs);
-        bs->dev_ops->change_media_cb(bs->dev_opaque, load);
-        if (tray_was_closed) {
-            /* tray open */
-            qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
-                                              true, &error_abort);
-        }
-        if (load) {
-            /* tray close */
-            qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
-                                              false, &error_abort);
-        }
-    }
-}
-
-bool bdrv_dev_has_removable_media(BlockDriverState *bs)
-{
-    return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
-}
-
-void bdrv_dev_eject_request(BlockDriverState *bs, bool force)
-{
-    if (bs->dev_ops && bs->dev_ops->eject_request_cb) {
-        bs->dev_ops->eject_request_cb(bs->dev_opaque, force);
-    }
-}
-
-bool bdrv_dev_is_tray_open(BlockDriverState *bs)
-{
-    if (bs->dev_ops && bs->dev_ops->is_tray_open) {
-        return bs->dev_ops->is_tray_open(bs->dev_opaque);
-    }
-    return false;
-}
-
-static void bdrv_dev_resize_cb(BlockDriverState *bs)
-{
-    if (bs->dev_ops && bs->dev_ops->resize_cb) {
-        bs->dev_ops->resize_cb(bs->dev_opaque);
-    }
-}
-
-bool bdrv_dev_is_medium_locked(BlockDriverState *bs)
-{
-    if (bs->dev_ops && bs->dev_ops->is_medium_locked) {
-        return bs->dev_ops->is_medium_locked(bs->dev_opaque);
-    }
-    return false;
-}
-
 /*
  * Run consistency checks on an image
  *
@@ -3543,7 +3439,9 @@  int bdrv_truncate(BlockDriverState *bs, int64_t offset)
     ret = drv->bdrv_truncate(bs, offset);
     if (ret == 0) {
         ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
-        bdrv_dev_resize_cb(bs);
+        if (bs->blk) {
+            blk_dev_resize_cb(bs->blk);
+        }
     }
     return ret;
 }
@@ -3744,8 +3642,10 @@  int bdrv_set_key(BlockDriverState *bs, const char *key)
         bs->valid_key = 0;
     } else if (!bs->valid_key) {
         bs->valid_key = 1;
-        /* call the change callback now, we skipped it on open */
-        bdrv_dev_change_media_cb(bs, true);
+        if (bs->blk) {
+            /* call the change callback now, we skipped it on open */
+            blk_dev_change_media_cb(bs->blk, true);
+        }
     }
     return ret;
 }
diff --git a/block/block-backend.c b/block/block-backend.c
index b55f0b4..d49c988 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;
     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);
@@ -81,6 +90,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;
@@ -233,34 +243,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 bdrv_get_attached_dev(blk->bs);
+    return blk->dev;
 }
 
-void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, void *opaque)
+/*
+ * 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)
 {
-    bdrv_set_dev_ops(blk->bs, ops, opaque);
+    blk->dev_ops = ops;
+    blk->dev_opaque = 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)
+{
+    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,
diff --git a/block/qapi.c b/block/qapi.c
index fca981d..1301144 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -275,12 +275,12 @@  static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
     Error *local_err = NULL;
     info->device = g_strdup(blk_name(blk));
     info->type = g_strdup("unknown");
-    info->locked = bdrv_dev_is_medium_locked(bs);
-    info->removable = bdrv_dev_has_removable_media(bs);
+    info->locked = blk_dev_is_medium_locked(blk);
+    info->removable = blk_dev_has_removable_media(blk);
 
-    if (bdrv_dev_has_removable_media(bs)) {
+    if (blk_dev_has_removable_media(blk)) {
         info->has_tray_open = true;
-        info->tray_open = bdrv_dev_is_tray_open(bs);
+        info->tray_open = blk_dev_is_tray_open(blk);
     }
 
     if (bdrv_iostatus_is_enabled(bs)) {
diff --git a/blockdev.c b/blockdev.c
index e115bde..d3dccb9 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1509,14 +1509,14 @@  static void eject_device(BlockBackend *blk, int force, Error **errp)
     if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
         return;
     }
-    if (!bdrv_dev_has_removable_media(bs)) {
+    if (!blk_dev_has_removable_media(blk)) {
         error_setg(errp, "Device '%s' is not removable",
                    bdrv_get_device_name(bs));
         return;
     }
 
-    if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
-        bdrv_dev_eject_request(bs, force);
+    if (blk_dev_is_medium_locked(blk) && !blk_dev_is_tray_open(blk)) {
+        blk_dev_eject_request(blk, force);
         if (!force) {
             error_setg(errp, "Device '%s' is locked",
                        bdrv_get_device_name(bs));
@@ -1753,7 +1753,7 @@  int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
      * can be removed.  If this is a drive with no device backing
      * then we can just get rid of the block driver state right here.
      */
-    if (bdrv_get_attached_dev(bs)) {
+    if (blk_get_attached_dev(blk)) {
         blk_hide_on_behalf_of_do_drive_del(blk);
         /* Further I/O must not pause the guest */
         bdrv_set_on_error(bs, BLOCKDEV_ON_ERROR_REPORT,
diff --git a/include/block/block.h b/include/block/block.h
index 5b45743..bc9ec50 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -48,41 +48,6 @@  typedef struct BlockFragInfo {
     uint64_t compressed_clusters;
 } BlockFragInfo;
 
-/* Callbacks for block device models */
-typedef struct BlockDevOps {
-    /*
-     * Runs when virtual media changed (monitor commands eject, change)
-     * Argument load is true on load and false on eject.
-     * Beware: doesn't run when a host device's physical media
-     * changes.  Sure would be useful if it did.
-     * Device models with removable media must implement this callback.
-     */
-    void (*change_media_cb)(void *opaque, bool load);
-    /*
-     * Runs when an eject request is issued from the monitor, the tray
-     * is closed, and the medium is locked.
-     * Device models that do not implement is_medium_locked will not need
-     * this callback.  Device models that can lock the medium or tray might
-     * want to implement the callback and unlock the tray when "force" is
-     * true, even if they do not support eject requests.
-     */
-    void (*eject_request_cb)(void *opaque, bool force);
-    /*
-     * Is the virtual tray open?
-     * Device models implement this only when the device has a tray.
-     */
-    bool (*is_tray_open)(void *opaque);
-    /*
-     * Is the virtual medium locked into the device?
-     * Device models implement this only when device has such a lock.
-     */
-    bool (*is_medium_locked)(void *opaque);
-    /*
-     * Runs when the size changed (e.g. monitor command block_resize)
-     */
-    void (*resize_cb)(void *opaque);
-} BlockDevOps;
-
 typedef enum {
     BDRV_REQ_COPY_ON_READ = 0x1,
     BDRV_REQ_ZERO_WRITE   = 0x2,
@@ -230,16 +195,6 @@  void bdrv_reopen_commit(BDRVReopenState *reopen_state);
 void bdrv_reopen_abort(BDRVReopenState *reopen_state);
 void bdrv_close(BlockDriverState *bs);
 void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify);
-int bdrv_attach_dev(BlockDriverState *bs, void *dev);
-void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev);
-void bdrv_detach_dev(BlockDriverState *bs, void *dev);
-void *bdrv_get_attached_dev(BlockDriverState *bs);
-void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
-                      void *opaque);
-void bdrv_dev_eject_request(BlockDriverState *bs, bool force);
-bool bdrv_dev_has_removable_media(BlockDriverState *bs);
-bool bdrv_dev_is_tray_open(BlockDriverState *bs);
-bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
 int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors);
 int bdrv_read_unthrottled(BlockDriverState *bs, int64_t sector_num,
diff --git a/include/block/block_int.h b/include/block/block_int.h
index e8e33a8..8898c6c 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -326,11 +326,6 @@  struct BlockDriverState {
 
     BlockBackend *blk;          /* owning backend, if any */
 
-    void *dev;                  /* attached device model, if any */
-    /* TODO change to DeviceState when all users are qdevified */
-    const BlockDevOps *dev_ops;
-    void *dev_opaque;
-
     AioContext *aio_context; /* event loop used for fd handlers, timers, etc */
     /* long-running tasks intended to always use the same AioContext as this
      * BDS may register themselves in this list to be notified of changes
@@ -587,4 +582,11 @@  void backup_start(BlockDriverState *bs, BlockDriverState *target,
                   BlockCompletionFunc *cb, void *opaque,
                   Error **errp);
 
+void blk_dev_change_media_cb(BlockBackend *blk, bool load);
+bool blk_dev_has_removable_media(BlockBackend *blk);
+void blk_dev_eject_request(BlockBackend *blk, bool force);
+bool blk_dev_is_tray_open(BlockBackend *blk);
+bool blk_dev_is_medium_locked(BlockBackend *blk);
+void blk_dev_resize_cb(BlockBackend *blk);
+
 #endif /* BLOCK_INT_H */
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index e4bfea5..02305a1 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -25,6 +25,41 @@ 
  */
 #include "block/block.h"
 
+/* Callbacks for block device models */
+typedef struct BlockDevOps {
+    /*
+     * Runs when virtual media changed (monitor commands eject, change)
+     * Argument load is true on load and false on eject.
+     * Beware: doesn't run when a host device's physical media
+     * changes.  Sure would be useful if it did.
+     * Device models with removable media must implement this callback.
+     */
+    void (*change_media_cb)(void *opaque, bool load);
+    /*
+     * Runs when an eject request is issued from the monitor, the tray
+     * is closed, and the medium is locked.
+     * Device models that do not implement is_medium_locked will not need
+     * this callback.  Device models that can lock the medium or tray might
+     * want to implement the callback and unlock the tray when "force" is
+     * true, even if they do not support eject requests.
+     */
+    void (*eject_request_cb)(void *opaque, bool force);
+    /*
+     * Is the virtual tray open?
+     * Device models implement this only when the device has a tray.
+     */
+    bool (*is_tray_open)(void *opaque);
+    /*
+     * Is the virtual medium locked into the device?
+     * Device models implement this only when device has such a lock.
+     */
+    bool (*is_medium_locked)(void *opaque);
+    /*
+     * Runs when the size changed (e.g. monitor command block_resize)
+     */
+    void (*resize_cb)(void *opaque);
+} BlockDevOps;
+
 BlockBackend *blk_new(const char *name, Error **errp);
 BlockBackend *blk_new_with_bs(const char *name, Error **errp);
 void blk_ref(BlockBackend *blk);