Skip to content

Commit

Permalink
blockdev: acquire AioContext in eject, change, and block_passwd
Browse files Browse the repository at this point in the history
By acquiring the AioContext we avoid race conditions with the dataplane
thread which may also be accessing the BlockDriverState.

Fix up eject, change, and block_passwd in a single patch because
qmp_eject() and qmp_change_blockdev() both call eject_device().  Also
fix block_passwd while we're tackling a command that takes a block
encryption password.

Signed-off-by: Stefan Hajnoczi <[email protected]>
Reviewed-by: Max Reitz <[email protected]>
Signed-off-by: Max Reitz <[email protected]>
Signed-off-by: Kevin Wolf <[email protected]>
  • Loading branch information
stefanhaRH authored and kevmw committed Dec 10, 2014
1 parent 0b92885 commit e344209
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 7 deletions.
36 changes: 29 additions & 7 deletions blockdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1617,26 +1617,33 @@ void qmp_transaction(TransactionActionList *dev_list, Error **errp)
static void eject_device(BlockBackend *blk, int force, Error **errp)
{
BlockDriverState *bs = blk_bs(blk);
AioContext *aio_context;

aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);

if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
return;
goto out;
}
if (!blk_dev_has_removable_media(blk)) {
error_setg(errp, "Device '%s' is not removable",
bdrv_get_device_name(bs));
return;
goto out;
}

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));
return;
goto out;
}
}

bdrv_close(bs);

out:
aio_context_release(aio_context);
}

void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
Expand All @@ -1658,6 +1665,7 @@ void qmp_block_passwd(bool has_device, const char *device,
{
Error *local_err = NULL;
BlockDriverState *bs;
AioContext *aio_context;
int err;

bs = bdrv_lookup_bs(has_device ? device : NULL,
Expand All @@ -1668,16 +1676,23 @@ void qmp_block_passwd(bool has_device, const char *device,
return;
}

aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);

err = bdrv_set_key(bs, password);
if (err == -EINVAL) {
error_set(errp, QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
return;
goto out;
} else if (err < 0) {
error_set(errp, QERR_INVALID_PASSWORD);
return;
goto out;
}

out:
aio_context_release(aio_context);
}

/* Assumes AioContext is held */
static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
int bdrv_flags, BlockDriver *drv,
const char *password, Error **errp)
Expand Down Expand Up @@ -1710,6 +1725,7 @@ void qmp_change_blockdev(const char *device, const char *filename,
{
BlockBackend *blk;
BlockDriverState *bs;
AioContext *aio_context;
BlockDriver *drv = NULL;
int bdrv_flags;
Error *err = NULL;
Expand All @@ -1721,24 +1737,30 @@ void qmp_change_blockdev(const char *device, const char *filename,
}
bs = blk_bs(blk);

aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);

if (format) {
drv = bdrv_find_whitelisted_format(format, bs->read_only);
if (!drv) {
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
return;
goto out;
}
}

eject_device(blk, 0, &err);
if (err) {
error_propagate(errp, err);
return;
goto out;
}

bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;

qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp);

out:
aio_context_release(aio_context);
}

/* throttling disk I/O limits */
Expand Down
1 change: 1 addition & 0 deletions hw/block/dataplane/virtio-blk.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
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_COMMIT, s->blocker);
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EJECT, 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, s->blocker);
Expand Down

0 comments on commit e344209

Please sign in to comment.