提交 ee55b173 编写于 作者: K Kevin Wolf

qcow2: Make qcow2_update_options() suitable for transactions

Before we can allow updating options at runtime with bdrv_reopen(), we
need to split the function into prepare/commit/abort parts.
Signed-off-by: NKevin Wolf <kwolf@redhat.com>
Reviewed-by: NMax Reitz <mreitz@redhat.com>
上级 c1344ded
...@@ -589,18 +589,25 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, ...@@ -589,18 +589,25 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts,
} }
} }
static int qcow2_update_options(BlockDriverState *bs, QDict *options, typedef struct Qcow2ReopenState {
int flags, Error **errp) Qcow2Cache *l2_table_cache;
Qcow2Cache *refcount_block_cache;
bool use_lazy_refcounts;
int overlap_check;
bool discard_passthrough[QCOW2_DISCARD_MAX];
uint64_t cache_clean_interval;
} Qcow2ReopenState;
static int qcow2_update_options_prepare(BlockDriverState *bs,
Qcow2ReopenState *r,
QDict *options, int flags,
Error **errp)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
QemuOpts *opts = NULL; QemuOpts *opts = NULL;
const char *opt_overlap_check, *opt_overlap_check_template; const char *opt_overlap_check, *opt_overlap_check_template;
int overlap_check_template = 0; int overlap_check_template = 0;
uint64_t l2_cache_size, refcount_cache_size; uint64_t l2_cache_size, refcount_cache_size;
Qcow2Cache *l2_table_cache = NULL;
Qcow2Cache *refcount_block_cache = NULL;
uint64_t cache_clean_interval;
bool use_lazy_refcounts;
int i; int i;
Error *local_err = NULL; Error *local_err = NULL;
int ret; int ret;
...@@ -643,27 +650,27 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options, ...@@ -643,27 +650,27 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
} }
/* alloc L2 table/refcount block cache */ /* alloc L2 table/refcount block cache */
l2_table_cache = qcow2_cache_create(bs, l2_cache_size); r->l2_table_cache = qcow2_cache_create(bs, l2_cache_size);
refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size); r->refcount_block_cache = qcow2_cache_create(bs, refcount_cache_size);
if (l2_table_cache == NULL || refcount_block_cache == NULL) { if (r->l2_table_cache == NULL || r->refcount_block_cache == NULL) {
error_setg(errp, "Could not allocate metadata caches"); error_setg(errp, "Could not allocate metadata caches");
ret = -ENOMEM; ret = -ENOMEM;
goto fail; goto fail;
} }
/* New interval for cache cleanup timer */ /* New interval for cache cleanup timer */
cache_clean_interval = r->cache_clean_interval =
qemu_opt_get_number(opts, QCOW2_OPT_CACHE_CLEAN_INTERVAL, 0); qemu_opt_get_number(opts, QCOW2_OPT_CACHE_CLEAN_INTERVAL, 0);
if (cache_clean_interval > UINT_MAX) { if (r->cache_clean_interval > UINT_MAX) {
error_setg(errp, "Cache clean interval too big"); error_setg(errp, "Cache clean interval too big");
ret = -EINVAL; ret = -EINVAL;
goto fail; goto fail;
} }
/* Enable lazy_refcounts according to image and command line options */ /* Enable lazy_refcounts according to image and command line options */
use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS, r->use_lazy_refcounts = qemu_opt_get_bool(opts, QCOW2_OPT_LAZY_REFCOUNTS,
(s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS)); (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS));
if (use_lazy_refcounts && s->qcow_version < 3) { if (r->use_lazy_refcounts && s->qcow_version < 3) {
error_setg(errp, "Lazy refcounts require a qcow2 image with at least " error_setg(errp, "Lazy refcounts require a qcow2 image with at least "
"qemu 1.1 compatibility level"); "qemu 1.1 compatibility level");
ret = -EINVAL; ret = -EINVAL;
...@@ -702,49 +709,75 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options, ...@@ -702,49 +709,75 @@ static int qcow2_update_options(BlockDriverState *bs, QDict *options,
goto fail; goto fail;
} }
/* r->overlap_check = 0;
* Start updating fields in BDRVQcow2State.
* After this point no failure is allowed any more.
*/
s->overlap_check = 0;
for (i = 0; i < QCOW2_OL_MAX_BITNR; i++) { for (i = 0; i < QCOW2_OL_MAX_BITNR; i++) {
/* overlap-check defines a template bitmask, but every flag may be /* overlap-check defines a template bitmask, but every flag may be
* overwritten through the associated boolean option */ * overwritten through the associated boolean option */
s->overlap_check |= r->overlap_check |=
qemu_opt_get_bool(opts, overlap_bool_option_names[i], qemu_opt_get_bool(opts, overlap_bool_option_names[i],
overlap_check_template & (1 << i)) << i; overlap_check_template & (1 << i)) << i;
} }
s->l2_table_cache = l2_table_cache; r->discard_passthrough[QCOW2_DISCARD_NEVER] = false;
s->refcount_block_cache = refcount_block_cache; r->discard_passthrough[QCOW2_DISCARD_ALWAYS] = true;
r->discard_passthrough[QCOW2_DISCARD_REQUEST] =
s->use_lazy_refcounts = use_lazy_refcounts;
s->discard_passthrough[QCOW2_DISCARD_NEVER] = false;
s->discard_passthrough[QCOW2_DISCARD_ALWAYS] = true;
s->discard_passthrough[QCOW2_DISCARD_REQUEST] =
qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_REQUEST, qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_REQUEST,
flags & BDRV_O_UNMAP); flags & BDRV_O_UNMAP);
s->discard_passthrough[QCOW2_DISCARD_SNAPSHOT] = r->discard_passthrough[QCOW2_DISCARD_SNAPSHOT] =
qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_SNAPSHOT, true); qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_SNAPSHOT, true);
s->discard_passthrough[QCOW2_DISCARD_OTHER] = r->discard_passthrough[QCOW2_DISCARD_OTHER] =
qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false); qemu_opt_get_bool(opts, QCOW2_OPT_DISCARD_OTHER, false);
s->cache_clean_interval = cache_clean_interval;
cache_clean_timer_init(bs, bdrv_get_aio_context(bs));
ret = 0; ret = 0;
fail: fail:
if (ret < 0) {
if (l2_table_cache) {
qcow2_cache_destroy(bs, l2_table_cache);
}
if (refcount_block_cache) {
qcow2_cache_destroy(bs, refcount_block_cache);
}
}
qemu_opts_del(opts); qemu_opts_del(opts);
opts = NULL; opts = NULL;
return ret;
}
static void qcow2_update_options_commit(BlockDriverState *bs,
Qcow2ReopenState *r)
{
BDRVQcow2State *s = bs->opaque;
int i;
s->l2_table_cache = r->l2_table_cache;
s->refcount_block_cache = r->refcount_block_cache;
s->overlap_check = r->overlap_check;
s->use_lazy_refcounts = r->use_lazy_refcounts;
for (i = 0; i < QCOW2_DISCARD_MAX; i++) {
s->discard_passthrough[i] = r->discard_passthrough[i];
}
s->cache_clean_interval = r->cache_clean_interval;
cache_clean_timer_init(bs, bdrv_get_aio_context(bs));
}
static void qcow2_update_options_abort(BlockDriverState *bs,
Qcow2ReopenState *r)
{
if (r->l2_table_cache) {
qcow2_cache_destroy(bs, r->l2_table_cache);
}
if (r->refcount_block_cache) {
qcow2_cache_destroy(bs, r->refcount_block_cache);
}
}
static int qcow2_update_options(BlockDriverState *bs, QDict *options,
int flags, Error **errp)
{
Qcow2ReopenState r = {};
int ret;
ret = qcow2_update_options_prepare(bs, &r, options, flags, errp);
if (ret >= 0) {
qcow2_update_options_commit(bs, &r);
} else {
qcow2_update_options_abort(bs, &r);
}
return ret; return ret;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册