qcow2: Invoke refcount order amendment function

Make use of qcow2_change_refcount_order() to support changing the
refcount order with qemu-img amend.

Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
master
Max Reitz 2015-07-27 17:51:38 +02:00 committed by Kevin Wolf
parent 791c9a004e
commit 61ce55fc02
1 changed files with 35 additions and 9 deletions

View File

@ -2885,13 +2885,7 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
}
if (s->refcount_order != 4) {
/* we would have to convert the image to a refcount_order == 4 image
* here; however, since qemu (at the time of writing this) does not
* support anything different than 4 anyway, there is no point in doing
* so right now; however, we should error out (if qemu supports this in
* the future and this code has not been adapted) */
error_report("qcow2_downgrade: Image refcount orders other than 4 are "
"currently not supported.");
error_report("compat=0.10 requires refcount_bits=16");
return -ENOTSUP;
}
@ -2939,6 +2933,7 @@ typedef enum Qcow2AmendOperation {
* invocation from an operation change */
QCOW2_NO_OPERATION = 0,
QCOW2_CHANGING_REFCOUNT_ORDER,
QCOW2_DOWNGRADING,
} Qcow2AmendOperation;
@ -3014,6 +3009,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
const char *compat = NULL;
uint64_t cluster_size = s->cluster_size;
bool encrypt;
int refcount_bits = s->refcount_bits;
int ret;
QemuOptDesc *desc = opts->list->desc;
Qcow2AmendHelperCBInfo helper_cb_info;
@ -3065,8 +3061,16 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
lazy_refcounts = qemu_opt_get_bool(opts, BLOCK_OPT_LAZY_REFCOUNTS,
lazy_refcounts);
} else if (!strcmp(desc->name, BLOCK_OPT_REFCOUNT_BITS)) {
error_report("Cannot change refcount entry width");
return -ENOTSUP;
refcount_bits = qemu_opt_get_number(opts, BLOCK_OPT_REFCOUNT_BITS,
refcount_bits);
if (refcount_bits <= 0 || refcount_bits > 64 ||
!is_power_of_2(refcount_bits))
{
error_report("Refcount width must be a power of two and may "
"not exceed 64 bits");
return -EINVAL;
}
} else {
/* if this point is reached, this probably means a new option was
* added without having it covered here */
@ -3080,6 +3084,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
.original_status_cb = status_cb,
.original_cb_opaque = cb_opaque,
.total_operations = (new_version < old_version)
+ (s->refcount_bits != refcount_bits)
};
/* Upgrade first (some features may require compat=1.1) */
@ -3092,6 +3097,27 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
}
}
if (s->refcount_bits != refcount_bits) {
int refcount_order = ctz32(refcount_bits);
Error *local_error = NULL;
if (new_version < 3 && refcount_bits != 16) {
error_report("Different refcount widths than 16 bits require "
"compatibility level 1.1 or above (use compat=1.1 or "
"greater)");
return -EINVAL;
}
helper_cb_info.current_operation = QCOW2_CHANGING_REFCOUNT_ORDER;
ret = qcow2_change_refcount_order(bs, refcount_order,
&qcow2_amend_helper_cb,
&helper_cb_info, &local_error);
if (ret < 0) {
error_report_err(local_error);
return ret;
}
}
if (backing_file || backing_format) {
ret = qcow2_change_backing_file(bs,
backing_file ?: s->image_backing_file,