提交 007e620a 编写于 作者: P Peter Maydell

Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging

Block layer patches (v2)

# gpg: Signature made Mon 14 Sep 2015 15:56:54 BST using RSA key ID C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"

* remotes/kevin/tags/for-upstream: (23 commits)
  qcow2: Make qcow2_alloc_bytes() more explicit
  vmdk: Fix next_cluster_sector for compressed write
  iotests: Add test for checking large image files
  qcow2: Make size_to_clusters() return uint64_t
  qemu-iotests: More qcow2 reopen tests
  qemu-iotests: Reopen qcow2 with lazy-refcounts change
  qcow2: Support updating driver-specific options in reopen
  qcow2: Make qcow2_update_options() suitable for transactions
  qcow2: Fix memory leak in qcow2_update_options() error path
  qcow2: Leave s unchanged on qcow2_update_options() failure
  qcow2: Move rest of option handling to qcow2_update_options()
  qcow2: Move qcow2_update_options() call up
  qcow2: Factor out qcow2_update_options()
  qcow2: Improve error message
  qemu-io: Add command 'reopen'
  qemu-io: Remove duplicate 'open' error message
  block: Allow specifying driver-specific options to reopen
  qcow2: Rename BDRVQcowState to BDRVQcow2State
  block: Drop bdrv_find_whitelisted_format()
  block: Drop drv parameter from bdrv_fill_options()
  ...
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
...@@ -85,8 +85,7 @@ static QLIST_HEAD(, BlockDriver) bdrv_drivers = ...@@ -85,8 +85,7 @@ static QLIST_HEAD(, BlockDriver) bdrv_drivers =
static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
const char *reference, QDict *options, int flags, const char *reference, QDict *options, int flags,
BlockDriverState *parent, BlockDriverState *parent,
const BdrvChildRole *child_role, const BdrvChildRole *child_role, Error **errp);
BlockDriver *drv, Error **errp);
static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs); static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
/* If non-zero, use only whitelisted block drivers */ /* If non-zero, use only whitelisted block drivers */
...@@ -314,13 +313,6 @@ static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) ...@@ -314,13 +313,6 @@ static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
return 0; return 0;
} }
BlockDriver *bdrv_find_whitelisted_format(const char *format_name,
bool read_only)
{
BlockDriver *drv = bdrv_find_format(format_name);
return drv && bdrv_is_whitelisted(drv, read_only) ? drv : NULL;
}
typedef struct CreateCo { typedef struct CreateCo {
BlockDriver *drv; BlockDriver *drv;
char *filename; char *filename;
...@@ -997,13 +989,13 @@ static QDict *parse_json_filename(const char *filename, Error **errp) ...@@ -997,13 +989,13 @@ static QDict *parse_json_filename(const char *filename, Error **errp)
* block driver has been specified explicitly. * block driver has been specified explicitly.
*/ */
static int bdrv_fill_options(QDict **options, const char **pfilename, static int bdrv_fill_options(QDict **options, const char **pfilename,
int *flags, BlockDriver *drv, Error **errp) int *flags, Error **errp)
{ {
const char *filename = *pfilename; const char *filename = *pfilename;
const char *drvname; const char *drvname;
bool protocol = *flags & BDRV_O_PROTOCOL; bool protocol = *flags & BDRV_O_PROTOCOL;
bool parse_filename = false; bool parse_filename = false;
BlockDriver *tmp_drv; BlockDriver *drv = NULL;
Error *local_err = NULL; Error *local_err = NULL;
/* Parse json: pseudo-protocol */ /* Parse json: pseudo-protocol */
...@@ -1022,15 +1014,15 @@ static int bdrv_fill_options(QDict **options, const char **pfilename, ...@@ -1022,15 +1014,15 @@ static int bdrv_fill_options(QDict **options, const char **pfilename,
} }
drvname = qdict_get_try_str(*options, "driver"); drvname = qdict_get_try_str(*options, "driver");
if (drvname) {
/* If the user has explicitly specified the driver, this choice should drv = bdrv_find_format(drvname);
* override the BDRV_O_PROTOCOL flag */ if (!drv) {
tmp_drv = drv; error_setg(errp, "Unknown driver '%s'", drvname);
if (!tmp_drv && drvname) { return -ENOENT;
tmp_drv = bdrv_find_format(drvname); }
} /* If the user has explicitly specified the driver, this choice should
if (tmp_drv) { * override the BDRV_O_PROTOCOL flag */
protocol = tmp_drv->bdrv_file_open; protocol = drv->bdrv_file_open;
} }
if (protocol) { if (protocol) {
...@@ -1054,33 +1046,18 @@ static int bdrv_fill_options(QDict **options, const char **pfilename, ...@@ -1054,33 +1046,18 @@ static int bdrv_fill_options(QDict **options, const char **pfilename,
/* Find the right block driver */ /* Find the right block driver */
filename = qdict_get_try_str(*options, "filename"); filename = qdict_get_try_str(*options, "filename");
if (drv) { if (!drvname && protocol) {
if (drvname) { if (filename) {
error_setg(errp, "Driver specified twice"); drv = bdrv_find_protocol(filename, parse_filename, errp);
return -EINVAL;
}
drvname = drv->format_name;
qdict_put(*options, "driver", qstring_from_str(drvname));
} else {
if (!drvname && protocol) {
if (filename) {
drv = bdrv_find_protocol(filename, parse_filename, errp);
if (!drv) {
return -EINVAL;
}
drvname = drv->format_name;
qdict_put(*options, "driver", qstring_from_str(drvname));
} else {
error_setg(errp, "Must specify either driver or file");
return -EINVAL;
}
} else if (drvname) {
drv = bdrv_find_format(drvname);
if (!drv) { if (!drv) {
error_setg(errp, "Unknown driver '%s'", drvname); return -EINVAL;
return -ENOENT;
} }
drvname = drv->format_name;
qdict_put(*options, "driver", qstring_from_str(drvname));
} else {
error_setg(errp, "Must specify either driver or file");
return -EINVAL;
} }
} }
...@@ -1227,8 +1204,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) ...@@ -1227,8 +1204,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
assert(bs->backing_hd == NULL); assert(bs->backing_hd == NULL);
ret = bdrv_open_inherit(&backing_hd, ret = bdrv_open_inherit(&backing_hd,
*backing_filename ? backing_filename : NULL, *backing_filename ? backing_filename : NULL,
NULL, options, 0, bs, &child_backing, NULL, options, 0, bs, &child_backing, &local_err);
NULL, &local_err);
if (ret < 0) { if (ret < 0) {
bdrv_unref(backing_hd); bdrv_unref(backing_hd);
backing_hd = NULL; backing_hd = NULL;
...@@ -1291,7 +1267,7 @@ BdrvChild *bdrv_open_child(const char *filename, ...@@ -1291,7 +1267,7 @@ BdrvChild *bdrv_open_child(const char *filename,
bs = NULL; bs = NULL;
ret = bdrv_open_inherit(&bs, filename, reference, image_options, 0, ret = bdrv_open_inherit(&bs, filename, reference, image_options, 0,
parent, child_role, NULL, errp); parent, child_role, errp);
if (ret < 0) { if (ret < 0) {
goto done; goto done;
} }
...@@ -1385,11 +1361,13 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp) ...@@ -1385,11 +1361,13 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
qstring_from_str("file")); qstring_from_str("file"));
qdict_put(snapshot_options, "file.filename", qdict_put(snapshot_options, "file.filename",
qstring_from_str(tmp_filename)); qstring_from_str(tmp_filename));
qdict_put(snapshot_options, "driver",
qstring_from_str("qcow2"));
bs_snapshot = bdrv_new(); bs_snapshot = bdrv_new();
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options, ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
flags, &bdrv_qcow2, &local_err); flags, &local_err);
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto out; goto out;
...@@ -1420,11 +1398,11 @@ out: ...@@ -1420,11 +1398,11 @@ out:
static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
const char *reference, QDict *options, int flags, const char *reference, QDict *options, int flags,
BlockDriverState *parent, BlockDriverState *parent,
const BdrvChildRole *child_role, const BdrvChildRole *child_role, Error **errp)
BlockDriver *drv, Error **errp)
{ {
int ret; int ret;
BlockDriverState *file = NULL, *bs; BlockDriverState *file = NULL, *bs;
BlockDriver *drv = NULL;
const char *drvname; const char *drvname;
Error *local_err = NULL; Error *local_err = NULL;
int snapshot_flags = 0; int snapshot_flags = 0;
...@@ -1474,13 +1452,12 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, ...@@ -1474,13 +1452,12 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
flags = child_role->inherit_flags(parent->open_flags); flags = child_role->inherit_flags(parent->open_flags);
} }
ret = bdrv_fill_options(&options, &filename, &flags, drv, &local_err); ret = bdrv_fill_options(&options, &filename, &flags, &local_err);
if (local_err) { if (local_err) {
goto fail; goto fail;
} }
/* Find the right image format driver */ /* Find the right image format driver */
drv = NULL;
drvname = qdict_get_try_str(options, "driver"); drvname = qdict_get_try_str(options, "driver");
if (drvname) { if (drvname) {
drv = bdrv_find_format(drvname); drv = bdrv_find_format(drvname);
...@@ -1635,11 +1612,10 @@ close_and_fail: ...@@ -1635,11 +1612,10 @@ close_and_fail:
} }
int bdrv_open(BlockDriverState **pbs, const char *filename, int bdrv_open(BlockDriverState **pbs, const char *filename,
const char *reference, QDict *options, int flags, const char *reference, QDict *options, int flags, Error **errp)
BlockDriver *drv, Error **errp)
{ {
return bdrv_open_inherit(pbs, filename, reference, options, flags, NULL, return bdrv_open_inherit(pbs, filename, reference, options, flags, NULL,
NULL, drv, errp); NULL, errp);
} }
typedef struct BlockReopenQueueEntry { typedef struct BlockReopenQueueEntry {
...@@ -1660,6 +1636,9 @@ typedef struct BlockReopenQueueEntry { ...@@ -1660,6 +1636,9 @@ typedef struct BlockReopenQueueEntry {
* *
* bs is the BlockDriverState to add to the reopen queue. * bs is the BlockDriverState to add to the reopen queue.
* *
* options contains the changed options for the associated bs
* (the BlockReopenQueue takes ownership)
*
* flags contains the open flags for the associated bs * flags contains the open flags for the associated bs
* *
* returns a pointer to bs_queue, which is either the newly allocated * returns a pointer to bs_queue, which is either the newly allocated
...@@ -1667,18 +1646,28 @@ typedef struct BlockReopenQueueEntry { ...@@ -1667,18 +1646,28 @@ typedef struct BlockReopenQueueEntry {
* *
*/ */
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
BlockDriverState *bs, int flags) BlockDriverState *bs,
QDict *options, int flags)
{ {
assert(bs != NULL); assert(bs != NULL);
BlockReopenQueueEntry *bs_entry; BlockReopenQueueEntry *bs_entry;
BdrvChild *child; BdrvChild *child;
QDict *old_options;
if (bs_queue == NULL) { if (bs_queue == NULL) {
bs_queue = g_new0(BlockReopenQueue, 1); bs_queue = g_new0(BlockReopenQueue, 1);
QSIMPLEQ_INIT(bs_queue); QSIMPLEQ_INIT(bs_queue);
} }
if (!options) {
options = qdict_new();
}
old_options = qdict_clone_shallow(bs->options);
qdict_join(options, old_options, false);
QDECREF(old_options);
/* bdrv_open() masks this flag out */ /* bdrv_open() masks this flag out */
flags &= ~BDRV_O_PROTOCOL; flags &= ~BDRV_O_PROTOCOL;
...@@ -1690,13 +1679,15 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, ...@@ -1690,13 +1679,15 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
} }
child_flags = child->role->inherit_flags(flags); child_flags = child->role->inherit_flags(flags);
bdrv_reopen_queue(bs_queue, child->bs, child_flags); /* TODO Pass down child flags (backing.*, extents.*, ...) */
bdrv_reopen_queue(bs_queue, child->bs, NULL, child_flags);
} }
bs_entry = g_new0(BlockReopenQueueEntry, 1); bs_entry = g_new0(BlockReopenQueueEntry, 1);
QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry); QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry);
bs_entry->state.bs = bs; bs_entry->state.bs = bs;
bs_entry->state.options = options;
bs_entry->state.flags = flags; bs_entry->state.flags = flags;
return bs_queue; return bs_queue;
...@@ -1749,6 +1740,7 @@ cleanup: ...@@ -1749,6 +1740,7 @@ cleanup:
if (ret && bs_entry->prepared) { if (ret && bs_entry->prepared) {
bdrv_reopen_abort(&bs_entry->state); bdrv_reopen_abort(&bs_entry->state);
} }
QDECREF(bs_entry->state.options);
g_free(bs_entry); g_free(bs_entry);
} }
g_free(bs_queue); g_free(bs_queue);
...@@ -1761,7 +1753,7 @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp) ...@@ -1761,7 +1753,7 @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp)
{ {
int ret = -1; int ret = -1;
Error *local_err = NULL; Error *local_err = NULL;
BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, bdrv_flags); BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags);
ret = bdrv_reopen_multiple(queue, &local_err); ret = bdrv_reopen_multiple(queue, &local_err);
if (local_err != NULL) { if (local_err != NULL) {
...@@ -1837,6 +1829,26 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, ...@@ -1837,6 +1829,26 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
goto error; goto error;
} }
/* Options that are not handled are only okay if they are unchanged
* compared to the old state. It is expected that some options are only
* used for the initial open, but not reopen (e.g. filename) */
if (qdict_size(reopen_state->options)) {
const QDictEntry *entry = qdict_first(reopen_state->options);
do {
QString *new_obj = qobject_to_qstring(entry->value);
const char *new = qstring_get_str(new_obj);
const char *old = qdict_get_try_str(reopen_state->bs->options,
entry->key);
if (!old || strcmp(new, old)) {
error_setg(errp, "Cannot change the option '%s'", entry->key);
ret = -EINVAL;
goto error;
}
} while ((entry = qdict_next(reopen_state->options, entry)));
}
ret = 0; ret = 0;
error: error:
...@@ -3739,7 +3751,6 @@ void bdrv_img_create(const char *filename, const char *fmt, ...@@ -3739,7 +3751,6 @@ void bdrv_img_create(const char *filename, const char *fmt,
const char *backing_fmt, *backing_file; const char *backing_fmt, *backing_file;
int64_t size; int64_t size;
BlockDriver *drv, *proto_drv; BlockDriver *drv, *proto_drv;
BlockDriver *backing_drv = NULL;
Error *local_err = NULL; Error *local_err = NULL;
int ret = 0; int ret = 0;
...@@ -3813,14 +3824,6 @@ void bdrv_img_create(const char *filename, const char *fmt, ...@@ -3813,14 +3824,6 @@ void bdrv_img_create(const char *filename, const char *fmt,
} }
backing_fmt = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT); backing_fmt = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
if (backing_fmt) {
backing_drv = bdrv_find_format(backing_fmt);
if (!backing_drv) {
error_setg(errp, "Unknown backing file format '%s'",
backing_fmt);
goto out;
}
}
// The size for the image must always be specified, with one exception: // The size for the image must always be specified, with one exception:
// If we are using a backing file, we can obtain the size from there // If we are using a backing file, we can obtain the size from there
...@@ -3831,6 +3834,7 @@ void bdrv_img_create(const char *filename, const char *fmt, ...@@ -3831,6 +3834,7 @@ void bdrv_img_create(const char *filename, const char *fmt,
char *full_backing = g_new0(char, PATH_MAX); char *full_backing = g_new0(char, PATH_MAX);
int64_t size; int64_t size;
int back_flags; int back_flags;
QDict *backing_options = NULL;
bdrv_get_full_backing_filename_from_filename(filename, backing_file, bdrv_get_full_backing_filename_from_filename(filename, backing_file,
full_backing, PATH_MAX, full_backing, PATH_MAX,
...@@ -3844,9 +3848,15 @@ void bdrv_img_create(const char *filename, const char *fmt, ...@@ -3844,9 +3848,15 @@ void bdrv_img_create(const char *filename, const char *fmt,
back_flags = back_flags =
flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING); flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
if (backing_fmt) {
backing_options = qdict_new();
qdict_put(backing_options, "driver",
qstring_from_str(backing_fmt));
}
bs = NULL; bs = NULL;
ret = bdrv_open(&bs, full_backing, NULL, NULL, back_flags, ret = bdrv_open(&bs, full_backing, NULL, backing_options,
backing_drv, &local_err); back_flags, &local_err);
g_free(full_backing); g_free(full_backing);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
......
...@@ -126,7 +126,7 @@ BlockBackend *blk_new_open(const char *name, const char *filename, ...@@ -126,7 +126,7 @@ BlockBackend *blk_new_open(const char *name, const char *filename,
return NULL; return NULL;
} }
ret = bdrv_open(&blk->bs, filename, reference, options, flags, NULL, errp); ret = bdrv_open(&blk->bs, filename, reference, options, flags, errp);
if (ret < 0) { if (ret < 0) {
blk_unref(blk); blk_unref(blk);
return NULL; return NULL;
......
...@@ -236,11 +236,11 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base, ...@@ -236,11 +236,11 @@ void commit_start(BlockDriverState *bs, BlockDriverState *base,
/* convert base & overlay_bs to r/w, if necessary */ /* convert base & overlay_bs to r/w, if necessary */
if (!(orig_base_flags & BDRV_O_RDWR)) { if (!(orig_base_flags & BDRV_O_RDWR)) {
reopen_queue = bdrv_reopen_queue(reopen_queue, base, reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
orig_base_flags | BDRV_O_RDWR); orig_base_flags | BDRV_O_RDWR);
} }
if (!(orig_overlay_flags & BDRV_O_RDWR)) { if (!(orig_overlay_flags & BDRV_O_RDWR)) {
reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL,
orig_overlay_flags | BDRV_O_RDWR); orig_overlay_flags | BDRV_O_RDWR);
} }
if (reopen_queue) { if (reopen_queue) {
......
...@@ -476,7 +476,7 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp) ...@@ -476,7 +476,7 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
file = NULL; file = NULL;
ret = bdrv_open(&file, filename, NULL, NULL, ret = bdrv_open(&file, filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err); BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
return ret; return ret;
......
...@@ -793,7 +793,7 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp) ...@@ -793,7 +793,7 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
qcow_bs = NULL; qcow_bs = NULL;
ret = bdrv_open(&qcow_bs, filename, NULL, NULL, ret = bdrv_open(&qcow_bs, filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err); BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto cleanup; goto cleanup;
......
...@@ -55,14 +55,14 @@ struct Qcow2Cache { ...@@ -55,14 +55,14 @@ struct Qcow2Cache {
static inline void *qcow2_cache_get_table_addr(BlockDriverState *bs, static inline void *qcow2_cache_get_table_addr(BlockDriverState *bs,
Qcow2Cache *c, int table) Qcow2Cache *c, int table)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
return (uint8_t *) c->table_array + (size_t) table * s->cluster_size; return (uint8_t *) c->table_array + (size_t) table * s->cluster_size;
} }
static inline int qcow2_cache_get_table_idx(BlockDriverState *bs, static inline int qcow2_cache_get_table_idx(BlockDriverState *bs,
Qcow2Cache *c, void *table) Qcow2Cache *c, void *table)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
ptrdiff_t table_offset = (uint8_t *) table - (uint8_t *) c->table_array; ptrdiff_t table_offset = (uint8_t *) table - (uint8_t *) c->table_array;
int idx = table_offset / s->cluster_size; int idx = table_offset / s->cluster_size;
assert(idx >= 0 && idx < c->size && table_offset % s->cluster_size == 0); assert(idx >= 0 && idx < c->size && table_offset % s->cluster_size == 0);
...@@ -73,7 +73,7 @@ static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c, ...@@ -73,7 +73,7 @@ static void qcow2_cache_table_release(BlockDriverState *bs, Qcow2Cache *c,
int i, int num_tables) int i, int num_tables)
{ {
#if QEMU_MADV_DONTNEED != QEMU_MADV_INVALID #if QEMU_MADV_DONTNEED != QEMU_MADV_INVALID
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
void *t = qcow2_cache_get_table_addr(bs, c, i); void *t = qcow2_cache_get_table_addr(bs, c, i);
int align = getpagesize(); int align = getpagesize();
size_t mem_size = (size_t) s->cluster_size * num_tables; size_t mem_size = (size_t) s->cluster_size * num_tables;
...@@ -121,7 +121,7 @@ void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c) ...@@ -121,7 +121,7 @@ void qcow2_cache_clean_unused(BlockDriverState *bs, Qcow2Cache *c)
Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables) Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
Qcow2Cache *c; Qcow2Cache *c;
c = g_new0(Qcow2Cache, 1); c = g_new0(Qcow2Cache, 1);
...@@ -172,7 +172,7 @@ static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c) ...@@ -172,7 +172,7 @@ static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int ret = 0; int ret = 0;
if (!c->entries[i].dirty || !c->entries[i].offset) { if (!c->entries[i].dirty || !c->entries[i].offset) {
...@@ -229,7 +229,7 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) ...@@ -229,7 +229,7 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c) int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int result = 0; int result = 0;
int ret; int ret;
int i; int i;
...@@ -306,7 +306,7 @@ int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c) ...@@ -306,7 +306,7 @@ int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c)
static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c, static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c,
uint64_t offset, void **table, bool read_from_disk) uint64_t offset, void **table, bool read_from_disk)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int i; int i;
int ret; int ret;
int lookup_index; int lookup_index;
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
bool exact_size) bool exact_size)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int new_l1_size2, ret, i; int new_l1_size2, ret, i;
uint64_t *new_l1_table; uint64_t *new_l1_table;
int64_t old_l1_table_offset, old_l1_size; int64_t old_l1_table_offset, old_l1_size;
...@@ -148,7 +148,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, ...@@ -148,7 +148,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
static int l2_load(BlockDriverState *bs, uint64_t l2_offset, static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
uint64_t **l2_table) uint64_t **l2_table)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int ret; int ret;
ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset, (void**) l2_table); ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset, (void**) l2_table);
...@@ -163,7 +163,7 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset, ...@@ -163,7 +163,7 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
#define L1_ENTRIES_PER_SECTOR (512 / 8) #define L1_ENTRIES_PER_SECTOR (512 / 8)
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index) int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t buf[L1_ENTRIES_PER_SECTOR] = { 0 }; uint64_t buf[L1_ENTRIES_PER_SECTOR] = { 0 };
int l1_start_index; int l1_start_index;
int i, ret; int i, ret;
...@@ -203,7 +203,7 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index) ...@@ -203,7 +203,7 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table) static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t old_l2_offset; uint64_t old_l2_offset;
uint64_t *l2_table = NULL; uint64_t *l2_table = NULL;
int64_t l2_offset; int64_t l2_offset;
...@@ -298,7 +298,7 @@ fail: ...@@ -298,7 +298,7 @@ fail:
* as contiguous. (This allows it, for example, to stop at the first compressed * as contiguous. (This allows it, for example, to stop at the first compressed
* cluster which may require a different handling) * cluster which may require a different handling)
*/ */
static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size, static int count_contiguous_clusters(int nb_clusters, int cluster_size,
uint64_t *l2_table, uint64_t stop_flags) uint64_t *l2_table, uint64_t stop_flags)
{ {
int i; int i;
...@@ -321,7 +321,7 @@ static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size, ...@@ -321,7 +321,7 @@ static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
return i; return i;
} }
static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table) static int count_contiguous_free_clusters(int nb_clusters, uint64_t *l2_table)
{ {
int i; int i;
...@@ -339,7 +339,7 @@ static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_tab ...@@ -339,7 +339,7 @@ static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_tab
/* The crypt function is compatible with the linux cryptoloop /* The crypt function is compatible with the linux cryptoloop
algorithm for < 4 GB images. NOTE: out_buf == in_buf is algorithm for < 4 GB images. NOTE: out_buf == in_buf is
supported */ supported */
int qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num, int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf, uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, bool enc, int nb_sectors, bool enc,
Error **errp) Error **errp)
...@@ -387,7 +387,7 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs, ...@@ -387,7 +387,7 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
uint64_t cluster_offset, uint64_t cluster_offset,
int n_start, int n_end) int n_start, int n_end)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
QEMUIOVector qiov; QEMUIOVector qiov;
struct iovec iov; struct iovec iov;
int n, ret; int n, ret;
...@@ -469,7 +469,7 @@ out: ...@@ -469,7 +469,7 @@ out:
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
int *num, uint64_t *cluster_offset) int *num, uint64_t *cluster_offset)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
unsigned int l2_index; unsigned int l2_index;
uint64_t l1_index, l2_offset, *l2_table; uint64_t l1_index, l2_offset, *l2_table;
int l1_bits, c; int l1_bits, c;
...@@ -495,6 +495,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, ...@@ -495,6 +495,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
if (nb_needed > nb_available) { if (nb_needed > nb_available) {
nb_needed = nb_available; nb_needed = nb_available;
} }
assert(nb_needed <= INT_MAX);
*cluster_offset = 0; *cluster_offset = 0;
...@@ -530,6 +531,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, ...@@ -530,6 +531,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
*cluster_offset = be64_to_cpu(l2_table[l2_index]); *cluster_offset = be64_to_cpu(l2_table[l2_index]);
/* nb_needed <= INT_MAX, thus nb_clusters <= INT_MAX, too */
nb_clusters = size_to_clusters(s, nb_needed << 9); nb_clusters = size_to_clusters(s, nb_needed << 9);
ret = qcow2_get_cluster_type(*cluster_offset); ret = qcow2_get_cluster_type(*cluster_offset);
...@@ -606,7 +609,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset, ...@@ -606,7 +609,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
uint64_t **new_l2_table, uint64_t **new_l2_table,
int *new_l2_index) int *new_l2_index)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
unsigned int l2_index; unsigned int l2_index;
uint64_t l1_index, l2_offset; uint64_t l1_index, l2_offset;
uint64_t *l2_table = NULL; uint64_t *l2_table = NULL;
...@@ -680,7 +683,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, ...@@ -680,7 +683,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
uint64_t offset, uint64_t offset,
int compressed_size) int compressed_size)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int l2_index, ret; int l2_index, ret;
uint64_t *l2_table; uint64_t *l2_table;
int64_t cluster_offset; int64_t cluster_offset;
...@@ -725,7 +728,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, ...@@ -725,7 +728,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
static int perform_cow(BlockDriverState *bs, QCowL2Meta *m, Qcow2COWRegion *r) static int perform_cow(BlockDriverState *bs, QCowL2Meta *m, Qcow2COWRegion *r)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int ret; int ret;
if (r->nb_sectors == 0) { if (r->nb_sectors == 0) {
...@@ -754,7 +757,7 @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m, Qcow2COWRegion *r) ...@@ -754,7 +757,7 @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m, Qcow2COWRegion *r)
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m) int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int i, j = 0, l2_index, ret; int i, j = 0, l2_index, ret;
uint64_t *old_cluster, *l2_table; uint64_t *old_cluster, *l2_table;
uint64_t cluster_offset = m->alloc_offset; uint64_t cluster_offset = m->alloc_offset;
...@@ -837,7 +840,7 @@ err: ...@@ -837,7 +840,7 @@ err:
* write, but require COW to be performed (this includes yet unallocated space, * write, but require COW to be performed (this includes yet unallocated space,
* which must copy from the backing file) * which must copy from the backing file)
*/ */
static int count_cow_clusters(BDRVQcowState *s, int nb_clusters, static int count_cow_clusters(BDRVQcow2State *s, int nb_clusters,
uint64_t *l2_table, int l2_index) uint64_t *l2_table, int l2_index)
{ {
int i; int i;
...@@ -883,7 +886,7 @@ out: ...@@ -883,7 +886,7 @@ out:
static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset, static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
uint64_t *cur_bytes, QCowL2Meta **m) uint64_t *cur_bytes, QCowL2Meta **m)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
QCowL2Meta *old_alloc; QCowL2Meta *old_alloc;
uint64_t bytes = *cur_bytes; uint64_t bytes = *cur_bytes;
...@@ -956,11 +959,11 @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset, ...@@ -956,11 +959,11 @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
static int handle_copied(BlockDriverState *bs, uint64_t guest_offset, static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m) uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int l2_index; int l2_index;
uint64_t cluster_offset; uint64_t cluster_offset;
uint64_t *l2_table; uint64_t *l2_table;
unsigned int nb_clusters; uint64_t nb_clusters;
unsigned int keep_clusters; unsigned int keep_clusters;
int ret; int ret;
...@@ -979,6 +982,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset, ...@@ -979,6 +982,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
l2_index = offset_to_l2_index(s, guest_offset); l2_index = offset_to_l2_index(s, guest_offset);
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index); nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
assert(nb_clusters <= INT_MAX);
/* Find L2 entry for the first involved cluster */ /* Find L2 entry for the first involved cluster */
ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index); ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
...@@ -1061,9 +1065,9 @@ out: ...@@ -1061,9 +1065,9 @@ out:
* restarted, but the whole request should not be failed. * restarted, but the whole request should not be failed.
*/ */
static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
uint64_t *host_offset, unsigned int *nb_clusters) uint64_t *host_offset, uint64_t *nb_clusters)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
trace_qcow2_do_alloc_clusters_offset(qemu_coroutine_self(), guest_offset, trace_qcow2_do_alloc_clusters_offset(qemu_coroutine_self(), guest_offset,
*host_offset, *nb_clusters); *host_offset, *nb_clusters);
...@@ -1079,7 +1083,7 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, ...@@ -1079,7 +1083,7 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
*host_offset = cluster_offset; *host_offset = cluster_offset;
return 0; return 0;
} else { } else {
int ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters); int64_t ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
...@@ -1111,11 +1115,11 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, ...@@ -1111,11 +1115,11 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m) uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int l2_index; int l2_index;
uint64_t *l2_table; uint64_t *l2_table;
uint64_t entry; uint64_t entry;
unsigned int nb_clusters; uint64_t nb_clusters;
int ret; int ret;
uint64_t alloc_cluster_offset; uint64_t alloc_cluster_offset;
...@@ -1133,6 +1137,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, ...@@ -1133,6 +1137,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
l2_index = offset_to_l2_index(s, guest_offset); l2_index = offset_to_l2_index(s, guest_offset);
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index); nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
assert(nb_clusters <= INT_MAX);
/* Find L2 entry for the first involved cluster */ /* Find L2 entry for the first involved cluster */
ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index); ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
...@@ -1263,7 +1268,7 @@ fail: ...@@ -1263,7 +1268,7 @@ fail:
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
int *num, uint64_t *host_offset, QCowL2Meta **m) int *num, uint64_t *host_offset, QCowL2Meta **m)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t start, remaining; uint64_t start, remaining;
uint64_t cluster_offset; uint64_t cluster_offset;
uint64_t cur_bytes; uint64_t cur_bytes;
...@@ -1397,7 +1402,7 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size, ...@@ -1397,7 +1402,7 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset) int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int ret, csize, nb_csectors, sector_offset; int ret, csize, nb_csectors, sector_offset;
uint64_t coffset; uint64_t coffset;
...@@ -1426,9 +1431,10 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset) ...@@ -1426,9 +1431,10 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
* clusters. * clusters.
*/ */
static int discard_single_l2(BlockDriverState *bs, uint64_t offset, static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
unsigned int nb_clusters, enum qcow2_discard_type type, bool full_discard) uint64_t nb_clusters, enum qcow2_discard_type type,
bool full_discard)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t *l2_table; uint64_t *l2_table;
int l2_index; int l2_index;
int ret; int ret;
...@@ -1441,6 +1447,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset, ...@@ -1441,6 +1447,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
/* Limit nb_clusters to one L2 table */ /* Limit nb_clusters to one L2 table */
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index); nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
assert(nb_clusters <= INT_MAX);
for (i = 0; i < nb_clusters; i++) { for (i = 0; i < nb_clusters; i++) {
uint64_t old_l2_entry; uint64_t old_l2_entry;
...@@ -1501,9 +1508,9 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset, ...@@ -1501,9 +1508,9 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset, int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
int nb_sectors, enum qcow2_discard_type type, bool full_discard) int nb_sectors, enum qcow2_discard_type type, bool full_discard)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t end_offset; uint64_t end_offset;
unsigned int nb_clusters; uint64_t nb_clusters;
int ret; int ret;
end_offset = offset + (nb_sectors << BDRV_SECTOR_BITS); end_offset = offset + (nb_sectors << BDRV_SECTOR_BITS);
...@@ -1545,9 +1552,9 @@ fail: ...@@ -1545,9 +1552,9 @@ fail:
* clusters. * clusters.
*/ */
static int zero_single_l2(BlockDriverState *bs, uint64_t offset, static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
unsigned int nb_clusters) uint64_t nb_clusters)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t *l2_table; uint64_t *l2_table;
int l2_index; int l2_index;
int ret; int ret;
...@@ -1560,6 +1567,7 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset, ...@@ -1560,6 +1567,7 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
/* Limit nb_clusters to one L2 table */ /* Limit nb_clusters to one L2 table */
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index); nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
assert(nb_clusters <= INT_MAX);
for (i = 0; i < nb_clusters; i++) { for (i = 0; i < nb_clusters; i++) {
uint64_t old_offset; uint64_t old_offset;
...@@ -1583,8 +1591,8 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset, ...@@ -1583,8 +1591,8 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors) int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
unsigned int nb_clusters; uint64_t nb_clusters;
int ret; int ret;
/* The zero flag is only supported by version 3 and newer */ /* The zero flag is only supported by version 3 and newer */
...@@ -1628,7 +1636,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, ...@@ -1628,7 +1636,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
int64_t l1_entries, int64_t l1_entries,
BlockDriverAmendStatusCB *status_cb) BlockDriverAmendStatusCB *status_cb)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
bool is_active_l1 = (l1_table == s->l1_table); bool is_active_l1 = (l1_table == s->l1_table);
uint64_t *l2_table = NULL; uint64_t *l2_table = NULL;
int ret; int ret;
...@@ -1815,7 +1823,7 @@ fail: ...@@ -1815,7 +1823,7 @@ fail:
int qcow2_expand_zero_clusters(BlockDriverState *bs, int qcow2_expand_zero_clusters(BlockDriverState *bs,
BlockDriverAmendStatusCB *status_cb) BlockDriverAmendStatusCB *status_cb)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t *l1_table = NULL; uint64_t *l1_table = NULL;
int64_t l1_entries = 0, visited_l1_entries = 0; int64_t l1_entries = 0, visited_l1_entries = 0;
int ret; int ret;
......
...@@ -82,7 +82,7 @@ static Qcow2SetRefcountFunc *const set_refcount_funcs[] = { ...@@ -82,7 +82,7 @@ static Qcow2SetRefcountFunc *const set_refcount_funcs[] = {
int qcow2_refcount_init(BlockDriverState *bs) int qcow2_refcount_init(BlockDriverState *bs)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
unsigned int refcount_table_size2, i; unsigned int refcount_table_size2, i;
int ret; int ret;
...@@ -116,7 +116,7 @@ int qcow2_refcount_init(BlockDriverState *bs) ...@@ -116,7 +116,7 @@ int qcow2_refcount_init(BlockDriverState *bs)
void qcow2_refcount_close(BlockDriverState *bs) void qcow2_refcount_close(BlockDriverState *bs)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
g_free(s->refcount_table); g_free(s->refcount_table);
} }
...@@ -214,7 +214,7 @@ static int load_refcount_block(BlockDriverState *bs, ...@@ -214,7 +214,7 @@ static int load_refcount_block(BlockDriverState *bs,
int64_t refcount_block_offset, int64_t refcount_block_offset,
void **refcount_block) void **refcount_block)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int ret; int ret;
BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_LOAD); BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_LOAD);
...@@ -231,7 +231,7 @@ static int load_refcount_block(BlockDriverState *bs, ...@@ -231,7 +231,7 @@ static int load_refcount_block(BlockDriverState *bs,
int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index, int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
uint64_t *refcount) uint64_t *refcount)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t refcount_table_index, block_index; uint64_t refcount_table_index, block_index;
int64_t refcount_block_offset; int64_t refcount_block_offset;
int ret; int ret;
...@@ -274,7 +274,7 @@ int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index, ...@@ -274,7 +274,7 @@ int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
* Rounds the refcount table size up to avoid growing the table for each single * Rounds the refcount table size up to avoid growing the table for each single
* refcount block that is allocated. * refcount block that is allocated.
*/ */
static unsigned int next_refcount_table_size(BDRVQcowState *s, static unsigned int next_refcount_table_size(BDRVQcow2State *s,
unsigned int min_size) unsigned int min_size)
{ {
unsigned int min_clusters = (min_size >> (s->cluster_bits - 3)) + 1; unsigned int min_clusters = (min_size >> (s->cluster_bits - 3)) + 1;
...@@ -290,7 +290,7 @@ static unsigned int next_refcount_table_size(BDRVQcowState *s, ...@@ -290,7 +290,7 @@ static unsigned int next_refcount_table_size(BDRVQcowState *s,
/* Checks if two offsets are described by the same refcount block */ /* Checks if two offsets are described by the same refcount block */
static int in_same_refcount_block(BDRVQcowState *s, uint64_t offset_a, static int in_same_refcount_block(BDRVQcow2State *s, uint64_t offset_a,
uint64_t offset_b) uint64_t offset_b)
{ {
uint64_t block_a = offset_a >> (s->cluster_bits + s->refcount_block_bits); uint64_t block_a = offset_a >> (s->cluster_bits + s->refcount_block_bits);
...@@ -308,7 +308,7 @@ static int in_same_refcount_block(BDRVQcowState *s, uint64_t offset_a, ...@@ -308,7 +308,7 @@ static int in_same_refcount_block(BDRVQcowState *s, uint64_t offset_a,
static int alloc_refcount_block(BlockDriverState *bs, static int alloc_refcount_block(BlockDriverState *bs,
int64_t cluster_index, void **refcount_block) int64_t cluster_index, void **refcount_block)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
unsigned int refcount_table_index; unsigned int refcount_table_index;
int ret; int ret;
...@@ -605,7 +605,7 @@ fail_block: ...@@ -605,7 +605,7 @@ fail_block:
void qcow2_process_discards(BlockDriverState *bs, int ret) void qcow2_process_discards(BlockDriverState *bs, int ret)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
Qcow2DiscardRegion *d, *next; Qcow2DiscardRegion *d, *next;
QTAILQ_FOREACH_SAFE(d, &s->discards, next, next) { QTAILQ_FOREACH_SAFE(d, &s->discards, next, next) {
...@@ -625,7 +625,7 @@ void qcow2_process_discards(BlockDriverState *bs, int ret) ...@@ -625,7 +625,7 @@ void qcow2_process_discards(BlockDriverState *bs, int ret)
static void update_refcount_discard(BlockDriverState *bs, static void update_refcount_discard(BlockDriverState *bs,
uint64_t offset, uint64_t length) uint64_t offset, uint64_t length)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
Qcow2DiscardRegion *d, *p, *next; Qcow2DiscardRegion *d, *p, *next;
QTAILQ_FOREACH(d, &s->discards, next) { QTAILQ_FOREACH(d, &s->discards, next) {
...@@ -682,7 +682,7 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, ...@@ -682,7 +682,7 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
bool decrease, bool decrease,
enum qcow2_discard_type type) enum qcow2_discard_type type)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int64_t start, last, cluster_offset; int64_t start, last, cluster_offset;
void *refcount_block = NULL; void *refcount_block = NULL;
int64_t old_table_index = -1; int64_t old_table_index = -1;
...@@ -793,7 +793,7 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs, ...@@ -793,7 +793,7 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs,
uint64_t addend, bool decrease, uint64_t addend, bool decrease,
enum qcow2_discard_type type) enum qcow2_discard_type type)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int ret; int ret;
ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend, ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend,
...@@ -815,7 +815,7 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs, ...@@ -815,7 +815,7 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs,
/* return < 0 if error */ /* return < 0 if error */
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size) static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t i, nb_clusters, refcount; uint64_t i, nb_clusters, refcount;
int ret; int ret;
...@@ -875,10 +875,10 @@ int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size) ...@@ -875,10 +875,10 @@ int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size)
return offset; return offset;
} }
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset, int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
int nb_clusters) int64_t nb_clusters)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t cluster_index, refcount; uint64_t cluster_index, refcount;
uint64_t i; uint64_t i;
int ret; int ret;
...@@ -916,7 +916,7 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset, ...@@ -916,7 +916,7 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
contiguous sectors. size must be <= cluster_size */ contiguous sectors. size must be <= cluster_size */
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int64_t offset; int64_t offset;
size_t free_in_cluster; size_t free_in_cluster;
int ret; int ret;
...@@ -949,11 +949,17 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) ...@@ -949,11 +949,17 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
if (!offset || ROUND_UP(offset, s->cluster_size) != new_cluster) { if (!offset || ROUND_UP(offset, s->cluster_size) != new_cluster) {
offset = new_cluster; offset = new_cluster;
free_in_cluster = s->cluster_size;
} else {
free_in_cluster += s->cluster_size;
} }
} }
assert(offset); assert(offset);
ret = update_refcount(bs, offset, size, 1, false, QCOW2_DISCARD_NEVER); ret = update_refcount(bs, offset, size, 1, false, QCOW2_DISCARD_NEVER);
if (ret < 0) {
offset = 0;
}
} while (ret == -EAGAIN); } while (ret == -EAGAIN);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
...@@ -992,7 +998,7 @@ void qcow2_free_clusters(BlockDriverState *bs, ...@@ -992,7 +998,7 @@ void qcow2_free_clusters(BlockDriverState *bs,
void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry, void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
int nb_clusters, enum qcow2_discard_type type) int nb_clusters, enum qcow2_discard_type type)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
switch (qcow2_get_cluster_type(l2_entry)) { switch (qcow2_get_cluster_type(l2_entry)) {
case QCOW2_CLUSTER_COMPRESSED: case QCOW2_CLUSTER_COMPRESSED:
...@@ -1036,7 +1042,7 @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry, ...@@ -1036,7 +1042,7 @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry,
int qcow2_update_snapshot_refcount(BlockDriverState *bs, int qcow2_update_snapshot_refcount(BlockDriverState *bs,
int64_t l1_table_offset, int l1_size, int addend) int64_t l1_table_offset, int l1_size, int addend)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, refcount; uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, refcount;
bool l1_allocated = false; bool l1_allocated = false;
int64_t old_offset, old_l2_offset; int64_t old_offset, old_l2_offset;
...@@ -1233,7 +1239,7 @@ fail: ...@@ -1233,7 +1239,7 @@ fail:
/* refcount checking functions */ /* refcount checking functions */
static size_t refcount_array_byte_size(BDRVQcowState *s, uint64_t entries) static size_t refcount_array_byte_size(BDRVQcow2State *s, uint64_t entries)
{ {
/* This assertion holds because there is no way we can address more than /* This assertion holds because there is no way we can address more than
* 2^(64 - 9) clusters at once (with cluster size 512 = 2^9, and because * 2^(64 - 9) clusters at once (with cluster size 512 = 2^9, and because
...@@ -1256,10 +1262,10 @@ static size_t refcount_array_byte_size(BDRVQcowState *s, uint64_t entries) ...@@ -1256,10 +1262,10 @@ static size_t refcount_array_byte_size(BDRVQcowState *s, uint64_t entries)
* refcount array buffer will be aligned to a cluster boundary, and the newly * refcount array buffer will be aligned to a cluster boundary, and the newly
* allocated area will be zeroed. * allocated area will be zeroed.
*/ */
static int realloc_refcount_array(BDRVQcowState *s, void **array, static int realloc_refcount_array(BDRVQcow2State *s, void **array,
int64_t *size, int64_t new_size) int64_t *size, int64_t new_size)
{ {
size_t old_byte_size, new_byte_size; int64_t old_byte_size, new_byte_size;
void *new_ptr; void *new_ptr;
/* Round to clusters so the array can be directly written to disk */ /* Round to clusters so the array can be directly written to disk */
...@@ -1275,13 +1281,17 @@ static int realloc_refcount_array(BDRVQcowState *s, void **array, ...@@ -1275,13 +1281,17 @@ static int realloc_refcount_array(BDRVQcowState *s, void **array,
assert(new_byte_size > 0); assert(new_byte_size > 0);
if (new_byte_size > SIZE_MAX) {
return -ENOMEM;
}
new_ptr = g_try_realloc(*array, new_byte_size); new_ptr = g_try_realloc(*array, new_byte_size);
if (!new_ptr) { if (!new_ptr) {
return -ENOMEM; return -ENOMEM;
} }
if (new_byte_size > old_byte_size) { if (new_byte_size > old_byte_size) {
memset((void *)((uintptr_t)new_ptr + old_byte_size), 0, memset((char *)new_ptr + old_byte_size, 0,
new_byte_size - old_byte_size); new_byte_size - old_byte_size);
} }
...@@ -1304,7 +1314,7 @@ static int inc_refcounts(BlockDriverState *bs, ...@@ -1304,7 +1314,7 @@ static int inc_refcounts(BlockDriverState *bs,
int64_t *refcount_table_size, int64_t *refcount_table_size,
int64_t offset, int64_t size) int64_t offset, int64_t size)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t start, last, cluster_offset, k, refcount; uint64_t start, last, cluster_offset, k, refcount;
int ret; int ret;
...@@ -1357,7 +1367,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, ...@@ -1357,7 +1367,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
int64_t *refcount_table_size, int64_t l2_offset, int64_t *refcount_table_size, int64_t l2_offset,
int flags) int flags)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t *l2_table, l2_entry; uint64_t *l2_table, l2_entry;
uint64_t next_contiguous_offset = 0; uint64_t next_contiguous_offset = 0;
int i, l2_size, nb_csectors, ret; int i, l2_size, nb_csectors, ret;
...@@ -1477,7 +1487,7 @@ static int check_refcounts_l1(BlockDriverState *bs, ...@@ -1477,7 +1487,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
int64_t l1_table_offset, int l1_size, int64_t l1_table_offset, int l1_size,
int flags) int flags)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t *l1_table = NULL, l2_offset, l1_size2; uint64_t *l1_table = NULL, l2_offset, l1_size2;
int i, ret; int i, ret;
...@@ -1554,7 +1564,7 @@ fail: ...@@ -1554,7 +1564,7 @@ fail:
static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
BdrvCheckMode fix) BdrvCheckMode fix)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t *l2_table = qemu_blockalign(bs, s->cluster_size); uint64_t *l2_table = qemu_blockalign(bs, s->cluster_size);
int ret; int ret;
uint64_t refcount; uint64_t refcount;
...@@ -1673,7 +1683,7 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res, ...@@ -1673,7 +1683,7 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
BdrvCheckMode fix, bool *rebuild, BdrvCheckMode fix, bool *rebuild,
void **refcount_table, int64_t *nb_clusters) void **refcount_table, int64_t *nb_clusters)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int64_t i, size; int64_t i, size;
int ret; int ret;
...@@ -1776,7 +1786,7 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res, ...@@ -1776,7 +1786,7 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
BdrvCheckMode fix, bool *rebuild, BdrvCheckMode fix, bool *rebuild,
void **refcount_table, int64_t *nb_clusters) void **refcount_table, int64_t *nb_clusters)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int64_t i; int64_t i;
QCowSnapshot *sn; QCowSnapshot *sn;
int ret; int ret;
...@@ -1840,7 +1850,7 @@ static void compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res, ...@@ -1840,7 +1850,7 @@ static void compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
int64_t *highest_cluster, int64_t *highest_cluster,
void *refcount_table, int64_t nb_clusters) void *refcount_table, int64_t nb_clusters)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int64_t i; int64_t i;
uint64_t refcount1, refcount2; uint64_t refcount1, refcount2;
int ret; int ret;
...@@ -1917,7 +1927,7 @@ static int64_t alloc_clusters_imrt(BlockDriverState *bs, ...@@ -1917,7 +1927,7 @@ static int64_t alloc_clusters_imrt(BlockDriverState *bs,
int64_t *imrt_nb_clusters, int64_t *imrt_nb_clusters,
int64_t *first_free_cluster) int64_t *first_free_cluster)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int64_t cluster = *first_free_cluster, i; int64_t cluster = *first_free_cluster, i;
bool first_gap = true; bool first_gap = true;
int contiguous_free_clusters; int contiguous_free_clusters;
...@@ -1987,7 +1997,7 @@ static int rebuild_refcount_structure(BlockDriverState *bs, ...@@ -1987,7 +1997,7 @@ static int rebuild_refcount_structure(BlockDriverState *bs,
void **refcount_table, void **refcount_table,
int64_t *nb_clusters) int64_t *nb_clusters)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int64_t first_free_cluster = 0, reftable_offset = -1, cluster = 0; int64_t first_free_cluster = 0, reftable_offset = -1, cluster = 0;
int64_t refblock_offset, refblock_start, refblock_index; int64_t refblock_offset, refblock_start, refblock_index;
uint32_t reftable_size = 0; uint32_t reftable_size = 0;
...@@ -2174,7 +2184,7 @@ fail: ...@@ -2174,7 +2184,7 @@ fail:
int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
BdrvCheckMode fix) BdrvCheckMode fix)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
BdrvCheckResult pre_compare_res; BdrvCheckResult pre_compare_res;
int64_t size, highest_cluster, nb_clusters; int64_t size, highest_cluster, nb_clusters;
void *refcount_table = NULL; void *refcount_table = NULL;
...@@ -2311,7 +2321,7 @@ fail: ...@@ -2311,7 +2321,7 @@ fail:
int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset, int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
int64_t size) int64_t size)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int chk = s->overlap_check & ~ign; int chk = s->overlap_check & ~ign;
int i, j; int i, j;
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
void qcow2_free_snapshots(BlockDriverState *bs) void qcow2_free_snapshots(BlockDriverState *bs)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int i; int i;
for(i = 0; i < s->nb_snapshots; i++) { for(i = 0; i < s->nb_snapshots; i++) {
...@@ -43,7 +43,7 @@ void qcow2_free_snapshots(BlockDriverState *bs) ...@@ -43,7 +43,7 @@ void qcow2_free_snapshots(BlockDriverState *bs)
int qcow2_read_snapshots(BlockDriverState *bs) int qcow2_read_snapshots(BlockDriverState *bs)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
QCowSnapshotHeader h; QCowSnapshotHeader h;
QCowSnapshotExtraData extra; QCowSnapshotExtraData extra;
QCowSnapshot *sn; QCowSnapshot *sn;
...@@ -136,7 +136,7 @@ fail: ...@@ -136,7 +136,7 @@ fail:
/* add at the end of the file a new list of snapshots */ /* add at the end of the file a new list of snapshots */
static int qcow2_write_snapshots(BlockDriverState *bs) static int qcow2_write_snapshots(BlockDriverState *bs)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
QCowSnapshot *sn; QCowSnapshot *sn;
QCowSnapshotHeader h; QCowSnapshotHeader h;
QCowSnapshotExtraData extra; QCowSnapshotExtraData extra;
...@@ -278,7 +278,7 @@ fail: ...@@ -278,7 +278,7 @@ fail:
static void find_new_snapshot_id(BlockDriverState *bs, static void find_new_snapshot_id(BlockDriverState *bs,
char *id_str, int id_str_size) char *id_str, int id_str_size)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
QCowSnapshot *sn; QCowSnapshot *sn;
int i; int i;
unsigned long id, id_max = 0; unsigned long id, id_max = 0;
...@@ -296,7 +296,7 @@ static int find_snapshot_by_id_and_name(BlockDriverState *bs, ...@@ -296,7 +296,7 @@ static int find_snapshot_by_id_and_name(BlockDriverState *bs,
const char *id, const char *id,
const char *name) const char *name)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int i; int i;
if (id && name) { if (id && name) {
...@@ -338,7 +338,7 @@ static int find_snapshot_by_id_or_name(BlockDriverState *bs, ...@@ -338,7 +338,7 @@ static int find_snapshot_by_id_or_name(BlockDriverState *bs,
/* if no id is provided, a new one is constructed */ /* if no id is provided, a new one is constructed */
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
QCowSnapshot *new_snapshot_list = NULL; QCowSnapshot *new_snapshot_list = NULL;
QCowSnapshot *old_snapshot_list = NULL; QCowSnapshot *old_snapshot_list = NULL;
QCowSnapshot sn1, *sn = &sn1; QCowSnapshot sn1, *sn = &sn1;
...@@ -461,7 +461,7 @@ fail: ...@@ -461,7 +461,7 @@ fail:
/* copy the snapshot 'snapshot_name' into the current disk image */ /* copy the snapshot 'snapshot_name' into the current disk image */
int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
QCowSnapshot *sn; QCowSnapshot *sn;
int i, snapshot_index; int i, snapshot_index;
int cur_l1_bytes, sn_l1_bytes; int cur_l1_bytes, sn_l1_bytes;
...@@ -587,7 +587,7 @@ int qcow2_snapshot_delete(BlockDriverState *bs, ...@@ -587,7 +587,7 @@ int qcow2_snapshot_delete(BlockDriverState *bs,
const char *name, const char *name,
Error **errp) Error **errp)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
QCowSnapshot sn; QCowSnapshot sn;
int snapshot_index, ret; int snapshot_index, ret;
...@@ -650,7 +650,7 @@ int qcow2_snapshot_delete(BlockDriverState *bs, ...@@ -650,7 +650,7 @@ int qcow2_snapshot_delete(BlockDriverState *bs,
int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
QEMUSnapshotInfo *sn_tab, *sn_info; QEMUSnapshotInfo *sn_tab, *sn_info;
QCowSnapshot *sn; QCowSnapshot *sn;
int i; int i;
...@@ -683,7 +683,7 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, ...@@ -683,7 +683,7 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
Error **errp) Error **errp)
{ {
int i, snapshot_index; int i, snapshot_index;
BDRVQcowState *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
QCowSnapshot *sn; QCowSnapshot *sn;
uint64_t *new_l1_table; uint64_t *new_l1_table;
int new_l1_bytes; int new_l1_bytes;
......
此差异已折叠。
...@@ -222,7 +222,7 @@ typedef uint64_t Qcow2GetRefcountFunc(const void *refcount_array, ...@@ -222,7 +222,7 @@ typedef uint64_t Qcow2GetRefcountFunc(const void *refcount_array,
typedef void Qcow2SetRefcountFunc(void *refcount_array, typedef void Qcow2SetRefcountFunc(void *refcount_array,
uint64_t index, uint64_t value); uint64_t index, uint64_t value);
typedef struct BDRVQcowState { typedef struct BDRVQcow2State {
int cluster_bits; int cluster_bits;
int cluster_size; int cluster_size;
int cluster_sectors; int cluster_sectors;
...@@ -293,7 +293,7 @@ typedef struct BDRVQcowState { ...@@ -293,7 +293,7 @@ typedef struct BDRVQcowState {
* override) */ * override) */
char *image_backing_file; char *image_backing_file;
char *image_backing_format; char *image_backing_format;
} BDRVQcowState; } BDRVQcow2State;
struct QCowAIOCB; struct QCowAIOCB;
...@@ -405,28 +405,28 @@ typedef enum QCow2MetadataOverlap { ...@@ -405,28 +405,28 @@ typedef enum QCow2MetadataOverlap {
#define REFT_OFFSET_MASK 0xfffffffffffffe00ULL #define REFT_OFFSET_MASK 0xfffffffffffffe00ULL
static inline int64_t start_of_cluster(BDRVQcowState *s, int64_t offset) static inline int64_t start_of_cluster(BDRVQcow2State *s, int64_t offset)
{ {
return offset & ~(s->cluster_size - 1); return offset & ~(s->cluster_size - 1);
} }
static inline int64_t offset_into_cluster(BDRVQcowState *s, int64_t offset) static inline int64_t offset_into_cluster(BDRVQcow2State *s, int64_t offset)
{ {
return offset & (s->cluster_size - 1); return offset & (s->cluster_size - 1);
} }
static inline int size_to_clusters(BDRVQcowState *s, int64_t size) static inline uint64_t size_to_clusters(BDRVQcow2State *s, uint64_t size)
{ {
return (size + (s->cluster_size - 1)) >> s->cluster_bits; return (size + (s->cluster_size - 1)) >> s->cluster_bits;
} }
static inline int64_t size_to_l1(BDRVQcowState *s, int64_t size) static inline int64_t size_to_l1(BDRVQcow2State *s, int64_t size)
{ {
int shift = s->cluster_bits + s->l2_bits; int shift = s->cluster_bits + s->l2_bits;
return (size + (1ULL << shift) - 1) >> shift; return (size + (1ULL << shift) - 1) >> shift;
} }
static inline int offset_to_l2_index(BDRVQcowState *s, int64_t offset) static inline int offset_to_l2_index(BDRVQcow2State *s, int64_t offset)
{ {
return (offset >> s->cluster_bits) & (s->l2_size - 1); return (offset >> s->cluster_bits) & (s->l2_size - 1);
} }
...@@ -437,12 +437,12 @@ static inline int64_t align_offset(int64_t offset, int n) ...@@ -437,12 +437,12 @@ static inline int64_t align_offset(int64_t offset, int n)
return offset; return offset;
} }
static inline int64_t qcow2_vm_state_offset(BDRVQcowState *s) static inline int64_t qcow2_vm_state_offset(BDRVQcow2State *s)
{ {
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits); return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
} }
static inline uint64_t qcow2_max_refcount_clusters(BDRVQcowState *s) static inline uint64_t qcow2_max_refcount_clusters(BDRVQcow2State *s)
{ {
return QCOW_MAX_REFTABLE_SIZE >> s->cluster_bits; return QCOW_MAX_REFTABLE_SIZE >> s->cluster_bits;
} }
...@@ -461,7 +461,7 @@ static inline int qcow2_get_cluster_type(uint64_t l2_entry) ...@@ -461,7 +461,7 @@ static inline int qcow2_get_cluster_type(uint64_t l2_entry)
} }
/* Check whether refcounts are eager or lazy */ /* Check whether refcounts are eager or lazy */
static inline bool qcow2_need_accurate_refcounts(BDRVQcowState *s) static inline bool qcow2_need_accurate_refcounts(BDRVQcow2State *s)
{ {
return !(s->incompatible_features & QCOW2_INCOMPAT_DIRTY); return !(s->incompatible_features & QCOW2_INCOMPAT_DIRTY);
} }
...@@ -509,8 +509,8 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index, ...@@ -509,8 +509,8 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
enum qcow2_discard_type type); enum qcow2_discard_type type);
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size); int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset, int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
int nb_clusters); int64_t nb_clusters);
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size); int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
void qcow2_free_clusters(BlockDriverState *bs, void qcow2_free_clusters(BlockDriverState *bs,
int64_t offset, int64_t size, int64_t offset, int64_t size,
...@@ -537,7 +537,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, ...@@ -537,7 +537,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index); int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
void qcow2_l2_cache_reset(BlockDriverState *bs); void qcow2_l2_cache_reset(BlockDriverState *bs);
int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
int qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num, int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
uint8_t *out_buf, const uint8_t *in_buf, uint8_t *out_buf, const uint8_t *in_buf,
int nb_sectors, bool enc, Error **errp); int nb_sectors, bool enc, Error **errp);
......
...@@ -583,7 +583,7 @@ static int qed_create(const char *filename, uint32_t cluster_size, ...@@ -583,7 +583,7 @@ static int qed_create(const char *filename, uint32_t cluster_size,
bs = NULL; bs = NULL;
ret = bdrv_open(&bs, filename, NULL, NULL, ret = bdrv_open(&bs, filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_PROTOCOL,
&local_err); &local_err);
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
......
...@@ -1554,7 +1554,7 @@ static int sd_prealloc(const char *filename, Error **errp) ...@@ -1554,7 +1554,7 @@ static int sd_prealloc(const char *filename, Error **errp)
int ret; int ret;
ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
NULL, errp); errp);
if (ret < 0) { if (ret < 0) {
goto out_with_err_set; goto out_with_err_set;
} }
...@@ -1746,8 +1746,7 @@ static int sd_create(const char *filename, QemuOpts *opts, ...@@ -1746,8 +1746,7 @@ static int sd_create(const char *filename, QemuOpts *opts,
} }
bs = NULL; bs = NULL;
ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_PROTOCOL, NULL, ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_PROTOCOL, errp);
errp);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
......
...@@ -764,7 +764,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp) ...@@ -764,7 +764,7 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
goto exit; goto exit;
} }
ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
NULL, &local_err); &local_err);
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto exit; goto exit;
......
...@@ -1842,7 +1842,7 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp) ...@@ -1842,7 +1842,7 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
bs = NULL; bs = NULL;
ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
NULL, &local_err); &local_err);
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto exit; goto exit;
......
...@@ -1324,8 +1324,12 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, ...@@ -1324,8 +1324,12 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
write_end_sector = DIV_ROUND_UP(write_offset + write_len, BDRV_SECTOR_SIZE); write_end_sector = DIV_ROUND_UP(write_offset + write_len, BDRV_SECTOR_SIZE);
extent->next_cluster_sector = MAX(extent->next_cluster_sector, if (extent->compressed) {
write_end_sector); extent->next_cluster_sector = write_end_sector;
} else {
extent->next_cluster_sector = MAX(extent->next_cluster_sector,
write_end_sector);
}
if (ret != write_len) { if (ret != write_len) {
ret = ret < 0 ? ret : -EIO; ret = ret < 0 ? ret : -EIO;
...@@ -1632,7 +1636,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, ...@@ -1632,7 +1636,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
assert(bs == NULL); assert(bs == NULL);
ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
NULL, &local_err); &local_err);
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto exit; goto exit;
...@@ -1905,8 +1909,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) ...@@ -1905,8 +1909,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
ret = -ENOENT; ret = -ENOENT;
goto exit; goto exit;
} }
ret = bdrv_open(&bs, full_backing, NULL, NULL, BDRV_O_NO_BACKING, NULL, ret = bdrv_open(&bs, full_backing, NULL, NULL, BDRV_O_NO_BACKING, errp);
errp);
g_free(full_backing); g_free(full_backing);
if (ret != 0) { if (ret != 0) {
goto exit; goto exit;
...@@ -1977,7 +1980,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) ...@@ -1977,7 +1980,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
} }
assert(new_bs == NULL); assert(new_bs == NULL);
ret = bdrv_open(&new_bs, filename, NULL, NULL, ret = bdrv_open(&new_bs, filename, NULL, NULL,
BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err); BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err);
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto exit; goto exit;
......
...@@ -794,7 +794,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp) ...@@ -794,7 +794,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
goto out; goto out;
} }
ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
NULL, &local_err); &local_err);
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto out; goto out;
......
...@@ -2926,6 +2926,8 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp) ...@@ -2926,6 +2926,8 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
QemuOpts *opts = NULL; QemuOpts *opts = NULL;
int ret; int ret;
int size = sector2cluster(s, s->sector_count); int size = sector2cluster(s, s->sector_count);
QDict *options;
s->used_clusters = calloc(size, 1); s->used_clusters = calloc(size, 1);
array_init(&(s->commits), sizeof(commit_t)); array_init(&(s->commits), sizeof(commit_t));
...@@ -2956,9 +2958,11 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp) ...@@ -2956,9 +2958,11 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
} }
s->qcow = NULL; s->qcow = NULL;
ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, NULL, options = qdict_new();
qdict_put(options, "driver", qstring_from_str("qcow"));
ret = bdrv_open(&s->qcow, s->qcow_filename, NULL, options,
BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH,
bdrv_qcow, errp); errp);
if (ret < 0) { if (ret < 0) {
goto err; goto err;
} }
......
...@@ -1422,9 +1422,8 @@ typedef struct ExternalSnapshotState { ...@@ -1422,9 +1422,8 @@ typedef struct ExternalSnapshotState {
static void external_snapshot_prepare(BlkTransactionState *common, static void external_snapshot_prepare(BlkTransactionState *common,
Error **errp) Error **errp)
{ {
BlockDriver *drv;
int flags, ret; int flags, ret;
QDict *options = NULL; QDict *options;
Error *local_err = NULL; Error *local_err = NULL;
bool has_device = false; bool has_device = false;
const char *device; const char *device;
...@@ -1459,12 +1458,6 @@ static void external_snapshot_prepare(BlkTransactionState *common, ...@@ -1459,12 +1458,6 @@ static void external_snapshot_prepare(BlkTransactionState *common,
} }
/* start processing */ /* start processing */
drv = bdrv_find_format(format);
if (!drv) {
error_setg(errp, QERR_INVALID_BLOCK_FORMAT, format);
return;
}
state->old_bs = bdrv_lookup_bs(has_device ? device : NULL, state->old_bs = bdrv_lookup_bs(has_device ? device : NULL,
has_node_name ? node_name : NULL, has_node_name ? node_name : NULL,
&local_err); &local_err);
...@@ -1523,17 +1516,18 @@ static void external_snapshot_prepare(BlkTransactionState *common, ...@@ -1523,17 +1516,18 @@ static void external_snapshot_prepare(BlkTransactionState *common,
} }
} }
options = qdict_new();
if (has_snapshot_node_name) { if (has_snapshot_node_name) {
options = qdict_new();
qdict_put(options, "node-name", qdict_put(options, "node-name",
qstring_from_str(snapshot_node_name)); qstring_from_str(snapshot_node_name));
} }
qdict_put(options, "driver", qstring_from_str(format));
/* TODO Inherit bs->options or only take explicit options with an /* TODO Inherit bs->options or only take explicit options with an
* extended QMP command? */ * extended QMP command? */
assert(state->new_bs == NULL); assert(state->new_bs == NULL);
ret = bdrv_open(&state->new_bs, new_image_file, NULL, options, ret = bdrv_open(&state->new_bs, new_image_file, NULL, options,
flags | BDRV_O_NO_BACKING, drv, &local_err); flags | BDRV_O_NO_BACKING, &local_err);
/* We will manually add the backing_hd field to the bs later */ /* We will manually add the backing_hd field to the bs later */
if (ret != 0) { if (ret != 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
...@@ -1895,13 +1889,19 @@ void qmp_block_passwd(bool has_device, const char *device, ...@@ -1895,13 +1889,19 @@ void qmp_block_passwd(bool has_device, const char *device,
/* Assumes AioContext is held */ /* Assumes AioContext is held */
static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename, static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
int bdrv_flags, BlockDriver *drv, int bdrv_flags, const char *format,
const char *password, Error **errp) const char *password, Error **errp)
{ {
Error *local_err = NULL; Error *local_err = NULL;
QDict *options = NULL;
int ret; int ret;
ret = bdrv_open(&bs, filename, NULL, NULL, bdrv_flags, drv, &local_err); if (format) {
options = qdict_new();
qdict_put(options, "driver", qstring_from_str(format));
}
ret = bdrv_open(&bs, filename, NULL, options, bdrv_flags, &local_err);
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
return; return;
...@@ -1916,7 +1916,6 @@ void qmp_change_blockdev(const char *device, const char *filename, ...@@ -1916,7 +1916,6 @@ void qmp_change_blockdev(const char *device, const char *filename,
BlockBackend *blk; BlockBackend *blk;
BlockDriverState *bs; BlockDriverState *bs;
AioContext *aio_context; AioContext *aio_context;
BlockDriver *drv = NULL;
int bdrv_flags; int bdrv_flags;
Error *err = NULL; Error *err = NULL;
...@@ -1931,14 +1930,6 @@ void qmp_change_blockdev(const char *device, const char *filename, ...@@ -1931,14 +1930,6 @@ void qmp_change_blockdev(const char *device, const char *filename,
aio_context = bdrv_get_aio_context(bs); aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
if (format) {
drv = bdrv_find_whitelisted_format(format, bs->read_only);
if (!drv) {
error_setg(errp, QERR_INVALID_BLOCK_FORMAT, format);
goto out;
}
}
eject_device(blk, 0, &err); eject_device(blk, 0, &err);
if (err) { if (err) {
error_propagate(errp, err); error_propagate(errp, err);
...@@ -1948,7 +1939,7 @@ void qmp_change_blockdev(const char *device, const char *filename, ...@@ -1948,7 +1939,7 @@ void qmp_change_blockdev(const char *device, const char *filename,
bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR; bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0; 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, format, NULL, errp);
out: out:
aio_context_release(aio_context); aio_context_release(aio_context);
...@@ -2466,7 +2457,7 @@ void qmp_drive_backup(const char *device, const char *target, ...@@ -2466,7 +2457,7 @@ void qmp_drive_backup(const char *device, const char *target,
BlockDriverState *source = NULL; BlockDriverState *source = NULL;
BdrvDirtyBitmap *bmap = NULL; BdrvDirtyBitmap *bmap = NULL;
AioContext *aio_context; AioContext *aio_context;
BlockDriver *drv = NULL; QDict *options = NULL;
Error *local_err = NULL; Error *local_err = NULL;
int flags; int flags;
int64_t size; int64_t size;
...@@ -2506,13 +2497,6 @@ void qmp_drive_backup(const char *device, const char *target, ...@@ -2506,13 +2497,6 @@ void qmp_drive_backup(const char *device, const char *target,
if (!has_format) { if (!has_format) {
format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name; format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;
} }
if (format) {
drv = bdrv_find_format(format);
if (!drv) {
error_setg(errp, QERR_INVALID_BLOCK_FORMAT, format);
goto out;
}
}
/* Early check to avoid creating target */ /* Early check to avoid creating target */
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) { if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
...@@ -2540,7 +2524,7 @@ void qmp_drive_backup(const char *device, const char *target, ...@@ -2540,7 +2524,7 @@ void qmp_drive_backup(const char *device, const char *target,
} }
if (mode != NEW_IMAGE_MODE_EXISTING) { if (mode != NEW_IMAGE_MODE_EXISTING) {
assert(format && drv); assert(format);
if (source) { if (source) {
bdrv_img_create(target, format, source->filename, bdrv_img_create(target, format, source->filename,
source->drv->format_name, NULL, source->drv->format_name, NULL,
...@@ -2556,8 +2540,13 @@ void qmp_drive_backup(const char *device, const char *target, ...@@ -2556,8 +2540,13 @@ void qmp_drive_backup(const char *device, const char *target,
goto out; goto out;
} }
if (format) {
options = qdict_new();
qdict_put(options, "driver", qstring_from_str(format));
}
target_bs = NULL; target_bs = NULL;
ret = bdrv_open(&target_bs, target, NULL, NULL, flags, drv, &local_err); ret = bdrv_open(&target_bs, target, NULL, options, flags, &local_err);
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto out; goto out;
...@@ -2663,9 +2652,8 @@ void qmp_drive_mirror(const char *device, const char *target, ...@@ -2663,9 +2652,8 @@ void qmp_drive_mirror(const char *device, const char *target,
BlockDriverState *bs; BlockDriverState *bs;
BlockDriverState *source, *target_bs; BlockDriverState *source, *target_bs;
AioContext *aio_context; AioContext *aio_context;
BlockDriver *drv = NULL;
Error *local_err = NULL; Error *local_err = NULL;
QDict *options = NULL; QDict *options;
int flags; int flags;
int64_t size; int64_t size;
int ret; int ret;
...@@ -2722,13 +2710,6 @@ void qmp_drive_mirror(const char *device, const char *target, ...@@ -2722,13 +2710,6 @@ void qmp_drive_mirror(const char *device, const char *target,
if (!has_format) { if (!has_format) {
format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name; format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;
} }
if (format) {
drv = bdrv_find_format(format);
if (!drv) {
error_setg(errp, QERR_INVALID_BLOCK_FORMAT, format);
goto out;
}
}
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) { if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) {
goto out; goto out;
...@@ -2783,7 +2764,7 @@ void qmp_drive_mirror(const char *device, const char *target, ...@@ -2783,7 +2764,7 @@ void qmp_drive_mirror(const char *device, const char *target,
&& mode != NEW_IMAGE_MODE_EXISTING) && mode != NEW_IMAGE_MODE_EXISTING)
{ {
/* create new image w/o backing file */ /* create new image w/o backing file */
assert(format && drv); assert(format);
bdrv_img_create(target, format, bdrv_img_create(target, format,
NULL, NULL, NULL, size, flags, &local_err, false); NULL, NULL, NULL, size, flags, &local_err, false);
} else { } else {
...@@ -2807,17 +2788,20 @@ void qmp_drive_mirror(const char *device, const char *target, ...@@ -2807,17 +2788,20 @@ void qmp_drive_mirror(const char *device, const char *target,
goto out; goto out;
} }
options = qdict_new();
if (has_node_name) { if (has_node_name) {
options = qdict_new();
qdict_put(options, "node-name", qstring_from_str(node_name)); qdict_put(options, "node-name", qstring_from_str(node_name));
} }
if (format) {
qdict_put(options, "driver", qstring_from_str(format));
}
/* Mirroring takes care of copy-on-write using the source's backing /* Mirroring takes care of copy-on-write using the source's backing
* file. * file.
*/ */
target_bs = NULL; target_bs = NULL;
ret = bdrv_open(&target_bs, target, NULL, options, ret = bdrv_open(&target_bs, target, NULL, options,
flags | BDRV_O_NO_BACKING, drv, &local_err); flags | BDRV_O_NO_BACKING, &local_err);
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto out; goto out;
......
...@@ -147,6 +147,7 @@ typedef QSIMPLEQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue; ...@@ -147,6 +147,7 @@ typedef QSIMPLEQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue;
typedef struct BDRVReopenState { typedef struct BDRVReopenState {
BlockDriverState *bs; BlockDriverState *bs;
int flags; int flags;
QDict *options;
void *opaque; void *opaque;
} BDRVReopenState; } BDRVReopenState;
...@@ -193,8 +194,6 @@ BlockDriver *bdrv_find_protocol(const char *filename, ...@@ -193,8 +194,6 @@ BlockDriver *bdrv_find_protocol(const char *filename,
bool allow_protocol_prefix, bool allow_protocol_prefix,
Error **errp); Error **errp);
BlockDriver *bdrv_find_format(const char *format_name); BlockDriver *bdrv_find_format(const char *format_name);
BlockDriver *bdrv_find_whitelisted_format(const char *format_name,
bool readonly);
int bdrv_create(BlockDriver *drv, const char* filename, int bdrv_create(BlockDriver *drv, const char* filename,
QemuOpts *opts, Error **errp); QemuOpts *opts, Error **errp);
int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp); int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp);
...@@ -218,10 +217,10 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd); ...@@ -218,10 +217,10 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd);
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp); int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp);
int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp); int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp);
int bdrv_open(BlockDriverState **pbs, const char *filename, int bdrv_open(BlockDriverState **pbs, const char *filename,
const char *reference, QDict *options, int flags, const char *reference, QDict *options, int flags, Error **errp);
BlockDriver *drv, Error **errp);
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
BlockDriverState *bs, int flags); BlockDriverState *bs,
QDict *options, int flags);
int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp); int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp); int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp);
int bdrv_reopen_prepare(BDRVReopenState *reopen_state, int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
......
...@@ -1979,6 +1979,95 @@ static const cmdinfo_t map_cmd = { ...@@ -1979,6 +1979,95 @@ static const cmdinfo_t map_cmd = {
.oneline = "prints the allocated areas of a file", .oneline = "prints the allocated areas of a file",
}; };
static void reopen_help(void)
{
printf(
"\n"
" Changes the open options of an already opened image\n"
"\n"
" Example:\n"
" 'reopen -o lazy-refcounts=on' - activates lazy refcount writeback on a qcow2 image\n"
"\n"
" -r, -- Reopen the image read-only\n"
" -c, -- Change the cache mode to the given value\n"
" -o, -- Changes block driver options (cf. 'open' command)\n"
"\n");
}
static int reopen_f(BlockBackend *blk, int argc, char **argv);
static QemuOptsList reopen_opts = {
.name = "reopen",
.merge_lists = true,
.head = QTAILQ_HEAD_INITIALIZER(reopen_opts.head),
.desc = {
/* no elements => accept any params */
{ /* end of list */ }
},
};
static const cmdinfo_t reopen_cmd = {
.name = "reopen",
.argmin = 0,
.argmax = -1,
.cfunc = reopen_f,
.args = "[-r] [-c cache] [-o options]",
.oneline = "reopens an image with new options",
.help = reopen_help,
};
static int reopen_f(BlockBackend *blk, int argc, char **argv)
{
BlockDriverState *bs = blk_bs(blk);
QemuOpts *qopts;
QDict *opts;
int c;
int flags = bs->open_flags;
BlockReopenQueue *brq;
Error *local_err = NULL;
while ((c = getopt(argc, argv, "c:o:r")) != -1) {
switch (c) {
case 'c':
if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
error_report("Invalid cache option: %s", optarg);
return 0;
}
break;
case 'o':
if (!qemu_opts_parse_noisily(&reopen_opts, optarg, 0)) {
qemu_opts_reset(&reopen_opts);
return 0;
}
break;
case 'r':
flags &= ~BDRV_O_RDWR;
break;
default:
qemu_opts_reset(&reopen_opts);
return qemuio_command_usage(&reopen_cmd);
}
}
if (optind != argc) {
qemu_opts_reset(&reopen_opts);
return qemuio_command_usage(&reopen_cmd);
}
qopts = qemu_opts_find(&reopen_opts, NULL);
opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
qemu_opts_reset(&reopen_opts);
brq = bdrv_reopen_queue(NULL, bs, opts, flags);
bdrv_reopen_multiple(brq, &local_err);
if (local_err) {
error_report_err(local_err);
}
return 0;
}
static int break_f(BlockBackend *blk, int argc, char **argv) static int break_f(BlockBackend *blk, int argc, char **argv)
{ {
int ret; int ret;
...@@ -2266,6 +2355,7 @@ static void __attribute((constructor)) init_qemuio_commands(void) ...@@ -2266,6 +2355,7 @@ static void __attribute((constructor)) init_qemuio_commands(void)
qemuio_add_command(&discard_cmd); qemuio_add_command(&discard_cmd);
qemuio_add_command(&alloc_cmd); qemuio_add_command(&alloc_cmd);
qemuio_add_command(&map_cmd); qemuio_add_command(&map_cmd);
qemuio_add_command(&reopen_cmd);
qemuio_add_command(&break_cmd); qemuio_add_command(&break_cmd);
qemuio_add_command(&remove_break_cmd); qemuio_add_command(&remove_break_cmd);
qemuio_add_command(&resume_cmd); qemuio_add_command(&resume_cmd);
......
...@@ -156,7 +156,6 @@ static int open_f(BlockBackend *blk, int argc, char **argv) ...@@ -156,7 +156,6 @@ static int open_f(BlockBackend *blk, int argc, char **argv)
break; break;
case 'o': case 'o':
if (!qemu_opts_parse_noisily(&empty_opts, optarg, false)) { if (!qemu_opts_parse_noisily(&empty_opts, optarg, false)) {
printf("could not parse option list -- %s\n", optarg);
qemu_opts_reset(&empty_opts); qemu_opts_reset(&empty_opts);
return 0; return 0;
} }
......
...@@ -147,6 +147,33 @@ $PYTHON qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features ...@@ -147,6 +147,33 @@ $PYTHON qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features
_check_test_img _check_test_img
TEST_IMG="$TEST_IMG".base _check_test_img TEST_IMG="$TEST_IMG".base _check_test_img
echo
echo "== Changing lazy_refcounts setting at runtime =="
IMGOPTS="compat=1.1,lazy_refcounts=off"
_make_test_img $size
$QEMU_IO -c "reopen -o lazy-refcounts=on" \
-c "write -P 0x5a 0 512" \
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
| _filter_qemu_io
# The dirty bit must be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_check_test_img
IMGOPTS="compat=1.1,lazy_refcounts=on"
_make_test_img $size
$QEMU_IO -c "reopen -o lazy-refcounts=off" \
-c "write -P 0x5a 0 512" \
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
| _filter_qemu_io
# The dirty bit must not be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
_check_test_img
# success, all done # success, all done
echo "*** done" echo "*** done"
......
...@@ -74,4 +74,22 @@ incompatible_features 0x0 ...@@ -74,4 +74,22 @@ incompatible_features 0x0
incompatible_features 0x0 incompatible_features 0x0
No errors were found on the image. No errors were found on the image.
No errors were found on the image. No errors were found on the image.
== Changing lazy_refcounts setting at runtime ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" )
incompatible_features 0x1
ERROR cluster 5 refcount=0 reference=1
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
2 errors were found on the image.
Data may be corrupted, or further writes to the image may corrupt it.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" )
incompatible_features 0x0
No errors were found on the image.
*** done *** done
#!/bin/bash
#
# Test qcow2 reopen
#
# Copyright (C) 2015 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# creator
owner=kwolf@redhat.com
seq="$(basename $0)"
echo "QA output created by $seq"
here="$PWD"
tmp=/tmp/$$
status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
. ./common.qemu
_supported_fmt qcow2
_supported_proto generic
_supported_os Linux
_make_test_img 64M
echo === Try setting valid values for all options ===
echo
# Try all options and then check that all of the basic I/O operations still
# work on this image.
$QEMU_IO \
-c "reopen -o lazy-refcounts=on,pass-discard-request=on" \
-c "reopen -o lazy-refcounts=off,pass-discard-request=off" \
-c "reopen -o pass-discard-snapshot=on,pass-discard-other=on" \
-c "reopen -o pass-discard-snapshot=off,pass-discard-other=off" \
-c "reopen -o overlap-check=all" \
-c "reopen -o overlap-check=none" \
-c "reopen -o overlap-check=cached" \
-c "reopen -o overlap-check=constant" \
-c "reopen -o overlap-check.template=all" \
-c "reopen -o overlap-check.template=none" \
-c "reopen -o overlap-check.template=cached" \
-c "reopen -o overlap-check.template=constant" \
-c "reopen -o overlap-check.main-header=on" \
-c "reopen -o overlap-check.main-header=off" \
-c "reopen -o overlap-check.active-l1=on" \
-c "reopen -o overlap-check.active-l1=off" \
-c "reopen -o overlap-check.active-l2=on" \
-c "reopen -o overlap-check.active-l2=off" \
-c "reopen -o overlap-check.refcount-table=on" \
-c "reopen -o overlap-check.refcount-table=off" \
-c "reopen -o overlap-check.refcount-block=on" \
-c "reopen -o overlap-check.refcount-block=off" \
-c "reopen -o overlap-check.snapshot-table=on" \
-c "reopen -o overlap-check.snapshot-table=off" \
-c "reopen -o overlap-check.inactive-l1=on" \
-c "reopen -o overlap-check.inactive-l1=off" \
-c "reopen -o overlap-check.inactive-l2=on" \
-c "reopen -o overlap-check.inactive-l2=off" \
-c "reopen -o cache-size=1M" \
-c "reopen -o l2-cache-size=512k" \
-c "reopen -o refcount-cache-size=128k" \
-c "reopen -o cache-clean-interval=5" \
-c "reopen -o cache-clean-interval=0" \
-c "reopen -o cache-clean-interval=10" \
\
-c "write -P 55 0 32M" \
-c "read -P 55 0 32M" \
-c "discard 0 32M" \
-c "write -z 0 32M" \
-c "read -P 0 0 32M" \
\
"$TEST_IMG" | _filter_qemu_io
echo
echo === Try setting some invalid values ===
echo
$QEMU_IO \
-c "reopen -o lazy-refcounts=42" \
-c "reopen -o cache-size=1M,l2-cache-size=64k,refcount-cache-size=64k" \
-c "reopen -o cache-size=1M,l2-cache-size=2M" \
-c "reopen -o cache-size=1M,refcount-cache-size=2M" \
-c "reopen -o l2-cache-size=256T" \
-c "reopen -o refcount-cache-size=256T" \
-c "reopen -o overlap-check=constant,overlap-check.template=all" \
-c "reopen -o overlap-check=blubb" \
-c "reopen -o overlap-check.template=blubb" \
-c "reopen -o cache-clean-interval=-1" \
"$TEST_IMG" | _filter_qemu_io
echo
echo === Test transaction semantics ===
echo
# Whether lazy-refcounts was actually enabled can easily be tested: Check if
# the dirty bit is set after a crash
$QEMU_IO \
-c "reopen -o lazy-refcounts=on,overlap-check=blubb" \
-c "write -P 0x5a 0 512" \
-c "sigraise $(kill -l KILL)" \
"$TEST_IMG" 2>&1 | _filter_qemu_io
# The dirty bit must not be set
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
# Similarly we can test whether corruption detection has been enabled:
# Create L1/L2, overwrite first entry in refcount block, allocate something.
# Disabling the checks should fail, so the corruption must be detected.
_make_test_img 64M
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
poke_file "$TEST_IMG" "$((0x20000))" "\x00\x00"
$QEMU_IO \
-c "reopen -o overlap-check=none,lazy-refcounts=42" \
-c "write 64k 64k" \
"$TEST_IMG" 2>&1 | _filter_qemu_io
# success, all done
echo '*** done'
rm -f $seq.full
status=0
QA output created by 137
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
=== Try setting valid values for all options ===
wrote 33554432/33554432 bytes at offset 0
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 33554432/33554432 bytes at offset 0
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
discard 33554432/33554432 bytes at offset 0
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 33554432/33554432 bytes at offset 0
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 33554432/33554432 bytes at offset 0
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Try setting some invalid values ===
Parameter 'lazy-refcounts' expects 'on' or 'off'
cache-size, l2-cache-size and refcount-cache-size may not be set the same time
l2-cache-size may not exceed cache-size
refcount-cache-size may not exceed cache-size
L2 cache size too big
L2 cache size too big
Conflicting values for qcow2 options 'overlap-check' ('constant') and 'overlap-check.template' ('all')
Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
Cache clean interval too big
=== Test transaction semantics ===
Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
./common.config: Killed ( exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@" )
incompatible_features 0x0
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Parameter 'lazy-refcounts' expects 'on' or 'off'
qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with qcow2_header); further corruption events will be suppressed
write failed: Input/output error
*** done
#!/bin/bash
#
# General test case for qcow2's image check
#
# Copyright (C) 2015 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# creator
owner=mreitz@redhat.com
seq="$(basename $0)"
echo "QA output created by $seq"
here="$PWD"
tmp=/tmp/$$
status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
# This tests qocw2-specific low-level functionality
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
echo
echo '=== Check on an image with a multiple of 2^32 clusters ==='
echo
IMGOPTS=$(_optstr_add "$IMGOPTS" "cluster_size=512") \
_make_test_img 512
# Allocate L2 table
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
# Put the data cluster at a multiple of 2 TB, resulting in the image apparently
# having a multiple of 2^32 clusters
# (To be more specific: It is at 32 PB)
poke_file "$TEST_IMG" 2048 "\x80\x80\x00\x00\x00\x00\x00\x00"
# An offset of 32 PB results in qemu-img check having to allocate an in-memory
# refcount table of 128 TB (16 bit refcounts, 512 byte clusters).
# This should be generally too much for any system and thus fail.
# What this test is checking is that the qcow2 driver actually tries to allocate
# such a large amount of memory (and is consequently aborting) instead of having
# truncated the cluster count somewhere (which would result in much less memory
# being allocated and then a segfault occurring).
_check_test_img
# success, all done
echo "*** done"
rm -f $seq.full
status=0
QA output created by 138
=== Check on an image with a multiple of 2^32 clusters ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=512
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-img: Check failed: Cannot allocate memory
*** done
...@@ -134,3 +134,5 @@ ...@@ -134,3 +134,5 @@
132 rw auto quick 132 rw auto quick
134 rw auto quick 134 rw auto quick
135 rw auto 135 rw auto
137 rw auto
138 rw auto quick
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册