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;
|
||||
}
|
||||
|
||||
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 = {
|
||||
.get_parent_desc = bdrv_child_get_parent_desc,
|
||||
.attach = bdrv_backing_attach,
|
||||
@ -989,6 +1016,7 @@ const BdrvChildRole child_backing = {
|
||||
.drained_begin = bdrv_child_cb_drained_begin,
|
||||
.drained_end = bdrv_child_cb_drained_end,
|
||||
.inactivate = bdrv_child_cb_inactivate,
|
||||
.update_filename = bdrv_backing_update_filename,
|
||||
};
|
||||
|
||||
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
|
||||
*
|
||||
*/
|
||||
int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
|
||||
BlockDriverState *base, const char *backing_file_str)
|
||||
int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
|
||||
const char *backing_file_str)
|
||||
{
|
||||
BlockDriverState *new_top_bs = NULL;
|
||||
BdrvChild *c, *next;
|
||||
Error *local_err = NULL;
|
||||
int ret = -EIO;
|
||||
|
||||
bdrv_ref(top);
|
||||
|
||||
if (!top->drv || !base->drv) {
|
||||
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 */
|
||||
if (!bdrv_chain_contains(top, base)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
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);
|
||||
if (local_err) {
|
||||
ret = -EPERM;
|
||||
error_report_err(local_err);
|
||||
goto exit;
|
||||
QLIST_FOREACH_SAFE(c, &top->parents, next_parent, next) {
|
||||
/* Check whether we are allowed to switch c from top to base */
|
||||
GSList *ignore_children = g_slist_prepend(NULL, c);
|
||||
bdrv_check_update_perm(base, NULL, c->perm, c->shared_perm,
|
||||
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;
|
||||
exit:
|
||||
bdrv_unref(top);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -3545,12 +3582,18 @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
|
||||
assert(!(bs->open_flags & BDRV_O_INACTIVE));
|
||||
|
||||
ret = drv->bdrv_truncate(bs, offset, prealloc, errp);
|
||||
if (ret == 0) {
|
||||
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
|
||||
bdrv_dirty_bitmap_truncate(bs);
|
||||
bdrv_parent_cb_resize(bs);
|
||||
atomic_inc(&bs->write_gen);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
* 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)) {
|
||||
BlockDriverState *bs;
|
||||
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);
|
||||
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) */
|
||||
while ((offset = bdrv_dirty_iter_next(dbi) * BDRV_SECTOR_SIZE) >= 0) {
|
||||
while ((offset = bdrv_dirty_iter_next(dbi)) >= 0) {
|
||||
cluster = offset / job->cluster_size;
|
||||
|
||||
/* 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,
|
||||
* we need to advance the iterator pointer to the next cluster. */
|
||||
if (granularity < job->cluster_size) {
|
||||
bdrv_set_dirty_iter(dbi,
|
||||
cluster * job->cluster_size / BDRV_SECTOR_SIZE);
|
||||
bdrv_set_dirty_iter(dbi, cluster * job->cluster_size);
|
||||
}
|
||||
|
||||
last_cluster = cluster - 1;
|
||||
|
@ -36,13 +36,11 @@ enum {
|
||||
typedef struct CommitBlockJob {
|
||||
BlockJob common;
|
||||
RateLimit limit;
|
||||
BlockDriverState *active;
|
||||
BlockDriverState *commit_top_bs;
|
||||
BlockBackend *top;
|
||||
BlockBackend *base;
|
||||
BlockdevOnError on_error;
|
||||
int base_flags;
|
||||
int orig_overlay_flags;
|
||||
char *backing_file_str;
|
||||
} CommitBlockJob;
|
||||
|
||||
@ -81,18 +79,15 @@ static void commit_complete(BlockJob *job, void *opaque)
|
||||
{
|
||||
CommitBlockJob *s = container_of(job, CommitBlockJob, common);
|
||||
CommitCompleteData *data = opaque;
|
||||
BlockDriverState *active = s->active;
|
||||
BlockDriverState *top = blk_bs(s->top);
|
||||
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;
|
||||
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);
|
||||
if (overlay_bs) {
|
||||
bdrv_ref(overlay_bs);
|
||||
}
|
||||
bdrv_ref(commit_top_bs);
|
||||
|
||||
/* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
|
||||
* 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) {
|
||||
/* success */
|
||||
ret = bdrv_drop_intermediate(active, s->commit_top_bs, base,
|
||||
ret = bdrv_drop_intermediate(s->commit_top_bs, base,
|
||||
s->backing_file_str);
|
||||
} else if (overlay_bs) {
|
||||
} else {
|
||||
/* XXX Can (or should) we somehow keep 'consistent read' blocked even
|
||||
* after the failed/cancelled commit job is gone? If we already wrote
|
||||
* 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)) {
|
||||
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);
|
||||
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
|
||||
* the 'consistent read' permission can be granted. */
|
||||
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);
|
||||
}
|
||||
|
||||
@ -283,10 +278,8 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
{
|
||||
CommitBlockJob *s;
|
||||
BlockReopenQueue *reopen_queue = NULL;
|
||||
int orig_overlay_flags;
|
||||
int orig_base_flags;
|
||||
BlockDriverState *iter;
|
||||
BlockDriverState *overlay_bs;
|
||||
BlockDriverState *commit_top_bs = NULL;
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
@ -297,31 +290,19 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
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,
|
||||
speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
|
||||
orig_base_flags = bdrv_get_flags(base);
|
||||
orig_overlay_flags = bdrv_get_flags(overlay_bs);
|
||||
|
||||
/* convert base & overlay_bs to r/w, if necessary */
|
||||
/* convert base to r/w, if necessary */
|
||||
orig_base_flags = bdrv_get_flags(base);
|
||||
if (!(orig_base_flags & BDRV_O_RDWR)) {
|
||||
reopen_queue = bdrv_reopen_queue(reopen_queue, base, NULL,
|
||||
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) {
|
||||
bdrv_reopen_multiple(bdrv_get_aio_context(bs), reopen_queue, &local_err);
|
||||
if (local_err != NULL) {
|
||||
@ -350,7 +331,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
error_propagate(errp, local_err);
|
||||
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) {
|
||||
bdrv_unref(commit_top_bs);
|
||||
commit_top_bs = NULL;
|
||||
@ -382,14 +363,6 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
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
|
||||
| BLK_PERM_WRITE
|
||||
| BLK_PERM_RESIZE,
|
||||
@ -408,13 +381,8 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->active = bs;
|
||||
|
||||
s->base_flags = orig_base_flags;
|
||||
s->orig_overlay_flags = orig_overlay_flags;
|
||||
|
||||
s->base_flags = orig_base_flags;
|
||||
s->backing_file_str = g_strdup(backing_file_str);
|
||||
|
||||
s->on_error = on_error;
|
||||
|
||||
trace_commit_start(bs, base, top, s);
|
||||
@ -429,7 +397,7 @@ fail:
|
||||
blk_unref(s->top);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
130
block/crypto.c
130
block/crypto.c
@ -279,6 +279,9 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
|
||||
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);
|
||||
qemu_opts_absorb_qdict(opts, options, &local_err);
|
||||
if (local_err) {
|
||||
@ -364,8 +367,9 @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
|
||||
PreallocMode prealloc, Error **errp)
|
||||
{
|
||||
BlockCrypto *crypto = bs->opaque;
|
||||
size_t payload_offset =
|
||||
uint64_t payload_offset =
|
||||
qcrypto_block_get_payload_offset(crypto->block);
|
||||
assert(payload_offset < (INT64_MAX - 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
|
||||
block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
int remaining_sectors, QEMUIOVector *qiov)
|
||||
block_crypto_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
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;
|
||||
uint8_t *cipher_data = NULL;
|
||||
QEMUIOVector hd_qiov;
|
||||
int ret = 0;
|
||||
size_t payload_offset =
|
||||
qcrypto_block_get_payload_offset(crypto->block) / 512;
|
||||
uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
|
||||
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);
|
||||
|
||||
/* Bounce buffer so we have a linear mem region for
|
||||
* entire sector. XXX optimize so we avoid bounce
|
||||
* buffer in case that qiov->niov == 1
|
||||
/* Bounce buffer because we don't wish to expose cipher text
|
||||
* in qiov which points to guest memory.
|
||||
*/
|
||||
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));
|
||||
if (cipher_data == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (remaining_sectors) {
|
||||
cur_nr_sectors = remaining_sectors;
|
||||
|
||||
if (cur_nr_sectors > BLOCK_CRYPTO_MAX_SECTORS) {
|
||||
cur_nr_sectors = BLOCK_CRYPTO_MAX_SECTORS;
|
||||
}
|
||||
while (bytes) {
|
||||
cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE);
|
||||
|
||||
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,
|
||||
payload_offset + sector_num,
|
||||
cur_nr_sectors, &hd_qiov);
|
||||
ret = bdrv_co_preadv(bs->file, payload_offset + offset + bytes_done,
|
||||
cur_bytes, &hd_qiov, 0);
|
||||
if (ret < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (qcrypto_block_decrypt(crypto->block,
|
||||
sector_num,
|
||||
cipher_data, cur_nr_sectors * 512,
|
||||
NULL) < 0) {
|
||||
if (qcrypto_block_decrypt(crypto->block, offset + bytes_done,
|
||||
cipher_data, cur_bytes, NULL) < 0) {
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
qemu_iovec_from_buf(qiov, bytes_done,
|
||||
cipher_data, cur_nr_sectors * 512);
|
||||
qemu_iovec_from_buf(qiov, bytes_done, cipher_data, cur_bytes);
|
||||
|
||||
remaining_sectors -= cur_nr_sectors;
|
||||
sector_num += cur_nr_sectors;
|
||||
bytes_done += cur_nr_sectors * 512;
|
||||
bytes -= cur_bytes;
|
||||
bytes_done += cur_bytes;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
@ -450,63 +453,58 @@ block_crypto_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
|
||||
static coroutine_fn int
|
||||
block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
int remaining_sectors, QEMUIOVector *qiov)
|
||||
block_crypto_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
|
||||
QEMUIOVector *qiov, int flags)
|
||||
{
|
||||
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;
|
||||
uint8_t *cipher_data = NULL;
|
||||
QEMUIOVector hd_qiov;
|
||||
int ret = 0;
|
||||
size_t payload_offset =
|
||||
qcrypto_block_get_payload_offset(crypto->block) / 512;
|
||||
uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
|
||||
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);
|
||||
|
||||
/* Bounce buffer so we have a linear mem region for
|
||||
* entire sector. XXX optimize so we avoid bounce
|
||||
* buffer in case that qiov->niov == 1
|
||||
/* Bounce buffer because we're not permitted to touch
|
||||
* contents of qiov - it points to guest memory.
|
||||
*/
|
||||
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));
|
||||
if (cipher_data == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (remaining_sectors) {
|
||||
cur_nr_sectors = remaining_sectors;
|
||||
while (bytes) {
|
||||
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_to_buf(qiov, bytes_done, cipher_data, cur_bytes);
|
||||
|
||||
qemu_iovec_to_buf(qiov, bytes_done,
|
||||
cipher_data, cur_nr_sectors * 512);
|
||||
|
||||
if (qcrypto_block_encrypt(crypto->block,
|
||||
sector_num,
|
||||
cipher_data, cur_nr_sectors * 512,
|
||||
NULL) < 0) {
|
||||
if (qcrypto_block_encrypt(crypto->block, offset + bytes_done,
|
||||
cipher_data, cur_bytes, NULL) < 0) {
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
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,
|
||||
payload_offset + sector_num,
|
||||
cur_nr_sectors, &hd_qiov);
|
||||
ret = bdrv_co_pwritev(bs->file, payload_offset + offset + bytes_done,
|
||||
cur_bytes, &hd_qiov, flags);
|
||||
if (ret < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
remaining_sectors -= cur_nr_sectors;
|
||||
sector_num += cur_nr_sectors;
|
||||
bytes_done += cur_nr_sectors * 512;
|
||||
bytes -= cur_bytes;
|
||||
bytes_done += cur_bytes;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
@ -516,13 +514,22 @@ block_crypto_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
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)
|
||||
{
|
||||
BlockCrypto *crypto = bs->opaque;
|
||||
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;
|
||||
|
||||
@ -613,8 +620,9 @@ BlockDriver bdrv_crypto_luks = {
|
||||
.bdrv_truncate = block_crypto_truncate,
|
||||
.create_opts = &block_crypto_create_opts_luks,
|
||||
|
||||
.bdrv_co_readv = block_crypto_co_readv,
|
||||
.bdrv_co_writev = block_crypto_co_writev,
|
||||
.bdrv_refresh_limits = block_crypto_refresh_limits,
|
||||
.bdrv_co_preadv = block_crypto_co_preadv,
|
||||
.bdrv_co_pwritev = block_crypto_co_pwritev,
|
||||
.bdrv_getlength = block_crypto_getlength,
|
||||
.bdrv_get_info = block_crypto_get_info_luks,
|
||||
.bdrv_get_specific_info = block_crypto_get_specific_info_luks,
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -38,11 +38,11 @@
|
||||
*/
|
||||
struct BdrvDirtyBitmap {
|
||||
QemuMutex *mutex;
|
||||
HBitmap *bitmap; /* Dirty sector bitmap implementation */
|
||||
HBitmap *bitmap; /* Dirty bitmap implementation */
|
||||
HBitmap *meta; /* Meta dirty bitmap */
|
||||
BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
|
||||
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
|
||||
the device */
|
||||
int active_iterators; /* How many iterators are active */
|
||||
@ -115,17 +115,14 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
|
||||
{
|
||||
int64_t bitmap_size;
|
||||
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)) {
|
||||
error_setg(errp, "Bitmap already exists: %s", name);
|
||||
return NULL;
|
||||
}
|
||||
sector_granularity = granularity >> BDRV_SECTOR_BITS;
|
||||
assert(sector_granularity);
|
||||
bitmap_size = bdrv_nb_sectors(bs);
|
||||
bitmap_size = bdrv_getlength(bs);
|
||||
if (bitmap_size < 0) {
|
||||
error_setg_errno(errp, -bitmap_size, "could not get length of device");
|
||||
errno = -bitmap_size;
|
||||
@ -133,7 +130,7 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
|
||||
}
|
||||
bitmap = g_new0(BdrvDirtyBitmap, 1);
|
||||
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->name = g_strdup(name);
|
||||
bitmap->disabled = false;
|
||||
@ -173,45 +170,6 @@ void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
|
||||
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)
|
||||
{
|
||||
return bitmap->size;
|
||||
@ -341,17 +299,16 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
|
||||
* Truncates _all_ bitmaps attached to a BDS.
|
||||
* Called with BQL taken.
|
||||
*/
|
||||
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
|
||||
void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes)
|
||||
{
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
uint64_t size = bdrv_nb_sectors(bs);
|
||||
|
||||
bdrv_dirty_bitmaps_lock(bs);
|
||||
QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
|
||||
assert(!bdrv_dirty_bitmap_frozen(bitmap));
|
||||
assert(!bitmap->active_iterators);
|
||||
hbitmap_truncate(bitmap->bitmap, size);
|
||||
bitmap->size = size;
|
||||
hbitmap_truncate(bitmap->bitmap, bytes);
|
||||
bitmap->size = bytes;
|
||||
}
|
||||
bdrv_dirty_bitmaps_unlock(bs);
|
||||
}
|
||||
@ -461,7 +418,7 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
|
||||
QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
|
||||
BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 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->has_name = !!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 */
|
||||
int bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t sector)
|
||||
bool bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t offset)
|
||||
{
|
||||
if (bitmap) {
|
||||
return hbitmap_get(bitmap->bitmap, sector);
|
||||
return hbitmap_get(bitmap->bitmap, offset);
|
||||
} 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)
|
||||
{
|
||||
return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
|
||||
return 1U << hbitmap_granularity(bitmap->bitmap);
|
||||
}
|
||||
|
||||
uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->meta);
|
||||
}
|
||||
|
||||
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
|
||||
uint64_t first_sector)
|
||||
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
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;
|
||||
bitmap->active_iterators++;
|
||||
return iter;
|
||||
@ -552,35 +503,35 @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
|
||||
|
||||
/* Called within bdrv_dirty_bitmap_lock..unlock */
|
||||
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_readonly(bitmap));
|
||||
hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
|
||||
hbitmap_set(bitmap->bitmap, offset, bytes);
|
||||
}
|
||||
|
||||
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_set_dirty_bitmap_locked(bitmap, cur_sector, nr_sectors);
|
||||
bdrv_set_dirty_bitmap_locked(bitmap, offset, bytes);
|
||||
bdrv_dirty_bitmap_unlock(bitmap);
|
||||
}
|
||||
|
||||
/* Called within bdrv_dirty_bitmap_lock..unlock */
|
||||
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_readonly(bitmap));
|
||||
hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
|
||||
hbitmap_reset(bitmap->bitmap, offset, bytes);
|
||||
}
|
||||
|
||||
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_reset_dirty_bitmap_locked(bitmap, cur_sector, nr_sectors);
|
||||
bdrv_reset_dirty_bitmap_locked(bitmap, offset, bytes);
|
||||
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 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)
|
||||
{
|
||||
return hbitmap_serialization_granularity(bitmap->bitmap);
|
||||
return hbitmap_serialization_align(bitmap->bitmap);
|
||||
}
|
||||
|
||||
void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
|
||||
uint8_t *buf, uint64_t start,
|
||||
uint64_t count)
|
||||
uint8_t *buf, uint64_t offset,
|
||||
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,
|
||||
uint8_t *buf, uint64_t start,
|
||||
uint64_t count, bool finish)
|
||||
uint8_t *buf, uint64_t offset,
|
||||
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,
|
||||
uint64_t start, uint64_t count,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
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,
|
||||
uint64_t start, uint64_t count,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
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)
|
||||
@ -653,8 +604,7 @@ void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
|
||||
hbitmap_deserialize_finish(bitmap->bitmap);
|
||||
}
|
||||
|
||||
void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
int64_t nr_sectors)
|
||||
void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes)
|
||||
{
|
||||
BdrvDirtyBitmap *bitmap;
|
||||
|
||||
@ -668,7 +618,7 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
}
|
||||
@ -676,9 +626,9 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
|
||||
/**
|
||||
* 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)
|
||||
|
135
block/io.c
135
block/io.c
@ -34,6 +34,9 @@
|
||||
|
||||
#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,
|
||||
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;
|
||||
struct iovec iov;
|
||||
QEMUIOVector bounce_qiov;
|
||||
QEMUIOVector local_qiov;
|
||||
int64_t cluster_offset;
|
||||
unsigned int cluster_bytes;
|
||||
size_t skip_bytes;
|
||||
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
|
||||
* 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
|
||||
* 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
|
||||
* it could request permissions. Therefore we have to bypass the permission
|
||||
* system for the moment. */
|
||||
// assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
|
||||
|
||||
/* 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);
|
||||
skip_bytes = offset - cluster_offset;
|
||||
|
||||
trace_bdrv_co_do_copy_on_readv(bs, offset, bytes,
|
||||
cluster_offset, cluster_bytes);
|
||||
|
||||
iov.iov_len = cluster_bytes;
|
||||
iov.iov_base = bounce_buffer = qemu_try_blockalign(bs, iov.iov_len);
|
||||
bounce_buffer = qemu_try_blockalign(bs,
|
||||
MIN(MIN(max_transfer, cluster_bytes),
|
||||
MAX_BOUNCE_BUFFER));
|
||||
if (bounce_buffer == NULL) {
|
||||
ret = -ENOMEM;
|
||||
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,
|
||||
&bounce_qiov, 0);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
ret = bdrv_is_allocated(bs, cluster_offset,
|
||||
MIN(cluster_bytes, max_transfer), &pnum);
|
||||
if (ret < 0) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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);
|
||||
ret = 0;
|
||||
|
||||
err:
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
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 alignment = MAX(bs->bl.pwrite_zeroes_alignment,
|
||||
bs->bl.request_alignment);
|
||||
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer,
|
||||
MAX_WRITE_ZEROES_BOUNCE_BUFFER);
|
||||
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFFER);
|
||||
|
||||
assert(alignment % bs->bl.request_alignment == 0);
|
||||
head = offset % alignment;
|
||||
@ -1334,7 +1379,6 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
|
||||
bool waited;
|
||||
int ret;
|
||||
|
||||
int64_t start_sector = offset >> BDRV_SECTOR_BITS;
|
||||
int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
|
||||
uint64_t bytes_remaining = bytes;
|
||||
int max_transfer;
|
||||
@ -1409,7 +1453,7 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
|
||||
bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE);
|
||||
|
||||
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);
|
||||
|
||||
@ -1778,6 +1822,10 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
*pnum = 0;
|
||||
return BDRV_BLOCK_EOF;
|
||||
}
|
||||
if (!nb_sectors) {
|
||||
*pnum = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = total_sectors - sector_num;
|
||||
if (n < nb_sectors) {
|
||||
@ -2438,8 +2486,7 @@ int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
|
||||
ret = 0;
|
||||
out:
|
||||
atomic_inc(&bs->write_gen);
|
||||
bdrv_set_dirty(bs, req.offset >> BDRV_SECTOR_BITS,
|
||||
req.bytes >> BDRV_SECTOR_BITS);
|
||||
bdrv_set_dirty(bs, req.offset, req.bytes);
|
||||
tracked_request_end(&req);
|
||||
bdrv_dec_in_flight(bs);
|
||||
return ret;
|
||||
|
@ -141,8 +141,7 @@ static void mirror_write_complete(void *opaque, int ret)
|
||||
if (ret < 0) {
|
||||
BlockErrorAction action;
|
||||
|
||||
bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset >> BDRV_SECTOR_BITS,
|
||||
op->bytes >> BDRV_SECTOR_BITS);
|
||||
bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset, op->bytes);
|
||||
action = mirror_error_action(s, false, -ret);
|
||||
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
||||
s->ret = ret;
|
||||
@ -161,8 +160,7 @@ static void mirror_read_complete(void *opaque, int ret)
|
||||
if (ret < 0) {
|
||||
BlockErrorAction action;
|
||||
|
||||
bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset >> BDRV_SECTOR_BITS,
|
||||
op->bytes >> BDRV_SECTOR_BITS);
|
||||
bdrv_set_dirty_bitmap(s->dirty_bitmap, op->offset, op->bytes);
|
||||
action = mirror_error_action(s, true, -ret);
|
||||
if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
|
||||
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);
|
||||
|
||||
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) {
|
||||
bdrv_set_dirty_iter(s->dbi, 0);
|
||||
offset = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE;
|
||||
trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap) *
|
||||
BDRV_SECTOR_SIZE);
|
||||
offset = bdrv_dirty_iter_next(s->dbi);
|
||||
trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap));
|
||||
assert(offset >= 0);
|
||||
}
|
||||
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_chunk = next_offset / s->granularity;
|
||||
if (next_offset >= s->bdev_length ||
|
||||
!bdrv_get_dirty_locked(source, s->dirty_bitmap,
|
||||
next_offset >> BDRV_SECTOR_BITS)) {
|
||||
!bdrv_get_dirty_locked(source, s->dirty_bitmap, next_offset)) {
|
||||
break;
|
||||
}
|
||||
if (test_bit(next_chunk, s->in_flight_bitmap)) {
|
||||
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) {
|
||||
/* The bitmap iterator's cache is stale, refresh it */
|
||||
bdrv_set_dirty_iter(s->dbi, next_offset >> BDRV_SECTOR_BITS);
|
||||
next_dirty = bdrv_dirty_iter_next(s->dbi) * BDRV_SECTOR_SIZE;
|
||||
bdrv_set_dirty_iter(s->dbi, next_offset);
|
||||
next_dirty = bdrv_dirty_iter_next(s->dbi);
|
||||
}
|
||||
assert(next_dirty == next_offset);
|
||||
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
|
||||
* marked dirty in this window, we need to know.
|
||||
*/
|
||||
bdrv_reset_dirty_bitmap_locked(s->dirty_bitmap, offset >> BDRV_SECTOR_BITS,
|
||||
nb_chunks * sectors_per_chunk);
|
||||
bdrv_reset_dirty_bitmap_locked(s->dirty_bitmap, offset,
|
||||
nb_chunks * s->granularity);
|
||||
bdrv_dirty_bitmap_unlock(s->dirty_bitmap);
|
||||
|
||||
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)
|
||||
{
|
||||
int64_t sector_num, end;
|
||||
int64_t offset;
|
||||
BlockDriverState *base = s->base;
|
||||
BlockDriverState *bs = s->source;
|
||||
BlockDriverState *target_bs = blk_bs(s->target);
|
||||
int ret, n;
|
||||
int ret;
|
||||
int64_t count;
|
||||
|
||||
end = s->bdev_length / BDRV_SECTOR_SIZE;
|
||||
|
||||
if (base == NULL && !bdrv_has_zero_init(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;
|
||||
}
|
||||
|
||||
s->initial_zeroing_ongoing = true;
|
||||
for (sector_num = 0; sector_num < end; ) {
|
||||
int nb_sectors = MIN(end - sector_num,
|
||||
QEMU_ALIGN_DOWN(INT_MAX, s->granularity) >> BDRV_SECTOR_BITS);
|
||||
for (offset = 0; offset < s->bdev_length; ) {
|
||||
int bytes = MIN(s->bdev_length - offset,
|
||||
QEMU_ALIGN_DOWN(INT_MAX, s->granularity));
|
||||
|
||||
mirror_throttle(s);
|
||||
|
||||
@ -650,9 +644,8 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
|
||||
continue;
|
||||
}
|
||||
|
||||
mirror_do_zero_or_discard(s, sector_num * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE, false);
|
||||
sector_num += nb_sectors;
|
||||
mirror_do_zero_or_discard(s, offset, bytes, false);
|
||||
offset += bytes;
|
||||
}
|
||||
|
||||
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. */
|
||||
for (sector_num = 0; sector_num < end; ) {
|
||||
for (offset = 0; offset < s->bdev_length; ) {
|
||||
/* Just to make sure we are not exceeding int limit. */
|
||||
int nb_sectors = MIN(INT_MAX >> BDRV_SECTOR_BITS,
|
||||
end - sector_num);
|
||||
int bytes = MIN(s->bdev_length - offset,
|
||||
QEMU_ALIGN_DOWN(INT_MAX, s->granularity));
|
||||
|
||||
mirror_throttle(s);
|
||||
|
||||
@ -671,21 +664,16 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = bdrv_is_allocated_above(bs, base, sector_num * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE, &count);
|
||||
ret = bdrv_is_allocated_above(bs, base, offset, bytes, &count);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TODO: Relax this once bdrv_is_allocated_above and dirty
|
||||
* bitmaps no longer require sector alignment. */
|
||||
assert(QEMU_IS_ALIGNED(count, BDRV_SECTOR_SIZE));
|
||||
n = count >> BDRV_SECTOR_BITS;
|
||||
assert(n > 0);
|
||||
assert(count);
|
||||
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;
|
||||
}
|
||||
@ -796,7 +784,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
}
|
||||
|
||||
assert(!s->dbi);
|
||||
s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap, 0);
|
||||
s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap);
|
||||
for (;;) {
|
||||
uint64_t delay_ns = 0;
|
||||
int64_t cnt, delta;
|
||||
@ -811,11 +799,10 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
|
||||
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
|
||||
/* 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
|
||||
* processed; together those are the current total operation length */
|
||||
s->common.len = s->common.offset + s->bytes_in_flight +
|
||||
cnt * BDRV_SECTOR_SIZE;
|
||||
s->common.len = s->common.offset + s->bytes_in_flight + cnt;
|
||||
|
||||
/* 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.
|
||||
@ -827,8 +814,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
s->common.iostatus == BLOCK_DEVICE_IO_STATUS_OK) {
|
||||
if (s->in_flight >= MAX_IN_FLIGHT || s->buf_free_count == 0 ||
|
||||
(cnt == 0 && s->in_flight > 0)) {
|
||||
trace_mirror_yield(s, cnt * BDRV_SECTOR_SIZE,
|
||||
s->buf_free_count, s->in_flight);
|
||||
trace_mirror_yield(s, cnt, s->buf_free_count, s->in_flight);
|
||||
mirror_wait_for_io(s);
|
||||
continue;
|
||||
} 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
|
||||
* 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);
|
||||
cnt = bdrv_get_dirty_count(s->dirty_bitmap);
|
||||
@ -888,8 +874,7 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
trace_mirror_before_sleep(s, cnt * BDRV_SECTOR_SIZE,
|
||||
s->synced, delay_ns);
|
||||
trace_mirror_before_sleep(s, cnt, s->synced, delay_ns);
|
||||
if (!s->synced) {
|
||||
block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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)
|
||||
{
|
||||
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);
|
||||
pstrcpy(bs->exact_filename, sizeof(bs->exact_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++) {
|
||||
if (i < n_start || i >= n_end) {
|
||||
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,
|
||||
BDRV_SECTOR_SIZE,
|
||||
NULL) < 0) {
|
||||
@ -668,7 +670,8 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
if (bs->encrypted) {
|
||||
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) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
@ -740,8 +743,8 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
if (bs->encrypted) {
|
||||
assert(s->crypto);
|
||||
if (qcrypto_block_encrypt(s->crypto, sector_num, buf,
|
||||
n * BDRV_SECTOR_SIZE, NULL) < 0) {
|
||||
if (qcrypto_block_encrypt(s->crypto, sector_num * BDRV_SECTOR_SIZE,
|
||||
buf, n * BDRV_SECTOR_SIZE, NULL) < 0) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
@ -269,15 +269,16 @@ static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function returns the number of disk sectors covered by a single qcow2
|
||||
* cluster of bitmap data. */
|
||||
static uint64_t sectors_covered_by_bitmap_cluster(const BDRVQcow2State *s,
|
||||
const BdrvDirtyBitmap *bitmap)
|
||||
/* Return the disk size covered by a single qcow2 cluster of bitmap data. */
|
||||
static uint64_t bytes_covered_by_bitmap_cluster(const BDRVQcow2State *s,
|
||||
const BdrvDirtyBitmap *bitmap)
|
||||
{
|
||||
uint32_t sector_granularity =
|
||||
bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
|
||||
uint64_t granularity = bdrv_dirty_bitmap_granularity(bitmap);
|
||||
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
|
||||
@ -290,7 +291,7 @@ static int load_bitmap_data(BlockDriverState *bs,
|
||||
{
|
||||
int ret = 0;
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
uint64_t sector, sbc;
|
||||
uint64_t offset, limit;
|
||||
uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
|
||||
uint8_t *buf = NULL;
|
||||
uint64_t i, tab_size =
|
||||
@ -302,28 +303,28 @@ static int load_bitmap_data(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
buf = g_malloc(s->cluster_size);
|
||||
sbc = sectors_covered_by_bitmap_cluster(s, bitmap);
|
||||
for (i = 0, sector = 0; i < tab_size; ++i, sector += sbc) {
|
||||
uint64_t count = MIN(bm_size - sector, sbc);
|
||||
limit = bytes_covered_by_bitmap_cluster(s, bitmap);
|
||||
for (i = 0, offset = 0; i < tab_size; ++i, offset += limit) {
|
||||
uint64_t count = MIN(bm_size - offset, limit);
|
||||
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);
|
||||
|
||||
if (offset == 0) {
|
||||
if (data_offset == 0) {
|
||||
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);
|
||||
} else {
|
||||
/* No need to deserialize zeros because the dirty bitmap is
|
||||
* already cleared */
|
||||
}
|
||||
} 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) {
|
||||
goto finish;
|
||||
}
|
||||
bdrv_dirty_bitmap_deserialize_part(bitmap, buf, sector, count,
|
||||
bdrv_dirty_bitmap_deserialize_part(bitmap, buf, offset, count,
|
||||
false);
|
||||
}
|
||||
}
|
||||
@ -1071,8 +1072,8 @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
|
||||
{
|
||||
int ret;
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int64_t sector;
|
||||
uint64_t sbc;
|
||||
int64_t offset;
|
||||
uint64_t limit;
|
||||
uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
|
||||
const char *bm_name = bdrv_dirty_bitmap_name(bitmap);
|
||||
uint8_t *buf = NULL;
|
||||
@ -1095,20 +1096,25 @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbi = bdrv_dirty_iter_new(bitmap, 0);
|
||||
dbi = bdrv_dirty_iter_new(bitmap);
|
||||
buf = g_malloc(s->cluster_size);
|
||||
sbc = sectors_covered_by_bitmap_cluster(s, bitmap);
|
||||
assert(DIV_ROUND_UP(bm_size, sbc) == tb_size);
|
||||
limit = bytes_covered_by_bitmap_cluster(s, bitmap);
|
||||
assert(DIV_ROUND_UP(bm_size, limit) == tb_size);
|
||||
|
||||
while ((sector = bdrv_dirty_iter_next(dbi)) != -1) {
|
||||
uint64_t cluster = sector / sbc;
|
||||
while ((offset = bdrv_dirty_iter_next(dbi)) >= 0) {
|
||||
uint64_t cluster = offset / limit;
|
||||
uint64_t end, write_size;
|
||||
int64_t off;
|
||||
|
||||
sector = cluster * sbc;
|
||||
end = MIN(bm_size, sector + sbc);
|
||||
write_size =
|
||||
bdrv_dirty_bitmap_serialization_size(bitmap, sector, end - sector);
|
||||
/*
|
||||
* We found the first dirty offset, but want to write out the
|
||||
* entire cluster of the bitmap that includes that offset,
|
||||
* 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);
|
||||
|
||||
off = qcow2_alloc_clusters(bs, s->cluster_size);
|
||||
@ -1120,7 +1126,7 @@ static uint64_t *store_bitmap_data(BlockDriverState *bs,
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
int64_t sector = (s->crypt_physical_offset ?
|
||||
int64_t offset = (s->crypt_physical_offset ?
|
||||
(cluster_offset + offset_in_cluster) :
|
||||
(src_cluster_offset + offset_in_cluster))
|
||||
>> BDRV_SECTOR_BITS;
|
||||
(src_cluster_offset + offset_in_cluster));
|
||||
assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
|
||||
assert((bytes & ~BDRV_SECTOR_MASK) == 0);
|
||||
assert(s->crypto);
|
||||
if (qcrypto_block_encrypt(s->crypto, sector, buffer,
|
||||
bytes, NULL) < 0) {
|
||||
if (qcrypto_block_encrypt(s->crypto, offset, buffer, bytes, NULL) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -3181,3 +3181,25 @@ out:
|
||||
g_free(reftable_tmp);
|
||||
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,
|
||||
(s->crypt_physical_offset ?
|
||||
cluster_offset + offset_in_cluster :
|
||||
offset) >> BDRV_SECTOR_BITS,
|
||||
offset),
|
||||
cluster_data,
|
||||
cur_bytes,
|
||||
NULL) < 0) {
|
||||
@ -1946,7 +1946,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
|
||||
if (qcrypto_block_encrypt(s->crypto,
|
||||
(s->crypt_physical_offset ?
|
||||
cluster_offset + offset_in_cluster :
|
||||
offset) >> BDRV_SECTOR_BITS,
|
||||
offset),
|
||||
cluster_data,
|
||||
cur_bytes, NULL) < 0) {
|
||||
ret = -EIO;
|
||||
@ -3107,6 +3107,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
|
||||
new_l1_size = size_to_l1(s, offset);
|
||||
|
||||
if (offset < old_length) {
|
||||
int64_t last_cluster, old_file_size;
|
||||
if (prealloc != PREALLOC_MODE_OFF) {
|
||||
error_setg(errp,
|
||||
"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");
|
||||
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 {
|
||||
ret = qcow2_grow_l1_table(bs, new_l1_size, true);
|
||||
if (ret < 0) {
|
||||
@ -3167,7 +3190,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset,
|
||||
if (old_file_size < 0) {
|
||||
error_setg_errno(errp, -old_file_size,
|
||||
"Failed to inquire current file length");
|
||||
return ret;
|
||||
return old_file_size;
|
||||
}
|
||||
|
||||
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) {
|
||||
error_setg_errno(errp, -allocation_start,
|
||||
"Failed to resize refcount structures");
|
||||
return -allocation_start;
|
||||
return 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;
|
||||
} else {
|
||||
int cluster_sectors = cluster_size / BDRV_SECTOR_SIZE;
|
||||
int64_t sector_num;
|
||||
int64_t offset;
|
||||
int pnum = 0;
|
||||
|
||||
for (sector_num = 0;
|
||||
sector_num < ssize / BDRV_SECTOR_SIZE;
|
||||
sector_num += pnum) {
|
||||
int nb_sectors = MIN(ssize / BDRV_SECTOR_SIZE - sector_num,
|
||||
BDRV_REQUEST_MAX_SECTORS);
|
||||
for (offset = 0; offset < ssize;
|
||||
offset += pnum * BDRV_SECTOR_SIZE) {
|
||||
int nb_sectors = MIN(ssize - offset,
|
||||
BDRV_REQUEST_MAX_BYTES) / BDRV_SECTOR_SIZE;
|
||||
BlockDriverState *file;
|
||||
int64_t ret;
|
||||
|
||||
ret = bdrv_get_block_status_above(in_bs, NULL,
|
||||
sector_num, nb_sectors,
|
||||
offset >> BDRV_SECTOR_BITS,
|
||||
nb_sectors,
|
||||
&pnum, &file);
|
||||
if (ret < 0) {
|
||||
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)) ==
|
||||
(BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED)) {
|
||||
/* Extend pnum to end of cluster for next iteration */
|
||||
pnum = ROUND_UP(sector_num + pnum, cluster_sectors) -
|
||||
sector_num;
|
||||
pnum = (ROUND_UP(offset + pnum * BDRV_SECTOR_SIZE,
|
||||
cluster_size) - offset) >> BDRV_SECTOR_BITS;
|
||||
|
||||
/* Count clusters we've seen */
|
||||
required += (sector_num % cluster_sectors + pnum) *
|
||||
BDRV_SECTOR_SIZE;
|
||||
required += offset % cluster_size + pnum * BDRV_SECTOR_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -597,6 +597,7 @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
|
||||
BlockDriverAmendStatusCB *status_cb,
|
||||
void *cb_opaque, Error **errp);
|
||||
int qcow2_shrink_reftable(BlockDriverState *bs);
|
||||
int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
|
||||
|
||||
/* qcow2-cluster.c functions */
|
||||
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 *
|
||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
|
||||
block->sector_size;
|
||||
|
||||
luks->cipher_alg = cipheralg;
|
||||
luks->cipher_mode = ciphermode;
|
||||
@ -1240,8 +1241,9 @@ qcrypto_block_luks_create(QCryptoBlock *block,
|
||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) *
|
||||
QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);
|
||||
|
||||
block->sector_size = QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
|
||||
block->payload_offset = luks->header.payload_offset *
|
||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
|
||||
block->sector_size;
|
||||
|
||||
/* Reserve header space to match payload offset */
|
||||
initfunc(block, block->payload_offset, opaque, &local_err);
|
||||
@ -1397,29 +1399,33 @@ static void qcrypto_block_luks_cleanup(QCryptoBlock *block)
|
||||
|
||||
static int
|
||||
qcrypto_block_luks_decrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint64_t offset,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
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,
|
||||
block->niv, block->ivgen,
|
||||
QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
|
||||
startsector, buf, len, errp);
|
||||
offset, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_luks_encrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint64_t offset,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
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,
|
||||
block->niv, block->ivgen,
|
||||
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;
|
||||
}
|
||||
|
||||
block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE;
|
||||
block->payload_offset = 0;
|
||||
|
||||
return 0;
|
||||
@ -142,29 +143,33 @@ qcrypto_block_qcow_cleanup(QCryptoBlock *block)
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_decrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint64_t offset,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
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,
|
||||
block->niv, block->ivgen,
|
||||
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
|
||||
startsector, buf, len, errp);
|
||||
offset, buf, len, errp);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_block_qcow_encrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint64_t offset,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
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,
|
||||
block->niv, block->ivgen,
|
||||
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,
|
||||
uint64_t startsector,
|
||||
uint64_t offset,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
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,
|
||||
uint64_t startsector,
|
||||
uint64_t offset,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
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)
|
||||
{
|
||||
if (!block) {
|
||||
@ -188,13 +194,17 @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint64_t offset,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *iv;
|
||||
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;
|
||||
|
||||
@ -237,13 +247,17 @@ int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint64_t offset,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
uint8_t *iv;
|
||||
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;
|
||||
|
||||
|
@ -36,6 +36,7 @@ struct QCryptoBlock {
|
||||
QCryptoHashAlgorithm kdfhash;
|
||||
size_t niv;
|
||||
uint64_t payload_offset; /* In bytes */
|
||||
uint64_t sector_size; /* In bytes */
|
||||
};
|
||||
|
||||
struct QCryptoBlockDriver {
|
||||
@ -81,7 +82,7 @@ int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint64_t offset,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
@ -90,7 +91,7 @@ int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
|
||||
size_t niv,
|
||||
QCryptoIVGen *ivgen,
|
||||
int sectorsize,
|
||||
uint64_t startsector,
|
||||
uint64_t offset,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
@ -520,10 +520,6 @@ static void onenand_command(OneNANDState *s)
|
||||
s->intstatus |= ONEN_INT;
|
||||
|
||||
for (b = 0; b < s->blocks; b ++) {
|
||||
if (b >= s->blocks) {
|
||||
s->status |= ONEN_ERR_CMD;
|
||||
break;
|
||||
}
|
||||
if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN)
|
||||
break;
|
||||
|
||||
|
@ -315,8 +315,7 @@ int bdrv_commit(BlockDriverState *bs);
|
||||
int bdrv_change_backing_file(BlockDriverState *bs,
|
||||
const char *backing_file, const char *backing_fmt);
|
||||
void bdrv_register(BlockDriver *bdrv);
|
||||
int bdrv_drop_intermediate(BlockDriverState *active, BlockDriverState *top,
|
||||
BlockDriverState *base,
|
||||
int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
|
||||
const char *backing_file_str);
|
||||
BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
|
||||
BlockDriverState *bs);
|
||||
|
@ -544,6 +544,12 @@ struct BdrvChildRole {
|
||||
|
||||
void (*attach)(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;
|
||||
@ -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_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);
|
||||
|
||||
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);
|
||||
uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
|
||||
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_frozen(BdrvDirtyBitmap *bitmap);
|
||||
const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap);
|
||||
int64_t bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap);
|
||||
DirtyBitmapStatus bdrv_dirty_bitmap_status(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,
|
||||
int64_t cur_sector, int64_t nr_sectors);
|
||||
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);
|
||||
int64_t offset, int64_t bytes);
|
||||
BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
|
||||
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
|
||||
uint64_t first_sector);
|
||||
BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap);
|
||||
void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
|
||||
|
||||
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);
|
||||
void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
|
||||
uint8_t *buf, uint64_t start,
|
||||
uint64_t count);
|
||||
uint8_t *buf, uint64_t offset,
|
||||
uint64_t bytes);
|
||||
void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
|
||||
uint8_t *buf, uint64_t start,
|
||||
uint64_t count, bool finish);
|
||||
uint8_t *buf, uint64_t offset,
|
||||
uint64_t bytes, bool finish);
|
||||
void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
|
||||
uint64_t start, uint64_t count,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
bool finish);
|
||||
void bdrv_dirty_bitmap_deserialize_ones(BdrvDirtyBitmap *bitmap,
|
||||
uint64_t start, uint64_t count,
|
||||
uint64_t offset, uint64_t bytes,
|
||||
bool finish);
|
||||
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. */
|
||||
void bdrv_dirty_bitmap_lock(BdrvDirtyBitmap *bitmap);
|
||||
void bdrv_dirty_bitmap_unlock(BdrvDirtyBitmap *bitmap);
|
||||
int bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t sector);
|
||||
bool bdrv_get_dirty_locked(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
|
||||
int64_t offset);
|
||||
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,
|
||||
int64_t cur_sector, int64_t nr_sectors);
|
||||
int64_t offset, int64_t bytes);
|
||||
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_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_has_readonly_bitmaps(BlockDriverState *bs);
|
||||
bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
|
||||
|
@ -161,18 +161,19 @@ QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
|
||||
/**
|
||||
* @qcrypto_block_decrypt:
|
||||
* @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
|
||||
* @len: the length of @buf in bytes
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
int qcrypto_block_decrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint64_t offset,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
@ -180,18 +181,19 @@ int qcrypto_block_decrypt(QCryptoBlock *block,
|
||||
/**
|
||||
* @qcrypto_block_encrypt:
|
||||
* @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
|
||||
* @len: the length of @buf in bytes
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
int qcrypto_block_encrypt(QCryptoBlock *block,
|
||||
uint64_t startsector,
|
||||
uint64_t offset,
|
||||
uint8_t *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
@ -240,6 +242,21 @@ QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(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:
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* hbitmap_serialization_granularity:
|
||||
* hbitmap_serialization_align:
|
||||
* @hb: HBitmap to operate on.
|
||||
*
|
||||
* Granularity of serialization chunks, used by other serialization functions.
|
||||
* For every chunk:
|
||||
* Required alignment of serialization chunks, used by other serialization
|
||||
* functions. For every chunk:
|
||||
* 1. Chunk start should be aligned to this granularity.
|
||||
* 2. Chunk size should be aligned too, except for last chunk (for which
|
||||
* start + count == hb->size)
|
||||
*/
|
||||
uint64_t hbitmap_serialization_granularity(const HBitmap *hb);
|
||||
uint64_t hbitmap_serialization_align(const HBitmap *hb);
|
||||
|
||||
/**
|
||||
* 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,
|
||||
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));
|
||||
qemu_mutex_unlock_iothread();
|
||||
|
||||
@ -535,13 +536,16 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
|
||||
blk_mig_unlock();
|
||||
}
|
||||
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) {
|
||||
nr_sectors = total_sectors - sector;
|
||||
} else {
|
||||
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);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
return dirty << BDRV_SECTOR_BITS;
|
||||
return dirty;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2538,6 +2538,8 @@
|
||||
#
|
||||
# @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
|
||||
##
|
||||
{ 'enum': 'BlkdebugEvent', 'prefix': 'BLKDBG',
|
||||
@ -2555,7 +2557,8 @@
|
||||
'flush_to_disk', 'pwritev_rmw_head', 'pwritev_rmw_after_head',
|
||||
'pwritev_rmw_tail', 'pwritev_rmw_after_tail', 'pwritev',
|
||||
'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:
|
||||
|
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"
|
||||
" -r, -- open file read-only\n"
|
||||
" -s, -- use snapshot file\n"
|
||||
" -C, -- use copy-on-read\n"
|
||||
" -n, -- disable host cache, short for -t none\n"
|
||||
" -U, -- force shared permissions\n"
|
||||
" -k, -- use kernel AIO implementation (on Linux only)\n"
|
||||
@ -120,7 +121,7 @@ static const cmdinfo_t open_cmd = {
|
||||
.argmin = 1,
|
||||
.argmax = -1,
|
||||
.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",
|
||||
.help = open_help,
|
||||
};
|
||||
@ -145,7 +146,7 @@ static int open_f(BlockBackend *blk, int argc, char **argv)
|
||||
QDict *opts;
|
||||
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) {
|
||||
case 's':
|
||||
flags |= BDRV_O_SNAPSHOT;
|
||||
@ -154,6 +155,9 @@ static int open_f(BlockBackend *blk, int argc, char **argv)
|
||||
flags |= BDRV_O_NOCACHE;
|
||||
writethrough = false;
|
||||
break;
|
||||
case 'C':
|
||||
flags |= BDRV_O_COPY_ON_READ;
|
||||
break;
|
||||
case 'r':
|
||||
readonly = 1;
|
||||
break;
|
||||
@ -251,6 +255,7 @@ static void usage(const char *name)
|
||||
" -r, --read-only export read-only\n"
|
||||
" -s, --snapshot use snapshot file\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"
|
||||
" -k, --native-aio use kernel AIO implementation (on Linux only)\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 readonly = 0;
|
||||
const char *sopt = "hVc:d:f:rsnmkt:T:U";
|
||||
const char *sopt = "hVc:d:f:rsnCmkt:T:U";
|
||||
const struct option lopt[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
@ -448,6 +453,7 @@ int main(int argc, char **argv)
|
||||
{ "read-only", no_argument, NULL, 'r' },
|
||||
{ "snapshot", no_argument, NULL, 's' },
|
||||
{ "nocache", no_argument, NULL, 'n' },
|
||||
{ "copy-on-read", no_argument, NULL, 'C' },
|
||||
{ "misalign", no_argument, NULL, 'm' },
|
||||
{ "native-aio", no_argument, NULL, 'k' },
|
||||
{ "discard", required_argument, NULL, 'd' },
|
||||
@ -492,6 +498,9 @@ int main(int argc, char **argv)
|
||||
flags |= BDRV_O_NOCACHE;
|
||||
writethrough = false;
|
||||
break;
|
||||
case 'C':
|
||||
flags |= BDRV_O_COPY_ON_READ;
|
||||
break;
|
||||
case 'd':
|
||||
if (bdrv_parse_discard_flags(optarg, &flags) < 0) {
|
||||
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')
|
||||
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
|
||||
result = self.vm.qmp('block-stream', device='drive0', base=self.imgs[5], job_id='stream-drive0')
|
||||
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
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( 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 "$@";
|
||||
else
|
||||
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
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( 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 "$@";
|
||||
else
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||
@ -68,7 +68,7 @@ incompatible_features 0x0
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( 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 "$@";
|
||||
else
|
||||
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
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( 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 "$@";
|
||||
else
|
||||
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
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( 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 "$@";
|
||||
else
|
||||
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
|
||||
wrote 131072/131072 bytes at offset 0
|
||||
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 "$@";
|
||||
else
|
||||
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
|
||||
wrote 131072/131072 bytes at offset 0
|
||||
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 "$@";
|
||||
else
|
||||
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
|
||||
wrote 512/512 bytes at offset 0
|
||||
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
./common.config: Killed ( 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 "$@";
|
||||
else
|
||||
exec "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@";
|
||||
|
@ -27,7 +27,7 @@ disk = os.path.join(iotests.test_dir, 'disk')
|
||||
disk_size = 0x40000000 # 1G
|
||||
|
||||
# regions for qemu_io: (start, count) in bytes
|
||||
regions1 = ((0, 0x100000),
|
||||
regions1 = ((0x0fff00, 0x10000),
|
||||
(0x200000, 0x100000))
|
||||
|
||||
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()
|
||||
{
|
||||
echo Testing: "$@" | _filter_imgfmt
|
||||
echo Testing: "$@"
|
||||
$QEMU -nographic -qmp-pretty stdio -serial none "$@"
|
||||
echo
|
||||
}
|
||||
|
||||
function run_qemu()
|
||||
{
|
||||
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp \
|
||||
| _filter_qemu_io | _filter_generated_node_ids
|
||||
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_imgfmt | _filter_qemu \
|
||||
| _filter_qmp | _filter_qemu_io \
|
||||
| _filter_generated_node_ids
|
||||
}
|
||||
|
||||
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
|
||||
timestamp=${TIMESTAMP:=false}
|
||||
|
||||
# generic initialization
|
||||
iam=check
|
||||
|
||||
_init_error()
|
||||
{
|
||||
echo "$iam: $1" >&2
|
||||
echo "check: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
@ -60,48 +57,6 @@ fi
|
||||
|
||||
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
|
||||
if ! . "$build_iotests/common.env"
|
||||
then
|
||||
@ -114,22 +69,550 @@ then
|
||||
_init_error "failed to source common.config"
|
||||
fi
|
||||
|
||||
# we need common.rc
|
||||
if ! . "$source_iotests/common.rc"
|
||||
then
|
||||
_init_error "failed to source common.rc"
|
||||
_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"
|
||||
}
|
||||
|
||||
# $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
|
||||
|
||||
# we need common
|
||||
. "$source_iotests/common"
|
||||
if [ ! -e "$TEST_DIR" ]; then
|
||||
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
|
||||
|
||||
tmp="${TEST_DIR}"/$$
|
||||
|
||||
_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()
|
||||
@ -140,12 +623,6 @@ _timestamp()
|
||||
|
||||
_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
|
||||
then
|
||||
:
|
||||
@ -154,7 +631,7 @@ _wrapup()
|
||||
if [ -f $TIMESTAMP_FILE -a -f $tmp.time ]
|
||||
then
|
||||
cat $TIMESTAMP_FILE $tmp.time \
|
||||
| $AWK_PROG '
|
||||
| awk '
|
||||
{ t[$1] = $2 }
|
||||
END { if (NR > 0) {
|
||||
for (i in t) print i " " t[i]
|
||||
@ -194,6 +671,9 @@ END { if (NR > 0) {
|
||||
needwrap=false
|
||||
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}"/check.pid "${TEST_DIR}"/check.sts
|
||||
rm -f $tmp.*
|
||||
@ -201,24 +681,6 @@ END { if (NR > 0) {
|
||||
|
||||
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
|
||||
|
||||
FULL_IMGFMT_DETAILS=`_full_imgfmt_details`
|
||||
@ -276,9 +738,6 @@ do
|
||||
fi
|
||||
rm -f core $seq.notrun
|
||||
|
||||
# for hangcheck ...
|
||||
echo "$seq" > "${TEST_DIR}"/check.sts
|
||||
|
||||
start=`_wallclock`
|
||||
$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
|
||||
# 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
|
||||
# output mismatches.
|
||||
export LANG=C
|
||||
|
||||
PATH=".:$PATH"
|
||||
|
||||
HOST=`hostname -s 2> /dev/null`
|
||||
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 _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
|
||||
set_prog_path()
|
||||
_optstr_add()
|
||||
{
|
||||
p=`command -v $1 2> /dev/null`
|
||||
if [ -n "$p" -a -x "$p" ]; then
|
||||
echo $p
|
||||
return 0
|
||||
if [ -n "$1" ]; then
|
||||
echo "$1,$2"
|
||||
else
|
||||
echo "$2"
|
||||
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
|
||||
true
|
||||
|
@ -111,6 +111,7 @@ _filter_img_create()
|
||||
sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
|
||||
-e "s#$TEST_DIR#TEST_DIR#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# cluster_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_HANDLE=0
|
||||
export _QEMU_HANDLE=0
|
||||
|
||||
# If bash version is >= 4.1, these will be overwritten and dynamic
|
||||
# file descriptor values assigned.
|
||||
@ -55,13 +56,13 @@ function _timed_wait_for()
|
||||
shift
|
||||
|
||||
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
|
||||
if [ -z "${silent}" ]; then
|
||||
echo "${resp}" | _filter_testdir | _filter_qemu \
|
||||
| _filter_qemu_io | _filter_qmp | _filter_hmp
|
||||
fi
|
||||
grep -q "${*}" < <(echo ${resp})
|
||||
grep -q "${*}" < <(echo "${resp}")
|
||||
if [ $? -eq 0 ]; then
|
||||
return
|
||||
fi
|
||||
@ -129,6 +130,7 @@ function _send_qemu_cmd()
|
||||
# $qemu_comm_method: set this variable to 'monitor' (case insensitive)
|
||||
# to use the QEMU HMP monitor for communication.
|
||||
# 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.
|
||||
# If this variable is empty, stderr will be redirected to stdout.
|
||||
# Returns:
|
||||
@ -145,7 +147,11 @@ function _launch_qemu()
|
||||
comm="-monitor stdio"
|
||||
else
|
||||
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
|
||||
|
||||
fifo_out=${QEMU_FIFO_OUT}_${_QEMU_HANDLE}
|
||||
@ -192,6 +198,9 @@ function _launch_qemu()
|
||||
then
|
||||
# Don't print response, since it has version information in it
|
||||
silent=yes _timed_wait_for ${_QEMU_HANDLE} "capabilities"
|
||||
if [ "$qmp_pretty" = "y" ]; then
|
||||
silent=yes _timed_wait_for ${_QEMU_HANDLE} "^}"
|
||||
fi
|
||||
fi
|
||||
QEMU_HANDLE=${_QEMU_HANDLE}
|
||||
let _QEMU_HANDLE++
|
||||
|
@ -40,21 +40,84 @@ poke_file()
|
||||
printf "$3" | dd "of=$1" bs=1 "seek=$2" conv=notrunc &>/dev/null
|
||||
}
|
||||
|
||||
# we need common.config
|
||||
if [ "$iam" != "check" ]
|
||||
then
|
||||
if ! . ./common.config
|
||||
then
|
||||
echo "$iam: failed to source common.config"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! . ./common.config
|
||||
then
|
||||
echo "$0: failed to source common.config"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# make sure we have a standard umask
|
||||
umask 022
|
||||
_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
|
||||
|
||||
if [ "$IMGOPTSSYNTAX" = "true" ]; then
|
||||
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
|
||||
DRIVER="$DRIVER,key-secret=keysec0"
|
||||
fi
|
||||
@ -74,6 +137,7 @@ if [ "$IMGOPTSSYNTAX" = "true" ]; then
|
||||
TEST_IMG="$DRIVER,file.driver=$IMGPROTO,file.filename=$TEST_DIR/t.$IMGFMT"
|
||||
fi
|
||||
else
|
||||
QEMU_IMG_EXTRA_ARGS=
|
||||
if [ "$IMGPROTO" = "file" ]; then
|
||||
TEST_IMG=$TEST_DIR/t.$IMGFMT
|
||||
elif [ "$IMGPROTO" = "nbd" ]; then
|
||||
@ -94,24 +158,25 @@ else
|
||||
fi
|
||||
ORIG_TEST_IMG="$TEST_IMG"
|
||||
|
||||
_optstr_add()
|
||||
{
|
||||
if [ -n "$1" ]; then
|
||||
echo "$1,$2"
|
||||
else
|
||||
echo "$2"
|
||||
fi
|
||||
}
|
||||
if [ -z "$TEST_DIR" ]; then
|
||||
TEST_DIR=`pwd`/scratch
|
||||
fi
|
||||
|
||||
_set_default_imgopts()
|
||||
{
|
||||
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
|
||||
}
|
||||
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
|
||||
|
||||
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()
|
||||
{
|
||||
@ -293,51 +358,6 @@ _img_info()
|
||||
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
|
||||
#
|
||||
_notrun()
|
||||
@ -473,46 +493,5 @@ _require_command()
|
||||
[ -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
|
||||
true
|
||||
|
@ -188,6 +188,8 @@
|
||||
188 rw auto quick
|
||||
189 rw auto
|
||||
190 rw auto quick
|
||||
191 rw auto
|
||||
192 rw auto quick
|
||||
194 rw auto migration 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,
|
||||
const void *unused)
|
||||
static void test_hbitmap_serialize_align(TestHBitmapData *data,
|
||||
const void *unused)
|
||||
{
|
||||
int r;
|
||||
|
||||
hbitmap_test_init(data, L3 * 2, 3);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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/sector", test_hbitmap_meta_sector);
|
||||
|
||||
hbitmap_test_add("/hbitmap/serialize/granularity",
|
||||
test_hbitmap_serialize_granularity);
|
||||
hbitmap_test_add("/hbitmap/serialize/align",
|
||||
test_hbitmap_serialize_align);
|
||||
hbitmap_test_add("/hbitmap/serialize/basic",
|
||||
test_hbitmap_serialize_basic);
|
||||
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
|
||||
* 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).
|
||||
* That value is:
|
||||
* 64 << hb->granularity
|
||||
* 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).
|
||||
*
|
||||
* 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
|
||||
* 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;
|
||||
}
|
||||
|
||||
uint64_t hbitmap_serialization_granularity(const HBitmap *hb)
|
||||
uint64_t hbitmap_serialization_align(const HBitmap *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)
|
||||
{
|
||||
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((last >> hb->granularity) < hb->size);
|
||||
|
Loading…
Reference in New Issue
Block a user