Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-for-pe…
Browse files Browse the repository at this point in the history
…ter-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>
  • Loading branch information
pm215 committed Feb 2, 2016
2 parents 3bb1e82 + 8983b67 commit c65db77
Show file tree
Hide file tree
Showing 52 changed files with 1,302 additions and 323 deletions.
114 changes: 80 additions & 34 deletions block.c
Expand Up @@ -79,6 +79,9 @@ struct BdrvStates bdrv_states = QTAILQ_HEAD_INITIALIZER(bdrv_states);
static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
QTAILQ_HEAD_INITIALIZER(graph_bdrv_states);

static QTAILQ_HEAD(, BlockDriverState) all_bdrv_states =
QTAILQ_HEAD_INITIALIZER(all_bdrv_states);

static QLIST_HEAD(, BlockDriver) bdrv_drivers =
QLIST_HEAD_INITIALIZER(bdrv_drivers);

Expand All @@ -88,9 +91,13 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
const BdrvChildRole *child_role, Error **errp);

static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
static void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs);

/* If non-zero, use only whitelisted block drivers */
static int use_bdrv_whitelist;

static void bdrv_close(BlockDriverState *bs);

#ifdef _WIN32
static int is_windows_drive_prefix(const char *filename)
{
Expand Down Expand Up @@ -257,19 +264,15 @@ BlockDriverState *bdrv_new(void)
for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
QLIST_INIT(&bs->op_blockers[i]);
}
notifier_list_init(&bs->close_notifiers);
notifier_with_return_list_init(&bs->before_write_notifiers);
qemu_co_queue_init(&bs->throttled_reqs[0]);
qemu_co_queue_init(&bs->throttled_reqs[1]);
bs->refcnt = 1;
bs->aio_context = qemu_get_aio_context();

return bs;
}
QTAILQ_INSERT_TAIL(&all_bdrv_states, bs, bs_list);

void bdrv_add_close_notifier(BlockDriverState *bs, Notifier *notify)
{
notifier_list_add(&bs->close_notifiers, notify);
return bs;
}

BlockDriver *bdrv_find_format(const char *format_name)
Expand Down Expand Up @@ -2138,13 +2141,11 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
}


void bdrv_close(BlockDriverState *bs)
static void bdrv_close(BlockDriverState *bs)
{
BdrvAioNotifier *ban, *ban_next;

if (bs->job) {
block_job_cancel_sync(bs->job);
}
assert(!bs->job);

/* Disable I/O limits and drain all pending throttled requests */
if (bs->throttle_state) {
Expand All @@ -2155,7 +2156,8 @@ void bdrv_close(BlockDriverState *bs)
bdrv_flush(bs);
bdrv_drain(bs); /* in case flush left pending I/O */

notifier_list_notify(&bs->close_notifiers, bs);
bdrv_release_named_dirty_bitmaps(bs);
assert(QLIST_EMPTY(&bs->dirty_bitmaps));

if (bs->blk) {
blk_dev_change_media_cb(bs->blk, false);
Expand Down Expand Up @@ -2210,31 +2212,55 @@ void bdrv_close(BlockDriverState *bs)
void bdrv_close_all(void)
{
BlockDriverState *bs;
AioContext *aio_context;

QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
AioContext *aio_context = bdrv_get_aio_context(bs);
/* Drop references from requests still in flight, such as canceled block
* jobs whose AIO context has not been polled yet */
bdrv_drain_all();

aio_context_acquire(aio_context);
bdrv_close(bs);
aio_context_release(aio_context);
blk_remove_all_bs();
blockdev_close_all_bdrv_states();

/* Cancel all block jobs */
while (!QTAILQ_EMPTY(&all_bdrv_states)) {
QTAILQ_FOREACH(bs, &all_bdrv_states, bs_list) {
aio_context = bdrv_get_aio_context(bs);

aio_context_acquire(aio_context);
if (bs->job) {
block_job_cancel_sync(bs->job);
aio_context_release(aio_context);
break;
}
aio_context_release(aio_context);
}

/* All the remaining BlockDriverStates are referenced directly or
* indirectly from block jobs, so there needs to be at least one BDS
* directly used by a block job */
assert(bs);
}
}

/* Note that bs->device_list.tqe_prev is initially null,
* and gets set to non-null by QTAILQ_INSERT_TAIL(). Establish
* the useful invariant "bs in bdrv_states iff bs->tqe_prev" by
* resetting it to null on remove. */
void bdrv_device_remove(BlockDriverState *bs)
{
QTAILQ_REMOVE(&bdrv_states, bs, device_list);
bs->device_list.tqe_prev = NULL;
}

/* make a BlockDriverState anonymous by removing from bdrv_state and
* graph_bdrv_state list.
Also, NULL terminate the device_name to prevent double remove */
void bdrv_make_anon(BlockDriverState *bs)
{
/*
* Take care to remove bs from bdrv_states only when it's actually
* in it. Note that bs->device_list.tqe_prev is initially null,
* and gets set to non-null by QTAILQ_INSERT_TAIL(). Establish
* the useful invariant "bs in bdrv_states iff bs->tqe_prev" by
* resetting it to null on remove.
*/
/* Take care to remove bs from bdrv_states only when it's actually
* in it. */
if (bs->device_list.tqe_prev) {
QTAILQ_REMOVE(&bdrv_states, bs, device_list);
bs->device_list.tqe_prev = NULL;
bdrv_device_remove(bs);
}
if (bs->node_name[0] != '\0') {
QTAILQ_REMOVE(&graph_bdrv_states, bs, node_list);
Expand Down Expand Up @@ -2275,7 +2301,7 @@ static void change_parent_backing_link(BlockDriverState *from,
if (!to->device_list.tqe_prev) {
QTAILQ_INSERT_BEFORE(from, to, device_list);
}
QTAILQ_REMOVE(&bdrv_states, from, device_list);
bdrv_device_remove(from);
}
}

Expand Down Expand Up @@ -2366,13 +2392,14 @@ static void bdrv_delete(BlockDriverState *bs)
assert(!bs->job);
assert(bdrv_op_blocker_is_empty(bs));
assert(!bs->refcnt);
assert(QLIST_EMPTY(&bs->dirty_bitmaps));

bdrv_close(bs);

/* remove from list, if necessary */
bdrv_make_anon(bs);

QTAILQ_REMOVE(&all_bdrv_states, bs, bs_list);

g_free(bs);
}

Expand Down Expand Up @@ -3582,21 +3609,40 @@ static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
}
}

void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
static void bdrv_do_release_matching_dirty_bitmap(BlockDriverState *bs,
BdrvDirtyBitmap *bitmap,
bool only_named)
{
BdrvDirtyBitmap *bm, *next;
QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
if (bm == bitmap) {
if ((!bitmap || bm == bitmap) && (!only_named || bm->name)) {
assert(!bdrv_dirty_bitmap_frozen(bm));
QLIST_REMOVE(bitmap, list);
hbitmap_free(bitmap->bitmap);
g_free(bitmap->name);
g_free(bitmap);
return;
QLIST_REMOVE(bm, list);
hbitmap_free(bm->bitmap);
g_free(bm->name);
g_free(bm);

if (bitmap) {
return;
}
}
}
}

void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
{
bdrv_do_release_matching_dirty_bitmap(bs, bitmap, false);
}

/**
* Release all named dirty bitmaps attached to a BDS (for use in bdrv_close()).
* There must not be any frozen bitmaps attached.
*/
static void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs)
{
bdrv_do_release_matching_dirty_bitmap(bs, NULL, true);
}

void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
{
assert(!bdrv_dirty_bitmap_frozen(bitmap));
Expand Down
53 changes: 44 additions & 9 deletions block/block-backend.c
Expand Up @@ -49,6 +49,8 @@ struct BlockBackend {
BlockdevOnError on_read_error, on_write_error;
bool iostatus_enabled;
BlockDeviceIoStatus iostatus;

NotifierList remove_bs_notifiers, insert_bs_notifiers;
};

typedef struct BlockBackendAIOCB {
Expand Down Expand Up @@ -99,6 +101,8 @@ BlockBackend *blk_new(const char *name, Error **errp)
blk = g_new0(BlockBackend, 1);
blk->name = g_strdup(name);
blk->refcnt = 1;
notifier_list_init(&blk->remove_bs_notifiers);
notifier_list_init(&blk->insert_bs_notifiers);
QTAILQ_INSERT_TAIL(&blk_backends, blk, link);
return blk;
}
Expand Down Expand Up @@ -162,11 +166,10 @@ static void blk_delete(BlockBackend *blk)
assert(!blk->refcnt);
assert(!blk->dev);
if (blk->bs) {
assert(blk->bs->blk == blk);
blk->bs->blk = NULL;
bdrv_unref(blk->bs);
blk->bs = NULL;
blk_remove_bs(blk);
}
assert(QLIST_EMPTY(&blk->remove_bs_notifiers.notifiers));
assert(QLIST_EMPTY(&blk->insert_bs_notifiers.notifiers));
if (blk->root_state.throttle_state) {
g_free(blk->root_state.throttle_group);
throttle_group_unref(blk->root_state.throttle_state);
Expand Down Expand Up @@ -220,6 +223,21 @@ void blk_unref(BlockBackend *blk)
}
}

void blk_remove_all_bs(void)
{
BlockBackend *blk;

QTAILQ_FOREACH(blk, &blk_backends, link) {
AioContext *ctx = blk_get_aio_context(blk);

aio_context_acquire(ctx);
if (blk->bs) {
blk_remove_bs(blk);
}
aio_context_release(ctx);
}
}

/*
* Return the BlockBackend after @blk.
* If @blk is null, return the first one.
Expand Down Expand Up @@ -345,6 +363,10 @@ void blk_hide_on_behalf_of_hmp_drive_del(BlockBackend *blk)
*/
void blk_remove_bs(BlockBackend *blk)
{
assert(blk->bs->blk == blk);

notifier_list_notify(&blk->remove_bs_notifiers, blk);

blk_update_root_state(blk);

blk->bs->blk = NULL;
Expand All @@ -361,6 +383,8 @@ void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
bdrv_ref(bs);
blk->bs = bs;
bs->blk = blk;

notifier_list_notify(&blk->insert_bs_notifiers, blk);
}

/*
Expand Down Expand Up @@ -458,6 +482,14 @@ bool blk_dev_has_removable_media(BlockBackend *blk)
return !blk->dev || (blk->dev_ops && blk->dev_ops->change_media_cb);
}

/*
* Does @blk's attached device model have a tray?
*/
bool blk_dev_has_tray(BlockBackend *blk)
{
return blk->dev_ops && blk->dev_ops->is_tray_open;
}

/*
* Notify @blk's attached device model of a media eject request.
* If @force is true, the medium is about to be yanked out forcefully.
Expand All @@ -474,7 +506,7 @@ void blk_dev_eject_request(BlockBackend *blk, bool force)
*/
bool blk_dev_is_tray_open(BlockBackend *blk)
{
if (blk->dev_ops && blk->dev_ops->is_tray_open) {
if (blk_dev_has_tray(blk)) {
return blk->dev_ops->is_tray_open(blk->dev_opaque);
}
return false;
Expand Down Expand Up @@ -1118,11 +1150,14 @@ void blk_remove_aio_context_notifier(BlockBackend *blk,
}
}

void blk_add_close_notifier(BlockBackend *blk, Notifier *notify)
void blk_add_remove_bs_notifier(BlockBackend *blk, Notifier *notify)
{
if (blk->bs) {
bdrv_add_close_notifier(blk->bs, notify);
}
notifier_list_add(&blk->remove_bs_notifiers, notify);
}

void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify)
{
notifier_list_add(&blk->insert_bs_notifiers, notify);
}

void blk_io_plug(BlockBackend *blk)
Expand Down

0 comments on commit c65db77

Please sign in to comment.