mirror of
https://github.com/qemu/qemu.git
synced 2025-08-15 22:31:15 +00:00
Block layer patches
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJZ16bbAAoJEH8JsnLIjy/WjfIP/32TrOPs3e/z1/ojgKrGU48y muiX3j2sr/7s0tWQQg2c+CM6pogmRRubIXB2RzqesZhSrXO6/6vimkprpCcimWNx R5DWATzVWxNAwjpmPYvZ8uyLYaT38S/V3VKzZ+Ga2S96tTEDVuQa7tgnrpfet4vY AYr8gJVvWgWwZXH00w2wD0hpoAGsRtFf6o9oqS5wPJ/wWrael/HubRElRbSzTc9Z lNHibk7eejalLQ9xfCaB2KTaVgzwBaa4RNXkoRjjAIUqQ/JNEWZ2o6cQQTtah/Xl AMckw2EuOMJuti2eoWcXySXRBEVdnYLwgtXwcHpH6FxYrWpW3upwOgLRJuOiR5o0 ldIQAfYQW8bVSVc8XLzNTsEZu1XY/RQurdohJvhh+j7fYv9z9kBQeUjZkMloQfv+ /T3xxQc1zp7D33qvy9is8/qP1HiC9lD1JEnzs9PuOwGHHFusIglxaC8JP+9HSu/u jf0EJZfSXyw1wDX9bBsATcFNZB9upMN+rJ1SS/yr2V7Tki570wlAhH02Rq/IUiVE pVtRn7DjT3nBYUJp1se6fZ6v9aJC+lXMlpeZ/xZFUgdGRBi4k2KxD7UIRJIj9KTE 7BEI54n7AjVP0PcU5LCqEY32R4UBG8E3QZGl5MXJO8UfAly2CtU+JHOokY/MpuZA SkSecvctgPB9oc86uSaN =y2Kg -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block layer patches # gpg: Signature made Fri 06 Oct 2017 16:52:59 BST # gpg: using RSA key 0x7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: (54 commits) block/mirror: check backing in bdrv_mirror_top_flush qcow2: truncate the tail of the image file after shrinking the image qcow2: fix return error code in qcow2_truncate() iotests: Fix 195 if IMGFMT is part of TEST_DIR block/mirror: check backing in bdrv_mirror_top_refresh_filename block: support passthrough of BDRV_REQ_FUA in crypto driver block: convert qcrypto_block_encrypt|decrypt to take bytes offset block: convert crypto driver to bdrv_co_preadv|pwritev block: fix data type casting for crypto payload offset crypto: expose encryption sector size in APIs block: use 1 MB bounce buffers for crypto instead of 16KB iotests: Add test 197 for covering copy-on-read block: Perform copy-on-read in loop block: Add blkdebug hook for copy-on-read iotests: Restore stty settings on completion block: Uniform handling of 0-length bdrv_get_block_status() qemu-io: Add -C for opening with copy-on-read commit: Remove overlay_bs qemu-iotests: Test commit block job where top has two parents qemu-iotests: Allow QMP pretty printing in common.qemu ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
530049bc1d
109
block.c
109
block.c
@ -981,6 +981,33 @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
|
|||||||
*child_flags = flags;
|
*child_flags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int bdrv_backing_update_filename(BdrvChild *c, BlockDriverState *base,
|
||||||
|
const char *filename, Error **errp)
|
||||||
|
{
|
||||||
|
BlockDriverState *parent = c->opaque;
|
||||||
|
int orig_flags = bdrv_get_flags(parent);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!(orig_flags & BDRV_O_RDWR)) {
|
||||||
|
ret = bdrv_reopen(parent, orig_flags | BDRV_O_RDWR, errp);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = bdrv_change_backing_file(parent, filename,
|
||||||
|
base->drv ? base->drv->format_name : "");
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg_errno(errp, ret, "Could not update backing file link");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(orig_flags & BDRV_O_RDWR)) {
|
||||||
|
bdrv_reopen(parent, orig_flags, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
const BdrvChildRole child_backing = {
|
const BdrvChildRole child_backing = {
|
||||||
.get_parent_desc = bdrv_child_get_parent_desc,
|
.get_parent_desc = bdrv_child_get_parent_desc,
|
||||||
.attach = bdrv_backing_attach,
|
.attach = bdrv_backing_attach,
|
||||||
@ -989,6 +1016,7 @@ const BdrvChildRole child_backing = {
|
|||||||
.drained_begin = bdrv_child_cb_drained_begin,
|
.drained_begin = bdrv_child_cb_drained_begin,
|
||||||
.drained_end = bdrv_child_cb_drained_end,
|
.drained_end = bdrv_child_cb_drained_end,
|
||||||
.inactivate = bdrv_child_cb_inactivate,
|
.inactivate = bdrv_child_cb_inactivate,
|
||||||
|
.update_filename = bdrv_backing_update_filename,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
||||||
@ -3463,53 +3491,62 @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs)
|
|||||||
* if active == top, that is considered an error
|
* if active == top, that is considered an error
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
|
int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
|
||||||
BlockDriverState *base, const char *backing_file_str)
|
const char *backing_file_str)
|
||||||
{
|
{
|
||||||
BlockDriverState *new_top_bs = NULL;
|
BdrvChild *c, *next;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
int ret = -EIO;
|
int ret = -EIO;
|
||||||
|
|
||||||
|
bdrv_ref(top);
|
||||||
|
|
||||||
if (!top->drv || !base->drv) {
|
if (!top->drv || !base->drv) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_top_bs = bdrv_find_overlay(active, top);
|
|
||||||
|
|
||||||
if (new_top_bs == NULL) {
|
|
||||||
/* we could not find the image above 'top', this is an error */
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* special case of new_top_bs->backing->bs already pointing to base - nothing
|
|
||||||
* to do, no intermediate images */
|
|
||||||
if (backing_bs(new_top_bs) == base) {
|
|
||||||
ret = 0;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure that base is in the backing chain of top */
|
/* Make sure that base is in the backing chain of top */
|
||||||
if (!bdrv_chain_contains(top, base)) {
|
if (!bdrv_chain_contains(top, base)) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* success - we can delete the intermediate states, and link top->base */
|
/* success - we can delete the intermediate states, and link top->base */
|
||||||
|
/* TODO Check graph modification op blockers (BLK_PERM_GRAPH_MOD) once
|
||||||
|
* we've figured out how they should work. */
|
||||||
backing_file_str = backing_file_str ? backing_file_str : base->filename;
|
backing_file_str = backing_file_str ? backing_file_str : base->filename;
|
||||||
ret = bdrv_change_backing_file(new_top_bs, backing_file_str,
|
|
||||||
base->drv ? base->drv->format_name : "");
|
|
||||||
if (ret) {
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
bdrv_set_backing_hd(new_top_bs, base, &local_err);
|
QLIST_FOREACH_SAFE(c, &top->parents, next_parent, next) {
|
||||||
if (local_err) {
|
/* Check whether we are allowed to switch c from top to base */
|
||||||
ret = -EPERM;
|
GSList *ignore_children = g_slist_prepend(NULL, c);
|
||||||
error_report_err(local_err);
|
bdrv_check_update_perm(base, NULL, c->perm, c->shared_perm,
|
||||||
goto exit;
|
ignore_children, &local_err);
|
||||||
|
if (local_err) {
|
||||||
|
ret = -EPERM;
|
||||||
|
error_report_err(local_err);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
g_slist_free(ignore_children);
|
||||||
|
|
||||||
|
/* If so, update the backing file path in the image file */
|
||||||
|
if (c->role->update_filename) {
|
||||||
|
ret = c->role->update_filename(c, base, backing_file_str,
|
||||||
|
&local_err);
|
||||||
|
if (ret < 0) {
|
||||||
|
bdrv_abort_perm_update(base);
|
||||||
|
error_report_err(local_err);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do the actual switch in the in-memory graph.
|
||||||
|
* Completes bdrv_check_update_perm() transaction internally. */
|
||||||
|
bdrv_ref(base);
|
||||||
|
bdrv_replace_child(c, base);
|
||||||
|
bdrv_unref(top);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
exit:
|
exit:
|
||||||
|
bdrv_unref(top);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3545,12 +3582,18 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
|
|||||||
assert(!(bs->open_flags & BDRV_O_INACTIVE));
|
assert(!(bs->open_flags & BDRV_O_INACTIVE));
|
||||||
|
|
||||||
ret = drv->bdrv_truncate(bs, offset, prealloc, errp);
|
ret = drv->bdrv_truncate(bs, offset, prealloc, errp);
|
||||||
if (ret == 0) {
|
if (ret < 0) {
|
||||||
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
|
return ret;
|
||||||
bdrv_dirty_bitmap_truncate(bs);
|
|
||||||
bdrv_parent_cb_resize(bs);
|
|
||||||
atomic_inc(&bs->write_gen);
|
|
||||||
}
|
}
|
||||||
|
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_setg_errno(errp, -ret, "Could not refresh total sector count");
|
||||||
|
} else {
|
||||||
|
offset = bs->total_sectors * BDRV_SECTOR_SIZE;
|
||||||
|
}
|
||||||
|
bdrv_dirty_bitmap_truncate(bs, offset);
|
||||||
|
bdrv_parent_cb_resize(bs);
|
||||||
|
atomic_inc(&bs->write_gen);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4488,7 +4531,7 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
|||||||
|
|
||||||
/* The size for the image must always be specified, unless we have a backing
|
/* The size for the image must always be specified, unless we have a backing
|
||||||
* file and we have not been forbidden from opening it. */
|
* file and we have not been forbidden from opening it. */
|
||||||
size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0);
|
size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, img_size);
|
||||||
if (backing_file && !(flags & BDRV_O_NO_BACKING)) {
|
if (backing_file && !(flags & BDRV_O_NO_BACKING)) {
|
||||||
BlockDriverState *bs;
|
BlockDriverState *bs;
|
||||||
char *full_backing = g_new0(char, PATH_MAX);
|
char *full_backing = g_new0(char, PATH_MAX);
|
||||||
|
@ -372,10 +372,10 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
|
|||||||
|
|
||||||
granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap);
|
granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap);
|
||||||
clusters_per_iter = MAX((granularity / job->cluster_size), 1);
|
clusters_per_iter = MAX((granularity / job->cluster_size), 1);
|
||||||
dbi = bdrv_dirty_iter_new(job->sync_bitmap, 0);
|
dbi = bdrv_dirty_iter_new(job->sync_bitmap);
|
||||||
|
|
||||||
/* Find the next dirty sector(s) */
|
/* Find the next dirty sector(s) */
|
||||||
while ((offset = bdrv_dirty_iter_next(dbi) * BDRV_SECTOR_SIZE) >= 0) {
|
while ((offset = bdrv_dirty_iter_next(dbi)) >= 0) {
|
||||||
cluster = offset / job->cluster_size;
|
cluster = offset / job->cluster_size;
|
||||||
|
|
||||||
/* Fake progress updates for any clusters we skipped */
|
/* Fake progress updates for any clusters we skipped */
|
||||||
@ -403,8 +403,7 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
|
|||||||
/* If the bitmap granularity is smaller than the backup granularity,
|
/* If the bitmap granularity is smaller than the backup granularity,
|
||||||
* we need to advance the iterator pointer to the next cluster. */
|
* we need to advance the iterator pointer to the next cluster. */
|
||||||
if (granularity < job->cluster_size) {
|
if (granularity < job->cluster_size) {
|
||||||
bdrv_set_dirty_iter(dbi,
|
bdrv_set_dirty_iter(dbi, cluster * job->cluster_size);
|
||||||
cluster * job->cluster_size / BDRV_SECTOR_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
last_cluster = cluster - 1;
|
last_cluster = cluster - 1;
|
||||||
|
@ -36,13 +36,11 @@ enum {
|
|||||||
typedef struct CommitBlockJob {
|
typedef struct CommitBlockJob {
|
||||||
BlockJob common;
|
BlockJob common;
|
||||||
RateLimit limit;
|
RateLimit limit;
|
||||||
BlockDriverState *active;
|
|
||||||
BlockDriverState *commit_top_bs;
|
BlockDriverState *commit_top_bs;
|
||||||
BlockBackend *top;
|
BlockBackend *top;
|
||||||
BlockBackend *base;
|
BlockBackend *base;
|
||||||
BlockdevOnError on_error;
|
BlockdevOnError on_error;
|
||||||
int base_flags;
|
int base_flags;
|
||||||
int orig_overlay_flags;
|
|
||||||
char *backing_file_str;
|
char *backing_file_str;
|
||||||
} CommitBlockJob;
|
} CommitBlockJob;
|
||||||
|
|
||||||
@ -81,18 +79,15 @@ static void commit_complete(BlockJob *job, void *opaque)
|
|||||||
{
|
{
|
||||||
CommitBlockJob *s = container_of(job, CommitBlockJob, common);
|
CommitBlockJob *s = container_of(job, CommitBlockJob, common);
|
||||||
CommitCompleteData *data = opaque;
|
CommitCompleteData *data = opaque;
|
||||||
BlockDriverState *active = s->active;
|
|
||||||
BlockDriverState *top = blk_bs(s->top);
|
BlockDriverState *top = blk_bs(s->top);
|
||||||
BlockDriverState *base = blk_bs(s->base);
|
BlockDriverState *base = blk_bs(s->base);
|
||||||
BlockDriverState *overlay_bs = bdrv_find_overlay(active, s->commit_top_bs);
|
BlockDriverState *commit_top_bs = s->commit_top_bs;
|
||||||
int ret = data->ret;
|
int ret = data->ret;
|
||||||
bool remove_commit_top_bs = false;
|
bool remove_commit_top_bs = false;
|
||||||
|
|
||||||
/* Make sure overlay_bs and top stay around until bdrv_set_backing_hd() */
|
/* Make sure commit_top_bs and top stay around until bdrv_replace_node() */
|
||||||
bdrv_ref(top);
|
bdrv_ref(top);
|
||||||
if (overlay_bs) {
|
bdrv_ref(commit_top_bs);
|
||||||
bdrv_ref(overlay_bs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
|
/* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
|
||||||
* the normal backing chain can be restored. */
|
* the normal backing chain can be restored. */
|
||||||
@ -100,9 +95,9 @@ static void commit_complete(BlockJob *job, void *opaque)
|
|||||||
|
|
||||||
if (!block_job_is_cancelled(&s->common) && ret == 0) {
|
if (!block_job_is_cancelled(&s->common) && ret == 0) {
|
||||||
/* success */
|
/* success */
|
||||||
ret = bdrv_drop_intermediate(active, s->commit_top_bs, base,
|
ret = bdrv_drop_intermediate(s->commit_top_bs, base,
|
||||||
s->backing_file_str);
|
s->backing_file_str);
|
||||||
} else if (overlay_bs) {
|
} else {
|
||||||
/* XXX Can (or should) we somehow keep 'consistent read' blocked even
|
/* XXX Can (or should) we somehow keep 'consistent read' blocked even
|
||||||
* after the failed/cancelled commit job is gone? If we already wrote
|
* after the failed/cancelled commit job is gone? If we already wrote
|
||||||
* something to base, the intermediate images aren't valid any more. */
|
* something to base, the intermediate images aren't valid any more. */
|
||||||
@ -115,9 +110,6 @@ static void commit_complete(BlockJob *job, void *opaque)
|
|||||||
if (s->base_flags != bdrv_get_flags(base)) {
|
if (s->base_flags != bdrv_get_flags(base)) {
|
||||||
bdrv_reopen(base, s->base_flags, NULL);
|
bdrv_reopen(base, s->base_flags, NULL);
|
||||||
}
|
}
|
||||||
if (overlay_bs && s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) {
|
|
||||||
bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL);
|
|
||||||
}
|
|
||||||
g_free(s->backing_file_str);
|
g_free(s->backing_file_str);
|
||||||
blk_unref(s->top);
|
blk_unref(s->top);
|
||||||
|
|
||||||
@ -134,10 +126,13 @@ static void commit_complete(BlockJob *job, void *opaque)
|
|||||||
* filter driver from the backing chain. Do this as the final step so that
|
* filter driver from the backing chain. Do this as the final step so that
|
||||||
* the 'consistent read' permission can be granted. */
|
* the 'consistent read' permission can be granted. */
|
||||||
if (remove_commit_top_bs) {
|
if (remove_commit_top_bs) {
|
||||||
bdrv_set_backing_hd(overlay_bs, top, &error_abort);
|
bdrv_child_try_set_perm(commit_top_bs->backing, 0, BLK_PERM_ALL,
|
||||||
|
&error_abort);
|
||||||
|
bdrv_replace_node(commit_top_bs, backing_bs(commit_top_bs),
|
||||||
|
&error_abort);
|
||||||
}
|
}
|
||||||
|
|
||||||
bdrv_unref(overlay_bs);
|
bdrv_unref(commit_top_bs);
|
||||||
bdrv_unref(top);
|
bdrv_unref(top);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,10 +278,8 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
|||||||
{
|
{
|
||||||
CommitBlockJob *s;
|
CommitBlockJob *s;
|
||||||
BlockReopenQueue *reopen_queue = NULL;
|
BlockReopenQueue *reopen_queue = NULL;
|
||||||
int orig_overlay_flags;
|
|
||||||
int orig_base_flags;
|
int orig_base_flags;
|
||||||
BlockDriverState *iter;
|
BlockDriverState *iter;
|
||||||
BlockDriverState *overlay_bs;
|
|
||||||
BlockDriverState *commit_top_bs = NULL;
|
BlockDriverState *commit_top_bs = NULL;
|
||||||
Error *local_err = NULL;
|
Error *local_err = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
@ -297,31 +290,19 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
overlay_bs = bdrv_find_overlay(bs, top);
|
|
||||||
|
|
||||||
if (overlay_bs == NULL) {
|
|
||||||
error_setg(errp, "Could not find overlay image for %s:", top->filename);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
s = block_job_create(job_id, &commit_job_driver, bs, 0, BLK_PERM_ALL,
|
s = block_job_create(job_id, &commit_job_driver, bs, 0, BLK_PERM_ALL,
|
||||||
speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
|
speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
|
||||||
if (!s) {
|
if (!s) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
orig_base_flags = bdrv_get_flags(base);
|
/* convert base to r/w, if necessary */
|
||||||
orig_overlay_flags = bdrv_get_flags(overlay_bs);
|
orig_base_flags = bdrv_get_flags(base);
|
||||||
|
|
||||||
/* 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, NULL,
|
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)) {
|
|
||||||
reopen_queue = bdrv_reopen_queue(reopen_queue, overlay_bs, NULL,
|
|
||||||
orig_overlay_flags | BDRV_O_RDWR);
|
|
||||||
}
|
|
||||||
if (reopen_queue) {
|
if (reopen_queue) {
|
||||||
bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
|
bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
|
||||||
if (local_err != NULL) {
|
if (local_err != NULL) {
|
||||||
@ -350,7 +331,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
|||||||
error_propagate(errp, local_err);
|
error_propagate(errp, local_err);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
bdrv_set_backing_hd(overlay_bs, commit_top_bs, &local_err);
|
bdrv_replace_node(top, commit_top_bs, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
bdrv_unref(commit_top_bs);
|
bdrv_unref(commit_top_bs);
|
||||||
commit_top_bs = NULL;
|
commit_top_bs = NULL;
|
||||||
@ -382,14 +363,6 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* overlay_bs must be blocked because it needs to be modified to
|
|
||||||
* update the backing image string. */
|
|
||||||
ret = block_job_add_bdrv(&s->common, "overlay of top", overlay_bs,
|
|
||||||
BLK_PERM_GRAPH_MOD, BLK_PERM_ALL, errp);
|
|
||||||
if (ret < 0) {
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->base = blk_new(BLK_PERM_CONSISTENT_READ
|
s->base = blk_new(BLK_PERM_CONSISTENT_READ
|
||||||
| BLK_PERM_WRITE
|
| BLK_PERM_WRITE
|
||||||
| BLK_PERM_RESIZE,
|
| BLK_PERM_RESIZE,
|
||||||
@ -408,13 +381,8 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->active = bs;
|
s->base_flags = orig_base_flags;
|
||||||
|
|
||||||
s->base_flags = orig_base_flags;
|
|
||||||
s->orig_overlay_flags = orig_overlay_flags;
|
|
||||||
|
|
||||||
s->backing_file_str = g_strdup(backing_file_str);
|
s->backing_file_str = g_strdup(backing_file_str);
|
||||||
|
|
||||||
s->on_error = on_error;
|
s->on_error = on_error;
|
||||||
|
|
||||||
trace_commit_start(bs, base, top, s);
|
trace_commit_start(bs, base, top, s);
|
||||||
@ -429,7 +397,7 @@ fail:
|
|||||||
blk_unref(s->top);
|
blk_unref(s->top);
|
||||||
}
|
}
|
||||||
if (commit_top_bs) {
|
if (commit_top_bs) {
|
||||||
bdrv_set_backing_hd(overlay_bs, top, &error_abort);
|
bdrv_replace_node(commit_top_bs, top, &error_abort);
|
||||||
}
|
}
|
||||||
block_job_early_fail(&s->common);
|
block_job_early_fail(&s->common);
|
||||||
}
|
}
|
||||||
|
130
block/crypto.c
130
block/crypto.c
@ -279,6 +279,9 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bs->supported_write_flags = BDRV_REQ_FUA &
|
||||||
|
bs->file->bs->supported_write_flags;
|
||||||
|
|
||||||
opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
|
opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
|
||||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||||
if (local_err) {
|
if (local_err) {
|
||||||
@ -364,8 +367,9 @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
|
|||||||
PreallocMode prealloc, Error **errp)
|
PreallocMode prealloc, Error **errp)
|
||||||
{
|
{
|
||||||
BlockCrypto *crypto = bs->opaque;
|
BlockCrypto *crypto = bs->opaque;
|
||||||
size_t payload_offset =
|
uint64_t payload_offset =
|
||||||
qcrypto_block_get_payload_offset(crypto->block);
|
qcrypto_block_get_payload_offset(crypto->block);
|
||||||
|
assert(payload_offset < (INT64_MAX - offset));
|
||||||
|
|
||||||
offset += payload_offset;
|
offset += payload_offset;
|
||||||
|
|
||||||
@ -379,66 +383,65 @@ static void block_crypto_close(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define BLOCK_CRYPTO_MAX_SECTORS 32
|
/*
|
||||||
|
* 1 MB bounce buffer gives good performance / memory tradeoff
|
||||||
|
* when using cache=none|directsync.
|
||||||
|
*/
|
||||||
|
#define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024)
|
||||||
|
|
||||||
static coroutine_fn int
|
static coroutine_fn int
|
||||||
block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
|
block_crypto_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||||
int remaining_sectors, QEMUIOVector *qiov)
|
QEMUIOVector *qiov, int flags)
|
||||||
{
|
{
|
||||||
BlockCrypto *crypto = bs->opaque;
|
BlockCrypto *crypto = bs->opaque;
|
||||||
int cur_nr_sectors; /* number of sectors in current iteration */
|
uint64_t cur_bytes; /* number of bytes in current iteration */
|
||||||
uint64_t bytes_done = 0;
|
uint64_t bytes_done = 0;
|
||||||
uint8_t *cipher_data = NULL;
|
uint8_t *cipher_data = NULL;
|
||||||
QEMUIOVector hd_qiov;
|
QEMUIOVector hd_qiov;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
size_t payload_offset =
|
uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
|
||||||
qcrypto_block_get_payload_offset(crypto->block) / 512;
|
uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);
|
||||||
|
|
||||||
|
assert(!flags);
|
||||||
|
assert(payload_offset < INT64_MAX);
|
||||||
|
assert(QEMU_IS_ALIGNED(offset, sector_size));
|
||||||
|
assert(QEMU_IS_ALIGNED(bytes, sector_size));
|
||||||
|
|
||||||
qemu_iovec_init(&hd_qiov, qiov->niov);
|
qemu_iovec_init(&hd_qiov, qiov->niov);
|
||||||
|
|
||||||
/* Bounce buffer so we have a linear mem region for
|
/* Bounce buffer because we don't wish to expose cipher text
|
||||||
* entire sector. XXX optimize so we avoid bounce
|
* in qiov which points to guest memory.
|
||||||
* buffer in case that qiov->niov == 1
|
|
||||||
*/
|
*/
|
||||||
cipher_data =
|
cipher_data =
|
||||||
qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
|
qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE,
|
||||||
qiov->size));
|
qiov->size));
|
||||||
if (cipher_data == NULL) {
|
if (cipher_data == NULL) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (remaining_sectors) {
|
while (bytes) {
|
||||||
cur_nr_sectors = remaining_sectors;
|
cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE);
|
||||||
|
|
||||||
if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
|
|
||||||
cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_iovec_reset(&hd_qiov);
|
qemu_iovec_reset(&hd_qiov);
|
||||||
qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
|
qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes);
|
||||||
|
|
||||||
ret = bdrv_co_readv(bs->file,
|
ret = bdrv_co_preadv(bs->file, payload_offset + offset + bytes_done,
|
||||||
payload_offset + sector_num,
|
cur_bytes, &hd_qiov, 0);
|
||||||
cur_nr_sectors, &hd_qiov);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qcrypto_block_decrypt(crypto->block,
|
if (qcrypto_block_decrypt(crypto->block, offset + bytes_done,
|
||||||
sector_num,
|
cipher_data, cur_bytes, NULL) < 0) {
|
||||||
cipher_data, cur_nr_sectors * 512,
|
|
||||||
NULL) < 0) {
|
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_iovec_from_buf(qiov, bytes_done,
|
qemu_iovec_from_buf(qiov, bytes_done, cipher_data, cur_bytes);
|
||||||
cipher_data, cur_nr_sectors * 512);
|
|
||||||
|
|
||||||
remaining_sectors -= cur_nr_sectors;
|
bytes -= cur_bytes;
|
||||||
sector_num += cur_nr_sectors;
|
bytes_done += cur_bytes;
|
||||||
bytes_done += cur_nr_sectors * 512;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -450,63 +453,58 @@ block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
|
|
||||||
|
|
||||||
static coroutine_fn int
|
static coroutine_fn int
|
||||||
block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
|
block_crypto_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||||
int remaining_sectors, QEMUIOVector *qiov)
|
QEMUIOVector *qiov, int flags)
|
||||||
{
|
{
|
||||||
BlockCrypto *crypto = bs->opaque;
|
BlockCrypto *crypto = bs->opaque;
|
||||||
int cur_nr_sectors; /* number of sectors in current iteration */
|
uint64_t cur_bytes; /* number of bytes in current iteration */
|
||||||
uint64_t bytes_done = 0;
|
uint64_t bytes_done = 0;
|
||||||
uint8_t *cipher_data = NULL;
|
uint8_t *cipher_data = NULL;
|
||||||
QEMUIOVector hd_qiov;
|
QEMUIOVector hd_qiov;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
size_t payload_offset =
|
uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
|
||||||
qcrypto_block_get_payload_offset(crypto->block) / 512;
|
uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);
|
||||||
|
|
||||||
|
assert(!(flags & ~BDRV_REQ_FUA));
|
||||||
|
assert(payload_offset < INT64_MAX);
|
||||||
|
assert(QEMU_IS_ALIGNED(offset, sector_size));
|
||||||
|
assert(QEMU_IS_ALIGNED(bytes, sector_size));
|
||||||
|
|
||||||
qemu_iovec_init(&hd_qiov, qiov->niov);
|
qemu_iovec_init(&hd_qiov, qiov->niov);
|
||||||
|
|
||||||
/* Bounce buffer so we have a linear mem region for
|
/* Bounce buffer because we're not permitted to touch
|
||||||
* entire sector. XXX optimize so we avoid bounce
|
* contents of qiov - it points to guest memory.
|
||||||
* buffer in case that qiov->niov == 1
|
|
||||||
*/
|
*/
|
||||||
cipher_data =
|
cipher_data =
|
||||||
qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_SECTORS * 512,
|
qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE,
|
||||||
qiov->size));
|
qiov->size));
|
||||||
if (cipher_data == NULL) {
|
if (cipher_data == NULL) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (remaining_sectors) {
|
while (bytes) {
|
||||||
cur_nr_sectors = remaining_sectors;
|
cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE);
|
||||||
|
|
||||||
if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
|
qemu_iovec_to_buf(qiov, bytes_done, cipher_data, cur_bytes);
|
||||||
cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemu_iovec_to_buf(qiov, bytes_done,
|
if (qcrypto_block_encrypt(crypto->block, offset + bytes_done,
|
||||||
cipher_data, cur_nr_sectors * 512);
|
cipher_data, cur_bytes, NULL) < 0) {
|
||||||
|
|
||||||
if (qcrypto_block_encrypt(crypto->block,
|
|
||||||
sector_num,
|
|
||||||
cipher_data, cur_nr_sectors * 512,
|
|
||||||
NULL) < 0) {
|
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_iovec_reset(&hd_qiov);
|
qemu_iovec_reset(&hd_qiov);
|
||||||
qemu_iovec_add(&hd_qiov, cipher_data, cur_nr_sectors * 512);
|
qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes);
|
||||||
|
|
||||||
ret = bdrv_co_writev(bs->file,
|
ret = bdrv_co_pwritev(bs->file, payload_offset + offset + bytes_done,
|
||||||
payload_offset + sector_num,
|
cur_bytes, &hd_qiov, flags);
|
||||||
cur_nr_sectors, &hd_qiov);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
remaining_sectors -= cur_nr_sectors;
|
bytes -= cur_bytes;
|
||||||
sector_num += cur_nr_sectors;
|
bytes_done += cur_bytes;
|
||||||
bytes_done += cur_nr_sectors * 512;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -516,13 +514,22 @@ block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void block_crypto_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||||
|
{
|
||||||
|
BlockCrypto *crypto = bs->opaque;
|
||||||
|
uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
|
||||||
|
bs->bl.request_alignment = sector_size; /* No sub-sector I/O */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int64_t block_crypto_getlength(BlockDriverState *bs)
|
static int64_t block_crypto_getlength(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BlockCrypto *crypto = bs->opaque;
|
BlockCrypto *crypto = bs->opaque;
|
||||||
int64_t len = bdrv_getlength(bs->file->bs);
|
int64_t len = bdrv_getlength(bs->file->bs);
|
||||||
|
|
||||||
ssize_t offset = qcrypto_block_get_payload_offset(crypto->block);
|
uint64_t offset = qcrypto_block_get_payload_offset(crypto->block);
|
||||||
|
assert(offset < INT64_MAX);
|
||||||
|
assert(offset < len);
|
||||||
|
|
||||||
len -= offset;
|
len -= offset;
|
||||||
|
|
||||||
@ -613,8 +620,9 @@ BlockDriver bdrv_crypto_luks = {
|
|||||||
.bdrv_truncate = block_crypto_truncate,
|
.bdrv_truncate = block_crypto_truncate,
|
||||||
.create_opts = &block_crypto_create_opts_luks,
|
.create_opts = &block_crypto_create_opts_luks,
|
||||||
|
|
||||||
.bdrv_co_readv = block_crypto_co_readv,
|
.bdrv_refresh_limits = block_crypto_refresh_limits,
|
||||||
.bdrv_co_writev = block_crypto_co_writev,
|
.bdrv_co_preadv = block_crypto_co_preadv,
|
||||||
|
.bdrv_co_pwritev = block_crypto_co_pwritev,
|
||||||
.bdrv_getlength = block_crypto_getlength,
|
.bdrv_getlength = block_crypto_getlength,
|
||||||
.bdrv_get_info = block_crypto_get_info_luks,
|
.bdrv_get_info = block_crypto_get_info_luks,
|
||||||
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
|
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Block Dirty Bitmap
|
* Block Dirty Bitmap
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016 Red Hat. Inc
|
* Copyright (c) 2016-2017 Red Hat. Inc
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -38,11 +38,11 @@
|
|||||||
*/
|
*/
|
||||||
struct BdrvDirtyBitmap {
|
struct BdrvDirtyBitmap {
|
||||||
QemuMutex *mutex;
|
QemuMutex *mutex;
|
||||||
HBitmap *bitmap; /* Dirty sector bitmap implementation */
|
HBitmap *bitmap; /* Dirty bitmap implementation */
|
||||||
HBitmap *meta; /* Meta dirty bitmap */
|
HBitmap *meta; /* Meta dirty bitmap */
|
||||||
BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
|
BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
|
||||||
char *name; /* Optional non-empty unique ID */
|
char *name; /* Optional non-empty unique ID */
|
||||||
int64_t size; /* Size of the bitmap (Number of sectors) */
|
int64_t size; /* Size of the bitmap, in bytes */
|
||||||
bool disabled; /* Bitmap is disabled. It ignores all writes to
|
bool disabled; /* Bitmap is disabled. It ignores all writes to
|
||||||
the device */
|
the device */
|
||||||
int active_iterators; /* How many iterators are active */
|
int active_iterators; /* How many iterators are active */
|
||||||
@ -115,17 +115,14 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
|
|||||||
{
|
{
|
||||||
int64_t bitmap_size;
|
int64_t bitmap_size;
|
||||||
BdrvDirtyBitmap *bitmap;
|
BdrvDirtyBitmap *bitmap;
|
||||||
uint32_t sector_granularity;
|
|
||||||
|
|
||||||
assert((granularity & (granularity - 1)) == 0);
|
assert(is_power_of_2(granularity) && granularity >= BDRV_SECTOR_SIZE);
|
||||||
|
|
||||||
if (name && bdrv_find_dirty_bitmap(bs, name)) {
|
if (name && bdrv_find_dirty_bitmap(bs, name)) {
|
||||||
error_setg(errp, "Bitmap already exists: %s", name);
|
error_setg(errp, "Bitmap already exists: %s", name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
sector_granularity = granularity >> BDRV_SECTOR_BITS;
|
bitmap_size = bdrv_getlength(bs);
|
||||||
assert(sector_granularity);
|
|
||||||
bitmap_size = bdrv_nb_sectors(bs);
|
|
||||||
if (bitmap_size < 0) {
|
if (bitmap_size < 0) {
|
||||||
error_setg_errno(errp, -bitmap_size, "could not get length of device");
|
error_setg_errno(errp, -bitmap_size, "could not get length of device");
|
||||||
errno = -bitmap_size;
|
errno = -bitmap_size;
|
||||||
@ -133,7 +130,7 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
bitmap = g_new0(BdrvDirtyBitmap, 1);
|
bitmap = g_new0(BdrvDirtyBitmap, 1);
|
||||||
bitmap->mutex = &bs->dirty_bitmap_mutex;
|
bitmap->mutex = &bs->dirty_bitmap_mutex;
|
||||||
bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(sector_granularity));
|
bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(granularity));
|
||||||
bitmap->size = bitmap_size;
|
bitmap->size = bitmap_size;
|
||||||
bitmap->name = g_strdup(name);
|
bitmap->name = g_strdup(name);
|
||||||
bitmap->disabled = false;
|
bitmap->disabled = false;
|
||||||
@ -173,45 +170,6 @@ void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
|
|||||||
qemu_mutex_unlock(bitmap->mutex);
|
qemu_mutex_unlock(bitmap->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bdrv_dirty_bitmap_get_meta_locked(BlockDriverState *bs,
|
|
||||||
BdrvDirtyBitmap *bitmap, int64_t sector,
|
|
||||||
int nb_sectors)
|
|
||||||
{
|
|
||||||
uint64_t i;
|
|
||||||
int sectors_per_bit = 1 << hbitmap_granularity(bitmap->meta);
|
|
||||||
|
|
||||||
/* To optimize: we can make hbitmap to internally check the range in a
|
|
||||||
* coarse level, or at least do it word by word. */
|
|
||||||
for (i = sector; i < sector + nb_sectors; i += sectors_per_bit) {
|
|
||||||
if (hbitmap_get(bitmap->meta, i)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
|
|
||||||
BdrvDirtyBitmap *bitmap, int64_t sector,
|
|
||||||
int nb_sectors)
|
|
||||||
{
|
|
||||||
bool dirty;
|
|
||||||
|
|
||||||
qemu_mutex_lock(bitmap->mutex);
|
|
||||||
dirty = bdrv_dirty_bitmap_get_meta_locked(bs, bitmap, sector, nb_sectors);
|
|
||||||
qemu_mutex_unlock(bitmap->mutex);
|
|
||||||
|
|
||||||
return dirty;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
|
|
||||||
BdrvDirtyBitmap *bitmap, int64_t sector,
|
|
||||||
int nb_sectors)
|
|
||||||
{
|
|
||||||
qemu_mutex_lock(bitmap->mutex);
|
|
||||||
hbitmap_reset(bitmap->meta, sector, nb_sectors);
|
|
||||||
qemu_mutex_unlock(bitmap->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap)
|
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap)
|
||||||
{
|
{
|
||||||
return bitmap->size;
|
return bitmap->size;
|
||||||
@ -341,17 +299,16 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
|
|||||||
* Truncates _all_ bitmaps attached to a BDS.
|
* Truncates _all_ bitmaps attached to a BDS.
|
||||||
* Called with BQL taken.
|
* Called with BQL taken.
|
||||||
*/
|
*/
|
||||||
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
|
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes)
|
||||||
{
|
{
|
||||||
BdrvDirtyBitmap *bitmap;
|
BdrvDirtyBitmap *bitmap;
|
||||||
uint64_t size = bdrv_nb_sectors(bs);
|
|
||||||
|
|
||||||
bdrv_dirty_bitmaps_lock(bs);
|
bdrv_dirty_bitmaps_lock(bs);
|
||||||
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
||||||
assert(!bdrv_dirty_bitmap_frozen(bitmap));
|
assert(!bdrv_dirty_bitmap_frozen(bitmap));
|
||||||
assert(!bitmap->active_iterators);
|
assert(!bitmap->active_iterators);
|
||||||
hbitmap_truncate(bitmap->bitmap, size);
|
hbitmap_truncate(bitmap->bitmap, bytes);
|
||||||
bitmap->size = size;
|
bitmap->size = bytes;
|
||||||
}
|
}
|
||||||
bdrv_dirty_bitmaps_unlock(bs);
|
bdrv_dirty_bitmaps_unlock(bs);
|
||||||
}
|
}
|
||||||
@ -461,7 +418,7 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
|
|||||||
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
|
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
|
||||||
BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1);
|
BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1);
|
||||||
BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1);
|
BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1);
|
||||||
info->count = bdrv_get_dirty_count(bm) << BDRV_SECTOR_BITS;
|
info->count = bdrv_get_dirty_count(bm);
|
||||||
info->granularity = bdrv_dirty_bitmap_granularity(bm);
|
info->granularity = bdrv_dirty_bitmap_granularity(bm);
|
||||||
info->has_name = !!bm->name;
|
info->has_name = !!bm->name;
|
||||||
info->name = g_strdup(bm->name);
|
info->name = g_strdup(bm->name);
|
||||||
@ -476,13 +433,13 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Called within bdrv_dirty_bitmap_lock..unlock */
|
/* Called within bdrv_dirty_bitmap_lock..unlock */
|
||||||
int bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
bool bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||||
int64_t sector)
|
int64_t offset)
|
||||||
{
|
{
|
||||||
if (bitmap) {
|
if (bitmap) {
|
||||||
return hbitmap_get(bitmap->bitmap, sector);
|
return hbitmap_get(bitmap->bitmap, offset);
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,19 +465,13 @@ uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
|
|||||||
|
|
||||||
uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap)
|
uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap)
|
||||||
{
|
{
|
||||||
return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
|
return 1U << hbitmap_granularity(bitmap->bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap)
|
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap)
|
||||||
{
|
|
||||||
return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
|
|
||||||
uint64_t first_sector)
|
|
||||||
{
|
{
|
||||||
BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
|
BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
|
||||||
hbitmap_iter_init(&iter->hbi, bitmap->bitmap, first_sector);
|
hbitmap_iter_init(&iter->hbi, bitmap->bitmap, 0);
|
||||||
iter->bitmap = bitmap;
|
iter->bitmap = bitmap;
|
||||||
bitmap->active_iterators++;
|
bitmap->active_iterators++;
|
||||||
return iter;
|
return iter;
|
||||||
@ -552,35 +503,35 @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
|
|||||||
|
|
||||||
/* Called within bdrv_dirty_bitmap_lock..unlock */
|
/* Called within bdrv_dirty_bitmap_lock..unlock */
|
||||||
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
|
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
|
||||||
int64_t cur_sector, int64_t nr_sectors)
|
int64_t offset, int64_t bytes)
|
||||||
{
|
{
|
||||||
assert(bdrv_dirty_bitmap_enabled(bitmap));
|
assert(bdrv_dirty_bitmap_enabled(bitmap));
|
||||||
assert(!bdrv_dirty_bitmap_readonly(bitmap));
|
assert(!bdrv_dirty_bitmap_readonly(bitmap));
|
||||||
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
|
hbitmap_set(bitmap->bitmap, offset, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
||||||
int64_t cur_sector, int64_t nr_sectors)
|
int64_t offset, int64_t bytes)
|
||||||
{
|
{
|
||||||
bdrv_dirty_bitmap_lock(bitmap);
|
bdrv_dirty_bitmap_lock(bitmap);
|
||||||
bdrv_set_dirty_bitmap_locked(bitmap, cur_sector, nr_sectors);
|
bdrv_set_dirty_bitmap_locked(bitmap, offset, bytes);
|
||||||
bdrv_dirty_bitmap_unlock(bitmap);
|
bdrv_dirty_bitmap_unlock(bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called within bdrv_dirty_bitmap_lock..unlock */
|
/* Called within bdrv_dirty_bitmap_lock..unlock */
|
||||||
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
|
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
|
||||||
int64_t cur_sector, int64_t nr_sectors)
|
int64_t offset, int64_t bytes)
|
||||||
{
|
{
|
||||||
assert(bdrv_dirty_bitmap_enabled(bitmap));
|
assert(bdrv_dirty_bitmap_enabled(bitmap));
|
||||||
assert(!bdrv_dirty_bitmap_readonly(bitmap));
|
assert(!bdrv_dirty_bitmap_readonly(bitmap));
|
||||||
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
|
hbitmap_reset(bitmap->bitmap, offset, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
||||||
int64_t cur_sector, int64_t nr_sectors)
|
int64_t offset, int64_t bytes)
|
||||||
{
|
{
|
||||||
bdrv_dirty_bitmap_lock(bitmap);
|
bdrv_dirty_bitmap_lock(bitmap);
|
||||||
bdrv_reset_dirty_bitmap_locked(bitmap, cur_sector, nr_sectors);
|
bdrv_reset_dirty_bitmap_locked(bitmap, offset, bytes);
|
||||||
bdrv_dirty_bitmap_unlock(bitmap);
|
bdrv_dirty_bitmap_unlock(bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,42 +561,42 @@ void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
|
uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
|
||||||
uint64_t start, uint64_t count)
|
uint64_t offset, uint64_t bytes)
|
||||||
{
|
{
|
||||||
return hbitmap_serialization_size(bitmap->bitmap, start, count);
|
return hbitmap_serialization_size(bitmap->bitmap, offset, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap)
|
uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap)
|
||||||
{
|
{
|
||||||
return hbitmap_serialization_granularity(bitmap->bitmap);
|
return hbitmap_serialization_align(bitmap->bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
|
void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
|
||||||
uint8_t *buf, uint64_t start,
|
uint8_t *buf, uint64_t offset,
|
||||||
uint64_t count)
|
uint64_t bytes)
|
||||||
{
|
{
|
||||||
hbitmap_serialize_part(bitmap->bitmap, buf, start, count);
|
hbitmap_serialize_part(bitmap->bitmap, buf, offset, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
|
void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
|
||||||
uint8_t *buf, uint64_t start,
|
uint8_t *buf, uint64_t offset,
|
||||||
uint64_t count, bool finish)
|
uint64_t bytes, bool finish)
|
||||||
{
|
{
|
||||||
hbitmap_deserialize_part(bitmap->bitmap, buf, start, count, finish);
|
hbitmap_deserialize_part(bitmap->bitmap, buf, offset, bytes, finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
|
void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
|
||||||
uint64_t start, uint64_t count,
|
uint64_t offset, uint64_t bytes,
|
||||||
bool finish)
|
bool finish)
|
||||||
{
|
{
|
||||||
hbitmap_deserialize_zeroes(bitmap->bitmap, start, count, finish);
|
hbitmap_deserialize_zeroes(bitmap->bitmap, offset, bytes, finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
|
void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
|
||||||
uint64_t start, uint64_t count,
|
uint64_t offset, uint64_t bytes,
|
||||||
bool finish)
|
bool finish)
|
||||||
{
|
{
|
||||||
hbitmap_deserialize_ones(bitmap->bitmap, start, count, finish);
|
hbitmap_deserialize_ones(bitmap->bitmap, offset, bytes, finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
|
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
|
||||||
@ -653,8 +604,7 @@ void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
|
|||||||
hbitmap_deserialize_finish(bitmap->bitmap);
|
hbitmap_deserialize_finish(bitmap->bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes)
|
||||||
int64_t nr_sectors)
|
|
||||||
{
|
{
|
||||||
BdrvDirtyBitmap *bitmap;
|
BdrvDirtyBitmap *bitmap;
|
||||||
|
|
||||||
@ -668,7 +618,7 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
assert(!bdrv_dirty_bitmap_readonly(bitmap));
|
assert(!bdrv_dirty_bitmap_readonly(bitmap));
|
||||||
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
|
hbitmap_set(bitmap->bitmap, offset, bytes);
|
||||||
}
|
}
|
||||||
bdrv_dirty_bitmaps_unlock(bs);
|
bdrv_dirty_bitmaps_unlock(bs);
|
||||||
}
|
}
|
||||||
@ -676,9 +626,9 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
|||||||
/**
|
/**
|
||||||
* Advance a BdrvDirtyBitmapIter to an arbitrary offset.
|
* Advance a BdrvDirtyBitmapIter to an arbitrary offset.
|
||||||
*/
|
*/
|
||||||
void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *iter, int64_t sector_num)
|
void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *iter, int64_t offset)
|
||||||
{
|
{
|
||||||
hbitmap_iter_init(&iter->hbi, iter->hbi.hb, sector_num);
|
hbitmap_iter_init(&iter->hbi, iter->hbi.hb, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
|
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
|
||||||
|
135
block/io.c
135
block/io.c
@ -34,6 +34,9 @@
|
|||||||
|
|
||||||
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
|
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
|
||||||
|
|
||||||
|
/* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */
|
||||||
|
#define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS)
|
||||||
|
|
||||||
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
||||||
int64_t offset, int bytes, BdrvRequestFlags flags);
|
int64_t offset, int bytes, BdrvRequestFlags flags);
|
||||||
|
|
||||||
@ -945,68 +948,114 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
|
|||||||
|
|
||||||
BlockDriver *drv = bs->drv;
|
BlockDriver *drv = bs->drv;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
QEMUIOVector bounce_qiov;
|
QEMUIOVector local_qiov;
|
||||||
int64_t cluster_offset;
|
int64_t cluster_offset;
|
||||||
unsigned int cluster_bytes;
|
unsigned int cluster_bytes;
|
||||||
size_t skip_bytes;
|
size_t skip_bytes;
|
||||||
int ret;
|
int ret;
|
||||||
|
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
|
||||||
|
BDRV_REQUEST_MAX_BYTES);
|
||||||
|
unsigned int progress = 0;
|
||||||
|
|
||||||
/* FIXME We cannot require callers to have write permissions when all they
|
/* FIXME We cannot require callers to have write permissions when all they
|
||||||
* are doing is a read request. If we did things right, write permissions
|
* are doing is a read request. If we did things right, write permissions
|
||||||
* would be obtained anyway, but internally by the copy-on-read code. As
|
* would be obtained anyway, but internally by the copy-on-read code. As
|
||||||
* long as it is implemented here rather than in a separat filter driver,
|
* long as it is implemented here rather than in a separate filter driver,
|
||||||
* the copy-on-read code doesn't have its own BdrvChild, however, for which
|
* the copy-on-read code doesn't have its own BdrvChild, however, for which
|
||||||
* it could request permissions. Therefore we have to bypass the permission
|
* it could request permissions. Therefore we have to bypass the permission
|
||||||
* system for the moment. */
|
* system for the moment. */
|
||||||
// assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
|
// assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
|
||||||
|
|
||||||
/* Cover entire cluster so no additional backing file I/O is required when
|
/* Cover entire cluster so no additional backing file I/O is required when
|
||||||
* allocating cluster in the image file.
|
* allocating cluster in the image file. Note that this value may exceed
|
||||||
|
* BDRV_REQUEST_MAX_BYTES (even when the original read did not), which
|
||||||
|
* is one reason we loop rather than doing it all at once.
|
||||||
*/
|
*/
|
||||||
bdrv_round_to_clusters(bs, offset, bytes, &cluster_offset, &cluster_bytes);
|
bdrv_round_to_clusters(bs, offset, bytes, &cluster_offset, &cluster_bytes);
|
||||||
|
skip_bytes = offset - cluster_offset;
|
||||||
|
|
||||||
trace_bdrv_co_do_copy_on_readv(bs, offset, bytes,
|
trace_bdrv_co_do_copy_on_readv(bs, offset, bytes,
|
||||||
cluster_offset, cluster_bytes);
|
cluster_offset, cluster_bytes);
|
||||||
|
|
||||||
iov.iov_len = cluster_bytes;
|
bounce_buffer = qemu_try_blockalign(bs,
|
||||||
iov.iov_base = bounce_buffer = qemu_try_blockalign(bs, iov.iov_len);
|
MIN(MIN(max_transfer, cluster_bytes),
|
||||||
|
MAX_BOUNCE_BUFFER));
|
||||||
if (bounce_buffer == NULL) {
|
if (bounce_buffer == NULL) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_iovec_init_external(&bounce_qiov, &iov, 1);
|
while (cluster_bytes) {
|
||||||
|
int64_t pnum;
|
||||||
|
|
||||||
ret = bdrv_driver_preadv(bs, cluster_offset, cluster_bytes,
|
ret = bdrv_is_allocated(bs, cluster_offset,
|
||||||
&bounce_qiov, 0);
|
MIN(cluster_bytes, max_transfer), &pnum);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto err;
|
/* Safe to treat errors in querying allocation as if
|
||||||
|
* unallocated; we'll probably fail again soon on the
|
||||||
|
* read, but at least that will set a decent errno.
|
||||||
|
*/
|
||||||
|
pnum = MIN(cluster_bytes, max_transfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(skip_bytes < pnum);
|
||||||
|
|
||||||
|
if (ret <= 0) {
|
||||||
|
/* Must copy-on-read; use the bounce buffer */
|
||||||
|
iov.iov_base = bounce_buffer;
|
||||||
|
iov.iov_len = pnum = MIN(pnum, MAX_BOUNCE_BUFFER);
|
||||||
|
qemu_iovec_init_external(&local_qiov, &iov, 1);
|
||||||
|
|
||||||
|
ret = bdrv_driver_preadv(bs, cluster_offset, pnum,
|
||||||
|
&local_qiov, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
bdrv_debug_event(bs, BLKDBG_COR_WRITE);
|
||||||
|
if (drv->bdrv_co_pwrite_zeroes &&
|
||||||
|
buffer_is_zero(bounce_buffer, pnum)) {
|
||||||
|
/* FIXME: Should we (perhaps conditionally) be setting
|
||||||
|
* BDRV_REQ_MAY_UNMAP, if it will allow for a sparser copy
|
||||||
|
* that still correctly reads as zero? */
|
||||||
|
ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, pnum, 0);
|
||||||
|
} else {
|
||||||
|
/* This does not change the data on the disk, it is not
|
||||||
|
* necessary to flush even in cache=writethrough mode.
|
||||||
|
*/
|
||||||
|
ret = bdrv_driver_pwritev(bs, cluster_offset, pnum,
|
||||||
|
&local_qiov, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
/* It might be okay to ignore write errors for guest
|
||||||
|
* requests. If this is a deliberate copy-on-read
|
||||||
|
* then we don't want to ignore the error. Simply
|
||||||
|
* report it in all cases.
|
||||||
|
*/
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_iovec_from_buf(qiov, progress, bounce_buffer + skip_bytes,
|
||||||
|
pnum - skip_bytes);
|
||||||
|
} else {
|
||||||
|
/* Read directly into the destination */
|
||||||
|
qemu_iovec_init(&local_qiov, qiov->niov);
|
||||||
|
qemu_iovec_concat(&local_qiov, qiov, progress, pnum - skip_bytes);
|
||||||
|
ret = bdrv_driver_preadv(bs, offset + progress, local_qiov.size,
|
||||||
|
&local_qiov, 0);
|
||||||
|
qemu_iovec_destroy(&local_qiov);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster_offset += pnum;
|
||||||
|
cluster_bytes -= pnum;
|
||||||
|
progress += pnum - skip_bytes;
|
||||||
|
skip_bytes = 0;
|
||||||
}
|
}
|
||||||
|
ret = 0;
|
||||||
if (drv->bdrv_co_pwrite_zeroes &&
|
|
||||||
buffer_is_zero(bounce_buffer, iov.iov_len)) {
|
|
||||||
/* FIXME: Should we (perhaps conditionally) be setting
|
|
||||||
* BDRV_REQ_MAY_UNMAP, if it will allow for a sparser copy
|
|
||||||
* that still correctly reads as zero? */
|
|
||||||
ret = bdrv_co_do_pwrite_zeroes(bs, cluster_offset, cluster_bytes, 0);
|
|
||||||
} else {
|
|
||||||
/* This does not change the data on the disk, it is not necessary
|
|
||||||
* to flush even in cache=writethrough mode.
|
|
||||||
*/
|
|
||||||
ret = bdrv_driver_pwritev(bs, cluster_offset, cluster_bytes,
|
|
||||||
&bounce_qiov, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
/* It might be okay to ignore write errors for guest requests. If this
|
|
||||||
* is a deliberate copy-on-read then we don't want to ignore the error.
|
|
||||||
* Simply report it in all cases.
|
|
||||||
*/
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
skip_bytes = offset - cluster_offset;
|
|
||||||
qemu_iovec_from_buf(qiov, 0, bounce_buffer + skip_bytes, bytes);
|
|
||||||
|
|
||||||
err:
|
err:
|
||||||
qemu_vfree(bounce_buffer);
|
qemu_vfree(bounce_buffer);
|
||||||
@ -1212,9 +1261,6 @@ int coroutine_fn bdrv_co_readv(BdrvChild *child, int64_t sector_num,
|
|||||||
return bdrv_co_do_readv(child, sector_num, nb_sectors, qiov, 0);
|
return bdrv_co_do_readv(child, sector_num, nb_sectors, qiov, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Maximum buffer for write zeroes fallback, in bytes */
|
|
||||||
#define MAX_WRITE_ZEROES_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS)
|
|
||||||
|
|
||||||
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
||||||
int64_t offset, int bytes, BdrvRequestFlags flags)
|
int64_t offset, int bytes, BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
@ -1229,8 +1275,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
|
|||||||
int max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, INT_MAX);
|
int max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, INT_MAX);
|
||||||
int alignment = MAX(bs->bl.pwrite_zeroes_alignment,
|
int alignment = MAX(bs->bl.pwrite_zeroes_alignment,
|
||||||
bs->bl.request_alignment);
|
bs->bl.request_alignment);
|
||||||
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
|
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFFER);
|
||||||
MAX_WRITE_ZEROES_BOUNCE_BUFFER);
|
|
||||||
|
|
||||||
assert(alignment % bs->bl.request_alignment == 0);
|
assert(alignment % bs->bl.request_alignment == 0);
|
||||||
head = offset % alignment;
|
head = offset % alignment;
|
||||||
@ -1334,7 +1379,6 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
|
|||||||
bool waited;
|
bool waited;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
int64_t start_sector = offset >> BDRV_SECTOR_BITS;
|
|
||||||
int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
|
int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
|
||||||
uint64_t bytes_remaining = bytes;
|
uint64_t bytes_remaining = bytes;
|
||||||
int max_transfer;
|
int max_transfer;
|
||||||
@ -1409,7 +1453,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
|
|||||||
bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE);
|
bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE);
|
||||||
|
|
||||||
atomic_inc(&bs->write_gen);
|
atomic_inc(&bs->write_gen);
|
||||||
bdrv_set_dirty(bs, start_sector, end_sector - start_sector);
|
bdrv_set_dirty(bs, offset, bytes);
|
||||||
|
|
||||||
stat64_max(&bs->wr_highest_offset, offset + bytes);
|
stat64_max(&bs->wr_highest_offset, offset + bytes);
|
||||||
|
|
||||||
@ -1778,6 +1822,10 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
|||||||
*pnum = 0;
|
*pnum = 0;
|
||||||
return BDRV_BLOCK_EOF;
|
return BDRV_BLOCK_EOF;
|
||||||
}
|
}
|
||||||
|
if (!nb_sectors) {
|
||||||
|
*pnum = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
n = total_sectors - sector_num;
|
n = total_sectors - sector_num;
|
||||||
if (n < nb_sectors) {
|
if (n < nb_sectors) {
|
||||||
@ -2438,8 +2486,7 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
atomic_inc(&bs->write_gen);
|
atomic_inc(&bs->write_gen);
|
||||||
bdrv_set_dirty(bs, req.offset >> BDRV_SECTOR_BITS,
|
bdrv_set_dirty(bs, req.offset, req.bytes);
|
||||||
req.bytes >> BDRV_SECTOR_BITS);
|
|
||||||
tracked_request_end(&req);
|
tracked_request_end(&req);
|
||||||
bdrv_dec_in_flight(bs);
|
bdrv_dec_in_flight(bs);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -141,8 +141,7 @@ static void mirror_write_complete(void *opaque, int ret)
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
BlockErrorAction action;
|
BlockErrorAction action;
|
||||||
|
|
||||||
bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset >> BDRV_SECTOR_BITS,
|
bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset, op->bytes);
|
||||||
op->bytes >> BDRV_SECTOR_BITS);
|
|
||||||
action = mirror_error_action(s, false, -ret);
|
action = mirror_error_action(s, false, -ret);
|
||||||
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
||||||
s->ret = ret;
|
s->ret = ret;
|
||||||
@ -161,8 +160,7 @@ static void mirror_read_complete(void *opaque, int ret)
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
BlockErrorAction action;
|
BlockErrorAction action;
|
||||||
|
|
||||||
bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset >> BDRV_SECTOR_BITS,
|
bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset, op->bytes);
|
||||||
op->bytes >> BDRV_SECTOR_BITS);
|
|
||||||
action = mirror_error_action(s, true, -ret);
|
action = mirror_error_action(s, true, -ret);
|
||||||
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
||||||
s->ret = ret;
|
s->ret = ret;
|
||||||
@ -336,12 +334,11 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
|||||||
int max_io_bytes = MAX(s->buf_size / MAX_IN_FLIGHT, MAX_IO_BYTES);
|
int max_io_bytes = MAX(s->buf_size / MAX_IN_FLIGHT, MAX_IO_BYTES);
|
||||||
|
|
||||||
bdrv_dirty_bitmap_lock(s->dirty_bitmap);
|
bdrv_dirty_bitmap_lock(s->dirty_bitmap);
|
||||||
offset = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE;
|
offset = bdrv_dirty_iter_next(s->dbi);
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
bdrv_set_dirty_iter(s->dbi, 0);
|
bdrv_set_dirty_iter(s->dbi, 0);
|
||||||
offset = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE;
|
offset = bdrv_dirty_iter_next(s->dbi);
|
||||||
trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap) *
|
trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap));
|
||||||
BDRV_SECTOR_SIZE);
|
|
||||||
assert(offset >= 0);
|
assert(offset >= 0);
|
||||||
}
|
}
|
||||||
bdrv_dirty_bitmap_unlock(s->dirty_bitmap);
|
bdrv_dirty_bitmap_unlock(s->dirty_bitmap);
|
||||||
@ -362,19 +359,18 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
|||||||
int64_t next_offset = offset + nb_chunks * s->granularity;
|
int64_t next_offset = offset + nb_chunks * s->granularity;
|
||||||
int64_t next_chunk = next_offset / s->granularity;
|
int64_t next_chunk = next_offset / s->granularity;
|
||||||
if (next_offset >= s->bdev_length ||
|
if (next_offset >= s->bdev_length ||
|
||||||
!bdrv_get_dirty_locked(source, s->dirty_bitmap,
|
!bdrv_get_dirty_locked(source, s->dirty_bitmap, next_offset)) {
|
||||||
next_offset >> BDRV_SECTOR_BITS)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (test_bit(next_chunk, s->in_flight_bitmap)) {
|
if (test_bit(next_chunk, s->in_flight_bitmap)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
next_dirty = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE;
|
next_dirty = bdrv_dirty_iter_next(s->dbi);
|
||||||
if (next_dirty > next_offset || next_dirty < 0) {
|
if (next_dirty > next_offset || next_dirty < 0) {
|
||||||
/* The bitmap iterator's cache is stale, refresh it */
|
/* The bitmap iterator's cache is stale, refresh it */
|
||||||
bdrv_set_dirty_iter(s->dbi, next_offset >> BDRV_SECTOR_BITS);
|
bdrv_set_dirty_iter(s->dbi, next_offset);
|
||||||
next_dirty = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE;
|
next_dirty = bdrv_dirty_iter_next(s->dbi);
|
||||||
}
|
}
|
||||||
assert(next_dirty == next_offset);
|
assert(next_dirty == next_offset);
|
||||||
nb_chunks++;
|
nb_chunks++;
|
||||||
@ -384,8 +380,8 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
|||||||
* calling bdrv_get_block_status_above could yield - if some blocks are
|
* calling bdrv_get_block_status_above could yield - if some blocks are
|
||||||
* marked dirty in this window, we need to know.
|
* marked dirty in this window, we need to know.
|
||||||
*/
|
*/
|
||||||
bdrv_reset_dirty_bitmap_locked(s->dirty_bitmap, offset >> BDRV_SECTOR_BITS,
|
bdrv_reset_dirty_bitmap_locked(s->dirty_bitmap, offset,
|
||||||
nb_chunks * sectors_per_chunk);
|
nb_chunks * s->granularity);
|
||||||
bdrv_dirty_bitmap_unlock(s->dirty_bitmap);
|
bdrv_dirty_bitmap_unlock(s->dirty_bitmap);
|
||||||
|
|
||||||
bitmap_set(s->in_flight_bitmap, offset / s->granularity, nb_chunks);
|
bitmap_set(s->in_flight_bitmap, offset / s->granularity, nb_chunks);
|
||||||
@ -616,25 +612,23 @@ static void mirror_throttle(MirrorBlockJob *s)
|
|||||||
|
|
||||||
static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
|
static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
|
||||||
{
|
{
|
||||||
int64_t sector_num, end;
|
int64_t offset;
|
||||||
BlockDriverState *base = s->base;
|
BlockDriverState *base = s->base;
|
||||||
BlockDriverState *bs = s->source;
|
BlockDriverState *bs = s->source;
|
||||||
BlockDriverState *target_bs = blk_bs(s->target);
|
BlockDriverState *target_bs = blk_bs(s->target);
|
||||||
int ret, n;
|
int ret;
|
||||||
int64_t count;
|
int64_t count;
|
||||||
|
|
||||||
end = s->bdev_length / BDRV_SECTOR_SIZE;
|
|
||||||
|
|
||||||
if (base == NULL && !bdrv_has_zero_init(target_bs)) {
|
if (base == NULL && !bdrv_has_zero_init(target_bs)) {
|
||||||
if (!bdrv_can_write_zeroes_with_unmap(target_bs)) {
|
if (!bdrv_can_write_zeroes_with_unmap(target_bs)) {
|
||||||
bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, end);
|
bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->initial_zeroing_ongoing = true;
|
s->initial_zeroing_ongoing = true;
|
||||||
for (sector_num = 0; sector_num < end; ) {
|
for (offset = 0; offset < s->bdev_length; ) {
|
||||||
int nb_sectors = MIN(end - sector_num,
|
int bytes = MIN(s->bdev_length - offset,
|
||||||
QEMU_ALIGN_DOWN(INT_MAX, s->granularity) >> BDRV_SECTOR_BITS);
|
QEMU_ALIGN_DOWN(INT_MAX, s->granularity));
|
||||||
|
|
||||||
mirror_throttle(s);
|
mirror_throttle(s);
|
||||||
|
|
||||||
@ -650,9 +644,8 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
mirror_do_zero_or_discard(s, sector_num * BDRV_SECTOR_SIZE,
|
mirror_do_zero_or_discard(s, offset, bytes, false);
|
||||||
nb_sectors * BDRV_SECTOR_SIZE, false);
|
offset += bytes;
|
||||||
sector_num += nb_sectors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mirror_wait_for_all_io(s);
|
mirror_wait_for_all_io(s);
|
||||||
@ -660,10 +653,10 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* First part, loop on the sectors and initialize the dirty bitmap. */
|
/* First part, loop on the sectors and initialize the dirty bitmap. */
|
||||||
for (sector_num = 0; sector_num < end; ) {
|
for (offset = 0; offset < s->bdev_length; ) {
|
||||||
/* Just to make sure we are not exceeding int limit. */
|
/* Just to make sure we are not exceeding int limit. */
|
||||||
int nb_sectors = MIN(INT_MAX >> BDRV_SECTOR_BITS,
|
int bytes = MIN(s->bdev_length - offset,
|
||||||
end - sector_num);
|
QEMU_ALIGN_DOWN(INT_MAX, s->granularity));
|
||||||
|
|
||||||
mirror_throttle(s);
|
mirror_throttle(s);
|
||||||
|
|
||||||
@ -671,21 +664,16 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_is_allocated_above(bs, base, sector_num * BDRV_SECTOR_SIZE,
|
ret = bdrv_is_allocated_above(bs, base, offset, bytes, &count);
|
||||||
nb_sectors * BDRV_SECTOR_SIZE, &count);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Relax this once bdrv_is_allocated_above and dirty
|
assert(count);
|
||||||
* bitmaps no longer require sector alignment. */
|
|
||||||
assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
|
|
||||||
n = count >> BDRV_SECTOR_BITS;
|
|
||||||
assert(n > 0);
|
|
||||||
if (ret == 1) {
|
if (ret == 1) {
|
||||||
bdrv_set_dirty_bitmap(s->dirty_bitmap, sector_num, n);
|
bdrv_set_dirty_bitmap(s->dirty_bitmap, offset, count);
|
||||||
}
|
}
|
||||||
sector_num += n;
|
offset += count;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -796,7 +784,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(!s->dbi);
|
assert(!s->dbi);
|
||||||
s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap, 0);
|
s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint64_t delay_ns = 0;
|
uint64_t delay_ns = 0;
|
||||||
int64_t cnt, delta;
|
int64_t cnt, delta;
|
||||||
@ -811,11 +799,10 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
|
|
||||||
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
|
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
|
||||||
/* s->common.offset contains the number of bytes already processed so
|
/* s->common.offset contains the number of bytes already processed so
|
||||||
* far, cnt is the number of dirty sectors remaining and
|
* far, cnt is the number of dirty bytes remaining and
|
||||||
* s->bytes_in_flight is the number of bytes currently being
|
* s->bytes_in_flight is the number of bytes currently being
|
||||||
* processed; together those are the current total operation length */
|
* processed; together those are the current total operation length */
|
||||||
s->common.len = s->common.offset + s->bytes_in_flight +
|
s->common.len = s->common.offset + s->bytes_in_flight + cnt;
|
||||||
cnt * BDRV_SECTOR_SIZE;
|
|
||||||
|
|
||||||
/* Note that even when no rate limit is applied we need to yield
|
/* Note that even when no rate limit is applied we need to yield
|
||||||
* periodically with no pending I/O so that bdrv_drain_all() returns.
|
* periodically with no pending I/O so that bdrv_drain_all() returns.
|
||||||
@ -827,8 +814,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
|
s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
|
||||||
if (s->in_flight >= MAX_IN_FLIGHT || s->buf_free_count == 0 ||
|
if (s->in_flight >= MAX_IN_FLIGHT || s->buf_free_count == 0 ||
|
||||||
(cnt == 0 && s->in_flight > 0)) {
|
(cnt == 0 && s->in_flight > 0)) {
|
||||||
trace_mirror_yield(s, cnt * BDRV_SECTOR_SIZE,
|
trace_mirror_yield(s, cnt, s->buf_free_count, s->in_flight);
|
||||||
s->buf_free_count, s->in_flight);
|
|
||||||
mirror_wait_for_io(s);
|
mirror_wait_for_io(s);
|
||||||
continue;
|
continue;
|
||||||
} else if (cnt != 0) {
|
} else if (cnt != 0) {
|
||||||
@ -869,7 +855,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
* whether to switch to target check one last time if I/O has
|
* whether to switch to target check one last time if I/O has
|
||||||
* come in the meanwhile, and if not flush the data to disk.
|
* come in the meanwhile, and if not flush the data to disk.
|
||||||
*/
|
*/
|
||||||
trace_mirror_before_drain(s, cnt * BDRV_SECTOR_SIZE);
|
trace_mirror_before_drain(s, cnt);
|
||||||
|
|
||||||
bdrv_drained_begin(bs);
|
bdrv_drained_begin(bs);
|
||||||
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
|
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
|
||||||
@ -888,8 +874,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
trace_mirror_before_sleep(s, cnt * BDRV_SECTOR_SIZE,
|
trace_mirror_before_sleep(s, cnt, s->synced, delay_ns);
|
||||||
s->synced, delay_ns);
|
|
||||||
if (!s->synced) {
|
if (!s->synced) {
|
||||||
block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns);
|
block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns);
|
||||||
if (block_job_is_cancelled(&s->common)) {
|
if (block_job_is_cancelled(&s->common)) {
|
||||||
@ -1056,6 +1041,10 @@ static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,
|
|||||||
|
|
||||||
static int coroutine_fn bdrv_mirror_top_flush(BlockDriverState *bs)
|
static int coroutine_fn bdrv_mirror_top_flush(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
|
if (bs->backing == NULL) {
|
||||||
|
/* we can be here after failed bdrv_append in mirror_start_job */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return bdrv_co_flush(bs->backing->bs);
|
return bdrv_co_flush(bs->backing->bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1073,6 +1062,11 @@ static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs,
|
|||||||
|
|
||||||
static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs, QDict *opts)
|
static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs, QDict *opts)
|
||||||
{
|
{
|
||||||
|
if (bs->backing == NULL) {
|
||||||
|
/* we can be here after failed bdrv_attach_child in
|
||||||
|
* bdrv_set_backing_hd */
|
||||||
|
return;
|
||||||
|
}
|
||||||
bdrv_refresh_filename(bs->backing->bs);
|
bdrv_refresh_filename(bs->backing->bs);
|
||||||
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
|
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
|
||||||
bs->backing->bs->filename);
|
bs->backing->bs->filename);
|
||||||
|
11
block/qcow.c
11
block/qcow.c
@ -478,7 +478,9 @@ static int get_cluster_offset(BlockDriverState *bs,
|
|||||||
for(i = 0; i < s->cluster_sectors; i++) {
|
for(i = 0; i < s->cluster_sectors; i++) {
|
||||||
if (i < n_start || i >= n_end) {
|
if (i < n_start || i >= n_end) {
|
||||||
memset(s->cluster_data, 0x00, 512);
|
memset(s->cluster_data, 0x00, 512);
|
||||||
if (qcrypto_block_encrypt(s->crypto, start_sect + i,
|
if (qcrypto_block_encrypt(s->crypto,
|
||||||
|
(start_sect + i) *
|
||||||
|
BDRV_SECTOR_SIZE,
|
||||||
s->cluster_data,
|
s->cluster_data,
|
||||||
BDRV_SECTOR_SIZE,
|
BDRV_SECTOR_SIZE,
|
||||||
NULL) < 0) {
|
NULL) < 0) {
|
||||||
@ -668,7 +670,8 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
}
|
}
|
||||||
if (bs->encrypted) {
|
if (bs->encrypted) {
|
||||||
assert(s->crypto);
|
assert(s->crypto);
|
||||||
if (qcrypto_block_decrypt(s->crypto, sector_num, buf,
|
if (qcrypto_block_decrypt(s->crypto,
|
||||||
|
sector_num * BDRV_SECTOR_SIZE, buf,
|
||||||
n * BDRV_SECTOR_SIZE, NULL) < 0) {
|
n * BDRV_SECTOR_SIZE, NULL) < 0) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
break;
|
break;
|
||||||
@ -740,8 +743,8 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
|
|||||||
}
|
}
|
||||||
if (bs->encrypted) {
|
if (bs->encrypted) {
|
||||||
assert(s->crypto);
|
assert(s->crypto);
|
||||||
if (qcrypto_block_encrypt(s->crypto, sector_num, buf,
|
if (qcrypto_block_encrypt(s->crypto, sector_num * BDRV_SECTOR_SIZE,
|
||||||
n * BDRV_SECTOR_SIZE, NULL) < 0) {
|
buf, n * BDRV_SECTOR_SIZE, NULL) < 0) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -269,15 +269,16 @@ static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function returns the number of disk sectors covered by a single qcow2
|
/* Return the disk size covered by a single qcow2 cluster of bitmap data. */
|
||||||
* cluster of bitmap data. */
|
static uint64_t bytes_covered_by_bitmap_cluster(const BDRVQcow2State *s,
|
||||||
static uint64_t sectors_covered_by_bitmap_cluster(const BDRVQcow2State *s,
|
const BdrvDirtyBitmap *bitmap)
|
||||||
const BdrvDirtyBitmap *bitmap)
|
|
||||||
{
|
{
|
||||||
uint32_t sector_granularity =
|
uint64_t granularity = bdrv_dirty_bitmap_granularity(bitmap);
|
||||||
bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
|
uint64_t limit = granularity * (s->cluster_size << 3);
|
||||||
|
|
||||||
return (uint64_t)sector_granularity * (s->cluster_size << 3);
|
assert(QEMU_IS_ALIGNED(limit,
|
||||||
|
bdrv_dirty_bitmap_serialization_align(bitmap)));
|
||||||
|
return limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* load_bitmap_data
|
/* load_bitmap_data
|
||||||
@ -290,7 +291,7 @@ static int load_bitmap_data(BlockDriverState *bs,
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
uint64_t sector, sbc;
|
uint64_t offset, limit;
|
||||||
uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
|
uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
|
||||||
uint8_t *buf = NULL;
|
uint8_t *buf = NULL;
|
||||||
uint64_t i, tab_size =
|
uint64_t i, tab_size =
|
||||||
@ -302,28 +303,28 @@ static int load_bitmap_data(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
buf = g_malloc(s->cluster_size);
|
buf = g_malloc(s->cluster_size);
|
||||||
sbc = sectors_covered_by_bitmap_cluster(s, bitmap);
|
limit = bytes_covered_by_bitmap_cluster(s, bitmap);
|
||||||
for (i = 0, sector = 0; i < tab_size; ++i, sector += sbc) {
|
for (i = 0, offset = 0; i < tab_size; ++i, offset += limit) {
|
||||||
uint64_t count = MIN(bm_size - sector, sbc);
|
uint64_t count = MIN(bm_size - offset, limit);
|
||||||
uint64_t entry = bitmap_table[i];
|
uint64_t entry = bitmap_table[i];
|
||||||
uint64_t offset = entry & BME_TABLE_ENTRY_OFFSET_MASK;
|
uint64_t data_offset = entry & BME_TABLE_ENTRY_OFFSET_MASK;
|
||||||
|
|
||||||
assert(check_table_entry(entry, s->cluster_size) == 0);
|
assert(check_table_entry(entry, s->cluster_size) == 0);
|
||||||
|
|
||||||
if (offset == 0) {
|
if (data_offset == 0) {
|
||||||
if (entry & BME_TABLE_ENTRY_FLAG_ALL_ONES) {
|
if (entry & BME_TABLE_ENTRY_FLAG_ALL_ONES) {
|
||||||
bdrv_dirty_bitmap_deserialize_ones(bitmap, sector, count,
|
bdrv_dirty_bitmap_deserialize_ones(bitmap, offset, count,
|
||||||
false);
|
false);
|
||||||
} else {
|
} else {
|
||||||
/* No need to deserialize zeros because the dirty bitmap is
|
/* No need to deserialize zeros because the dirty bitmap is
|
||||||
* already cleared */
|
* already cleared */
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = bdrv_pread(bs->file, offset, buf, s->cluster_size);
|
ret = bdrv_pread(bs->file, data_offset, buf, s->cluster_size);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
bdrv_dirty_bitmap_deserialize_part(bitmap, buf, sector, count,
|
bdrv_dirty_bitmap_deserialize_part(bitmap, buf, offset, count,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1071,8 +1072,8 @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
int64_t sector;
|
int64_t offset;
|
||||||
uint64_t sbc;
|
uint64_t limit;
|
||||||
uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
|
uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
|
||||||
const char *bm_name = bdrv_dirty_bitmap_name(bitmap);
|
const char *bm_name = bdrv_dirty_bitmap_name(bitmap);
|
||||||
uint8_t *buf = NULL;
|
uint8_t *buf = NULL;
|
||||||
@ -1095,20 +1096,25 @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbi = bdrv_dirty_iter_new(bitmap, 0);
|
dbi = bdrv_dirty_iter_new(bitmap);
|
||||||
buf = g_malloc(s->cluster_size);
|
buf = g_malloc(s->cluster_size);
|
||||||
sbc = sectors_covered_by_bitmap_cluster(s, bitmap);
|
limit = bytes_covered_by_bitmap_cluster(s, bitmap);
|
||||||
assert(DIV_ROUND_UP(bm_size, sbc) == tb_size);
|
assert(DIV_ROUND_UP(bm_size, limit) == tb_size);
|
||||||
|
|
||||||
while ((sector = bdrv_dirty_iter_next(dbi)) != -1) {
|
while ((offset = bdrv_dirty_iter_next(dbi)) >= 0) {
|
||||||
uint64_t cluster = sector / sbc;
|
uint64_t cluster = offset / limit;
|
||||||
uint64_t end, write_size;
|
uint64_t end, write_size;
|
||||||
int64_t off;
|
int64_t off;
|
||||||
|
|
||||||
sector = cluster * sbc;
|
/*
|
||||||
end = MIN(bm_size, sector + sbc);
|
* We found the first dirty offset, but want to write out the
|
||||||
write_size =
|
* entire cluster of the bitmap that includes that offset,
|
||||||
bdrv_dirty_bitmap_serialization_size(bitmap, sector, end - sector);
|
* including any leading zero bits.
|
||||||
|
*/
|
||||||
|
offset = QEMU_ALIGN_DOWN(offset, limit);
|
||||||
|
end = MIN(bm_size, offset + limit);
|
||||||
|
write_size = bdrv_dirty_bitmap_serialization_size(bitmap, offset,
|
||||||
|
end - offset);
|
||||||
assert(write_size <= s->cluster_size);
|
assert(write_size <= s->cluster_size);
|
||||||
|
|
||||||
off = qcow2_alloc_clusters(bs, s->cluster_size);
|
off = qcow2_alloc_clusters(bs, s->cluster_size);
|
||||||
@ -1120,7 +1126,7 @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
tb[cluster] = off;
|
tb[cluster] = off;
|
||||||
|
|
||||||
bdrv_dirty_bitmap_serialize_part(bitmap, buf, sector, end - sector);
|
bdrv_dirty_bitmap_serialize_part(bitmap, buf, offset, end - offset);
|
||||||
if (write_size < s->cluster_size) {
|
if (write_size < s->cluster_size) {
|
||||||
memset(buf + write_size, 0, s->cluster_size - write_size);
|
memset(buf + write_size, 0, s->cluster_size - write_size);
|
||||||
}
|
}
|
||||||
|
@ -446,15 +446,13 @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs,
|
|||||||
{
|
{
|
||||||
if (bytes && bs->encrypted) {
|
if (bytes && bs->encrypted) {
|
||||||
BDRVQcow2State *s = bs->opaque;
|
BDRVQcow2State *s = bs->opaque;
|
||||||
int64_t sector = (s->crypt_physical_offset ?
|
int64_t offset = (s->crypt_physical_offset ?
|
||||||
(cluster_offset + offset_in_cluster) :
|
(cluster_offset + offset_in_cluster) :
|
||||||
(src_cluster_offset + offset_in_cluster))
|
(src_cluster_offset + offset_in_cluster));
|
||||||
>> BDRV_SECTOR_BITS;
|
|
||||||
assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
|
assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
|
||||||
assert((bytes & ~BDRV_SECTOR_MASK) == 0);
|
assert((bytes & ~BDRV_SECTOR_MASK) == 0);
|
||||||
assert(s->crypto);
|
assert(s->crypto);
|
||||||
if (qcrypto_block_encrypt(s->crypto, sector, buffer,
|
if (qcrypto_block_encrypt(s->crypto, offset, buffer, bytes, NULL) < 0) {
|
||||||
bytes, NULL) < 0) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3181,3 +3181,25 @@ out:
|
|||||||
g_free(reftable_tmp);
|
g_free(reftable_tmp);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size)
|
||||||
|
{
|
||||||
|
BDRVQcow2State *s = bs->opaque;
|
||||||
|
int64_t i;
|
||||||
|
|
||||||
|
for (i = size_to_clusters(s, size) - 1; i >= 0; i--) {
|
||||||
|
uint64_t refcount;
|
||||||
|
int ret = qcow2_get_refcount(bs, i, &refcount);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Can't get refcount for cluster %" PRId64 ": %s\n",
|
||||||
|
i, strerror(-ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (refcount > 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qcow2_signal_corruption(bs, true, -1, -1,
|
||||||
|
"There are no references in the refcount table.");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
@ -1811,7 +1811,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
|
|||||||
if (qcrypto_block_decrypt(s->crypto,
|
if (qcrypto_block_decrypt(s->crypto,
|
||||||
(s->crypt_physical_offset ?
|
(s->crypt_physical_offset ?
|
||||||
cluster_offset + offset_in_cluster :
|
cluster_offset + offset_in_cluster :
|
||||||
offset) >> BDRV_SECTOR_BITS,
|
offset),
|
||||||
cluster_data,
|
cluster_data,
|
||||||
cur_bytes,
|
cur_bytes,
|
||||||
NULL) < 0) {
|
NULL) < 0) {
|
||||||
@ -1946,7 +1946,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
|||||||
if (qcrypto_block_encrypt(s->crypto,
|
if (qcrypto_block_encrypt(s->crypto,
|
||||||
(s->crypt_physical_offset ?
|
(s->crypt_physical_offset ?
|
||||||
cluster_offset + offset_in_cluster :
|
cluster_offset + offset_in_cluster :
|
||||||
offset) >> BDRV_SECTOR_BITS,
|
offset),
|
||||||
cluster_data,
|
cluster_data,
|
||||||
cur_bytes, NULL) < 0) {
|
cur_bytes, NULL) < 0) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
@ -3107,6 +3107,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
|
|||||||
new_l1_size = size_to_l1(s, offset);
|
new_l1_size = size_to_l1(s, offset);
|
||||||
|
|
||||||
if (offset < old_length) {
|
if (offset < old_length) {
|
||||||
|
int64_t last_cluster, old_file_size;
|
||||||
if (prealloc != PREALLOC_MODE_OFF) {
|
if (prealloc != PREALLOC_MODE_OFF) {
|
||||||
error_setg(errp,
|
error_setg(errp,
|
||||||
"Preallocation can't be used for shrinking an image");
|
"Preallocation can't be used for shrinking an image");
|
||||||
@ -3135,6 +3136,28 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
|
|||||||
"Failed to discard unused refblocks");
|
"Failed to discard unused refblocks");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
old_file_size = bdrv_getlength(bs->file->bs);
|
||||||
|
if (old_file_size < 0) {
|
||||||
|
error_setg_errno(errp, -old_file_size,
|
||||||
|
"Failed to inquire current file length");
|
||||||
|
return old_file_size;
|
||||||
|
}
|
||||||
|
last_cluster = qcow2_get_last_cluster(bs, old_file_size);
|
||||||
|
if (last_cluster < 0) {
|
||||||
|
error_setg_errno(errp, -last_cluster,
|
||||||
|
"Failed to find the last cluster");
|
||||||
|
return last_cluster;
|
||||||
|
}
|
||||||
|
if ((last_cluster + 1) * s->cluster_size < old_file_size) {
|
||||||
|
ret = bdrv_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
|
||||||
|
PREALLOC_MODE_OFF, NULL);
|
||||||
|
if (ret < 0) {
|
||||||
|
warn_report("Failed to truncate the tail of the image: %s",
|
||||||
|
strerror(-ret));
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = qcow2_grow_l1_table(bs, new_l1_size, true);
|
ret = qcow2_grow_l1_table(bs, new_l1_size, true);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -3167,7 +3190,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
|
|||||||
if (old_file_size < 0) {
|
if (old_file_size < 0) {
|
||||||
error_setg_errno(errp, -old_file_size,
|
error_setg_errno(errp, -old_file_size,
|
||||||
"Failed to inquire current file length");
|
"Failed to inquire current file length");
|
||||||
return ret;
|
return old_file_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
nb_new_data_clusters = DIV_ROUND_UP(offset - old_length,
|
nb_new_data_clusters = DIV_ROUND_UP(offset - old_length,
|
||||||
@ -3196,7 +3219,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
|
|||||||
if (allocation_start < 0) {
|
if (allocation_start < 0) {
|
||||||
error_setg_errno(errp, -allocation_start,
|
error_setg_errno(errp, -allocation_start,
|
||||||
"Failed to resize refcount structures");
|
"Failed to resize refcount structures");
|
||||||
return -allocation_start;
|
return allocation_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
clusters_allocated = qcow2_alloc_clusters_at(bs, allocation_start,
|
clusters_allocated = qcow2_alloc_clusters_at(bs, allocation_start,
|
||||||
@ -3673,20 +3696,19 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
|
|||||||
*/
|
*/
|
||||||
required = virtual_size;
|
required = virtual_size;
|
||||||
} else {
|
} else {
|
||||||
int cluster_sectors = cluster_size / BDRV_SECTOR_SIZE;
|
int64_t offset;
|
||||||
int64_t sector_num;
|
|
||||||
int pnum = 0;
|
int pnum = 0;
|
||||||
|
|
||||||
for (sector_num = 0;
|
for (offset = 0; offset < ssize;
|
||||||
sector_num < ssize / BDRV_SECTOR_SIZE;
|
offset += pnum * BDRV_SECTOR_SIZE) {
|
||||||
sector_num += pnum) {
|
int nb_sectors = MIN(ssize - offset,
|
||||||
int nb_sectors = MIN(ssize / BDRV_SECTOR_SIZE - sector_num,
|
BDRV_REQUEST_MAX_BYTES) / BDRV_SECTOR_SIZE;
|
||||||
BDRV_REQUEST_MAX_SECTORS);
|
|
||||||
BlockDriverState *file;
|
BlockDriverState *file;
|
||||||
int64_t ret;
|
int64_t ret;
|
||||||
|
|
||||||
ret = bdrv_get_block_status_above(in_bs, NULL,
|
ret = bdrv_get_block_status_above(in_bs, NULL,
|
||||||
sector_num, nb_sectors,
|
offset >> BDRV_SECTOR_BITS,
|
||||||
|
nb_sectors,
|
||||||
&pnum, &file);
|
&pnum, &file);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg_errno(&local_err, -ret,
|
error_setg_errno(&local_err, -ret,
|
||||||
@ -3699,12 +3721,11 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs,
|
|||||||
} else if ((ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) ==
|
} else if ((ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) ==
|
||||||
(BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) {
|
(BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) {
|
||||||
/* Extend pnum to end of cluster for next iteration */
|
/* Extend pnum to end of cluster for next iteration */
|
||||||
pnum = ROUND_UP(sector_num + pnum, cluster_sectors) -
|
pnum = (ROUND_UP(offset + pnum * BDRV_SECTOR_SIZE,
|
||||||
sector_num;
|
cluster_size) - offset) >> BDRV_SECTOR_BITS;
|
||||||
|
|
||||||
/* Count clusters we've seen */
|
/* Count clusters we've seen */
|
||||||
required += (sector_num % cluster_sectors + pnum) *
|
required += offset % cluster_size + pnum * BDRV_SECTOR_SIZE;
|
||||||
BDRV_SECTOR_SIZE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -597,6 +597,7 @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
|
|||||||
BlockDriverAmendStatusCB *status_cb,
|
BlockDriverAmendStatusCB *status_cb,
|
||||||
void *cb_opaque, Error **errp);
|
void *cb_opaque, Error **errp);
|
||||||
int qcow2_shrink_reftable(BlockDriverState *bs);
|
int qcow2_shrink_reftable(BlockDriverState *bs);
|
||||||
|
int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
|
||||||
|
|
||||||
/* qcow2-cluster.c functions */
|
/* qcow2-cluster.c functions */
|
||||||
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
||||||
|
@ -846,8 +846,9 @@ qcrypto_block_luks_open(QCryptoBlock *block,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
block->sector_size = QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
|
||||||
block->payload_offset = luks->header.payload_offset *
|
block->payload_offset = luks->header.payload_offset *
|
||||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
|
block->sector_size;
|
||||||
|
|
||||||
luks->cipher_alg = cipheralg;
|
luks->cipher_alg = cipheralg;
|
||||||
luks->cipher_mode = ciphermode;
|
luks->cipher_mode = ciphermode;
|
||||||
@ -1240,8 +1241,9 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
|||||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) *
|
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) *
|
||||||
QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);
|
QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);
|
||||||
|
|
||||||
|
block->sector_size = QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
|
||||||
block->payload_offset = luks->header.payload_offset *
|
block->payload_offset = luks->header.payload_offset *
|
||||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
|
block->sector_size;
|
||||||
|
|
||||||
/* Reserve header space to match payload offset */
|
/* Reserve header space to match payload offset */
|
||||||
initfunc(block, block->payload_offset, opaque, &local_err);
|
initfunc(block, block->payload_offset, opaque, &local_err);
|
||||||
@ -1397,29 +1399,33 @@ static void qcrypto_block_luks_cleanup(QCryptoBlock *block)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
qcrypto_block_luks_decrypt(QCryptoBlock *block,
|
qcrypto_block_luks_decrypt(QCryptoBlock *block,
|
||||||
uint64_t startsector,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
|
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
|
||||||
|
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
|
||||||
return qcrypto_block_decrypt_helper(block->cipher,
|
return qcrypto_block_decrypt_helper(block->cipher,
|
||||||
block->niv, block->ivgen,
|
block->niv, block->ivgen,
|
||||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
||||||
startsector, buf, len, errp);
|
offset, buf, len, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qcrypto_block_luks_encrypt(QCryptoBlock *block,
|
qcrypto_block_luks_encrypt(QCryptoBlock *block,
|
||||||
uint64_t startsector,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
|
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
|
||||||
|
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE));
|
||||||
return qcrypto_block_encrypt_helper(block->cipher,
|
return qcrypto_block_encrypt_helper(block->cipher,
|
||||||
block->niv, block->ivgen,
|
block->niv, block->ivgen,
|
||||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
||||||
startsector, buf, len, errp);
|
offset, buf, len, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -80,6 +80,7 @@ qcrypto_block_qcow_init(QCryptoBlock *block,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE;
|
||||||
block->payload_offset = 0;
|
block->payload_offset = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -142,29 +143,33 @@ qcrypto_block_qcow_cleanup(QCryptoBlock *block)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
qcrypto_block_qcow_decrypt(QCryptoBlock *block,
|
qcrypto_block_qcow_decrypt(QCryptoBlock *block,
|
||||||
uint64_t startsector,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
|
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
|
||||||
|
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
|
||||||
return qcrypto_block_decrypt_helper(block->cipher,
|
return qcrypto_block_decrypt_helper(block->cipher,
|
||||||
block->niv, block->ivgen,
|
block->niv, block->ivgen,
|
||||||
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
||||||
startsector, buf, len, errp);
|
offset, buf, len, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qcrypto_block_qcow_encrypt(QCryptoBlock *block,
|
qcrypto_block_qcow_encrypt(QCryptoBlock *block,
|
||||||
uint64_t startsector,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
|
assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
|
||||||
|
assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
|
||||||
return qcrypto_block_encrypt_helper(block->cipher,
|
return qcrypto_block_encrypt_helper(block->cipher,
|
||||||
block->niv, block->ivgen,
|
block->niv, block->ivgen,
|
||||||
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
||||||
startsector, buf, len, errp);
|
offset, buf, len, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,22 +127,22 @@ QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
|
|||||||
|
|
||||||
|
|
||||||
int qcrypto_block_decrypt(QCryptoBlock *block,
|
int qcrypto_block_decrypt(QCryptoBlock *block,
|
||||||
uint64_t startsector,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
return block->driver->decrypt(block, startsector, buf, len, errp);
|
return block->driver->decrypt(block, offset, buf, len, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int qcrypto_block_encrypt(QCryptoBlock *block,
|
int qcrypto_block_encrypt(QCryptoBlock *block,
|
||||||
uint64_t startsector,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
return block->driver->encrypt(block, startsector, buf, len, errp);
|
return block->driver->encrypt(block, offset, buf, len, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -170,6 +170,12 @@ uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block)
|
||||||
|
{
|
||||||
|
return block->sector_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void qcrypto_block_free(QCryptoBlock *block)
|
void qcrypto_block_free(QCryptoBlock *block)
|
||||||
{
|
{
|
||||||
if (!block) {
|
if (!block) {
|
||||||
@ -188,13 +194,17 @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
|||||||
size_t niv,
|
size_t niv,
|
||||||
QCryptoIVGen *ivgen,
|
QCryptoIVGen *ivgen,
|
||||||
int sectorsize,
|
int sectorsize,
|
||||||
uint64_t startsector,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
uint8_t *iv;
|
uint8_t *iv;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
uint64_t startsector = offset / sectorsize;
|
||||||
|
|
||||||
|
assert(QEMU_IS_ALIGNED(offset, sectorsize));
|
||||||
|
assert(QEMU_IS_ALIGNED(len, sectorsize));
|
||||||
|
|
||||||
iv = niv ? g_new0(uint8_t, niv) : NULL;
|
iv = niv ? g_new0(uint8_t, niv) : NULL;
|
||||||
|
|
||||||
@ -237,13 +247,17 @@ int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
|
|||||||
size_t niv,
|
size_t niv,
|
||||||
QCryptoIVGen *ivgen,
|
QCryptoIVGen *ivgen,
|
||||||
int sectorsize,
|
int sectorsize,
|
||||||
uint64_t startsector,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
uint8_t *iv;
|
uint8_t *iv;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
uint64_t startsector = offset / sectorsize;
|
||||||
|
|
||||||
|
assert(QEMU_IS_ALIGNED(offset, sectorsize));
|
||||||
|
assert(QEMU_IS_ALIGNED(len, sectorsize));
|
||||||
|
|
||||||
iv = niv ? g_new0(uint8_t, niv) : NULL;
|
iv = niv ? g_new0(uint8_t, niv) : NULL;
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ struct QCryptoBlock {
|
|||||||
QCryptoHashAlgorithm kdfhash;
|
QCryptoHashAlgorithm kdfhash;
|
||||||
size_t niv;
|
size_t niv;
|
||||||
uint64_t payload_offset; /* In bytes */
|
uint64_t payload_offset; /* In bytes */
|
||||||
|
uint64_t sector_size; /* In bytes */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QCryptoBlockDriver {
|
struct QCryptoBlockDriver {
|
||||||
@ -81,7 +82,7 @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
|||||||
size_t niv,
|
size_t niv,
|
||||||
QCryptoIVGen *ivgen,
|
QCryptoIVGen *ivgen,
|
||||||
int sectorsize,
|
int sectorsize,
|
||||||
uint64_t startsector,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
@ -90,7 +91,7 @@ int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
|
|||||||
size_t niv,
|
size_t niv,
|
||||||
QCryptoIVGen *ivgen,
|
QCryptoIVGen *ivgen,
|
||||||
int sectorsize,
|
int sectorsize,
|
||||||
uint64_t startsector,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
|
@ -520,10 +520,6 @@ static void onenand_command(OneNANDState *s)
|
|||||||
s->intstatus |= ONEN_INT;
|
s->intstatus |= ONEN_INT;
|
||||||
|
|
||||||
for (b = 0; b < s->blocks; b ++) {
|
for (b = 0; b < s->blocks; b ++) {
|
||||||
if (b >= s->blocks) {
|
|
||||||
s->status |= ONEN_ERR_CMD;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
|
if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -315,8 +315,7 @@ int bdrv_commit(BlockDriverState *bs);
|
|||||||
int bdrv_change_backing_file(BlockDriverState *bs,
|
int bdrv_change_backing_file(BlockDriverState *bs,
|
||||||
const char *backing_file, const char *backing_fmt);
|
const char *backing_file, const char *backing_fmt);
|
||||||
void bdrv_register(BlockDriver *bdrv);
|
void bdrv_register(BlockDriver *bdrv);
|
||||||
int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
|
int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
|
||||||
BlockDriverState *base,
|
|
||||||
const char *backing_file_str);
|
const char *backing_file_str);
|
||||||
BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
|
BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
|
||||||
BlockDriverState *bs);
|
BlockDriverState *bs);
|
||||||
|
@ -544,6 +544,12 @@ struct BdrvChildRole {
|
|||||||
|
|
||||||
void (*attach)(BdrvChild *child);
|
void (*attach)(BdrvChild *child);
|
||||||
void (*detach)(BdrvChild *child);
|
void (*detach)(BdrvChild *child);
|
||||||
|
|
||||||
|
/* Notifies the parent that the filename of its child has changed (e.g.
|
||||||
|
* because the direct child was removed from the backing chain), so that it
|
||||||
|
* can update its reference. */
|
||||||
|
int (*update_filename)(BdrvChild *child, BlockDriverState *new_base,
|
||||||
|
const char *filename, Error **errp);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const BdrvChildRole child_file;
|
extern const BdrvChildRole child_file;
|
||||||
@ -1028,7 +1034,7 @@ void blk_dev_eject_request(BlockBackend *blk, bool force);
|
|||||||
bool blk_dev_is_tray_open(BlockBackend *blk);
|
bool blk_dev_is_tray_open(BlockBackend *blk);
|
||||||
bool blk_dev_is_medium_locked(BlockBackend *blk);
|
bool blk_dev_is_medium_locked(BlockBackend *blk);
|
||||||
|
|
||||||
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int64_t nr_sect);
|
void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
|
||||||
bool bdrv_requests_pending(BlockDriverState *bs);
|
bool bdrv_requests_pending(BlockDriverState *bs);
|
||||||
|
|
||||||
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
|
void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
|
||||||
|
@ -34,44 +34,33 @@ void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
|
|||||||
BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
|
BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
|
||||||
uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
|
uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
|
||||||
uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap);
|
uint32_t bdrv_dirty_bitmap_granularity(const BdrvDirtyBitmap *bitmap);
|
||||||
uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap);
|
|
||||||
bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
|
bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
|
||||||
bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
|
bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
|
||||||
const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap);
|
const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap);
|
||||||
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap);
|
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap);
|
||||||
DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap);
|
DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap);
|
||||||
void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
||||||
int64_t cur_sector, int64_t nr_sectors);
|
int64_t offset, int64_t bytes);
|
||||||
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
|
||||||
int64_t cur_sector, int64_t nr_sectors);
|
int64_t offset, int64_t bytes);
|
||||||
int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
|
|
||||||
BdrvDirtyBitmap *bitmap, int64_t sector,
|
|
||||||
int nb_sectors);
|
|
||||||
int bdrv_dirty_bitmap_get_meta_locked(BlockDriverState *bs,
|
|
||||||
BdrvDirtyBitmap *bitmap, int64_t sector,
|
|
||||||
int nb_sectors);
|
|
||||||
void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
|
|
||||||
BdrvDirtyBitmap *bitmap, int64_t sector,
|
|
||||||
int nb_sectors);
|
|
||||||
BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
|
BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
|
||||||
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
|
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap);
|
||||||
uint64_t first_sector);
|
|
||||||
void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
|
void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
|
||||||
|
|
||||||
uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
|
uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
|
||||||
uint64_t start, uint64_t count);
|
uint64_t offset, uint64_t bytes);
|
||||||
uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap);
|
uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap);
|
||||||
void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
|
void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
|
||||||
uint8_t *buf, uint64_t start,
|
uint8_t *buf, uint64_t offset,
|
||||||
uint64_t count);
|
uint64_t bytes);
|
||||||
void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
|
void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
|
||||||
uint8_t *buf, uint64_t start,
|
uint8_t *buf, uint64_t offset,
|
||||||
uint64_t count, bool finish);
|
uint64_t bytes, bool finish);
|
||||||
void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
|
void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
|
||||||
uint64_t start, uint64_t count,
|
uint64_t offset, uint64_t bytes,
|
||||||
bool finish);
|
bool finish);
|
||||||
void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
|
void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
|
||||||
uint64_t start, uint64_t count,
|
uint64_t offset, uint64_t bytes,
|
||||||
bool finish);
|
bool finish);
|
||||||
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
|
void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
|
||||||
|
|
||||||
@ -83,17 +72,17 @@ void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
|
|||||||
/* Functions that require manual locking. */
|
/* Functions that require manual locking. */
|
||||||
void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap);
|
void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap);
|
||||||
void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap);
|
void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap);
|
||||||
int bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
bool bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||||
int64_t sector);
|
int64_t offset);
|
||||||
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
|
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
|
||||||
int64_t cur_sector, int64_t nr_sectors);
|
int64_t offset, int64_t bytes);
|
||||||
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
|
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
|
||||||
int64_t cur_sector, int64_t nr_sectors);
|
int64_t offset, int64_t bytes);
|
||||||
int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
|
int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
|
||||||
void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
|
void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t offset);
|
||||||
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
|
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
|
||||||
int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
|
int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
|
||||||
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
|
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes);
|
||||||
bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
|
bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
|
||||||
bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);
|
bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);
|
||||||
bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
|
bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
|
||||||
|
@ -161,18 +161,19 @@ QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
|
|||||||
/**
|
/**
|
||||||
* @qcrypto_block_decrypt:
|
* @qcrypto_block_decrypt:
|
||||||
* @block: the block encryption object
|
* @block: the block encryption object
|
||||||
* @startsector: the sector from which @buf was read
|
* @offset: the position at which @iov was read
|
||||||
* @buf: the buffer to decrypt
|
* @buf: the buffer to decrypt
|
||||||
* @len: the length of @buf in bytes
|
* @len: the length of @buf in bytes
|
||||||
* @errp: pointer to a NULL-initialized error object
|
* @errp: pointer to a NULL-initialized error object
|
||||||
*
|
*
|
||||||
* Decrypt @len bytes of cipher text in @buf, writing
|
* Decrypt @len bytes of cipher text in @buf, writing
|
||||||
* plain text back into @buf
|
* plain text back into @buf. @len and @offset must be
|
||||||
|
* a multiple of the encryption format sector size.
|
||||||
*
|
*
|
||||||
* Returns 0 on success, -1 on failure
|
* Returns 0 on success, -1 on failure
|
||||||
*/
|
*/
|
||||||
int qcrypto_block_decrypt(QCryptoBlock *block,
|
int qcrypto_block_decrypt(QCryptoBlock *block,
|
||||||
uint64_t startsector,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
@ -180,18 +181,19 @@ int qcrypto_block_decrypt(QCryptoBlock *block,
|
|||||||
/**
|
/**
|
||||||
* @qcrypto_block_encrypt:
|
* @qcrypto_block_encrypt:
|
||||||
* @block: the block encryption object
|
* @block: the block encryption object
|
||||||
* @startsector: the sector to which @buf will be written
|
* @offset: the position at which @iov will be written
|
||||||
* @buf: the buffer to decrypt
|
* @buf: the buffer to decrypt
|
||||||
* @len: the length of @buf in bytes
|
* @len: the length of @buf in bytes
|
||||||
* @errp: pointer to a NULL-initialized error object
|
* @errp: pointer to a NULL-initialized error object
|
||||||
*
|
*
|
||||||
* Encrypt @len bytes of plain text in @buf, writing
|
* Encrypt @len bytes of plain text in @buf, writing
|
||||||
* cipher text back into @buf
|
* cipher text back into @buf. @len and @offset must be
|
||||||
|
* a multiple of the encryption format sector size.
|
||||||
*
|
*
|
||||||
* Returns 0 on success, -1 on failure
|
* Returns 0 on success, -1 on failure
|
||||||
*/
|
*/
|
||||||
int qcrypto_block_encrypt(QCryptoBlock *block,
|
int qcrypto_block_encrypt(QCryptoBlock *block,
|
||||||
uint64_t startsector,
|
uint64_t offset,
|
||||||
uint8_t *buf,
|
uint8_t *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
@ -240,6 +242,21 @@ QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block);
|
|||||||
*/
|
*/
|
||||||
uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block);
|
uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qcrypto_block_get_sector_size:
|
||||||
|
* @block: the block encryption object
|
||||||
|
*
|
||||||
|
* Get the size of sectors used for payload encryption. A new
|
||||||
|
* IV is used at the start of each sector. The encryption
|
||||||
|
* sector size is not required to match the sector size of the
|
||||||
|
* underlying storage. For example LUKS will always use a 512
|
||||||
|
* byte sector size, even if the volume is on a disk with 4k
|
||||||
|
* sectors.
|
||||||
|
*
|
||||||
|
* Returns: the sector in bytes
|
||||||
|
*/
|
||||||
|
uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qcrypto_block_free:
|
* qcrypto_block_free:
|
||||||
* @block: the block encryption object
|
* @block: the block encryption object
|
||||||
|
@ -159,16 +159,16 @@ bool hbitmap_get(const HBitmap *hb, uint64_t item);
|
|||||||
bool hbitmap_is_serializable(const HBitmap *hb);
|
bool hbitmap_is_serializable(const HBitmap *hb);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hbitmap_serialization_granularity:
|
* hbitmap_serialization_align:
|
||||||
* @hb: HBitmap to operate on.
|
* @hb: HBitmap to operate on.
|
||||||
*
|
*
|
||||||
* Granularity of serialization chunks, used by other serialization functions.
|
* Required alignment of serialization chunks, used by other serialization
|
||||||
* For every chunk:
|
* functions. For every chunk:
|
||||||
* 1. Chunk start should be aligned to this granularity.
|
* 1. Chunk start should be aligned to this granularity.
|
||||||
* 2. Chunk size should be aligned too, except for last chunk (for which
|
* 2. Chunk size should be aligned too, except for last chunk (for which
|
||||||
* start + count == hb->size)
|
* start + count == hb->size)
|
||||||
*/
|
*/
|
||||||
uint64_t hbitmap_serialization_granularity(const HBitmap *hb);
|
uint64_t hbitmap_serialization_align(const HBitmap *hb);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hbitmap_serialization_size:
|
* hbitmap_serialization_size:
|
||||||
|
@ -334,7 +334,8 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
|
|||||||
blk->aiocb = blk_aio_preadv(bb, cur_sector * BDRV_SECTOR_SIZE, &blk->qiov,
|
blk->aiocb = blk_aio_preadv(bb, cur_sector * BDRV_SECTOR_SIZE, &blk->qiov,
|
||||||
0, blk_mig_read_cb, blk);
|
0, blk_mig_read_cb, blk);
|
||||||
|
|
||||||
bdrv_reset_dirty_bitmap(bmds->dirty_bitmap, cur_sector, nr_sectors);
|
bdrv_reset_dirty_bitmap(bmds->dirty_bitmap, cur_sector * BDRV_SECTOR_SIZE,
|
||||||
|
nr_sectors * BDRV_SECTOR_SIZE);
|
||||||
aio_context_release(blk_get_aio_context(bmds->blk));
|
aio_context_release(blk_get_aio_context(bmds->blk));
|
||||||
qemu_mutex_unlock_iothread();
|
qemu_mutex_unlock_iothread();
|
||||||
|
|
||||||
@ -535,13 +536,16 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
|
|||||||
blk_mig_unlock();
|
blk_mig_unlock();
|
||||||
}
|
}
|
||||||
bdrv_dirty_bitmap_lock(bmds->dirty_bitmap);
|
bdrv_dirty_bitmap_lock(bmds->dirty_bitmap);
|
||||||
if (bdrv_get_dirty_locked(bs, bmds->dirty_bitmap, sector)) {
|
if (bdrv_get_dirty_locked(bs, bmds->dirty_bitmap,
|
||||||
|
sector * BDRV_SECTOR_SIZE)) {
|
||||||
if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
|
if (total_sectors - sector < BDRV_SECTORS_PER_DIRTY_CHUNK) {
|
||||||
nr_sectors = total_sectors - sector;
|
nr_sectors = total_sectors - sector;
|
||||||
} else {
|
} else {
|
||||||
nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
|
nr_sectors = BDRV_SECTORS_PER_DIRTY_CHUNK;
|
||||||
}
|
}
|
||||||
bdrv_reset_dirty_bitmap_locked(bmds->dirty_bitmap, sector, nr_sectors);
|
bdrv_reset_dirty_bitmap_locked(bmds->dirty_bitmap,
|
||||||
|
sector * BDRV_SECTOR_SIZE,
|
||||||
|
nr_sectors * BDRV_SECTOR_SIZE);
|
||||||
bdrv_dirty_bitmap_unlock(bmds->dirty_bitmap);
|
bdrv_dirty_bitmap_unlock(bmds->dirty_bitmap);
|
||||||
|
|
||||||
blk = g_new(BlkMigBlock, 1);
|
blk = g_new(BlkMigBlock, 1);
|
||||||
@ -672,7 +676,7 @@ static int64_t get_remaining_dirty(void)
|
|||||||
aio_context_release(blk_get_aio_context(bmds->blk));
|
aio_context_release(blk_get_aio_context(bmds->blk));
|
||||||
}
|
}
|
||||||
|
|
||||||
return dirty << BDRV_SECTOR_BITS;
|
return dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2538,6 +2538,8 @@
|
|||||||
#
|
#
|
||||||
# @l1_shrink_free_l2_clusters: discard the l2 tables. (since 2.11)
|
# @l1_shrink_free_l2_clusters: discard the l2 tables. (since 2.11)
|
||||||
#
|
#
|
||||||
|
# @cor_write: a write due to copy-on-read (since 2.11)
|
||||||
|
#
|
||||||
# Since: 2.9
|
# Since: 2.9
|
||||||
##
|
##
|
||||||
{ 'enum': 'BlkdebugEvent', 'prefix': 'BLKDBG',
|
{ 'enum': 'BlkdebugEvent', 'prefix': 'BLKDBG',
|
||||||
@ -2555,7 +2557,8 @@
|
|||||||
'flush_to_disk', 'pwritev_rmw_head', 'pwritev_rmw_after_head',
|
'flush_to_disk', 'pwritev_rmw_head', 'pwritev_rmw_after_head',
|
||||||
'pwritev_rmw_tail', 'pwritev_rmw_after_tail', 'pwritev',
|
'pwritev_rmw_tail', 'pwritev_rmw_after_tail', 'pwritev',
|
||||||
'pwritev_zero', 'pwritev_done', 'empty_image_prepare',
|
'pwritev_zero', 'pwritev_done', 'empty_image_prepare',
|
||||||
'l1_shrink_write_table', 'l1_shrink_free_l2_clusters' ] }
|
'l1_shrink_write_table', 'l1_shrink_free_l2_clusters',
|
||||||
|
'cor_write'] }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @BlkdebugInjectErrorOptions:
|
# @BlkdebugInjectErrorOptions:
|
||||||
|
15
qemu-io.c
15
qemu-io.c
@ -102,6 +102,7 @@ static void open_help(void)
|
|||||||
" Opens a file for subsequent use by all of the other qemu-io commands.\n"
|
" Opens a file for subsequent use by all of the other qemu-io commands.\n"
|
||||||
" -r, -- open file read-only\n"
|
" -r, -- open file read-only\n"
|
||||||
" -s, -- use snapshot file\n"
|
" -s, -- use snapshot file\n"
|
||||||
|
" -C, -- use copy-on-read\n"
|
||||||
" -n, -- disable host cache, short for -t none\n"
|
" -n, -- disable host cache, short for -t none\n"
|
||||||
" -U, -- force shared permissions\n"
|
" -U, -- force shared permissions\n"
|
||||||
" -k, -- use kernel AIO implementation (on Linux only)\n"
|
" -k, -- use kernel AIO implementation (on Linux only)\n"
|
||||||
@ -120,7 +121,7 @@ static const cmdinfo_t open_cmd = {
|
|||||||
.argmin = 1,
|
.argmin = 1,
|
||||||
.argmax = -1,
|
.argmax = -1,
|
||||||
.flags = CMD_NOFILE_OK,
|
.flags = CMD_NOFILE_OK,
|
||||||
.args = "[-rsnkU] [-t cache] [-d discard] [-o options] [path]",
|
.args = "[-rsCnkU] [-t cache] [-d discard] [-o options] [path]",
|
||||||
.oneline = "open the file specified by path",
|
.oneline = "open the file specified by path",
|
||||||
.help = open_help,
|
.help = open_help,
|
||||||
};
|
};
|
||||||
@ -145,7 +146,7 @@ static int open_f(BlockBackend *blk, int argc, char **argv)
|
|||||||
QDict *opts;
|
QDict *opts;
|
||||||
bool force_share = false;
|
bool force_share = false;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "snro:kt:d:U")) != -1) {
|
while ((c = getopt(argc, argv, "snCro:kt:d:U")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 's':
|
case 's':
|
||||||
flags |= BDRV_O_SNAPSHOT;
|
flags |= BDRV_O_SNAPSHOT;
|
||||||
@ -154,6 +155,9 @@ static int open_f(BlockBackend *blk, int argc, char **argv)
|
|||||||
flags |= BDRV_O_NOCACHE;
|
flags |= BDRV_O_NOCACHE;
|
||||||
writethrough = false;
|
writethrough = false;
|
||||||
break;
|
break;
|
||||||
|
case 'C':
|
||||||
|
flags |= BDRV_O_COPY_ON_READ;
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
readonly = 1;
|
readonly = 1;
|
||||||
break;
|
break;
|
||||||
@ -251,6 +255,7 @@ static void usage(const char *name)
|
|||||||
" -r, --read-only export read-only\n"
|
" -r, --read-only export read-only\n"
|
||||||
" -s, --snapshot use snapshot file\n"
|
" -s, --snapshot use snapshot file\n"
|
||||||
" -n, --nocache disable host cache, short for -t none\n"
|
" -n, --nocache disable host cache, short for -t none\n"
|
||||||
|
" -C, --copy-on-read enable copy-on-read\n"
|
||||||
" -m, --misalign misalign allocations for O_DIRECT\n"
|
" -m, --misalign misalign allocations for O_DIRECT\n"
|
||||||
" -k, --native-aio use kernel AIO implementation (on Linux only)\n"
|
" -k, --native-aio use kernel AIO implementation (on Linux only)\n"
|
||||||
" -t, --cache=MODE use the given cache mode for the image\n"
|
" -t, --cache=MODE use the given cache mode for the image\n"
|
||||||
@ -439,7 +444,7 @@ static QemuOptsList file_opts = {
|
|||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int readonly = 0;
|
int readonly = 0;
|
||||||
const char *sopt = "hVc:d:f:rsnmkt:T:U";
|
const char *sopt = "hVc:d:f:rsnCmkt:T:U";
|
||||||
const struct option lopt[] = {
|
const struct option lopt[] = {
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "version", no_argument, NULL, 'V' },
|
{ "version", no_argument, NULL, 'V' },
|
||||||
@ -448,6 +453,7 @@ int main(int argc, char **argv)
|
|||||||
{ "read-only", no_argument, NULL, 'r' },
|
{ "read-only", no_argument, NULL, 'r' },
|
||||||
{ "snapshot", no_argument, NULL, 's' },
|
{ "snapshot", no_argument, NULL, 's' },
|
||||||
{ "nocache", no_argument, NULL, 'n' },
|
{ "nocache", no_argument, NULL, 'n' },
|
||||||
|
{ "copy-on-read", no_argument, NULL, 'C' },
|
||||||
{ "misalign", no_argument, NULL, 'm' },
|
{ "misalign", no_argument, NULL, 'm' },
|
||||||
{ "native-aio", no_argument, NULL, 'k' },
|
{ "native-aio", no_argument, NULL, 'k' },
|
||||||
{ "discard", required_argument, NULL, 'd' },
|
{ "discard", required_argument, NULL, 'd' },
|
||||||
@ -492,6 +498,9 @@ int main(int argc, char **argv)
|
|||||||
flags |= BDRV_O_NOCACHE;
|
flags |= BDRV_O_NOCACHE;
|
||||||
writethrough = false;
|
writethrough = false;
|
||||||
break;
|
break;
|
||||||
|
case 'C':
|
||||||
|
flags |= BDRV_O_COPY_ON_READ;
|
||||||
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
|
if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
|
||||||
error_report("Invalid discard option: %s", optarg);
|
error_report("Invalid discard option: %s", optarg);
|
||||||
|
@ -287,10 +287,6 @@ class TestParallelOps(iotests.QMPTestCase):
|
|||||||
result = self.vm.qmp('block-stream', device='node6', base=self.imgs[4], job_id='stream-node6-v2')
|
result = self.vm.qmp('block-stream', device='node6', base=self.imgs[4], job_id='stream-node6-v2')
|
||||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||||
|
|
||||||
# This fails because block-commit needs to block node6, the overlay of the 'top' image
|
|
||||||
result = self.vm.qmp('block-stream', device='node7', base=self.imgs[5], job_id='stream-node6-v3')
|
|
||||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
|
||||||
|
|
||||||
# This fails because block-commit currently blocks the active layer even if it's not used
|
# This fails because block-commit currently blocks the active layer even if it's not used
|
||||||
result = self.vm.qmp('block-stream', device='drive0', base=self.imgs[5], job_id='stream-drive0')
|
result = self.vm.qmp('block-stream', device='drive0', base=self.imgs[5], job_id='stream-drive0')
|
||||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||||
|
@ -11,7 +11,7 @@ No errors were found on the image.
|
|||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||||
wrote 512/512 bytes at offset 0
|
wrote 512/512 bytes at offset 0
|
||||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
else
|
else
|
||||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
@ -50,7 +50,7 @@ read 512/512 bytes at offset 0
|
|||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||||
wrote 512/512 bytes at offset 0
|
wrote 512/512 bytes at offset 0
|
||||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
else
|
else
|
||||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
@ -68,7 +68,7 @@ incompatible_features 0x0
|
|||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||||
wrote 512/512 bytes at offset 0
|
wrote 512/512 bytes at offset 0
|
||||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
else
|
else
|
||||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
@ -91,7 +91,7 @@ No errors were found on the image.
|
|||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||||
wrote 512/512 bytes at offset 0
|
wrote 512/512 bytes at offset 0
|
||||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
else
|
else
|
||||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
@ -105,7 +105,7 @@ Data may be corrupted, or further writes to the image may corrupt it.
|
|||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||||
wrote 512/512 bytes at offset 0
|
wrote 512/512 bytes at offset 0
|
||||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
else
|
else
|
||||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
|
@ -57,7 +57,7 @@ No errors were found on the image.
|
|||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||||
wrote 131072/131072 bytes at offset 0
|
wrote 131072/131072 bytes at offset 0
|
||||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
else
|
else
|
||||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
@ -219,7 +219,7 @@ No errors were found on the image.
|
|||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
|
||||||
wrote 131072/131072 bytes at offset 0
|
wrote 131072/131072 bytes at offset 0
|
||||||
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
else
|
else
|
||||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
|
@ -31,7 +31,7 @@ Cache clean interval too big
|
|||||||
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
|
||||||
wrote 512/512 bytes at offset 0
|
wrote 512/512 bytes at offset 0
|
||||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
./common.rc: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
else
|
else
|
||||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||||
|
@ -27,7 +27,7 @@ disk = os.path.join(iotests.test_dir, 'disk')
|
|||||||
disk_size = 0x40000000 # 1G
|
disk_size = 0x40000000 # 1G
|
||||||
|
|
||||||
# regions for qemu_io: (start, count) in bytes
|
# regions for qemu_io: (start, count) in bytes
|
||||||
regions1 = ((0, 0x100000),
|
regions1 = ((0x0fff00, 0x10000),
|
||||||
(0x200000, 0x100000))
|
(0x200000, 0x100000))
|
||||||
|
|
||||||
regions2 = ((0x10000000, 0x20000),
|
regions2 = ((0x10000000, 0x20000),
|
||||||
|
153
tests/qemu-iotests/191
Executable file
153
tests/qemu-iotests/191
Executable file
@ -0,0 +1,153 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Test commit block job where top has two parents
|
||||||
|
#
|
||||||
|
# Copyright (C) 2017 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`
|
||||||
|
status=1 # failure is the default!
|
||||||
|
|
||||||
|
MIG_SOCKET="${TEST_DIR}/migrate"
|
||||||
|
|
||||||
|
_cleanup()
|
||||||
|
{
|
||||||
|
rm -f "${TEST_IMG}.mid"
|
||||||
|
rm -f "${TEST_IMG}.ovl2"
|
||||||
|
rm -f "${TEST_IMG}.ovl3"
|
||||||
|
_cleanup_test_img
|
||||||
|
_cleanup_qemu
|
||||||
|
}
|
||||||
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
# get standard environment, filters and checks
|
||||||
|
. ./common.rc
|
||||||
|
. ./common.filter
|
||||||
|
. ./common.qemu
|
||||||
|
|
||||||
|
_supported_fmt qcow2
|
||||||
|
_unsupported_imgopts compat=0.10
|
||||||
|
_supported_proto file
|
||||||
|
_supported_os Linux
|
||||||
|
|
||||||
|
size=64M
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === Preparing and starting VM ===
|
||||||
|
echo
|
||||||
|
|
||||||
|
TEST_IMG="${TEST_IMG}.base" _make_test_img $size
|
||||||
|
TEST_IMG="${TEST_IMG}.mid" _make_test_img -b "${TEST_IMG}.base"
|
||||||
|
_make_test_img -b "${TEST_IMG}.mid"
|
||||||
|
TEST_IMG="${TEST_IMG}.ovl2" _make_test_img -b "${TEST_IMG}.mid"
|
||||||
|
|
||||||
|
$QEMU_IO -c 'write -P 0x55 1M 64k' "${TEST_IMG}.mid" | _filter_qemu_io
|
||||||
|
|
||||||
|
qemu_comm_method="qmp"
|
||||||
|
qmp_pretty="y"
|
||||||
|
|
||||||
|
_launch_qemu \
|
||||||
|
-blockdev "driver=${IMGFMT},file.driver=file,file.filename=${TEST_IMG}.base,node-name=base" \
|
||||||
|
-blockdev "driver=${IMGFMT},file.driver=file,file.filename=${TEST_IMG}.mid,node-name=mid,backing=base" \
|
||||||
|
-blockdev "driver=${IMGFMT},file.driver=file,file.filename=${TEST_IMG},node-name=top,backing=mid" \
|
||||||
|
-blockdev "driver=${IMGFMT},file.driver=file,file.filename=${TEST_IMG}.ovl2,node-name=top2,backing=mid"
|
||||||
|
h=$QEMU_HANDLE
|
||||||
|
_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" '^}'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === Perform commit job ===
|
||||||
|
echo
|
||||||
|
|
||||||
|
_send_qemu_cmd $h \
|
||||||
|
"{ 'execute': 'block-commit',
|
||||||
|
'arguments': { 'job-id': 'commit0',
|
||||||
|
'device': 'top',
|
||||||
|
'base':'$TEST_IMG.base',
|
||||||
|
'top': '$TEST_IMG.mid' } }" \
|
||||||
|
"BLOCK_JOB_COMPLETED"
|
||||||
|
_send_qemu_cmd $h "" "^}"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === Check that both top and top2 point to base now ===
|
||||||
|
echo
|
||||||
|
|
||||||
|
_send_qemu_cmd $h "{ 'execute': 'query-named-block-nodes' }" "^}" |
|
||||||
|
_filter_generated_node_ids
|
||||||
|
|
||||||
|
_send_qemu_cmd $h "{ 'execute': 'quit' }" "^}"
|
||||||
|
wait=1 _cleanup_qemu
|
||||||
|
|
||||||
|
_img_info
|
||||||
|
TEST_IMG="$TEST_IMG.ovl2" _img_info
|
||||||
|
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === Preparing and starting VM with -drive ===
|
||||||
|
echo
|
||||||
|
|
||||||
|
TEST_IMG="${TEST_IMG}.base" _make_test_img $size
|
||||||
|
TEST_IMG="${TEST_IMG}.mid" _make_test_img -b "${TEST_IMG}.base"
|
||||||
|
_make_test_img -b "${TEST_IMG}.mid"
|
||||||
|
TEST_IMG="${TEST_IMG}.ovl2" _make_test_img -b "${TEST_IMG}.mid"
|
||||||
|
TEST_IMG="${TEST_IMG}.ovl3" _make_test_img -b "${TEST_IMG}.ovl2"
|
||||||
|
|
||||||
|
$QEMU_IO -c 'write -P 0x55 1M 64k' "${TEST_IMG}.mid" | _filter_qemu_io
|
||||||
|
|
||||||
|
qemu_comm_method="qmp"
|
||||||
|
qmp_pretty="y"
|
||||||
|
|
||||||
|
_launch_qemu \
|
||||||
|
-drive "driver=${IMGFMT},file=${TEST_IMG},node-name=top,backing.node-name=mid" \
|
||||||
|
-drive "driver=${IMGFMT},file=${TEST_IMG}.ovl3,node-name=top2,backing.backing=mid"
|
||||||
|
h=$QEMU_HANDLE
|
||||||
|
_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" '^}'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === Perform commit job ===
|
||||||
|
echo
|
||||||
|
|
||||||
|
_send_qemu_cmd $h \
|
||||||
|
"{ 'execute': 'block-commit',
|
||||||
|
'arguments': { 'job-id': 'commit0',
|
||||||
|
'device': 'top',
|
||||||
|
'base':'$TEST_IMG.base',
|
||||||
|
'top': '$TEST_IMG.mid' } }" \
|
||||||
|
"BLOCK_JOB_COMPLETED"
|
||||||
|
_send_qemu_cmd $h "" "^}"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo === Check that both top and top2 point to base now ===
|
||||||
|
echo
|
||||||
|
|
||||||
|
_send_qemu_cmd $h "{ 'execute': 'query-named-block-nodes' }" "^}" |
|
||||||
|
_filter_generated_node_ids
|
||||||
|
|
||||||
|
_send_qemu_cmd $h "{ 'execute': 'quit' }" "^}"
|
||||||
|
wait=1 _cleanup_qemu
|
||||||
|
|
||||||
|
_img_info
|
||||||
|
TEST_IMG="$TEST_IMG.ovl2" _img_info
|
||||||
|
|
||||||
|
# success, all done
|
||||||
|
echo "*** done"
|
||||||
|
rm -f $seq.full
|
||||||
|
status=0
|
827
tests/qemu-iotests/191.out
Normal file
827
tests/qemu-iotests/191.out
Normal file
@ -0,0 +1,827 @@
|
|||||||
|
QA output created by 191
|
||||||
|
|
||||||
|
=== Preparing and starting VM ===
|
||||||
|
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT.ovl2', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid
|
||||||
|
wrote 65536/65536 bytes at offset 1048576
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
=== Perform commit job ===
|
||||||
|
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"timestamp": {
|
||||||
|
"seconds": TIMESTAMP,
|
||||||
|
"microseconds": TIMESTAMP
|
||||||
|
},
|
||||||
|
"event": "BLOCK_JOB_COMPLETED",
|
||||||
|
"data": {
|
||||||
|
"device": "commit0",
|
||||||
|
"len": 67108864,
|
||||||
|
"offset": 67108864,
|
||||||
|
"speed": 0,
|
||||||
|
"type": "commit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
=== Check that both top and top2 point to base now ===
|
||||||
|
|
||||||
|
{
|
||||||
|
"return": [
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"backing-image": {
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 397312,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"backing-filename-format": "qcow2",
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.ovl2",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 200704,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"full-backing-filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"backing-filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": false,
|
||||||
|
"node-name": "top2",
|
||||||
|
"backing_file_depth": 1,
|
||||||
|
"drv": "qcow2",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"backing_file": "TEST_DIR/t.qcow2.base",
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2.ovl2",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"virtual-size": 197120,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.ovl2",
|
||||||
|
"format": "file",
|
||||||
|
"actual-size": 200704,
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": false,
|
||||||
|
"node-name": "NODE_NAME",
|
||||||
|
"backing_file_depth": 0,
|
||||||
|
"drv": "file",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2.ovl2",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"backing-image": {
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 397312,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"backing-filename-format": "qcow2",
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 200704,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"full-backing-filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"backing-filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": false,
|
||||||
|
"node-name": "top",
|
||||||
|
"backing_file_depth": 1,
|
||||||
|
"drv": "qcow2",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"backing_file": "TEST_DIR/t.qcow2.base",
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"virtual-size": 197120,
|
||||||
|
"filename": "TEST_DIR/t.qcow2",
|
||||||
|
"format": "file",
|
||||||
|
"actual-size": 200704,
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": false,
|
||||||
|
"node-name": "NODE_NAME",
|
||||||
|
"backing_file_depth": 0,
|
||||||
|
"drv": "file",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"backing-image": {
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 397312,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"backing-filename-format": "qcow2",
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.mid",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 397312,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"full-backing-filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"backing-filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": false,
|
||||||
|
"node-name": "mid",
|
||||||
|
"backing_file_depth": 1,
|
||||||
|
"drv": "qcow2",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"backing_file": "TEST_DIR/t.qcow2.base",
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2.mid",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"virtual-size": 393216,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.mid",
|
||||||
|
"format": "file",
|
||||||
|
"actual-size": 397312,
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": false,
|
||||||
|
"node-name": "NODE_NAME",
|
||||||
|
"backing_file_depth": 0,
|
||||||
|
"drv": "file",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2.mid",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 397312,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": false,
|
||||||
|
"node-name": "base",
|
||||||
|
"backing_file_depth": 0,
|
||||||
|
"drv": "qcow2",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2.base",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"virtual-size": 393216,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"format": "file",
|
||||||
|
"actual-size": 397312,
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": false,
|
||||||
|
"node-name": "NODE_NAME",
|
||||||
|
"backing_file_depth": 0,
|
||||||
|
"drv": "file",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2.base",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"timestamp": {
|
||||||
|
"seconds": TIMESTAMP,
|
||||||
|
"microseconds": TIMESTAMP
|
||||||
|
},
|
||||||
|
"event": "SHUTDOWN",
|
||||||
|
"data": {
|
||||||
|
"guest": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
image: TEST_DIR/t.IMGFMT
|
||||||
|
file format: IMGFMT
|
||||||
|
virtual size: 64M (67108864 bytes)
|
||||||
|
cluster_size: 65536
|
||||||
|
backing file: TEST_DIR/t.IMGFMT.base
|
||||||
|
backing file format: IMGFMT
|
||||||
|
image: TEST_DIR/t.IMGFMT.ovl2
|
||||||
|
file format: IMGFMT
|
||||||
|
virtual size: 64M (67108864 bytes)
|
||||||
|
cluster_size: 65536
|
||||||
|
backing file: TEST_DIR/t.IMGFMT.base
|
||||||
|
backing file format: IMGFMT
|
||||||
|
|
||||||
|
=== Preparing and starting VM with -drive ===
|
||||||
|
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT.ovl2', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.mid
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT.ovl3', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.ovl2
|
||||||
|
wrote 65536/65536 bytes at offset 1048576
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
=== Perform commit job ===
|
||||||
|
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"timestamp": {
|
||||||
|
"seconds": TIMESTAMP,
|
||||||
|
"microseconds": TIMESTAMP
|
||||||
|
},
|
||||||
|
"event": "BLOCK_JOB_COMPLETED",
|
||||||
|
"data": {
|
||||||
|
"device": "commit0",
|
||||||
|
"len": 67108864,
|
||||||
|
"offset": 67108864,
|
||||||
|
"speed": 0,
|
||||||
|
"type": "commit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
=== Check that both top and top2 point to base now ===
|
||||||
|
|
||||||
|
{
|
||||||
|
"return": [
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"backing-image": {
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 397312,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"backing-filename-format": "qcow2",
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.ovl2",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 200704,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"full-backing-filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"backing-filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": true,
|
||||||
|
"node-name": "NODE_NAME",
|
||||||
|
"backing_file_depth": 1,
|
||||||
|
"drv": "qcow2",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"backing_file": "TEST_DIR/t.qcow2.base",
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2.ovl2",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"virtual-size": 197120,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.ovl2",
|
||||||
|
"format": "file",
|
||||||
|
"actual-size": 200704,
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": true,
|
||||||
|
"node-name": "NODE_NAME",
|
||||||
|
"backing_file_depth": 0,
|
||||||
|
"drv": "file",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2.ovl2",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"backing-image": {
|
||||||
|
"backing-image": {
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 397312,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"backing-filename-format": "qcow2",
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.ovl2",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 200704,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"full-backing-filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"backing-filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"backing-filename-format": "qcow2",
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.ovl3",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 200704,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"full-backing-filename": "TEST_DIR/t.qcow2.ovl2",
|
||||||
|
"backing-filename": "TEST_DIR/t.qcow2.ovl2",
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": false,
|
||||||
|
"node-name": "top2",
|
||||||
|
"backing_file_depth": 2,
|
||||||
|
"drv": "qcow2",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"backing_file": "TEST_DIR/t.qcow2.ovl2",
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2.ovl3",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"virtual-size": 197120,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.ovl3",
|
||||||
|
"format": "file",
|
||||||
|
"actual-size": 200704,
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": false,
|
||||||
|
"node-name": "NODE_NAME",
|
||||||
|
"backing_file_depth": 0,
|
||||||
|
"drv": "file",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2.ovl3",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 397312,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": true,
|
||||||
|
"node-name": "NODE_NAME",
|
||||||
|
"backing_file_depth": 0,
|
||||||
|
"drv": "qcow2",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2.base",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"virtual-size": 393216,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"format": "file",
|
||||||
|
"actual-size": 397312,
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": true,
|
||||||
|
"node-name": "NODE_NAME",
|
||||||
|
"backing_file_depth": 0,
|
||||||
|
"drv": "file",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2.base",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"backing-image": {
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 397312,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"backing-filename-format": "qcow2",
|
||||||
|
"virtual-size": 67108864,
|
||||||
|
"filename": "TEST_DIR/t.qcow2",
|
||||||
|
"cluster-size": 65536,
|
||||||
|
"format": "qcow2",
|
||||||
|
"actual-size": 200704,
|
||||||
|
"format-specific": {
|
||||||
|
"type": "qcow2",
|
||||||
|
"data": {
|
||||||
|
"compat": "1.1",
|
||||||
|
"lazy-refcounts": false,
|
||||||
|
"refcount-bits": 16,
|
||||||
|
"corrupt": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"full-backing-filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"backing-filename": "TEST_DIR/t.qcow2.base",
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": false,
|
||||||
|
"node-name": "top",
|
||||||
|
"backing_file_depth": 1,
|
||||||
|
"drv": "qcow2",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"backing_file": "TEST_DIR/t.qcow2.base",
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"iops_rd": 0,
|
||||||
|
"detect_zeroes": "off",
|
||||||
|
"image": {
|
||||||
|
"virtual-size": 197120,
|
||||||
|
"filename": "TEST_DIR/t.qcow2",
|
||||||
|
"format": "file",
|
||||||
|
"actual-size": 200704,
|
||||||
|
"dirty-flag": false
|
||||||
|
},
|
||||||
|
"iops_wr": 0,
|
||||||
|
"ro": false,
|
||||||
|
"node-name": "NODE_NAME",
|
||||||
|
"backing_file_depth": 0,
|
||||||
|
"drv": "file",
|
||||||
|
"iops": 0,
|
||||||
|
"bps_wr": 0,
|
||||||
|
"write_threshold": 0,
|
||||||
|
"encrypted": false,
|
||||||
|
"bps": 0,
|
||||||
|
"bps_rd": 0,
|
||||||
|
"cache": {
|
||||||
|
"no-flush": false,
|
||||||
|
"direct": false,
|
||||||
|
"writeback": true
|
||||||
|
},
|
||||||
|
"file": "TEST_DIR/t.qcow2",
|
||||||
|
"encryption_key_missing": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"return": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"timestamp": {
|
||||||
|
"seconds": TIMESTAMP,
|
||||||
|
"microseconds": TIMESTAMP
|
||||||
|
},
|
||||||
|
"event": "SHUTDOWN",
|
||||||
|
"data": {
|
||||||
|
"guest": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
image: TEST_DIR/t.IMGFMT
|
||||||
|
file format: IMGFMT
|
||||||
|
virtual size: 64M (67108864 bytes)
|
||||||
|
cluster_size: 65536
|
||||||
|
backing file: TEST_DIR/t.IMGFMT.base
|
||||||
|
backing file format: IMGFMT
|
||||||
|
image: TEST_DIR/t.IMGFMT.ovl2
|
||||||
|
file format: IMGFMT
|
||||||
|
virtual size: 64M (67108864 bytes)
|
||||||
|
cluster_size: 65536
|
||||||
|
backing file: TEST_DIR/t.IMGFMT.base
|
||||||
|
backing file format: IMGFMT
|
||||||
|
*** done
|
@ -44,15 +44,16 @@ _supported_os Linux
|
|||||||
|
|
||||||
function do_run_qemu()
|
function do_run_qemu()
|
||||||
{
|
{
|
||||||
echo Testing: "$@" | _filter_imgfmt
|
echo Testing: "$@"
|
||||||
$QEMU -nographic -qmp-pretty stdio -serial none "$@"
|
$QEMU -nographic -qmp-pretty stdio -serial none "$@"
|
||||||
echo
|
echo
|
||||||
}
|
}
|
||||||
|
|
||||||
function run_qemu()
|
function run_qemu()
|
||||||
{
|
{
|
||||||
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp \
|
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_imgfmt | _filter_qemu \
|
||||||
| _filter_qemu_io | _filter_generated_node_ids
|
| _filter_qmp | _filter_qemu_io \
|
||||||
|
| _filter_generated_node_ids
|
||||||
}
|
}
|
||||||
|
|
||||||
size=64M
|
size=64M
|
||||||
|
109
tests/qemu-iotests/197
Executable file
109
tests/qemu-iotests/197
Executable file
@ -0,0 +1,109 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Test case for copy-on-read into qcow2
|
||||||
|
#
|
||||||
|
# Copyright (C) 2017 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=eblake@redhat.com
|
||||||
|
|
||||||
|
seq="$(basename $0)"
|
||||||
|
echo "QA output created by $seq"
|
||||||
|
|
||||||
|
here="$PWD"
|
||||||
|
status=1 # failure is the default!
|
||||||
|
|
||||||
|
# get standard environment, filters and checks
|
||||||
|
. ./common.rc
|
||||||
|
. ./common.filter
|
||||||
|
|
||||||
|
TEST_WRAP="$TEST_DIR/t.wrap.qcow2"
|
||||||
|
BLKDBG_CONF="$TEST_DIR/blkdebug.conf"
|
||||||
|
|
||||||
|
# Sanity check: our use of blkdebug fails if $TEST_DIR contains spaces
|
||||||
|
# or other problems
|
||||||
|
case "$TEST_DIR" in
|
||||||
|
*[^-_a-zA-Z0-9/]*)
|
||||||
|
_notrun "Suspicious TEST_DIR='$TEST_DIR', cowardly refusing to run" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
_cleanup()
|
||||||
|
{
|
||||||
|
_cleanup_test_img
|
||||||
|
rm -f "$BLKDBG_CONF"
|
||||||
|
}
|
||||||
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
# Test is supported for any backing file; but we force qcow2 for our wrapper.
|
||||||
|
_supported_fmt generic
|
||||||
|
_supported_proto generic
|
||||||
|
_supported_os Linux
|
||||||
|
# LUKS support may be possible, but it complicates things.
|
||||||
|
_unsupported_fmt luks
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo '=== Copy-on-read ==='
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Prep the images
|
||||||
|
_make_test_img 4G
|
||||||
|
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
|
||||||
|
IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
|
||||||
|
_make_test_img -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
|
||||||
|
$QEMU_IO -f qcow2 -c "write -z -u 1M 64k" "$TEST_WRAP" | _filter_qemu_io
|
||||||
|
|
||||||
|
# Ensure that a read of two clusters, but where one is already allocated,
|
||||||
|
# does not re-write the allocated cluster
|
||||||
|
cat > "$BLKDBG_CONF" <<EOF
|
||||||
|
[inject-error]
|
||||||
|
event = "cor_write"
|
||||||
|
sector = "2048"
|
||||||
|
EOF
|
||||||
|
$QEMU_IO -c "open -C \
|
||||||
|
-o driver=blkdebug,config=$BLKDBG_CONF,image.driver=qcow2 $TEST_WRAP" \
|
||||||
|
-c "read -P 0 1M 128k" | _filter_qemu_io
|
||||||
|
|
||||||
|
# Read the areas we want copied. A zero-length read should still be a
|
||||||
|
# no-op. The next read is under 2G, but aligned so that rounding to
|
||||||
|
# clusters copies more than 2G of zeroes. The final read will pick up
|
||||||
|
# the non-zero data in the same cluster. Since a 2G read may exhaust
|
||||||
|
# memory on some machines (particularly 32-bit), we skip the test if
|
||||||
|
# that fails due to memory pressure.
|
||||||
|
$QEMU_IO -f qcow2 -C -c "read 0 0" "$TEST_WRAP" | _filter_qemu_io
|
||||||
|
output=$($QEMU_IO -f qcow2 -C -c "read -P 0 1k $((2*1024*1024*1024 - 512))" \
|
||||||
|
"$TEST_WRAP" 2>&1 | _filter_qemu_io)
|
||||||
|
case $output in
|
||||||
|
*allocate*)
|
||||||
|
_notrun "Insufficent memory to run test" ;;
|
||||||
|
*) printf '%s\n' "$output" ;;
|
||||||
|
esac
|
||||||
|
$QEMU_IO -f qcow2 -C -c "read -P 0 $((3*1024*1024*1024 + 1024)) 1k" \
|
||||||
|
"$TEST_WRAP" | _filter_qemu_io
|
||||||
|
|
||||||
|
# Copy-on-read is incompatible with read-only
|
||||||
|
$QEMU_IO -f qcow2 -C -r "$TEST_WRAP" 2>&1 | _filter_testdir
|
||||||
|
|
||||||
|
# Break the backing chain, and show that images are identical, and that
|
||||||
|
# we properly copied over explicit zeros.
|
||||||
|
$QEMU_IMG rebase -u -b "" -f qcow2 "$TEST_WRAP"
|
||||||
|
$QEMU_IO -f qcow2 -c map "$TEST_WRAP"
|
||||||
|
_check_test_img
|
||||||
|
$QEMU_IMG compare -f $IMGFMT -F qcow2 "$TEST_IMG" "$TEST_WRAP"
|
||||||
|
|
||||||
|
# success, all done
|
||||||
|
echo '*** done'
|
||||||
|
status=0
|
26
tests/qemu-iotests/197.out
Normal file
26
tests/qemu-iotests/197.out
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
QA output created by 197
|
||||||
|
|
||||||
|
=== Copy-on-read ===
|
||||||
|
|
||||||
|
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296
|
||||||
|
wrote 1024/1024 bytes at offset 3221225472
|
||||||
|
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
Formatting 'TEST_DIR/t.wrap.IMGFMT', fmt=IMGFMT size=4294967296 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
|
||||||
|
wrote 65536/65536 bytes at offset 1048576
|
||||||
|
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 131072/131072 bytes at offset 1048576
|
||||||
|
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 0/0 bytes at offset 0
|
||||||
|
0 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 2147483136/2147483136 bytes at offset 1024
|
||||||
|
2 GiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
read 1024/1024 bytes at offset 3221226496
|
||||||
|
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||||
|
can't open device TEST_DIR/t.wrap.qcow2: Can't use copy-on-read on read-only device
|
||||||
|
2 GiB (0x80010000) bytes allocated at offset 0 bytes (0x0)
|
||||||
|
1023.938 MiB (0x3fff0000) bytes not allocated at offset 2 GiB (0x80010000)
|
||||||
|
64 KiB (0x10000) bytes allocated at offset 3 GiB (0xc0000000)
|
||||||
|
1023.938 MiB (0x3fff0000) bytes not allocated at offset 3 GiB (0xc0010000)
|
||||||
|
No errors were found on the image.
|
||||||
|
Images are identical.
|
||||||
|
*** done
|
@ -30,12 +30,9 @@ interrupt=true
|
|||||||
# by default don't output timestamps
|
# by default don't output timestamps
|
||||||
timestamp=${TIMESTAMP:=false}
|
timestamp=${TIMESTAMP:=false}
|
||||||
|
|
||||||
# generic initialization
|
|
||||||
iam=check
|
|
||||||
|
|
||||||
_init_error()
|
_init_error()
|
||||||
{
|
{
|
||||||
echo "$iam: $1" >&2
|
echo "check: $1" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,48 +57,6 @@ fi
|
|||||||
|
|
||||||
build_root="$build_iotests/../.."
|
build_root="$build_iotests/../.."
|
||||||
|
|
||||||
if [ -x "$build_iotests/socket_scm_helper" ]
|
|
||||||
then
|
|
||||||
export SOCKET_SCM_HELPER="$build_iotests/socket_scm_helper"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# if ./qemu exists, it should be prioritized and will be chosen by common.config
|
|
||||||
if [[ -z "$QEMU_PROG" && ! -x './qemu' ]]
|
|
||||||
then
|
|
||||||
arch=$(uname -m 2> /dev/null)
|
|
||||||
|
|
||||||
if [[ -n $arch && -x "$build_root/$arch-softmmu/qemu-system-$arch" ]]
|
|
||||||
then
|
|
||||||
export QEMU_PROG="$build_root/$arch-softmmu/qemu-system-$arch"
|
|
||||||
else
|
|
||||||
pushd "$build_root" > /dev/null
|
|
||||||
for binary in *-softmmu/qemu-system-*
|
|
||||||
do
|
|
||||||
if [ -x "$binary" ]
|
|
||||||
then
|
|
||||||
export QEMU_PROG="$build_root/$binary"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
popd > /dev/null
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z $QEMU_IMG_PROG && -x "$build_root/qemu-img" && ! -x './qemu-img' ]]
|
|
||||||
then
|
|
||||||
export QEMU_IMG_PROG="$build_root/qemu-img"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z $QEMU_IO_PROG && -x "$build_root/qemu-io" && ! -x './qemu-io' ]]
|
|
||||||
then
|
|
||||||
export QEMU_IO_PROG="$build_root/qemu-io"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z $QEMU_NBD_PROG && -x "$build_root/qemu-nbd" && ! -x './qemu-nbd' ]]
|
|
||||||
then
|
|
||||||
export QEMU_NBD_PROG="$build_root/qemu-nbd"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# we need common.env
|
# we need common.env
|
||||||
if ! . "$build_iotests/common.env"
|
if ! . "$build_iotests/common.env"
|
||||||
then
|
then
|
||||||
@ -114,22 +69,550 @@ then
|
|||||||
_init_error "failed to source common.config"
|
_init_error "failed to source common.config"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# we need common.rc
|
_full_imgfmt_details()
|
||||||
if ! . "$source_iotests/common.rc"
|
{
|
||||||
then
|
if [ -n "$IMGOPTS" ]; then
|
||||||
_init_error "failed to source common.rc"
|
echo "$IMGFMT ($IMGOPTS)"
|
||||||
|
else
|
||||||
|
echo "$IMGFMT"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_full_platform_details()
|
||||||
|
{
|
||||||
|
os=`uname -s`
|
||||||
|
host=`hostname -s`
|
||||||
|
kernel=`uname -r`
|
||||||
|
platform=`uname -m`
|
||||||
|
echo "$os/$platform $host $kernel"
|
||||||
|
}
|
||||||
|
|
||||||
|
# $1 = prog to look for
|
||||||
|
set_prog_path()
|
||||||
|
{
|
||||||
|
p=`command -v $1 2> /dev/null`
|
||||||
|
if [ -n "$p" -a -x "$p" ]; then
|
||||||
|
realpath -- "$(type -p "$p")"
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ -z "$TEST_DIR" ]; then
|
||||||
|
TEST_DIR=`pwd`/scratch
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# we need common
|
if [ ! -e "$TEST_DIR" ]; then
|
||||||
. "$source_iotests/common"
|
mkdir "$TEST_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
diff="diff -u"
|
||||||
|
verbose=false
|
||||||
|
debug=false
|
||||||
|
group=false
|
||||||
|
xgroup=false
|
||||||
|
imgopts=false
|
||||||
|
showme=false
|
||||||
|
sortme=false
|
||||||
|
expunge=true
|
||||||
|
have_test_arg=false
|
||||||
|
cachemode=false
|
||||||
|
|
||||||
|
tmp="${TEST_DIR}"/$$
|
||||||
|
rm -f $tmp.list $tmp.tmp $tmp.sed
|
||||||
|
|
||||||
|
export IMGFMT=raw
|
||||||
|
export IMGFMT_GENERIC=true
|
||||||
|
export IMGPROTO=file
|
||||||
|
export IMGOPTS=""
|
||||||
|
export CACHEMODE="writeback"
|
||||||
|
export QEMU_IO_OPTIONS=""
|
||||||
|
export QEMU_IO_OPTIONS_NO_FMT=""
|
||||||
|
export CACHEMODE_IS_DEFAULT=true
|
||||||
|
export QEMU_OPTIONS="-nodefaults -machine accel=qtest"
|
||||||
|
export VALGRIND_QEMU=
|
||||||
|
export IMGKEYSECRET=
|
||||||
|
export IMGOPTSSYNTAX=false
|
||||||
|
|
||||||
|
# Save current tty settings, since an aborting qemu call may leave things
|
||||||
|
# screwed up
|
||||||
|
STTY_RESTORE=
|
||||||
|
if test -t 0; then
|
||||||
|
STTY_RESTORE=$(stty -g)
|
||||||
|
fi
|
||||||
|
|
||||||
|
for r
|
||||||
|
do
|
||||||
|
|
||||||
|
if $group
|
||||||
|
then
|
||||||
|
# arg after -g
|
||||||
|
group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{
|
||||||
|
s/ .*//p
|
||||||
|
}'`
|
||||||
|
if [ -z "$group_list" ]
|
||||||
|
then
|
||||||
|
echo "Group \"$r\" is empty or not defined?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
[ ! -s $tmp.list ] && touch $tmp.list
|
||||||
|
for t in $group_list
|
||||||
|
do
|
||||||
|
if grep -s "^$t\$" $tmp.list >/dev/null
|
||||||
|
then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
echo "$t" >>$tmp.list
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
group=false
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif $xgroup
|
||||||
|
then
|
||||||
|
# arg after -x
|
||||||
|
# Populate $tmp.list with all tests
|
||||||
|
awk '/^[0-9]{3,}/ {print $1}' "${source_iotests}/group" > $tmp.list 2>/dev/null
|
||||||
|
group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{
|
||||||
|
s/ .*//p
|
||||||
|
}'`
|
||||||
|
if [ -z "$group_list" ]
|
||||||
|
then
|
||||||
|
echo "Group \"$r\" is empty or not defined?"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
numsed=0
|
||||||
|
rm -f $tmp.sed
|
||||||
|
for t in $group_list
|
||||||
|
do
|
||||||
|
if [ $numsed -gt 100 ]
|
||||||
|
then
|
||||||
|
sed -f $tmp.sed <$tmp.list >$tmp.tmp
|
||||||
|
mv $tmp.tmp $tmp.list
|
||||||
|
numsed=0
|
||||||
|
rm -f $tmp.sed
|
||||||
|
fi
|
||||||
|
echo "/^$t\$/d" >>$tmp.sed
|
||||||
|
numsed=`expr $numsed + 1`
|
||||||
|
done
|
||||||
|
sed -f $tmp.sed <$tmp.list >$tmp.tmp
|
||||||
|
mv $tmp.tmp $tmp.list
|
||||||
|
xgroup=false
|
||||||
|
continue
|
||||||
|
|
||||||
|
elif $imgopts
|
||||||
|
then
|
||||||
|
IMGOPTS="$r"
|
||||||
|
imgopts=false
|
||||||
|
continue
|
||||||
|
elif $cachemode
|
||||||
|
then
|
||||||
|
CACHEMODE="$r"
|
||||||
|
CACHEMODE_IS_DEFAULT=false
|
||||||
|
cachemode=false
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
xpand=true
|
||||||
|
case "$r"
|
||||||
|
in
|
||||||
|
|
||||||
|
-\? | -h | --help) # usage
|
||||||
|
echo "Usage: $0 [options] [testlist]"'
|
||||||
|
|
||||||
|
common options
|
||||||
|
-v verbose
|
||||||
|
-d debug
|
||||||
|
|
||||||
|
image format options
|
||||||
|
-raw test raw (default)
|
||||||
|
-bochs test bochs
|
||||||
|
-cloop test cloop
|
||||||
|
-parallels test parallels
|
||||||
|
-qcow test qcow
|
||||||
|
-qcow2 test qcow2
|
||||||
|
-qed test qed
|
||||||
|
-vdi test vdi
|
||||||
|
-vpc test vpc
|
||||||
|
-vhdx test vhdx
|
||||||
|
-vmdk test vmdk
|
||||||
|
-luks test luks
|
||||||
|
|
||||||
|
image protocol options
|
||||||
|
-file test file (default)
|
||||||
|
-rbd test rbd
|
||||||
|
-sheepdog test sheepdog
|
||||||
|
-nbd test nbd
|
||||||
|
-ssh test ssh
|
||||||
|
-nfs test nfs
|
||||||
|
-vxhs test vxhs
|
||||||
|
|
||||||
|
other options
|
||||||
|
-xdiff graphical mode diff
|
||||||
|
-nocache use O_DIRECT on backing file
|
||||||
|
-misalign misalign memory allocations
|
||||||
|
-n show me, do not run tests
|
||||||
|
-o options -o options to pass to qemu-img create/convert
|
||||||
|
-T output timestamps
|
||||||
|
-c mode cache mode
|
||||||
|
|
||||||
|
testlist options
|
||||||
|
-g group[,group...] include tests from these groups
|
||||||
|
-x group[,group...] exclude tests from these groups
|
||||||
|
NNN include test NNN
|
||||||
|
NNN-NNN include test range (eg. 012-021)
|
||||||
|
'
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
|
||||||
|
-raw)
|
||||||
|
IMGFMT=raw
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-bochs)
|
||||||
|
IMGFMT=bochs
|
||||||
|
IMGFMT_GENERIC=false
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-cloop)
|
||||||
|
IMGFMT=cloop
|
||||||
|
IMGFMT_GENERIC=false
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-parallels)
|
||||||
|
IMGFMT=parallels
|
||||||
|
IMGFMT_GENERIC=false
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-qcow)
|
||||||
|
IMGFMT=qcow
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-qcow2)
|
||||||
|
IMGFMT=qcow2
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-luks)
|
||||||
|
IMGOPTSSYNTAX=true
|
||||||
|
IMGFMT=luks
|
||||||
|
IMGKEYSECRET=123456
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-qed)
|
||||||
|
IMGFMT=qed
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-vdi)
|
||||||
|
IMGFMT=vdi
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-vmdk)
|
||||||
|
IMGFMT=vmdk
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-vpc)
|
||||||
|
IMGFMT=vpc
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-vhdx)
|
||||||
|
IMGFMT=vhdx
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-file)
|
||||||
|
IMGPROTO=file
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-rbd)
|
||||||
|
IMGPROTO=rbd
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-sheepdog)
|
||||||
|
IMGPROTO=sheepdog
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-nbd)
|
||||||
|
IMGPROTO=nbd
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-vxhs)
|
||||||
|
IMGPROTO=vxhs
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-ssh)
|
||||||
|
IMGPROTO=ssh
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-nfs)
|
||||||
|
IMGPROTO=nfs
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-nocache)
|
||||||
|
CACHEMODE="none"
|
||||||
|
CACHEMODE_IS_DEFAULT=false
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-misalign)
|
||||||
|
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --misalign"
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-valgrind)
|
||||||
|
VALGRIND_QEMU='y'
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-g) # -g group ... pick from group file
|
||||||
|
group=true
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-xdiff) # graphical diff mode
|
||||||
|
xpand=false
|
||||||
|
|
||||||
|
if [ ! -z "$DISPLAY" ]
|
||||||
|
then
|
||||||
|
command -v xdiff >/dev/null 2>&1 && diff=xdiff
|
||||||
|
command -v gdiff >/dev/null 2>&1 && diff=gdiff
|
||||||
|
command -v tkdiff >/dev/null 2>&1 && diff=tkdiff
|
||||||
|
command -v xxdiff >/dev/null 2>&1 && diff=xxdiff
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
-n) # show me, don't do it
|
||||||
|
showme=true
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
-o)
|
||||||
|
imgopts=true
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
-c)
|
||||||
|
cachemode=true
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
-T) # turn on timestamp output
|
||||||
|
timestamp=true
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
|
||||||
|
-v)
|
||||||
|
verbose=true
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
-d)
|
||||||
|
debug=true
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
-x) # -x group ... exclude from group file
|
||||||
|
xgroup=true
|
||||||
|
xpand=false
|
||||||
|
;;
|
||||||
|
'[0-9][0-9][0-9] [0-9][0-9][0-9][0-9]')
|
||||||
|
echo "No tests?"
|
||||||
|
status=1
|
||||||
|
exit $status
|
||||||
|
;;
|
||||||
|
|
||||||
|
[0-9]*-[0-9]*)
|
||||||
|
eval `echo $r | sed -e 's/^/start=/' -e 's/-/ end=/'`
|
||||||
|
;;
|
||||||
|
|
||||||
|
[0-9]*-)
|
||||||
|
eval `echo $r | sed -e 's/^/start=/' -e 's/-//'`
|
||||||
|
end=`echo [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] | sed -e 's/\[0-9]//g' -e 's/ *$//' -e 's/.* //'`
|
||||||
|
if [ -z "$end" ]
|
||||||
|
then
|
||||||
|
echo "No tests in range \"$r\"?"
|
||||||
|
status=1
|
||||||
|
exit $status
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
start=$r
|
||||||
|
end=$r
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
# get rid of leading 0s as can be interpreted as octal
|
||||||
|
start=`echo $start | sed 's/^0*//'`
|
||||||
|
end=`echo $end | sed 's/^0*//'`
|
||||||
|
|
||||||
|
if $xpand
|
||||||
|
then
|
||||||
|
have_test_arg=true
|
||||||
|
awk </dev/null '
|
||||||
|
BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
|
||||||
|
| while read id
|
||||||
|
do
|
||||||
|
if grep -s "^$id " "$source_iotests/group" >/dev/null
|
||||||
|
then
|
||||||
|
# in group file ... OK
|
||||||
|
echo $id >>$tmp.list
|
||||||
|
else
|
||||||
|
if [ -f expunged ] && $expunge && egrep "^$id([ ]|\$)" expunged >/dev/null
|
||||||
|
then
|
||||||
|
# expunged ... will be reported, but not run, later
|
||||||
|
echo $id >>$tmp.list
|
||||||
|
else
|
||||||
|
# oops
|
||||||
|
if [ "$start" == "$end" -a "$id" == "$end" ]
|
||||||
|
then
|
||||||
|
echo "$id - unknown test"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "$id - unknown test, ignored"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done || exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
# Set qemu-io cache mode with $CACHEMODE we have
|
||||||
|
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE"
|
||||||
|
|
||||||
|
QEMU_IO_OPTIONS_NO_FMT="$QEMU_IO_OPTIONS"
|
||||||
|
if [ "$IMGOPTSSYNTAX" != "true" ]; then
|
||||||
|
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set default options for qemu-img create -o if they were not specified
|
||||||
|
if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then
|
||||||
|
IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1")
|
||||||
|
fi
|
||||||
|
if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null); then
|
||||||
|
IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$SAMPLE_IMG_DIR" ]; then
|
||||||
|
SAMPLE_IMG_DIR="$source_iotests/sample_images"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export TEST_DIR
|
||||||
|
export SAMPLE_IMG_DIR
|
||||||
|
|
||||||
|
if [ -s $tmp.list ]
|
||||||
|
then
|
||||||
|
# found some valid test numbers ... this is good
|
||||||
|
:
|
||||||
|
else
|
||||||
|
if $have_test_arg
|
||||||
|
then
|
||||||
|
# had test numbers, but none in group file ... do nothing
|
||||||
|
touch $tmp.list
|
||||||
|
else
|
||||||
|
# no test numbers, do everything from group file
|
||||||
|
sed -n -e '/^[0-9][0-9][0-9]*/s/[ ].*//p' <"$source_iotests/group" >$tmp.list
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# should be sort -n, but this did not work for Linux when this
|
||||||
|
# was ported from IRIX
|
||||||
|
#
|
||||||
|
list=`sort $tmp.list`
|
||||||
|
rm -f $tmp.list $tmp.tmp $tmp.sed
|
||||||
|
|
||||||
|
if [ -z "$QEMU_PROG" ]
|
||||||
|
then
|
||||||
|
if [ -x "$build_iotests/qemu" ]; then
|
||||||
|
export QEMU_PROG="$build_iotests/qemu"
|
||||||
|
elif [ -x "$build_root/$arch-softmmu/qemu-system-$arch" ]; then
|
||||||
|
export QEMU_PROG="$build_root/$arch-softmmu/qemu-system-$arch"
|
||||||
|
else
|
||||||
|
pushd "$build_root" > /dev/null
|
||||||
|
for binary in *-softmmu/qemu-system-*
|
||||||
|
do
|
||||||
|
if [ -x "$binary" ]
|
||||||
|
then
|
||||||
|
export QEMU_PROG="$build_root/$binary"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
popd > /dev/null
|
||||||
|
[ "$QEMU_PROG" = "" ] && _init_error "qemu not found"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
export QEMU_PROG=$(realpath -- "$(type -p "$QEMU_PROG")")
|
||||||
|
|
||||||
|
if [ -z "$QEMU_IMG_PROG" ]; then
|
||||||
|
if [ -x "$build_iotests/qemu-img" ]; then
|
||||||
|
export QEMU_IMG_PROG="$build_iotests/qemu-img"
|
||||||
|
elif [ -x "$build_root/qemu-img" ]; then
|
||||||
|
export QEMU_IMG_PROG="$build_root/qemu-img"
|
||||||
|
else
|
||||||
|
_init_error "qemu-img not found"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
export QEMU_IMG_PROG=$(realpath -- "$(type -p "$QEMU_IMG_PROG")")
|
||||||
|
|
||||||
|
if [ -z "$QEMU_IO_PROG" ]; then
|
||||||
|
if [ -x "$build_iotests/qemu-io" ]; then
|
||||||
|
export QEMU_IO_PROG="$build_iotests/qemu-io"
|
||||||
|
elif [ -x "$build_root/qemu-io" ]; then
|
||||||
|
export QEMU_IO_PROG="$build_root/qemu-io"
|
||||||
|
else
|
||||||
|
_init_error "qemu-io not found"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
export QEMU_IO_PROG=$(realpath -- "$(type -p "$QEMU_IO_PROG")")
|
||||||
|
|
||||||
|
if [ -z $QEMU_NBD_PROG ]; then
|
||||||
|
if [ -x "$build_iotests/qemu-nbd" ]; then
|
||||||
|
export QEMU_NBD_PROG="$build_iotests/qemu-nbd"
|
||||||
|
elif [ -x "$build_root/qemu-nbd" ]; then
|
||||||
|
export QEMU_NBD_PROG="$build_root/qemu-nbd"
|
||||||
|
else
|
||||||
|
_init_error "qemu-nbd not found"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
export QEMU_NBD_PROG=$(realpath -- "$(type -p "$QEMU_NBD_PROG")")
|
||||||
|
|
||||||
|
if [ -z "$QEMU_VXHS_PROG" ]; then
|
||||||
|
export QEMU_VXHS_PROG="`set_prog_path qnio_server`"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -x "$build_iotests/socket_scm_helper" ]
|
||||||
|
then
|
||||||
|
export SOCKET_SCM_HELPER="$build_iotests/socket_scm_helper"
|
||||||
|
fi
|
||||||
|
|
||||||
|
default_machine=$($QEMU_PROG -machine help | sed -n '/(default)/ s/ .*//p')
|
||||||
|
default_alias_machine=$($QEMU_PROG -machine help | \
|
||||||
|
sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }")
|
||||||
|
if [[ "$default_alias_machine" ]]; then
|
||||||
|
default_machine="$default_alias_machine"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export QEMU_DEFAULT_MACHINE="$default_machine"
|
||||||
|
|
||||||
TIMESTAMP_FILE=check.time-$IMGPROTO-$IMGFMT
|
TIMESTAMP_FILE=check.time-$IMGPROTO-$IMGFMT
|
||||||
|
|
||||||
tmp="${TEST_DIR}"/$$
|
|
||||||
|
|
||||||
_wallclock()
|
_wallclock()
|
||||||
{
|
{
|
||||||
date "+%H %M %S" | $AWK_PROG '{ print $1*3600 + $2*60 + $3 }'
|
date "+%H %M %S" | awk '{ print $1*3600 + $2*60 + $3 }'
|
||||||
}
|
}
|
||||||
|
|
||||||
_timestamp()
|
_timestamp()
|
||||||
@ -140,12 +623,6 @@ _timestamp()
|
|||||||
|
|
||||||
_wrapup()
|
_wrapup()
|
||||||
{
|
{
|
||||||
# for hangcheck ...
|
|
||||||
# remove files that were used by hangcheck
|
|
||||||
#
|
|
||||||
[ -f "${TEST_DIR}"/check.pid ] && rm -rf "${TEST_DIR}"/check.pid
|
|
||||||
[ -f "${TEST_DIR}"/check.sts ] && rm -rf "${TEST_DIR}"/check.sts
|
|
||||||
|
|
||||||
if $showme
|
if $showme
|
||||||
then
|
then
|
||||||
:
|
:
|
||||||
@ -154,7 +631,7 @@ _wrapup()
|
|||||||
if [ -f $TIMESTAMP_FILE -a -f $tmp.time ]
|
if [ -f $TIMESTAMP_FILE -a -f $tmp.time ]
|
||||||
then
|
then
|
||||||
cat $TIMESTAMP_FILE $tmp.time \
|
cat $TIMESTAMP_FILE $tmp.time \
|
||||||
| $AWK_PROG '
|
| awk '
|
||||||
{ t[$1] = $2 }
|
{ t[$1] = $2 }
|
||||||
END { if (NR > 0) {
|
END { if (NR > 0) {
|
||||||
for (i in t) print i " " t[i]
|
for (i in t) print i " " t[i]
|
||||||
@ -194,6 +671,9 @@ END { if (NR > 0) {
|
|||||||
needwrap=false
|
needwrap=false
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test -n "$STTY_RESTORE"; then
|
||||||
|
stty $STTY_RESTORE
|
||||||
|
fi
|
||||||
rm -f "${TEST_DIR}"/*.out "${TEST_DIR}"/*.err "${TEST_DIR}"/*.time
|
rm -f "${TEST_DIR}"/*.out "${TEST_DIR}"/*.err "${TEST_DIR}"/*.time
|
||||||
rm -f "${TEST_DIR}"/check.pid "${TEST_DIR}"/check.sts
|
rm -f "${TEST_DIR}"/check.pid "${TEST_DIR}"/check.sts
|
||||||
rm -f $tmp.*
|
rm -f $tmp.*
|
||||||
@ -201,24 +681,6 @@ END { if (NR > 0) {
|
|||||||
|
|
||||||
trap "_wrapup; exit \$status" 0 1 2 3 15
|
trap "_wrapup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
# for hangcheck ...
|
|
||||||
# Save pid of check in a well known place, so that hangcheck can be sure it
|
|
||||||
# has the right pid (getting the pid from ps output is not reliable enough).
|
|
||||||
#
|
|
||||||
rm -rf "${TEST_DIR}"/check.pid
|
|
||||||
echo $$ > "${TEST_DIR}"/check.pid
|
|
||||||
|
|
||||||
# for hangcheck ...
|
|
||||||
# Save the status of check in a well known place, so that hangcheck can be
|
|
||||||
# sure to know where check is up to (getting test number from ps output is
|
|
||||||
# not reliable enough since the trace stuff has been introduced).
|
|
||||||
#
|
|
||||||
rm -rf "${TEST_DIR}"/check.sts
|
|
||||||
echo "preamble" > "${TEST_DIR}"/check.sts
|
|
||||||
|
|
||||||
# don't leave old full output behind on a clean run
|
|
||||||
rm -f check.full
|
|
||||||
|
|
||||||
[ -f $TIMESTAMP_FILE ] || touch $TIMESTAMP_FILE
|
[ -f $TIMESTAMP_FILE ] || touch $TIMESTAMP_FILE
|
||||||
|
|
||||||
FULL_IMGFMT_DETAILS=`_full_imgfmt_details`
|
FULL_IMGFMT_DETAILS=`_full_imgfmt_details`
|
||||||
@ -276,9 +738,6 @@ do
|
|||||||
fi
|
fi
|
||||||
rm -f core $seq.notrun
|
rm -f core $seq.notrun
|
||||||
|
|
||||||
# for hangcheck ...
|
|
||||||
echo "$seq" > "${TEST_DIR}"/check.sts
|
|
||||||
|
|
||||||
start=`_wallclock`
|
start=`_wallclock`
|
||||||
$timestamp && printf %s " [$(date "+%T")]"
|
$timestamp && printf %s " [$(date "+%T")]"
|
||||||
|
|
||||||
|
@ -1,459 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Copyright (C) 2009 Red Hat, Inc.
|
|
||||||
# Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it would 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/>.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# common procedures for QA scripts
|
|
||||||
#
|
|
||||||
|
|
||||||
_setenvironment()
|
|
||||||
{
|
|
||||||
MSGVERB="text:action"
|
|
||||||
export MSGVERB
|
|
||||||
}
|
|
||||||
|
|
||||||
rm -f "$OUTPUT_DIR/$iam.out"
|
|
||||||
_setenvironment
|
|
||||||
|
|
||||||
check=${check-true}
|
|
||||||
|
|
||||||
diff="diff -u"
|
|
||||||
verbose=false
|
|
||||||
debug=false
|
|
||||||
group=false
|
|
||||||
xgroup=false
|
|
||||||
imgopts=false
|
|
||||||
showme=false
|
|
||||||
sortme=false
|
|
||||||
expunge=true
|
|
||||||
have_test_arg=false
|
|
||||||
randomize=false
|
|
||||||
cachemode=false
|
|
||||||
rm -f $tmp.list $tmp.tmp $tmp.sed
|
|
||||||
|
|
||||||
export IMGFMT=raw
|
|
||||||
export IMGFMT_GENERIC=true
|
|
||||||
export IMGPROTO=file
|
|
||||||
export IMGOPTS=""
|
|
||||||
export CACHEMODE="writeback"
|
|
||||||
export QEMU_IO_OPTIONS=""
|
|
||||||
export QEMU_IO_OPTIONS_NO_FMT=""
|
|
||||||
export CACHEMODE_IS_DEFAULT=true
|
|
||||||
export QEMU_OPTIONS="-nodefaults -machine accel=qtest"
|
|
||||||
export VALGRIND_QEMU=
|
|
||||||
export IMGKEYSECRET=
|
|
||||||
export IMGOPTSSYNTAX=false
|
|
||||||
|
|
||||||
for r
|
|
||||||
do
|
|
||||||
|
|
||||||
if $group
|
|
||||||
then
|
|
||||||
# arg after -g
|
|
||||||
group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{
|
|
||||||
s/ .*//p
|
|
||||||
}'`
|
|
||||||
if [ -z "$group_list" ]
|
|
||||||
then
|
|
||||||
echo "Group \"$r\" is empty or not defined?"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
[ ! -s $tmp.list ] && touch $tmp.list
|
|
||||||
for t in $group_list
|
|
||||||
do
|
|
||||||
if grep -s "^$t\$" $tmp.list >/dev/null
|
|
||||||
then
|
|
||||||
:
|
|
||||||
else
|
|
||||||
echo "$t" >>$tmp.list
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
group=false
|
|
||||||
continue
|
|
||||||
|
|
||||||
elif $xgroup
|
|
||||||
then
|
|
||||||
# arg after -x
|
|
||||||
# Populate $tmp.list with all tests
|
|
||||||
awk '/^[0-9]{3,}/ {print $1}' "${source_iotests}/group" > $tmp.list 2>/dev/null
|
|
||||||
group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{
|
|
||||||
s/ .*//p
|
|
||||||
}'`
|
|
||||||
if [ -z "$group_list" ]
|
|
||||||
then
|
|
||||||
echo "Group \"$r\" is empty or not defined?"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
numsed=0
|
|
||||||
rm -f $tmp.sed
|
|
||||||
for t in $group_list
|
|
||||||
do
|
|
||||||
if [ $numsed -gt 100 ]
|
|
||||||
then
|
|
||||||
sed -f $tmp.sed <$tmp.list >$tmp.tmp
|
|
||||||
mv $tmp.tmp $tmp.list
|
|
||||||
numsed=0
|
|
||||||
rm -f $tmp.sed
|
|
||||||
fi
|
|
||||||
echo "/^$t\$/d" >>$tmp.sed
|
|
||||||
numsed=`expr $numsed + 1`
|
|
||||||
done
|
|
||||||
sed -f $tmp.sed <$tmp.list >$tmp.tmp
|
|
||||||
mv $tmp.tmp $tmp.list
|
|
||||||
xgroup=false
|
|
||||||
continue
|
|
||||||
|
|
||||||
elif $imgopts
|
|
||||||
then
|
|
||||||
IMGOPTS="$r"
|
|
||||||
imgopts=false
|
|
||||||
continue
|
|
||||||
elif $cachemode
|
|
||||||
then
|
|
||||||
CACHEMODE="$r"
|
|
||||||
CACHEMODE_IS_DEFAULT=false
|
|
||||||
cachemode=false
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
xpand=true
|
|
||||||
case "$r"
|
|
||||||
in
|
|
||||||
|
|
||||||
-\? | -h | --help) # usage
|
|
||||||
echo "Usage: $0 [options] [testlist]"'
|
|
||||||
|
|
||||||
common options
|
|
||||||
-v verbose
|
|
||||||
-d debug
|
|
||||||
|
|
||||||
image format options
|
|
||||||
-raw test raw (default)
|
|
||||||
-bochs test bochs
|
|
||||||
-cloop test cloop
|
|
||||||
-parallels test parallels
|
|
||||||
-qcow test qcow
|
|
||||||
-qcow2 test qcow2
|
|
||||||
-qed test qed
|
|
||||||
-vdi test vdi
|
|
||||||
-vpc test vpc
|
|
||||||
-vhdx test vhdx
|
|
||||||
-vmdk test vmdk
|
|
||||||
-luks test luks
|
|
||||||
|
|
||||||
image protocol options
|
|
||||||
-file test file (default)
|
|
||||||
-rbd test rbd
|
|
||||||
-sheepdog test sheepdog
|
|
||||||
-nbd test nbd
|
|
||||||
-ssh test ssh
|
|
||||||
-nfs test nfs
|
|
||||||
-vxhs test vxhs
|
|
||||||
|
|
||||||
other options
|
|
||||||
-xdiff graphical mode diff
|
|
||||||
-nocache use O_DIRECT on backing file
|
|
||||||
-misalign misalign memory allocations
|
|
||||||
-n show me, do not run tests
|
|
||||||
-o options -o options to pass to qemu-img create/convert
|
|
||||||
-T output timestamps
|
|
||||||
-r randomize test order
|
|
||||||
-c mode cache mode
|
|
||||||
|
|
||||||
testlist options
|
|
||||||
-g group[,group...] include tests from these groups
|
|
||||||
-x group[,group...] exclude tests from these groups
|
|
||||||
NNN include test NNN
|
|
||||||
NNN-NNN include test range (eg. 012-021)
|
|
||||||
'
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
|
|
||||||
-raw)
|
|
||||||
IMGFMT=raw
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-bochs)
|
|
||||||
IMGFMT=bochs
|
|
||||||
IMGFMT_GENERIC=false
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-cloop)
|
|
||||||
IMGFMT=cloop
|
|
||||||
IMGFMT_GENERIC=false
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-parallels)
|
|
||||||
IMGFMT=parallels
|
|
||||||
IMGFMT_GENERIC=false
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-qcow)
|
|
||||||
IMGFMT=qcow
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-qcow2)
|
|
||||||
IMGFMT=qcow2
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-luks)
|
|
||||||
IMGOPTSSYNTAX=true
|
|
||||||
IMGFMT=luks
|
|
||||||
IMGKEYSECRET=123456
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-qed)
|
|
||||||
IMGFMT=qed
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-vdi)
|
|
||||||
IMGFMT=vdi
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-vmdk)
|
|
||||||
IMGFMT=vmdk
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-vpc)
|
|
||||||
IMGFMT=vpc
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-vhdx)
|
|
||||||
IMGFMT=vhdx
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-file)
|
|
||||||
IMGPROTO=file
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-rbd)
|
|
||||||
IMGPROTO=rbd
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-sheepdog)
|
|
||||||
IMGPROTO=sheepdog
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-nbd)
|
|
||||||
IMGPROTO=nbd
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-vxhs)
|
|
||||||
IMGPROTO=vxhs
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-ssh)
|
|
||||||
IMGPROTO=ssh
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-nfs)
|
|
||||||
IMGPROTO=nfs
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-nocache)
|
|
||||||
CACHEMODE="none"
|
|
||||||
CACHEMODE_IS_DEFAULT=false
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-misalign)
|
|
||||||
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --misalign"
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-valgrind)
|
|
||||||
VALGRIND_QEMU='y'
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-g) # -g group ... pick from group file
|
|
||||||
group=true
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-xdiff) # graphical diff mode
|
|
||||||
xpand=false
|
|
||||||
|
|
||||||
if [ ! -z "$DISPLAY" ]
|
|
||||||
then
|
|
||||||
command -v xdiff >/dev/null 2>&1 && diff=xdiff
|
|
||||||
command -v gdiff >/dev/null 2>&1 && diff=gdiff
|
|
||||||
command -v tkdiff >/dev/null 2>&1 && diff=tkdiff
|
|
||||||
command -v xxdiff >/dev/null 2>&1 && diff=xxdiff
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
|
|
||||||
-n) # show me, don't do it
|
|
||||||
showme=true
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
-o)
|
|
||||||
imgopts=true
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
-c)
|
|
||||||
cachemode=true
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
-r) # randomize test order
|
|
||||||
randomize=true
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-T) # turn on timestamp output
|
|
||||||
timestamp=true
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
|
|
||||||
-v)
|
|
||||||
verbose=true
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
-d)
|
|
||||||
debug=true
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
-x) # -x group ... exclude from group file
|
|
||||||
xgroup=true
|
|
||||||
xpand=false
|
|
||||||
;;
|
|
||||||
'[0-9][0-9][0-9] [0-9][0-9][0-9][0-9]')
|
|
||||||
echo "No tests?"
|
|
||||||
status=1
|
|
||||||
exit $status
|
|
||||||
;;
|
|
||||||
|
|
||||||
[0-9]*-[0-9]*)
|
|
||||||
eval `echo $r | sed -e 's/^/start=/' -e 's/-/ end=/'`
|
|
||||||
;;
|
|
||||||
|
|
||||||
[0-9]*-)
|
|
||||||
eval `echo $r | sed -e 's/^/start=/' -e 's/-//'`
|
|
||||||
end=`echo [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] | sed -e 's/\[0-9]//g' -e 's/ *$//' -e 's/.* //'`
|
|
||||||
if [ -z "$end" ]
|
|
||||||
then
|
|
||||||
echo "No tests in range \"$r\"?"
|
|
||||||
status=1
|
|
||||||
exit $status
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
|
|
||||||
*)
|
|
||||||
start=$r
|
|
||||||
end=$r
|
|
||||||
;;
|
|
||||||
|
|
||||||
esac
|
|
||||||
|
|
||||||
# get rid of leading 0s as can be interpreted as octal
|
|
||||||
start=`echo $start | sed 's/^0*//'`
|
|
||||||
end=`echo $end | sed 's/^0*//'`
|
|
||||||
|
|
||||||
if $xpand
|
|
||||||
then
|
|
||||||
have_test_arg=true
|
|
||||||
$AWK_PROG </dev/null '
|
|
||||||
BEGIN { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
|
|
||||||
| while read id
|
|
||||||
do
|
|
||||||
if grep -s "^$id " "$source_iotests/group" >/dev/null
|
|
||||||
then
|
|
||||||
# in group file ... OK
|
|
||||||
echo $id >>$tmp.list
|
|
||||||
else
|
|
||||||
if [ -f expunged ] && $expunge && egrep "^$id([ ]|\$)" expunged >/dev/null
|
|
||||||
then
|
|
||||||
# expunged ... will be reported, but not run, later
|
|
||||||
echo $id >>$tmp.list
|
|
||||||
else
|
|
||||||
# oops
|
|
||||||
if [ "$start" == "$end" -a "$id" == "$end" ]
|
|
||||||
then
|
|
||||||
echo "$id - unknown test"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "$id - unknown test, ignored"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done || exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
done
|
|
||||||
|
|
||||||
# Set qemu-io cache mode with $CACHEMODE we have
|
|
||||||
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --cache $CACHEMODE"
|
|
||||||
|
|
||||||
QEMU_IO_OPTIONS_NO_FMT="$QEMU_IO_OPTIONS"
|
|
||||||
if [ "$IMGOPTSSYNTAX" != "true" ]; then
|
|
||||||
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS -f $IMGFMT"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Set default options for qemu-img create -o if they were not specified
|
|
||||||
_set_default_imgopts
|
|
||||||
|
|
||||||
if [ -s $tmp.list ]
|
|
||||||
then
|
|
||||||
# found some valid test numbers ... this is good
|
|
||||||
:
|
|
||||||
else
|
|
||||||
if $have_test_arg
|
|
||||||
then
|
|
||||||
# had test numbers, but none in group file ... do nothing
|
|
||||||
touch $tmp.list
|
|
||||||
else
|
|
||||||
# no test numbers, do everything from group file
|
|
||||||
sed -n -e '/^[0-9][0-9][0-9]*/s/[ ].*//p' <"$source_iotests/group" >$tmp.list
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# should be sort -n, but this did not work for Linux when this
|
|
||||||
# was ported from IRIX
|
|
||||||
#
|
|
||||||
list=`sort $tmp.list`
|
|
||||||
rm -f $tmp.list $tmp.tmp $tmp.sed
|
|
||||||
|
|
||||||
if $randomize
|
|
||||||
then
|
|
||||||
list=`echo $list | awk -f randomize.awk`
|
|
||||||
fi
|
|
||||||
|
|
||||||
[ "$QEMU" = "" ] && _fatal "qemu not found"
|
|
||||||
[ "$QEMU_IMG" = "" ] && _fatal "qemu-img not found"
|
|
||||||
[ "$QEMU_IO" = "" ] && _fatal "qemu-io not found"
|
|
||||||
|
|
||||||
if [ "$IMGPROTO" = "nbd" ] ; then
|
|
||||||
[ "$QEMU_NBD" = "" ] && _fatal "qemu-nbd not found"
|
|
||||||
fi
|
|
@ -15,218 +15,28 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
#
|
|
||||||
# setup and check for config parameters, and in particular
|
|
||||||
#
|
|
||||||
# EMAIL - email of the script runner.
|
|
||||||
# TEST_DIR - scratch test directory
|
|
||||||
#
|
|
||||||
# - These can be added to $HOST_CONFIG_DIR (witch default to ./config)
|
|
||||||
# below or a separate local configuration file can be used (using
|
|
||||||
# the HOST_OPTIONS variable).
|
|
||||||
# - This script is shared by the stress test system and the auto-qa
|
|
||||||
# system (includes both regression test and benchmark components).
|
|
||||||
# - this script shouldn't make any assertions about filesystem
|
|
||||||
# validity or mountedness.
|
|
||||||
#
|
|
||||||
|
|
||||||
# all tests should use a common language setting to prevent golden
|
# all tests should use a common language setting to prevent golden
|
||||||
# output mismatches.
|
# output mismatches.
|
||||||
export LANG=C
|
export LANG=C
|
||||||
|
|
||||||
PATH=".:$PATH"
|
PATH=".:$PATH"
|
||||||
|
|
||||||
HOST=`hostname -s 2> /dev/null`
|
|
||||||
HOSTOS=`uname -s`
|
HOSTOS=`uname -s`
|
||||||
|
arch=`uname -m`
|
||||||
|
|
||||||
EMAIL=root@localhost # where auto-qa will send its status messages
|
|
||||||
export HOST_OPTIONS=${HOST_OPTIONS:=local.config}
|
|
||||||
export CHECK_OPTIONS=${CHECK_OPTIONS:="-g auto"}
|
|
||||||
export PWD=`pwd`
|
export PWD=`pwd`
|
||||||
|
|
||||||
export _QEMU_HANDLE=0
|
# make sure we have a standard umask
|
||||||
|
umask 022
|
||||||
|
|
||||||
# $1 = prog to look for, $2* = default pathnames if not found in $PATH
|
_optstr_add()
|
||||||
set_prog_path()
|
|
||||||
{
|
{
|
||||||
p=`command -v $1 2> /dev/null`
|
if [ -n "$1" ]; then
|
||||||
if [ -n "$p" -a -x "$p" ]; then
|
echo "$1,$2"
|
||||||
echo $p
|
else
|
||||||
return 0
|
echo "$2"
|
||||||
fi
|
fi
|
||||||
p=$1
|
|
||||||
|
|
||||||
shift
|
|
||||||
for f; do
|
|
||||||
if [ -x $f ]; then
|
|
||||||
echo $f
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_fatal()
|
|
||||||
{
|
|
||||||
echo "$*"
|
|
||||||
status=1
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
export AWK_PROG="`set_prog_path awk`"
|
|
||||||
[ "$AWK_PROG" = "" ] && _fatal "awk not found"
|
|
||||||
|
|
||||||
export SED_PROG="`set_prog_path sed`"
|
|
||||||
[ "$SED_PROG" = "" ] && _fatal "sed not found"
|
|
||||||
|
|
||||||
export PS_ALL_FLAGS="-ef"
|
|
||||||
|
|
||||||
if [ -z "$QEMU_PROG" ]; then
|
|
||||||
export QEMU_PROG="`set_prog_path qemu`"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$QEMU_IMG_PROG" ]; then
|
|
||||||
export QEMU_IMG_PROG="`set_prog_path qemu-img`"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$QEMU_IO_PROG" ]; then
|
|
||||||
export QEMU_IO_PROG="`set_prog_path qemu-io`"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$QEMU_NBD_PROG" ]; then
|
|
||||||
export QEMU_NBD_PROG="`set_prog_path qemu-nbd`"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$QEMU_VXHS_PROG" ]; then
|
|
||||||
export QEMU_VXHS_PROG="`set_prog_path qnio_server`"
|
|
||||||
fi
|
|
||||||
|
|
||||||
export QEMU_PROG=$(realpath -- "$(type -p "$QEMU_PROG")")
|
|
||||||
export QEMU_IMG_PROG=$(realpath -- "$(type -p "$QEMU_IMG_PROG")")
|
|
||||||
export QEMU_IO_PROG=$(realpath -- "$(type -p "$QEMU_IO_PROG")")
|
|
||||||
export QEMU_NBD_PROG=$(realpath -- "$(type -p "$QEMU_NBD_PROG")")
|
|
||||||
|
|
||||||
# This program is not built as part of qemu but (possibly) provided by the
|
|
||||||
# system, so it may not be present at all
|
|
||||||
if [ -n "$QEMU_VXHS_PROG" ]; then
|
|
||||||
export QEMU_VXHS_PROG=$(realpath -- "$(type -p "$QEMU_VXHS_PROG")")
|
|
||||||
fi
|
|
||||||
|
|
||||||
_qemu_wrapper()
|
|
||||||
{
|
|
||||||
(
|
|
||||||
if [ -n "${QEMU_NEED_PID}" ]; then
|
|
||||||
echo $BASHPID > "${QEMU_TEST_DIR}/qemu-${_QEMU_HANDLE}.pid"
|
|
||||||
fi
|
|
||||||
exec "$QEMU_PROG" $QEMU_OPTIONS "$@"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
_qemu_img_wrapper()
|
|
||||||
{
|
|
||||||
(exec "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS "$@")
|
|
||||||
}
|
|
||||||
|
|
||||||
_qemu_io_wrapper()
|
|
||||||
{
|
|
||||||
local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
|
|
||||||
local QEMU_IO_ARGS="$QEMU_IO_OPTIONS"
|
|
||||||
if [ "$IMGOPTSSYNTAX" = "true" ]; then
|
|
||||||
QEMU_IO_ARGS="--image-opts $QEMU_IO_ARGS"
|
|
||||||
if [ -n "$IMGKEYSECRET" ]; then
|
|
||||||
QEMU_IO_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IO_ARGS"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
local RETVAL
|
|
||||||
(
|
|
||||||
if [ "${VALGRIND_QEMU}" == "y" ]; then
|
|
||||||
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
|
|
||||||
else
|
|
||||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
|
|
||||||
fi
|
|
||||||
)
|
|
||||||
RETVAL=$?
|
|
||||||
if [ "${VALGRIND_QEMU}" == "y" ]; then
|
|
||||||
if [ $RETVAL == 99 ]; then
|
|
||||||
cat "${VALGRIND_LOGFILE}"
|
|
||||||
fi
|
|
||||||
rm -f "${VALGRIND_LOGFILE}"
|
|
||||||
fi
|
|
||||||
(exit $RETVAL)
|
|
||||||
}
|
|
||||||
|
|
||||||
_qemu_nbd_wrapper()
|
|
||||||
{
|
|
||||||
(
|
|
||||||
echo $BASHPID > "${QEMU_TEST_DIR}/qemu-nbd.pid"
|
|
||||||
exec "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS "$@"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
_qemu_vxhs_wrapper()
|
|
||||||
{
|
|
||||||
(
|
|
||||||
echo $BASHPID > "${TEST_DIR}/qemu-vxhs.pid"
|
|
||||||
exec "$QEMU_VXHS_PROG" $QEMU_VXHS_OPTIONS "$@"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export QEMU=_qemu_wrapper
|
|
||||||
export QEMU_IMG=_qemu_img_wrapper
|
|
||||||
export QEMU_IO=_qemu_io_wrapper
|
|
||||||
export QEMU_NBD=_qemu_nbd_wrapper
|
|
||||||
export QEMU_VXHS=_qemu_vxhs_wrapper
|
|
||||||
|
|
||||||
QEMU_IMG_EXTRA_ARGS=
|
|
||||||
if [ "$IMGOPTSSYNTAX" = "true" ]; then
|
|
||||||
QEMU_IMG_EXTRA_ARGS="--image-opts $QEMU_IMG_EXTRA_ARGS"
|
|
||||||
if [ -n "$IMGKEYSECRET" ]; then
|
|
||||||
QEMU_IMG_EXTRA_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IMG_EXTRA_ARGS"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
export QEMU_IMG_EXTRA_ARGS
|
|
||||||
|
|
||||||
|
|
||||||
default_machine=$($QEMU -machine help | sed -n '/(default)/ s/ .*//p')
|
|
||||||
default_alias_machine=$($QEMU -machine help | \
|
|
||||||
sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }")
|
|
||||||
if [[ "$default_alias_machine" ]]; then
|
|
||||||
default_machine="$default_alias_machine"
|
|
||||||
fi
|
|
||||||
|
|
||||||
export QEMU_DEFAULT_MACHINE="$default_machine"
|
|
||||||
|
|
||||||
[ -f /etc/qemu-iotest.config ] && . /etc/qemu-iotest.config
|
|
||||||
|
|
||||||
if [ -z "$TEST_DIR" ]; then
|
|
||||||
TEST_DIR=`pwd`/scratch
|
|
||||||
fi
|
|
||||||
|
|
||||||
QEMU_TEST_DIR="${TEST_DIR}"
|
|
||||||
|
|
||||||
if [ ! -e "$TEST_DIR" ]; then
|
|
||||||
mkdir "$TEST_DIR"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -d "$TEST_DIR" ]; then
|
|
||||||
echo "common.config: Error: \$TEST_DIR ($TEST_DIR) is not a directory"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
export TEST_DIR
|
|
||||||
|
|
||||||
if [ -z "$SAMPLE_IMG_DIR" ]; then
|
|
||||||
SAMPLE_IMG_DIR="$source_iotests/sample_images"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -d "$SAMPLE_IMG_DIR" ]; then
|
|
||||||
echo "common.config: Error: \$SAMPLE_IMG_DIR ($SAMPLE_IMG_DIR) is not a directory"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
export SAMPLE_IMG_DIR
|
|
||||||
|
|
||||||
# make sure this script returns success
|
# make sure this script returns success
|
||||||
true
|
true
|
||||||
|
@ -111,6 +111,7 @@ _filter_img_create()
|
|||||||
sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
|
sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
|
||||||
-e "s#$TEST_DIR#TEST_DIR#g" \
|
-e "s#$TEST_DIR#TEST_DIR#g" \
|
||||||
-e "s#$IMGFMT#IMGFMT#g" \
|
-e "s#$IMGFMT#IMGFMT#g" \
|
||||||
|
-e 's#nbd:127.0.0.1:10810#TEST_DIR/t.IMGFMT#g' \
|
||||||
-e "s# encryption=off##g" \
|
-e "s# encryption=off##g" \
|
||||||
-e "s# cluster_size=[0-9]\\+##g" \
|
-e "s# cluster_size=[0-9]\\+##g" \
|
||||||
-e "s# table_size=[0-9]\\+##g" \
|
-e "s# table_size=[0-9]\\+##g" \
|
||||||
|
@ -31,6 +31,7 @@ QEMU_FIFO_IN="${QEMU_TEST_DIR}/qmp-in-$$"
|
|||||||
QEMU_FIFO_OUT="${QEMU_TEST_DIR}/qmp-out-$$"
|
QEMU_FIFO_OUT="${QEMU_TEST_DIR}/qmp-out-$$"
|
||||||
|
|
||||||
QEMU_HANDLE=0
|
QEMU_HANDLE=0
|
||||||
|
export _QEMU_HANDLE=0
|
||||||
|
|
||||||
# If bash version is >= 4.1, these will be overwritten and dynamic
|
# If bash version is >= 4.1, these will be overwritten and dynamic
|
||||||
# file descriptor values assigned.
|
# file descriptor values assigned.
|
||||||
@ -55,13 +56,13 @@ function _timed_wait_for()
|
|||||||
shift
|
shift
|
||||||
|
|
||||||
QEMU_STATUS[$h]=0
|
QEMU_STATUS[$h]=0
|
||||||
while read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]}
|
while IFS= read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]}
|
||||||
do
|
do
|
||||||
if [ -z "${silent}" ]; then
|
if [ -z "${silent}" ]; then
|
||||||
echo "${resp}" | _filter_testdir | _filter_qemu \
|
echo "${resp}" | _filter_testdir | _filter_qemu \
|
||||||
| _filter_qemu_io | _filter_qmp | _filter_hmp
|
| _filter_qemu_io | _filter_qmp | _filter_hmp
|
||||||
fi
|
fi
|
||||||
grep -q "${*}" < <(echo ${resp})
|
grep -q "${*}" < <(echo "${resp}")
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
@ -129,6 +130,7 @@ function _send_qemu_cmd()
|
|||||||
# $qemu_comm_method: set this variable to 'monitor' (case insensitive)
|
# $qemu_comm_method: set this variable to 'monitor' (case insensitive)
|
||||||
# to use the QEMU HMP monitor for communication.
|
# to use the QEMU HMP monitor for communication.
|
||||||
# Otherwise, the default of QMP is used.
|
# Otherwise, the default of QMP is used.
|
||||||
|
# $qmp_pretty: Set this variable to 'y' to enable QMP pretty printing.
|
||||||
# $keep_stderr: Set this variable to 'y' to keep QEMU's stderr output on stderr.
|
# $keep_stderr: Set this variable to 'y' to keep QEMU's stderr output on stderr.
|
||||||
# If this variable is empty, stderr will be redirected to stdout.
|
# If this variable is empty, stderr will be redirected to stdout.
|
||||||
# Returns:
|
# Returns:
|
||||||
@ -145,7 +147,11 @@ function _launch_qemu()
|
|||||||
comm="-monitor stdio"
|
comm="-monitor stdio"
|
||||||
else
|
else
|
||||||
local qemu_comm_method="qmp"
|
local qemu_comm_method="qmp"
|
||||||
comm="-monitor none -qmp stdio"
|
if [ "$qmp_pretty" = "y" ]; then
|
||||||
|
comm="-monitor none -qmp-pretty stdio"
|
||||||
|
else
|
||||||
|
comm="-monitor none -qmp stdio"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fifo_out=${QEMU_FIFO_OUT}_${_QEMU_HANDLE}
|
fifo_out=${QEMU_FIFO_OUT}_${_QEMU_HANDLE}
|
||||||
@ -192,6 +198,9 @@ function _launch_qemu()
|
|||||||
then
|
then
|
||||||
# Don't print response, since it has version information in it
|
# Don't print response, since it has version information in it
|
||||||
silent=yes _timed_wait_for ${_QEMU_HANDLE} "capabilities"
|
silent=yes _timed_wait_for ${_QEMU_HANDLE} "capabilities"
|
||||||
|
if [ "$qmp_pretty" = "y" ]; then
|
||||||
|
silent=yes _timed_wait_for ${_QEMU_HANDLE} "^}"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
QEMU_HANDLE=${_QEMU_HANDLE}
|
QEMU_HANDLE=${_QEMU_HANDLE}
|
||||||
let _QEMU_HANDLE++
|
let _QEMU_HANDLE++
|
||||||
|
@ -40,21 +40,84 @@ poke_file()
|
|||||||
printf "$3" | dd "of=$1" bs=1 "seek=$2" conv=notrunc &>/dev/null
|
printf "$3" | dd "of=$1" bs=1 "seek=$2" conv=notrunc &>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
# we need common.config
|
|
||||||
if [ "$iam" != "check" ]
|
if ! . ./common.config
|
||||||
then
|
then
|
||||||
if ! . ./common.config
|
echo "$0: failed to source common.config"
|
||||||
then
|
exit 1
|
||||||
echo "$iam: failed to source common.config"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# make sure we have a standard umask
|
_qemu_wrapper()
|
||||||
umask 022
|
{
|
||||||
|
(
|
||||||
|
if [ -n "${QEMU_NEED_PID}" ]; then
|
||||||
|
echo $BASHPID > "${QEMU_TEST_DIR}/qemu-${_QEMU_HANDLE}.pid"
|
||||||
|
fi
|
||||||
|
exec "$QEMU_PROG" $QEMU_OPTIONS "$@"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_qemu_img_wrapper()
|
||||||
|
{
|
||||||
|
(exec "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS "$@")
|
||||||
|
}
|
||||||
|
|
||||||
|
_qemu_io_wrapper()
|
||||||
|
{
|
||||||
|
local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
|
||||||
|
local QEMU_IO_ARGS="$QEMU_IO_OPTIONS"
|
||||||
|
if [ "$IMGOPTSSYNTAX" = "true" ]; then
|
||||||
|
QEMU_IO_ARGS="--image-opts $QEMU_IO_ARGS"
|
||||||
|
if [ -n "$IMGKEYSECRET" ]; then
|
||||||
|
QEMU_IO_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IO_ARGS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
local RETVAL
|
||||||
|
(
|
||||||
|
if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||||
|
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
|
||||||
|
else
|
||||||
|
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
RETVAL=$?
|
||||||
|
if [ "${VALGRIND_QEMU}" == "y" ]; then
|
||||||
|
if [ $RETVAL == 99 ]; then
|
||||||
|
cat "${VALGRIND_LOGFILE}"
|
||||||
|
fi
|
||||||
|
rm -f "${VALGRIND_LOGFILE}"
|
||||||
|
fi
|
||||||
|
(exit $RETVAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
_qemu_nbd_wrapper()
|
||||||
|
{
|
||||||
|
(
|
||||||
|
echo $BASHPID > "${QEMU_TEST_DIR}/qemu-nbd.pid"
|
||||||
|
exec "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS "$@"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_qemu_vxhs_wrapper()
|
||||||
|
{
|
||||||
|
(
|
||||||
|
echo $BASHPID > "${TEST_DIR}/qemu-vxhs.pid"
|
||||||
|
exec "$QEMU_VXHS_PROG" $QEMU_VXHS_OPTIONS "$@"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export QEMU=_qemu_wrapper
|
||||||
|
export QEMU_IMG=_qemu_img_wrapper
|
||||||
|
export QEMU_IO=_qemu_io_wrapper
|
||||||
|
export QEMU_NBD=_qemu_nbd_wrapper
|
||||||
|
export QEMU_VXHS=_qemu_vxhs_wrapper
|
||||||
|
|
||||||
if [ "$IMGOPTSSYNTAX" = "true" ]; then
|
if [ "$IMGOPTSSYNTAX" = "true" ]; then
|
||||||
DRIVER="driver=$IMGFMT"
|
DRIVER="driver=$IMGFMT"
|
||||||
|
QEMU_IMG_EXTRA_ARGS="--image-opts $QEMU_IMG_EXTRA_ARGS"
|
||||||
|
if [ -n "$IMGKEYSECRET" ]; then
|
||||||
|
QEMU_IMG_EXTRA_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IMG_EXTRA_ARGS"
|
||||||
|
fi
|
||||||
if [ "$IMGFMT" = "luks" ]; then
|
if [ "$IMGFMT" = "luks" ]; then
|
||||||
DRIVER="$DRIVER,key-secret=keysec0"
|
DRIVER="$DRIVER,key-secret=keysec0"
|
||||||
fi
|
fi
|
||||||
@ -74,6 +137,7 @@ if [ "$IMGOPTSSYNTAX" = "true" ]; then
|
|||||||
TEST_IMG="$DRIVER,file.driver=$IMGPROTO,file.filename=$TEST_DIR/t.$IMGFMT"
|
TEST_IMG="$DRIVER,file.driver=$IMGPROTO,file.filename=$TEST_DIR/t.$IMGFMT"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
QEMU_IMG_EXTRA_ARGS=
|
||||||
if [ "$IMGPROTO" = "file" ]; then
|
if [ "$IMGPROTO" = "file" ]; then
|
||||||
TEST_IMG=$TEST_DIR/t.$IMGFMT
|
TEST_IMG=$TEST_DIR/t.$IMGFMT
|
||||||
elif [ "$IMGPROTO" = "nbd" ]; then
|
elif [ "$IMGPROTO" = "nbd" ]; then
|
||||||
@ -94,24 +158,25 @@ else
|
|||||||
fi
|
fi
|
||||||
ORIG_TEST_IMG="$TEST_IMG"
|
ORIG_TEST_IMG="$TEST_IMG"
|
||||||
|
|
||||||
_optstr_add()
|
if [ -z "$TEST_DIR" ]; then
|
||||||
{
|
TEST_DIR=`pwd`/scratch
|
||||||
if [ -n "$1" ]; then
|
fi
|
||||||
echo "$1,$2"
|
|
||||||
else
|
|
||||||
echo "$2"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_set_default_imgopts()
|
QEMU_TEST_DIR="${TEST_DIR}"
|
||||||
{
|
|
||||||
if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then
|
if [ ! -e "$TEST_DIR" ]; then
|
||||||
IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1")
|
mkdir "$TEST_DIR"
|
||||||
fi
|
fi
|
||||||
if [ "$IMGFMT" == "luks" ] && ! (echo "$IMGOPTS" | grep "iter-time=" > /dev/null); then
|
|
||||||
IMGOPTS=$(_optstr_add "$IMGOPTS" "iter-time=10")
|
if [ ! -d "$TEST_DIR" ]; then
|
||||||
fi
|
echo "common.config: Error: \$TEST_DIR ($TEST_DIR) is not a directory"
|
||||||
}
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$SAMPLE_IMG_DIR" ]; then
|
||||||
|
echo "common.config: Error: \$SAMPLE_IMG_DIR ($SAMPLE_IMG_DIR) is not a directory"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
_use_sample_img()
|
_use_sample_img()
|
||||||
{
|
{
|
||||||
@ -293,51 +358,6 @@ _img_info()
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
_get_pids_by_name()
|
|
||||||
{
|
|
||||||
if [ $# -ne 1 ]
|
|
||||||
then
|
|
||||||
echo "Usage: _get_pids_by_name process-name" 1>&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Algorithm ... all ps(1) variants have a time of the form MM:SS or
|
|
||||||
# HH:MM:SS before the psargs field, use this as the search anchor.
|
|
||||||
#
|
|
||||||
# Matches with $1 (process-name) occur if the first psarg is $1
|
|
||||||
# or ends in /$1 ... the matching uses sed's regular expressions,
|
|
||||||
# so passing a regex into $1 will work.
|
|
||||||
|
|
||||||
ps $PS_ALL_FLAGS \
|
|
||||||
| sed -n \
|
|
||||||
-e 's/$/ /' \
|
|
||||||
-e 's/[ ][ ]*/ /g' \
|
|
||||||
-e 's/^ //' \
|
|
||||||
-e 's/^[^ ]* //' \
|
|
||||||
-e "/[0-9]:[0-9][0-9] *[^ ]*\/$1 /s/ .*//p" \
|
|
||||||
-e "/[0-9]:[0-9][0-9] *$1 /s/ .*//p"
|
|
||||||
}
|
|
||||||
|
|
||||||
# fqdn for localhost
|
|
||||||
#
|
|
||||||
_get_fqdn()
|
|
||||||
{
|
|
||||||
host=`hostname`
|
|
||||||
$NSLOOKUP_PROG $host | $AWK_PROG '{ if ($1 == "Name:") print $2 }'
|
|
||||||
}
|
|
||||||
|
|
||||||
# check if run as root
|
|
||||||
#
|
|
||||||
_need_to_be_root()
|
|
||||||
{
|
|
||||||
id=`id | $SED_PROG -e 's/(.*//' -e 's/.*=//'`
|
|
||||||
if [ "$id" -ne 0 ]
|
|
||||||
then
|
|
||||||
echo "Arrgh ... you need to be root (not uid=$id) to run this test"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# bail out, setting up .notrun file
|
# bail out, setting up .notrun file
|
||||||
#
|
#
|
||||||
_notrun()
|
_notrun()
|
||||||
@ -473,46 +493,5 @@ _require_command()
|
|||||||
[ -x "$c" ] || _notrun "$1 utility required, skipped this test"
|
[ -x "$c" ] || _notrun "$1 utility required, skipped this test"
|
||||||
}
|
}
|
||||||
|
|
||||||
_full_imgfmt_details()
|
|
||||||
{
|
|
||||||
if [ -n "$IMGOPTS" ]; then
|
|
||||||
echo "$IMGFMT ($IMGOPTS)"
|
|
||||||
else
|
|
||||||
echo "$IMGFMT"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_full_platform_details()
|
|
||||||
{
|
|
||||||
os=`uname -s`
|
|
||||||
host=`hostname -s`
|
|
||||||
kernel=`uname -r`
|
|
||||||
platform=`uname -m`
|
|
||||||
echo "$os/$platform $host $kernel"
|
|
||||||
}
|
|
||||||
|
|
||||||
_link_out_file()
|
|
||||||
{
|
|
||||||
if [ -z "$1" ]; then
|
|
||||||
echo Error must pass \$seq.
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
rm -f $1
|
|
||||||
if [ "`uname`" == "IRIX64" ] || [ "`uname`" == "IRIX" ]; then
|
|
||||||
ln -s $1.irix $1
|
|
||||||
elif [ "`uname`" == "Linux" ]; then
|
|
||||||
ln -s $1.linux $1
|
|
||||||
else
|
|
||||||
echo Error test $seq does not run on the operating system: `uname`
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_die()
|
|
||||||
{
|
|
||||||
echo $@
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# make sure this script returns success
|
# make sure this script returns success
|
||||||
true
|
true
|
||||||
|
@ -188,6 +188,8 @@
|
|||||||
188 rw auto quick
|
188 rw auto quick
|
||||||
189 rw auto
|
189 rw auto
|
||||||
190 rw auto quick
|
190 rw auto quick
|
||||||
|
191 rw auto
|
||||||
192 rw auto quick
|
192 rw auto quick
|
||||||
194 rw auto migration quick
|
194 rw auto migration quick
|
||||||
195 rw auto quick
|
195 rw auto quick
|
||||||
|
197 rw auto quick
|
||||||
|
@ -738,15 +738,15 @@ static void test_hbitmap_meta_one(TestHBitmapData *data, const void *unused)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_hbitmap_serialize_granularity(TestHBitmapData *data,
|
static void test_hbitmap_serialize_align(TestHBitmapData *data,
|
||||||
const void *unused)
|
const void *unused)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
hbitmap_test_init(data, L3 * 2, 3);
|
hbitmap_test_init(data, L3 * 2, 3);
|
||||||
g_assert(hbitmap_is_serializable(data->hb));
|
g_assert(hbitmap_is_serializable(data->hb));
|
||||||
|
|
||||||
r = hbitmap_serialization_granularity(data->hb);
|
r = hbitmap_serialization_align(data->hb);
|
||||||
g_assert_cmpint(r, ==, 64 << 3);
|
g_assert_cmpint(r, ==, 64 << 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -974,8 +974,8 @@ int main(int argc, char **argv)
|
|||||||
hbitmap_test_add("/hbitmap/meta/word", test_hbitmap_meta_word);
|
hbitmap_test_add("/hbitmap/meta/word", test_hbitmap_meta_word);
|
||||||
hbitmap_test_add("/hbitmap/meta/sector", test_hbitmap_meta_sector);
|
hbitmap_test_add("/hbitmap/meta/sector", test_hbitmap_meta_sector);
|
||||||
|
|
||||||
hbitmap_test_add("/hbitmap/serialize/granularity",
|
hbitmap_test_add("/hbitmap/serialize/align",
|
||||||
test_hbitmap_serialize_granularity);
|
test_hbitmap_serialize_align);
|
||||||
hbitmap_test_add("/hbitmap/serialize/basic",
|
hbitmap_test_add("/hbitmap/serialize/basic",
|
||||||
test_hbitmap_serialize_basic);
|
test_hbitmap_serialize_basic);
|
||||||
hbitmap_test_add("/hbitmap/serialize/part",
|
hbitmap_test_add("/hbitmap/serialize/part",
|
||||||
|
@ -413,14 +413,14 @@ bool hbitmap_is_serializable(const HBitmap *hb)
|
|||||||
{
|
{
|
||||||
/* Every serialized chunk must be aligned to 64 bits so that endianness
|
/* Every serialized chunk must be aligned to 64 bits so that endianness
|
||||||
* requirements can be fulfilled on both 64 bit and 32 bit hosts.
|
* requirements can be fulfilled on both 64 bit and 32 bit hosts.
|
||||||
* We have hbitmap_serialization_granularity() which converts this
|
* We have hbitmap_serialization_align() which converts this
|
||||||
* alignment requirement from bitmap bits to items covered (e.g. sectors).
|
* alignment requirement from bitmap bits to items covered (e.g. sectors).
|
||||||
* That value is:
|
* That value is:
|
||||||
* 64 << hb->granularity
|
* 64 << hb->granularity
|
||||||
* Since this value must not exceed UINT64_MAX, hb->granularity must be
|
* Since this value must not exceed UINT64_MAX, hb->granularity must be
|
||||||
* less than 58 (== 64 - 6, where 6 is ld(64), i.e. 1 << 6 == 64).
|
* less than 58 (== 64 - 6, where 6 is ld(64), i.e. 1 << 6 == 64).
|
||||||
*
|
*
|
||||||
* In order for hbitmap_serialization_granularity() to always return a
|
* In order for hbitmap_serialization_align() to always return a
|
||||||
* meaningful value, bitmaps that are to be serialized must have a
|
* meaningful value, bitmaps that are to be serialized must have a
|
||||||
* granularity of less than 58. */
|
* granularity of less than 58. */
|
||||||
|
|
||||||
@ -437,7 +437,7 @@ bool hbitmap_get(const HBitmap *hb, uint64_t item)
|
|||||||
return (hb->levels[HBITMAP_LEVELS - 1][pos >> BITS_PER_LEVEL] & bit) != 0;
|
return (hb->levels[HBITMAP_LEVELS - 1][pos >> BITS_PER_LEVEL] & bit) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t hbitmap_serialization_granularity(const HBitmap *hb)
|
uint64_t hbitmap_serialization_align(const HBitmap *hb)
|
||||||
{
|
{
|
||||||
assert(hbitmap_is_serializable(hb));
|
assert(hbitmap_is_serializable(hb));
|
||||||
|
|
||||||
@ -454,7 +454,7 @@ static void serialization_chunk(const HBitmap *hb,
|
|||||||
unsigned long **first_el, uint64_t *el_count)
|
unsigned long **first_el, uint64_t *el_count)
|
||||||
{
|
{
|
||||||
uint64_t last = start + count - 1;
|
uint64_t last = start + count - 1;
|
||||||
uint64_t gran = hbitmap_serialization_granularity(hb);
|
uint64_t gran = hbitmap_serialization_align(hb);
|
||||||
|
|
||||||
assert((start & (gran - 1)) == 0);
|
assert((start & (gran - 1)) == 0);
|
||||||
assert((last >> hb->granularity) < hb->size);
|
assert((last >> hb->granularity) < hb->size);
|
||||||
|
Loading…
Reference in New Issue
Block a user