Add an option to qmp_change_blockdev() which allows changing the read-only status of the block device to be changed.
Some drives do not have a inherently fixed read-only status; for instance, floppy disks can be set read-only or writable independently of the drive. Some users may find it useful to be able to therefore change the read-only status of a block device when changing the medium. Signed-off-by: Max Reitz <mre...@redhat.com> --- blockdev.c | 41 ++++++++++++++++++++++++++++++++++++++--- include/sysemu/blockdev.h | 3 ++- qapi-schema.json | 20 ++++++++++++++++++++ qmp.c | 3 ++- 4 files changed, 62 insertions(+), 5 deletions(-) diff --git a/blockdev.c b/blockdev.c index a52f205..4140a27 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1721,7 +1721,8 @@ static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename, } void qmp_change_blockdev(const char *device, const char *filename, - const char *format, Error **errp) + const char *format, + BlockdevChangeReadOnlyMode read_only, Error **errp) { BlockBackend *blk; BlockDriverState *bs; @@ -1754,10 +1755,44 @@ void qmp_change_blockdev(const char *device, const char *filename, goto out; } - bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR; + switch (read_only) { + case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN: + bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR; + break; + + case BLOCKDEV_CHANGE_READ_ONLY_MODE_RO: + bdrv_flags = 0; + break; + + case BLOCKDEV_CHANGE_READ_ONLY_MODE_RW: + bdrv_flags = BDRV_O_RDWR; + break; + + case BLOCKDEV_CHANGE_READ_ONLY_MODE_AUTO: + /* try RDWR first */ + bdrv_flags = BDRV_O_RDWR; + break; + + default: + abort(); + } + bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0; - qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp); + qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, &err); + + if (err) { + if (read_only == BLOCKDEV_CHANGE_READ_ONLY_MODE_AUTO) { + error_free(err); + err = NULL; + + /* RDWR did not work, try RO now */ + bdrv_flags &= ~BDRV_O_RDWR; + qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp); + } else { + error_propagate(errp, err); + } + } out: aio_context_release(aio_context); diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h index 09d1e30..14b4dfb 100644 --- a/include/sysemu/blockdev.h +++ b/include/sysemu/blockdev.h @@ -66,7 +66,8 @@ DriveInfo *drive_new(QemuOpts *arg, BlockInterfaceType block_default_type); DriveInfo *add_init_drive(const char *opts); void qmp_change_blockdev(const char *device, const char *filename, - const char *format, Error **errp); + const char *format, + BlockdevChangeReadOnlyMode read_only, Error **errp); void do_commit(Monitor *mon, const QDict *qdict); int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data); #endif diff --git a/qapi-schema.json b/qapi-schema.json index d0926d9..441e001 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1543,6 +1543,26 @@ { 'command': 'change-vnc-password', 'data': {'password': 'str'} } ## +# @BlockdevChangeReadOnlyMode: +# +# Specifies the new read-only mode of a block device subject to the @change +# command. +# +# @retain: Retains the current read-only mode +# +# @ro: Makes the device read-only +# +# @rw: Makes the device writable +# +# @auto: If the file specified can be opened with write access, the block +# device will be writable; otherwise it will be read-only +# +# Since: 2.3 +## +{ 'enum': 'BlockdevChangeReadOnlyMode', + 'data': ['retain', 'ro', 'rw', 'auto'] } + +## # @change: # # This command is multiple commands multiplexed together. diff --git a/qmp.c b/qmp.c index 0b4f131..bd63cf4 100644 --- a/qmp.c +++ b/qmp.c @@ -402,7 +402,8 @@ void qmp_change(const char *device, const char *target, if (strcmp(device, "vnc") == 0) { qmp_change_vnc(target, has_arg, arg, errp); } else { - qmp_change_blockdev(device, target, arg, errp); + qmp_change_blockdev(device, target, arg, + BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, errp); } } -- 1.9.3