diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-03-09 14:43:39 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-03-09 14:43:39 +0000 |
commit | 4c76137484878f42a2ce1ae1b888b6a7f66b4053 (patch) | |
tree | 0c1472199325e9282cff113a34643334c1433e57 | |
parent | 1eb5da3b732466320d6c0c81459bb3a8df72a1d1 (diff) | |
parent | e88153ea9a40009a8ae7648282c0eac1b7f5494f (diff) |
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches:
- qcow2: Support for external data files
- qcow2: Default to 4KB for the qcow2 cache entry size
- Apply block driver whitelist for -drive format=help
- Several qemu-iotests improvements
# gpg: Signature made Fri 08 Mar 2019 12:54:27 GMT
# gpg: using RSA key 7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6
* remotes/kevin/tags/for-upstream: (33 commits)
qcow2 spec: Describe string header extensions
qemu-iotests: Add dependency to qemu-nbd tool
ahci-test: Add dependency to qemu-img tool
qemu-iotests: amend with external data file
qemu-iotests: General tests for qcow2 with external data file
qemu-iotests: Preallocation with external data file
qcow2: Implement data-file-raw create option
qcow2: Store data file name in the image
qcow2: Creating images with external data file
qcow2: Add basic data-file infrastructure
qcow2: Support external data file in qemu-img check
qcow2: Return error for snapshot operation with data file
qcow2: External file I/O
qcow2: Prepare qcow2_co_block_status() for data file
qcow2: Return 0/-errno in qcow2_alloc_compressed_cluster_offset()
qcow2: Don't assume 0 is an invalid cluster offset
qcow2: Prepare count_contiguous_clusters() for external data file
qcow2: Prepare qcow2_get_cluster_type() for external data file
qcow2: Pass bs to qcow2_get_cluster_type()
qcow2: Basic definitions for external data files
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
215 files changed, 1584 insertions, 422 deletions
@@ -426,7 +426,7 @@ BlockDriver *bdrv_find_format(const char *format_name) return bdrv_do_find_format(format_name); } -int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) +static int bdrv_format_is_whitelisted(const char *format_name, bool read_only) { static const char *whitelist_rw[] = { CONFIG_BDRV_RW_WHITELIST @@ -441,13 +441,13 @@ int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) } for (p = whitelist_rw; *p; p++) { - if (!strcmp(drv->format_name, *p)) { + if (!strcmp(format_name, *p)) { return 1; } } if (read_only) { for (p = whitelist_ro; *p; p++) { - if (!strcmp(drv->format_name, *p)) { + if (!strcmp(format_name, *p)) { return 1; } } @@ -455,6 +455,11 @@ int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) return 0; } +int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) +{ + return bdrv_format_is_whitelisted(drv->format_name, read_only); +} + bool bdrv_uses_whitelist(void) { return use_bdrv_whitelist; @@ -4147,7 +4152,7 @@ static int qsort_strcmp(const void *a, const void *b) } void bdrv_iterate_format(void (*it)(void *opaque, const char *name), - void *opaque) + void *opaque, bool read_only) { BlockDriver *drv; int count = 0; @@ -4158,6 +4163,11 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name), if (drv->format_name) { bool found = false; int i = count; + + if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, read_only)) { + continue; + } + while (formats && i && !found) { found = !strcmp(formats[--i], drv->format_name); } @@ -4176,6 +4186,11 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name), bool found = false; int j = count; + if (use_bdrv_whitelist && + !bdrv_format_is_whitelisted(format_name, read_only)) { + continue; + } + while (formats && j && !found) { found = !strcmp(formats[--j], format_name); } diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 3ee524da4b..9d968bdcda 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -778,7 +778,8 @@ static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list, * directory in-place (actually, turn-off the extension), which is checked * in qcow2_check_metadata_overlap() */ ret = qcow2_pre_write_overlap_check( - bs, in_place ? QCOW2_OL_BITMAP_DIRECTORY : 0, dir_offset, dir_size); + bs, in_place ? QCOW2_OL_BITMAP_DIRECTORY : 0, dir_offset, dir_size, + false); if (ret < 0) { goto fail; } @@ -1224,7 +1225,7 @@ static uint64_t *store_bitmap_data(BlockDriverState *bs, memset(buf + write_size, 0, s->cluster_size - write_size); } - ret = qcow2_pre_write_overlap_check(bs, 0, off, s->cluster_size); + ret = qcow2_pre_write_overlap_check(bs, 0, off, s->cluster_size, false); if (ret < 0) { error_setg_errno(errp, -ret, "Qcow2 overlap check failed"); goto fail; @@ -1292,7 +1293,7 @@ static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp) } ret = qcow2_pre_write_overlap_check(bs, 0, tb_offset, - tb_size * sizeof(tb[0])); + tb_size * sizeof(tb[0]), false); if (ret < 0) { error_setg_errno(errp, -ret, "Qcow2 overlap check failed"); goto fail; diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index d9dafa31e5..df02e7b20a 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -205,13 +205,13 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) if (c == s->refcount_block_cache) { ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_REFCOUNT_BLOCK, - c->entries[i].offset, c->table_size); + c->entries[i].offset, c->table_size, false); } else if (c == s->l2_table_cache) { ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2, - c->entries[i].offset, c->table_size); + c->entries[i].offset, c->table_size, false); } else { ret = qcow2_pre_write_overlap_check(bs, 0, - c->entries[i].offset, c->table_size); + c->entries[i].offset, c->table_size, false); } if (ret < 0) { diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 179aa2c728..974a4e8656 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -153,7 +153,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, /* the L1 position has not yet been updated, so these clusters must * indeed be completely free */ ret = qcow2_pre_write_overlap_check(bs, 0, new_l1_table_offset, - new_l1_size2); + new_l1_size2, false); if (ret < 0) { goto fail; } @@ -238,7 +238,7 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index) } ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1, - s->l1_table_offset + 8 * l1_start_index, sizeof(buf)); + s->l1_table_offset + 8 * l1_start_index, sizeof(buf), false); if (ret < 0) { return ret; } @@ -380,8 +380,8 @@ fail: * as contiguous. (This allows it, for example, to stop at the first compressed * cluster which may require a different handling) */ -static int count_contiguous_clusters(int nb_clusters, int cluster_size, - uint64_t *l2_slice, uint64_t stop_flags) +static int count_contiguous_clusters(BlockDriverState *bs, int nb_clusters, + int cluster_size, uint64_t *l2_slice, uint64_t stop_flags) { int i; QCow2ClusterType first_cluster_type; @@ -389,12 +389,12 @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size, uint64_t first_entry = be64_to_cpu(l2_slice[0]); uint64_t offset = first_entry & mask; - if (!offset) { + first_cluster_type = qcow2_get_cluster_type(bs, first_entry); + if (first_cluster_type == QCOW2_CLUSTER_UNALLOCATED) { return 0; } /* must be allocated */ - first_cluster_type = qcow2_get_cluster_type(first_entry); assert(first_cluster_type == QCOW2_CLUSTER_NORMAL || first_cluster_type == QCOW2_CLUSTER_ZERO_ALLOC); @@ -412,7 +412,8 @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size, * Checks how many consecutive unallocated clusters in a given L2 * slice have the same cluster type. */ -static int count_contiguous_clusters_unallocated(int nb_clusters, +static int count_contiguous_clusters_unallocated(BlockDriverState *bs, + int nb_clusters, uint64_t *l2_slice, QCow2ClusterType wanted_type) { @@ -422,7 +423,7 @@ static int count_contiguous_clusters_unallocated(int nb_clusters, wanted_type == QCOW2_CLUSTER_UNALLOCATED); for (i = 0; i < nb_clusters; i++) { uint64_t entry = be64_to_cpu(l2_slice[i]); - QCow2ClusterType type = qcow2_get_cluster_type(entry); + QCow2ClusterType type = qcow2_get_cluster_type(bs, entry); if (type != wanted_type) { break; @@ -489,6 +490,7 @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs, unsigned offset_in_cluster, QEMUIOVector *qiov) { + BDRVQcow2State *s = bs->opaque; int ret; if (qiov->size == 0) { @@ -496,13 +498,13 @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs, } ret = qcow2_pre_write_overlap_check(bs, 0, - cluster_offset + offset_in_cluster, qiov->size); + cluster_offset + offset_in_cluster, qiov->size, true); if (ret < 0) { return ret; } BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE); - ret = bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster, + ret = bdrv_co_pwritev(s->data_file, cluster_offset + offset_in_cluster, qiov->size, qiov, 0); if (ret < 0) { return ret; @@ -595,7 +597,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, * true */ assert(nb_clusters <= INT_MAX); - type = qcow2_get_cluster_type(*cluster_offset); + type = qcow2_get_cluster_type(bs, *cluster_offset); if (s->qcow_version < 3 && (type == QCOW2_CLUSTER_ZERO_PLAIN || type == QCOW2_CLUSTER_ZERO_ALLOC)) { qcow2_signal_corruption(bs, true, -1, -1, "Zero cluster entry found" @@ -606,6 +608,14 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, } switch (type) { case QCOW2_CLUSTER_COMPRESSED: + if (has_data_file(bs)) { + qcow2_signal_corruption(bs, true, -1, -1, "Compressed cluster " + "entry found in image with external data " + "file (L2 offset: %#" PRIx64 ", L2 index: " + "%#x)", l2_offset, l2_index); + ret = -EIO; + goto fail; + } /* Compressed clusters can only be processed one by one */ c = 1; *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK; @@ -613,14 +623,14 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, case QCOW2_CLUSTER_ZERO_PLAIN: case QCOW2_CLUSTER_UNALLOCATED: /* how many empty clusters ? */ - c = count_contiguous_clusters_unallocated(nb_clusters, + c = count_contiguous_clusters_unallocated(bs, nb_clusters, &l2_slice[l2_index], type); *cluster_offset = 0; break; case QCOW2_CLUSTER_ZERO_ALLOC: case QCOW2_CLUSTER_NORMAL: /* how many allocated clusters ? */ - c = count_contiguous_clusters(nb_clusters, s->cluster_size, + c = count_contiguous_clusters(bs, nb_clusters, s->cluster_size, &l2_slice[l2_index], QCOW_OFLAG_ZERO); *cluster_offset &= L2E_OFFSET_MASK; if (offset_into_cluster(s, *cluster_offset)) { @@ -632,6 +642,17 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, ret = -EIO; goto fail; } + if (has_data_file(bs) && *cluster_offset != offset - offset_in_cluster) + { + qcow2_signal_corruption(bs, true, -1, -1, + "External data file host cluster offset %#" + PRIx64 " does not match guest cluster " + "offset: %#" PRIx64 + ", L2 index: %#x)", *cluster_offset, + offset - offset_in_cluster, l2_index); + ret = -EIO; + goto fail; + } break; default: abort(); @@ -735,19 +756,16 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset, /* * alloc_compressed_cluster_offset * - * For a given offset of the disk image, return cluster offset in - * qcow2 file. - * - * If the offset is not found, allocate a new compressed cluster. - * - * Return the cluster offset if successful, - * Return 0, otherwise. + * For a given offset on the virtual disk, allocate a new compressed cluster + * and put the host offset of the cluster into *host_offset. If a cluster is + * already allocated at the offset, return an error. * + * Return 0 on success and -errno in error cases */ - -uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, - uint64_t offset, - int compressed_size) +int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, + uint64_t offset, + int compressed_size, + uint64_t *host_offset) { BDRVQcow2State *s = bs->opaque; int l2_index, ret; @@ -755,9 +773,13 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, int64_t cluster_offset; int nb_csectors; + if (has_data_file(bs)) { + return 0; + } + ret = get_cluster_table(bs, offset, &l2_slice, &l2_index); if (ret < 0) { - return 0; + return ret; } /* Compression can't overwrite anything. Fail if the cluster was already @@ -765,13 +787,13 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, cluster_offset = be64_to_cpu(l2_slice[l2_index]); if (cluster_offset & L2E_OFFSET_MASK) { qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice); - return 0; + return -EIO; } cluster_offset = qcow2_alloc_bytes(bs, compressed_size); if (cluster_offset < 0) { qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice); - return 0; + return cluster_offset; } nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - @@ -789,7 +811,8 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, l2_slice[l2_index] = cpu_to_be64(cluster_offset); qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice); - return cluster_offset; + *host_offset = cluster_offset & s->cluster_offset_mask; + return 0; } static int perform_cow(BlockDriverState *bs, QCowL2Meta *m) @@ -1013,14 +1036,14 @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m) * write, but require COW to be performed (this includes yet unallocated space, * which must copy from the backing file) */ -static int count_cow_clusters(BDRVQcow2State *s, int nb_clusters, +static int count_cow_clusters(BlockDriverState *bs, int nb_clusters, uint64_t *l2_slice, int l2_index) { int i; for (i = 0; i < nb_clusters; i++) { uint64_t l2_entry = be64_to_cpu(l2_slice[l2_index + i]); - QCow2ClusterType cluster_type = qcow2_get_cluster_type(l2_entry); + QCow2ClusterType cluster_type = qcow2_get_cluster_type(bs, l2_entry); switch(cluster_type) { case QCOW2_CLUSTER_NORMAL: @@ -1108,9 +1131,9 @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset, /* * Checks how many already allocated clusters that don't require a copy on - * write there are at the given guest_offset (up to *bytes). If - * *host_offset is not zero, only physically contiguous clusters beginning at - * this host offset are counted. + * write there are at the given guest_offset (up to *bytes). If *host_offset is + * not INV_OFFSET, only physically contiguous clusters beginning at this host + * offset are counted. * * Note that guest_offset may not be cluster aligned. In this case, the * returned *host_offset points to exact byte referenced by guest_offset and @@ -1142,8 +1165,8 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset, trace_qcow2_handle_copied(qemu_coroutine_self(), guest_offset, *host_offset, *bytes); - assert(*host_offset == 0 || offset_into_cluster(s, guest_offset) - == offset_into_cluster(s, *host_offset)); + assert(*host_offset == INV_OFFSET || offset_into_cluster(s, guest_offset) + == offset_into_cluster(s, *host_offset)); /* * Calculate the number of clusters to look for. We stop at L2 slice @@ -1165,7 +1188,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset, cluster_offset = be64_to_cpu(l2_slice[l2_index]); /* Check how many clusters are already allocated and don't need COW */ - if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL + if (qcow2_get_cluster_type(bs, cluster_offset) == QCOW2_CLUSTER_NORMAL && (cluster_offset & QCOW_OFLAG_COPIED)) { /* If a specific host_offset is required, check it */ @@ -1181,7 +1204,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset, goto out; } - if (*host_offset != 0 && !offset_matches) { + if (*host_offset != INV_OFFSET && !offset_matches) { *bytes = 0; ret = 0; goto out; @@ -1189,7 +1212,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset, /* We keep all QCOW_OFLAG_COPIED clusters */ keep_clusters = - count_contiguous_clusters(nb_clusters, s->cluster_size, + count_contiguous_clusters(bs, nb_clusters, s->cluster_size, &l2_slice[l2_index], QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO); assert(keep_clusters <= nb_clusters); @@ -1224,10 +1247,10 @@ out: * contain the number of clusters that have been allocated and are contiguous * in the image file. * - * If *host_offset is non-zero, it specifies the offset in the image file at - * which the new clusters must start. *nb_clusters can be 0 on return in this - * case if the cluster at host_offset is already in use. If *host_offset is - * zero, the clusters can be allocated anywhere in the image file. + * If *host_offset is not INV_OFFSET, it specifies the offset in the image file + * at which the new clusters must start. *nb_clusters can be 0 on return in + * this case if the cluster at host_offset is already in use. If *host_offset + * is INV_OFFSET, the clusters can be allocated anywhere in the image file. * * *host_offset is updated to contain the offset into the image file at which * the first allocated cluster starts. @@ -1244,9 +1267,16 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, trace_qcow2_do_alloc_clusters_offset(qemu_coroutine_self(), guest_offset, *host_offset, *nb_clusters); + if (has_data_file(bs)) { + assert(*host_offset == INV_OFFSET || + *host_offset == start_of_cluster(s, guest_offset)); + *host_offset = start_of_cluster(s, guest_offset); + return 0; + } + /* Allocate new clusters */ trace_qcow2_cluster_alloc_phys(qemu_coroutine_self()); - if (*host_offset == 0) { + if (*host_offset == INV_OFFSET) { int64_t cluster_offset = qcow2_alloc_clusters(bs, *nb_clusters * s->cluster_size); if (cluster_offset < 0) { @@ -1266,8 +1296,8 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, /* * Allocates new clusters for an area that either is yet unallocated or needs a - * copy on write. If *host_offset is non-zero, clusters are only allocated if - * the new allocation can match the specified host offset. + * copy on write. If *host_offset is not INV_OFFSET, clusters are only + * allocated if the new allocation can match the specified host offset. * * Note that guest_offset may not be cluster aligned. In this case, the * returned *host_offset points to exact byte referenced by guest_offset and @@ -1295,7 +1325,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, int ret; bool keep_old_clusters = false; - uint64_t alloc_cluster_offset = 0; + uint64_t alloc_cluster_offset = INV_OFFSET; trace_qcow2_handle_alloc(qemu_coroutine_self(), guest_offset, *host_offset, *bytes); @@ -1324,7 +1354,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, if (entry & QCOW_OFLAG_COMPRESSED) { nb_clusters = 1; } else { - nb_clusters = count_cow_clusters(s, nb_clusters, l2_slice, l2_index); + nb_clusters = count_cow_clusters(bs, nb_clusters, l2_slice, l2_index); } /* This function is only called when there were no non-COW clusters, so if @@ -1332,9 +1362,9 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, * wrong with our code. */ assert(nb_clusters > 0); - if (qcow2_get_cluster_type(entry) == QCOW2_CLUSTER_ZERO_ALLOC && + if (qcow2_get_cluster_type(bs, entry) == QCOW2_CLUSTER_ZERO_ALLOC && (entry & QCOW_OFLAG_COPIED) && - (!*host_offset || + (*host_offset == INV_OFFSET || start_of_cluster(s, *host_offset) == (entry & L2E_OFFSET_MASK))) { int preallocated_nb_clusters; @@ -1352,7 +1382,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, * would be fine, too, but count_cow_clusters() above has limited * nb_clusters already to a range of COW clusters */ preallocated_nb_clusters = - count_contiguous_clusters(nb_clusters, s->cluster_size, + count_contiguous_clusters(bs, nb_clusters, s->cluster_size, &l2_slice[l2_index], QCOW_OFLAG_COPIED); assert(preallocated_nb_clusters > 0); @@ -1366,9 +1396,10 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice); - if (!alloc_cluster_offset) { + if (alloc_cluster_offset == INV_OFFSET) { /* Allocate, if necessary at a given offset in the image file */ - alloc_cluster_offset = start_of_cluster(s, *host_offset); + alloc_cluster_offset = *host_offset == INV_OFFSET ? INV_OFFSET : + start_of_cluster(s, *host_offset); ret = do_alloc_cluster_offset(bs, guest_offset, &alloc_cluster_offset, &nb_clusters); if (ret < 0) { @@ -1381,16 +1412,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, return 0; } - /* !*host_offset would overwrite the image header and is reserved for - * "no host offset preferred". If 0 was a valid host offset, it'd - * trigger the following overlap check; do that now to avoid having an - * invalid value in *host_offset. */ - if (!alloc_cluster_offset) { - ret = qcow2_pre_write_overlap_check(bs, 0, alloc_cluster_offset, - nb_clusters * s->cluster_size); - assert(ret < 0); - goto fail; - } + assert(alloc_cluster_offset != INV_OFFSET); } /* @@ -1482,14 +1504,14 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, again: start = offset; remaining = *bytes; - cluster_offset = 0; - *host_offset = 0; + cluster_offset = INV_OFFSET; + *host_offset = INV_OFFSET; cur_bytes = 0; *m = NULL; while (true) { - if (!*host_offset) { + if (*host_offset == INV_OFFSET && cluster_offset != INV_OFFSET) { *host_offset = start_of_cluster(s, cluster_offset); } @@ -1497,7 +1519,10 @@ again: start += cur_bytes; remaining -= cur_bytes; - cluster_offset += cur_bytes; + + if (cluster_offset != INV_OFFSET) { + cluster_offset += cur_bytes; + } if (remaining == 0) { break; @@ -1569,7 +1594,7 @@ again: *bytes -= remaining; assert(*bytes > 0); - assert(*host_offset != 0); + assert(*host_offset != INV_OFFSET); return 0; } @@ -1616,7 +1641,7 @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset, * If full_discard is true, the sector should not read back as zeroes, * but rather fall through to the backing file. */ - switch (qcow2_get_cluster_type(old_l2_entry)) { + switch (qcow2_get_cluster_type(bs, old_l2_entry)) { case QCOW2_CLUSTER_UNALLOCATED: if (full_discard || !bs->backing) { continue; @@ -1729,7 +1754,7 @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset, * Minimize L2 changes if the cluster already reads back as * zeroes with correct allocation. */ - cluster_type = qcow2_get_cluster_type(old_offset); + cluster_type = qcow2_get_cluster_type(bs, old_offset); if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN || (cluster_type == QCOW2_CLUSTER_ZERO_ALLOC && !unmap)) { continue; @@ -1758,6 +1783,16 @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset, int64_t cleared; int ret; + /* If we have to stay in sync with an external data file, zero out + * s->data_file first. */ + if (data_file_is_raw(bs)) { + assert(has_data_file(bs)); + ret = bdrv_co_pwrite_zeroes(s->data_file, offset, bytes, flags); + if (ret < 0) { + return ret; + } + } + /* Caller must pass aligned values, except at image end */ assert(QEMU_IS_ALIGNED(offset, s->cluster_size)); assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) || @@ -1871,7 +1906,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, uint64_t l2_entry = be64_to_cpu(l2_slice[j]); int64_t offset = l2_entry & L2E_OFFSET_MASK; QCow2ClusterType cluster_type = - qcow2_get_cluster_type(l2_entry); + qcow2_get_cluster_type(bs, l2_entry); if (cluster_type != QCOW2_CLUSTER_ZERO_PLAIN && cluster_type != QCOW2_CLUSTER_ZERO_ALLOC) { @@ -1925,7 +1960,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, } ret = qcow2_pre_write_overlap_check(bs, 0, offset, - s->cluster_size); + s->cluster_size, true); if (ret < 0) { if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) { qcow2_free_clusters(bs, offset, s->cluster_size, @@ -1934,7 +1969,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, goto fail; } - ret = bdrv_pwrite_zeroes(bs->file, offset, s->cluster_size, 0); + ret = bdrv_pwrite_zeroes(s->data_file, offset, + s->cluster_size, 0); if (ret < 0) { if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) { qcow2_free_clusters(bs, offset, s->cluster_size, @@ -1961,7 +1997,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, if (l2_dirty) { ret = qcow2_pre_write_overlap_check( bs, QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2, - slice_offset, slice_size2); + slice_offset, slice_size2, false); if (ret < 0) { goto fail; } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 6f13d470d3..e0fe322500 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1156,8 +1156,20 @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry, int nb_clusters, enum qcow2_discard_type type) { BDRVQcow2State *s = bs->opaque; + QCow2ClusterType ctype = qcow2_get_cluster_type(bs, l2_entry); - switch (qcow2_get_cluster_type(l2_entry)) { + if (has_data_file(bs)) { + if (s->discard_passthrough[type] && + (ctype == QCOW2_CLUSTER_NORMAL || + ctype == QCOW2_CLUSTER_ZERO_ALLOC)) + { + bdrv_pdiscard(s->data_file, l2_entry & L2E_OFFSET_MASK, + nb_clusters << s->cluster_bits); + } + return; + } + + switch (ctype) { case QCOW2_CLUSTER_COMPRESSED: { int nb_csectors; @@ -1300,7 +1312,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, entry &= ~QCOW_OFLAG_COPIED; offset = entry & L2E_OFFSET_MASK; - switch (qcow2_get_cluster_type(entry)) { + switch (qcow2_get_cluster_type(bs, entry)) { case QCOW2_CLUSTER_COMPRESSED: nb_csectors = ((entry >> s->csize_shift) & s->csize_mask) + 1; @@ -1582,7 +1594,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, for(i = 0; i < s->l2_size; i++) { l2_entry = be64_to_cpu(l2_table[i]); - switch (qcow2_get_cluster_type(l2_entry)) { + switch (qcow2_get_cluster_type(bs, l2_entry)) { case QCOW2_CLUSTER_COMPRESSED: /* Compressed clusters don't have QCOW_OFLAG_COPIED */ if (l2_entry & QCOW_OFLAG_COPIED) { @@ -1593,6 +1605,13 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, res->corruptions++; } + if (has_data_file(bs)) { + fprintf(stderr, "ERROR compressed cluster %d with data file, " + "entry=0x%" PRIx64 "\n", i, l2_entry); + res->corruptions++; + break; + } + /* Mark cluster as used */ nb_csectors = ((l2_entry >> s->csize_shift) & s->csize_mask) + 1; @@ -1633,7 +1652,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, /* Correct offsets are cluster aligned */ if (offset_into_cluster(s, offset)) { - if (qcow2_get_cluster_type(l2_entry) == + if (qcow2_get_cluster_type(bs, l2_entry) == QCOW2_CLUSTER_ZERO_ALLOC) { fprintf(stderr, "%s offset=%" PRIx64 ": Preallocated zero " @@ -1649,7 +1668,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, l2_table[i] = cpu_to_be64(l2_entry); ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2 | QCOW2_OL_INACTIVE_L2, - l2e_offset, sizeof(uint64_t)); + l2e_offset, sizeof(uint64_t), false); if (ret < 0) { fprintf(stderr, "ERROR: Overlap check failed\n"); res->check_errors++; @@ -1683,11 +1702,13 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, } /* Mark cluster as used */ - ret = qcow2_inc_refcounts_imrt(bs, res, - refcount_table, refcount_table_size, - offset, s->cluster_size); - if (ret < 0) { - goto fail; + if (!has_data_file(bs)) { + ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, + refcount_table_size, + offset, s->cluster_size); + if (ret < 0) { + goto fail; + } } break; } @@ -1868,16 +1889,20 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, for (j = 0; j < s->l2_size; j++) { uint64_t l2_entry = be64_to_cpu(l2_table[j]); uint64_t data_offset = l2_entry & L2E_OFFSET_MASK; - QCow2ClusterType cluster_type = qcow2_get_cluster_type(l2_entry); + QCow2ClusterType cluster_type = qcow2_get_cluster_type(bs, l2_entry); if (cluster_type == QCOW2_CLUSTER_NORMAL || cluster_type == QCOW2_CLUSTER_ZERO_ALLOC) { - ret = qcow2_get_refcount(bs, - data_offset >> s->cluster_bits, - &refcount); - if (ret < 0) { - /* don't print message nor increment check_errors */ - continue; + if (has_data_file(bs)) { + refcount = 1; + } else { + ret = qcow2_get_refcount(bs, + data_offset >> s->cluster_bits, + &refcount); + if (ret < 0) { + /* don't print message nor increment check_errors */ + continue; + } } if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) { fprintf(stderr, "%s OFLAG_COPIED data cluster: " @@ -1898,7 +1923,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, if (l2_dirty) { ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2, - l2_offset, s->cluster_size); + l2_offset, s->cluster_size, + false); if (ret < 0) { fprintf(stderr, "ERROR: Could not write L2 table; metadata " "overlap check failed: %s\n", strerror(-ret)); @@ -2070,6 +2096,12 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res, } /* snapshots */ + if (has_data_file(bs) && s->nb_snapshots) { + fprintf(stderr, "ERROR %d snapshots in image with data file\n", + s->nb_snapshots); + res->corruptions++; + } + for (i = 0; i < s->nb_snapshots; i++) { sn = s->snapshots + i; if (offset_into_cluster(s, sn->l1_table_offset)) { @@ -2366,7 +2398,7 @@ write_refblocks: } ret = qcow2_pre_write_overlap_check(bs, 0, refblock_offset, - s->cluster_size); + s->cluster_size, false); if (ret < 0) { fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret)); goto fail; @@ -2417,7 +2449,8 @@ write_refblocks: } ret = qcow2_pre_write_overlap_check(bs, 0, reftable_offset, - reftable_size * sizeof(uint64_t)); + reftable_size * sizeof(uint64_t), + false); if (ret < 0) { fprintf(stderr, "ERROR writing reftable: %s\n", strerror(-ret)); goto fail; @@ -2751,10 +2784,15 @@ QEMU_BUILD_BUG_ON(QCOW2_OL_MAX_BITNR != ARRAY_SIZE(metadata_ol_names)); * overlaps; or a negative value (-errno) on error. */ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset, - int64_t size) + int64_t size, bool data_file) { - int ret = qcow2_check_metadata_overlap(bs, ign, offset, size); + int ret; + + if (data_file && has_data_file(bs)) { + return 0; + } + ret = qcow2_check_metadata_overlap(bs, ign, offset, size); if (ret < 0) { return ret; } else if (ret > 0) { @@ -2855,7 +2893,8 @@ static int flush_refblock(BlockDriverState *bs, uint64_t **reftable, if (reftable_index < *reftable_size && (*reftable)[reftable_index]) { offset = (*reftable)[reftable_index]; - ret = qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_size); + ret = qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_size, + false); if (ret < 0) { error_setg_errno(errp, -ret, "Overlap check failed"); return ret; @@ -3121,7 +3160,8 @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, /* Write the new reftable */ ret = qcow2_pre_write_overlap_check(bs, 0, new_reftable_offset, - new_reftable_size * sizeof(uint64_t)); + new_reftable_size * sizeof(uint64_t), + false); if (ret < 0) { error_setg_errno(errp, -ret, "Overlap check failed"); goto done; diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 20e8472191..a6ffae89a6 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -184,7 +184,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs) /* The snapshot list position has not yet been updated, so these clusters * must indeed be completely free */ - ret = qcow2_pre_write_overlap_check(bs, 0, offset, snapshots_size); + ret = qcow2_pre_write_overlap_check(bs, 0, offset, snapshots_size, false); if (ret < 0) { goto fail; } @@ -353,6 +353,10 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) return -EFBIG; } + if (has_data_file(bs)) { + return -ENOTSUP; + } + memset(sn, 0, sizeof(*sn)); /* Generate an ID */ @@ -389,7 +393,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) } ret = qcow2_pre_write_overlap_check(bs, 0, sn->l1_table_offset, - s->l1_size * sizeof(uint64_t)); + s->l1_size * sizeof(uint64_t), false); if (ret < 0) { goto fail; } @@ -466,6 +470,10 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) int ret; uint64_t *sn_l1_table = NULL; + if (has_data_file(bs)) { + return -ENOTSUP; + } + /* Search the snapshot */ snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id); if (snapshot_index < 0) { @@ -528,7 +536,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) } ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1, - s->l1_table_offset, cur_l1_bytes); + s->l1_table_offset, cur_l1_bytes, + false); if (ret < 0) { goto fail; } @@ -598,6 +607,10 @@ int qcow2_snapshot_delete(BlockDriverState *bs, QCowSnapshot sn; int snapshot_index, ret; + if (has_data_file(bs)) { + return -ENOTSUP; + } + /* Search the snapshot */ snapshot_index = find_snapshot_by_id_and_name(bs, snapshot_id, name); if (snapshot_index < 0) { @@ -669,6 +682,9 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) QCowSnapshot *sn; int i; + if (has_data_file(bs)) { + return -ENOTSUP; + } if (!s->nb_snapshots) { *psn_tab = NULL; return s->nb_snapshots; diff --git a/block/qcow2.c b/block/qcow2.c index 7fb2730f09..c4dd876fb4 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -73,6 +73,7 @@ typedef struct { #define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857 #define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77 #define QCOW2_EXT_MAGIC_BITMAPS 0x23852875 +#define QCOW2_EXT_MAGIC_DATA_FILE 0x44415441 static int coroutine_fn qcow2_co_preadv_compressed(BlockDriverState *bs, @@ -139,7 +140,7 @@ static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, /* Zero fill remaining space in cluster so it has predictable * content in case of future spec changes */ clusterlen = size_to_clusters(s, headerlen) * s->cluster_size; - assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen) == 0); + assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen, false) == 0); ret = bdrv_pwrite_zeroes(bs->file, ret + headerlen, clusterlen - headerlen, 0); @@ -397,6 +398,21 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, #endif break; + case QCOW2_EXT_MAGIC_DATA_FILE: + { + s->image_data_file = g_malloc0(ext.len + 1); + ret = bdrv_pread(bs->file, offset, s->image_data_file, ext.len); + if (ret < 0) { + error_setg_errno(errp, -ret, + "ERROR: Could not read data file name"); + return ret; + } +#ifdef DEBUG_EXT + printf("Qcow2: Got external data file %s\n", s->image_data_file); +#endif + break; + } + default: /* unknown magic - save it in case we need to rewrite the header */ /* If you add a new feature, make sure to also update the fast @@ -788,6 +804,7 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, BDRVQcow2State *s = bs->opaque; uint64_t combined_cache_size, l2_cache_max_setting; bool l2_cache_size_set, refcount_cache_size_set, combined_cache_size_set; + bool l2_cache_entry_size_set; int min_refcount_cache = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size; uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE; uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8); @@ -795,6 +812,7 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE); l2_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_SIZE); refcount_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_REFCOUNT_CACHE_SIZE); + l2_cache_entry_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_ENTRY_SIZE); combined_cache_size = qemu_opt_get_size(opts, QCOW2_OPT_CACHE_SIZE, 0); l2_cache_max_setting = qemu_opt_get_size(opts, QCOW2_OPT_L2_CACHE_SIZE, @@ -841,6 +859,16 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, } } } + + /* + * If the L2 cache is not enough to cover the whole disk then + * default to 4KB entries. Smaller entries reduce the cost of + * loads and evictions and increase I/O performance. + */ + if (*l2_cache_size < max_l2_cache && !l2_cache_entry_size_set) { + *l2_cache_entry_size = MIN(s->cluster_size, 4096); + } + /* l2_cache_size and refcount_cache_size are ensured to have at least * their minimum values in qcow2_update_options_prepare() */ @@ -1440,6 +1468,47 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, goto fail; } + /* Open external data file */ + s->data_file = bdrv_open_child(NULL, options, "data-file", bs, &child_file, + true, &local_err); + if (local_err) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto fail; + } + + if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { + if (!s->data_file && s->image_data_file) { + s->data_file = bdrv_open_child(s->image_data_file, options, + "data-file", bs, &child_file, + false, errp); + if (!s->data_file) { + ret = -EINVAL; + goto fail; + } + } + if (!s->data_file) { + error_setg(errp, "'data-file' is required for this image"); + ret = -EINVAL; + goto fail; + } + } else { + if (s->data_file) { + error_setg(errp, "'data-file' can only be set for images with an " + "external data file"); + ret = -EINVAL; + goto fail; + } + + s->data_file = bs->file; + + if (data_file_is_raw(bs)) { + error_setg(errp, "data-file-raw requires a data file"); + ret = -EINVAL; + goto fail; + } + } + /* qcow2_read_extension may have set up the crypto context * if the crypt method needs a header region, some methods * don't need header extensions, so must check here @@ -1611,6 +1680,10 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, return ret; fail: + g_free(s->image_data_file); + if (has_data_file(bs)) { + bdrv_unref_child(bs, s->data_file); + } g_free(s->unknown_header_fields); cleanup_unknown_header_ext(bs); qcow2_free_snapshots(bs); @@ -1813,11 +1886,11 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs, *pnum = bytes; - if (cluster_offset != 0 && ret != QCOW2_CLUSTER_COMPRESSED && + if ((ret == QCOW2_CLUSTER_NORMAL || ret == QCOW2_CLUSTER_ZERO_ALLOC) && !s->crypto) { index_in_cluster = offset & (s->cluster_size - 1); *map = cluster_offset | index_in_cluster; - *file = bs->file->bs; + *file = s->data_file->bs; status |= BDRV_BLOCK_OFFSET_VALID; } if (ret == QCOW2_CLUSTER_ZERO_PLAIN || ret == QCOW2_CLUSTER_ZERO_ALLOC) { @@ -1949,7 +2022,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, */ if (!cluster_data) { cluster_data = - qemu_try_blockalign(bs->file->bs, + qemu_try_blockalign(s->data_file->bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); if (cluster_data == NULL) { @@ -1965,7 +2038,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO); qemu_co_mutex_unlock(&s->lock); - ret = bdrv_co_preadv(bs->file, + ret = bdrv_co_preadv(s->data_file, cluster_offset + offset_in_cluster, cur_bytes, &hd_qiov, 0); qemu_co_mutex_lock(&s->lock); @@ -2124,7 +2197,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, } ret = qcow2_pre_write_overlap_check(bs, 0, - cluster_offset + offset_in_cluster, cur_bytes); + cluster_offset + offset_in_cluster, cur_bytes, true); if (ret < 0) { goto fail; } @@ -2138,7 +2211,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); trace_qcow2_writev_data(qemu_coroutine_self(), cluster_offset + offset_in_cluster); - ret = bdrv_co_pwritev(bs->file, + ret = bdrv_co_pwritev(s->data_file, cluster_offset + offset_in_cluster, cur_bytes, &hd_qiov, 0); qemu_co_mutex_lock(&s->lock); @@ -2227,9 +2300,14 @@ static void qcow2_close(BlockDriverState *bs) g_free(s->unknown_header_fields); cleanup_unknown_header_ext(bs); + g_free(s->image_data_file); g_free(s->image_backing_file); g_free(s->image_backing_format); + if (has_data_file(bs)) { + bdrv_unref_child(bs, s->data_file); + } + qcow2_refcount_close(bs); qcow2_free_snapshots(bs); } @@ -2399,6 +2477,19 @@ int qcow2_update_header(BlockDriverState *bs) buflen -= ret; } + /* External data file header extension */ + if (has_data_file(bs) && s->image_data_file) { + ret = header_ext_add(buf, QCOW2_EXT_MAGIC_DATA_FILE, + s->image_data_file, strlen(s->image_data_file), + buflen); + if (ret < 0) { + goto fail; + } + + buf += ret; + buflen -= ret; + } + /* Full disk encryption header pointer extension */ if (s->crypto_header.offset != 0) { s->crypto_header.offset = cpu_to_be64(s->crypto_header.offset); @@ -2429,6 +2520,11 @@ int qcow2_update_header(BlockDriverState *bs) .name = "corrupt bit", }, { + .type = QCOW2_FEAT_TYPE_INCOMPATIBLE, + .bit = QCOW2_INCOMPAT_DATA_FILE_BITNR, + .name = "external data file", + }, + { .type = QCOW2_FEAT_TYPE_COMPATIBLE, .bit = QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR, .name = "lazy refcounts", @@ -2516,6 +2612,12 @@ static int qcow2_change_backing_file(BlockDriverState *bs, { BDRVQcow2State *s = bs->opaque; + /* Adding a backing file means that the external data file alone won't be + * enough to make sense of the content */ + if (backing_file && data_file_is_raw(bs)) { + return -EINVAL; + } + if (backing_file && strlen(backing_file) > 1023) { return -EINVAL; } @@ -2829,6 +2931,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) */ BlockBackend *blk = NULL; BlockDriverState *bs = NULL; + BlockDriverState *data_bs = NULL; QCowHeader *header; size_t cluster_size; int version; @@ -2925,6 +3028,32 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } refcount_order = ctz32(qcow2_opts->refcount_bits); + if (qcow2_opts->data_file_raw && !qcow2_opts->data_file) { + error_setg(errp, "data-file-raw requires data-file"); + ret = -EINVAL; + goto out; + } + if (qcow2_opts->data_file_raw && qcow2_opts->has_backing_file) { + error_setg(errp, "Backing file and data-file-raw cannot be used at " + "the same time"); + ret = -EINVAL; + goto out; + } + + if (qcow2_opts->data_file) { + if (version < 3) { + error_setg(errp, "External data files are only supported with " + "compatibility level 1.1 and above (use version=v3 or " + "greater)"); + ret = -EINVAL; + goto out; + } + data_bs = bdrv_open_blockdev_ref(qcow2_opts->data_file, errp); + if (bs == NULL) { + ret = -EIO; + goto out; + } + } /* Create BlockBackend to write to the image */ blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); @@ -2940,19 +3069,6 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) goto out; } - if (qcow2_opts->preallocation == PREALLOC_MODE_FULL || - qcow2_opts->preallocation == PREALLOC_MODE_FALLOC) - { - int64_t prealloc_size = - qcow2_calc_prealloc_size(qcow2_opts->size, cluster_size, - refcount_order); - - ret = blk_truncate(blk, prealloc_size, qcow2_opts->preallocation, errp); - if (ret < 0) { - goto out; - } - } - /* Write the header */ QEMU_BUILD_BUG_ON((1 << MIN_CLUSTER_BITS) < sizeof(*header)); header = g_malloc0(cluster_size); @@ -2976,6 +3092,14 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) header->compatible_features |= cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS); } + if (data_bs) { + header->incompatible_features |= + cpu_to_be64(QCOW2_INCOMPAT_DATA_FILE); + } + if (qcow2_opts->data_file_raw) { + header->autoclear_features |= + cpu_to_be64(QCOW2_AUTOCLEAR_DATA_FILE_RAW); + } ret = blk_pwrite(blk, 0, header, cluster_size, 0); g_free(header); @@ -3006,6 +3130,9 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) options = qdict_new(); qdict_put_str(options, "driver", "qcow2"); qdict_put_str(options, "file", bs->node_name); + if (data_bs) { + qdict_put_str(options, "data-file", data_bs->node_name); + } blk = blk_new_open(NULL, NULL, options, BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH, &local_err); @@ -3026,6 +3153,12 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) abort(); } + /* Set the external data file if necessary */ + if (data_bs) { + BDRVQcow2State *s = blk_bs(blk)->opaque; + s->image_data_file = g_strdup(data_bs->filename); + } + /* Create a full header (including things like feature table) */ ret = qcow2_update_header(blk_bs(blk)); if (ret < 0) { @@ -3034,7 +3167,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } /* Okay, now that we have a valid image, let's give it the right size */ - ret = blk_truncate(blk, qcow2_opts->size, PREALLOC_MODE_OFF, errp); + ret = blk_truncate(blk, qcow2_opts->size, qcow2_opts->preallocation, errp); if (ret < 0) { error_prepend(errp, "Could not resize image: "); goto out; @@ -3066,19 +3199,6 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } } - /* And if we're supposed to preallocate metadata, do that now */ - if (qcow2_opts->preallocation != PREALLOC_MODE_OFF) { - BDRVQcow2State *s = blk_bs(blk)->opaque; - qemu_co_mutex_lock(&s->lock); - ret = preallocate_co(blk_bs(blk), 0, qcow2_opts->size); - qemu_co_mutex_unlock(&s->lock); - - if (ret < 0) { - error_setg_errno(errp, -ret, "Could not preallocate metadata"); - goto out; - } - } - blk_unref(blk); blk = NULL; @@ -3091,6 +3211,9 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) options = qdict_new(); qdict_put_str(options, "driver", "qcow2"); qdict_put_str(options, "file", bs->node_name); + if (data_bs) { + qdict_put_str(options, "data-file", data_bs->node_name); + } blk = blk_new_open(NULL, NULL, options, BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO, &local_err); @@ -3104,6 +3227,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) out: blk_unref(blk); bdrv_unref(bs); + bdrv_unref(data_bs); return ret; } @@ -3114,6 +3238,7 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt QDict *qdict; Visitor *v; BlockDriverState *bs = NULL; + BlockDriverState *data_bs = NULL; Error *local_err = NULL; const char *val; int ret; @@ -3156,6 +3281,7 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt { BLOCK_OPT_REFCOUNT_BITS, "refcount-bits" }, { BLOCK_OPT_ENCRYPT, BLOCK_OPT_ENCRYPT_FORMAT }, { BLOCK_OPT_COMPAT_LEVEL, "version" }, + { BLOCK_OPT_DATA_FILE_RAW, "data-file-raw" }, { NULL, NULL }, }; @@ -3177,6 +3303,26 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt goto finish; } + /* Create and open an external data file (protocol layer) */ + val = qdict_get_try_str(qdict, BLOCK_OPT_DATA_FILE); + if (val) { + ret = bdrv_create_file(val, opts, errp); + if (ret < 0) { + goto finish; + } + + data_bs = bdrv_open(val, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, + errp); + if (data_bs == NULL) { + ret = -EIO; + goto finish; + } + + qdict_del(qdict, BLOCK_OPT_DATA_FILE); + qdict_put_str(qdict, "data-file", data_bs->node_name); + } + /* Set 'driver' and 'node' options */ qdict_put_str(qdict, "driver", "qcow2"); qdict_put_str(qdict, "file", bs->node_name); @@ -3211,6 +3357,7 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt finish: qobject_unref(qdict); bdrv_unref(bs); + bdrv_unref(data_bs); qapi_free_BlockdevCreateOptions(create_options); return ret; } @@ -3361,7 +3508,7 @@ qcow2_co_copy_range_from(BlockDriverState *bs, goto out; case QCOW2_CLUSTER_NORMAL: - child = bs->file; + child = s->data_file; copy_offset += offset_into_cluster(s, src_offset); if ((copy_offset & 511) != 0) { ret = -EIO; @@ -3431,14 +3578,14 @@ qcow2_co_copy_range_to(BlockDriverState *bs, assert((cluster_offset & 511) == 0); ret = qcow2_pre_write_overlap_check(bs, 0, - cluster_offset + offset_in_cluster, cur_bytes); + cluster_offset + offset_in_cluster, cur_bytes, true); if (ret < 0) { goto fail; } qemu_co_mutex_unlock(&s->lock); ret = bdrv_co_copy_range_to(src, src_offset, - bs->file, + s->data_file, cluster_offset + offset_in_cluster, cur_bytes, read_flags, write_flags); qemu_co_mutex_lock(&s->lock); @@ -3593,6 +3740,17 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, int64_t old_file_size, new_file_size; uint64_t nb_new_data_clusters, nb_new_l2_tables; + /* With a data file, preallocation means just allocating the metadata + * and forwarding the truncate request to the data file */ + if (has_data_file(bs)) { + ret = preallocate_co(bs, old_length, offset); + if (ret < 0) { + error_setg_errno(errp, -ret, "Preallocation failed"); + goto fail; + } + break; + } + old_file_size = bdrv_getlength(bs->file->bs); if (old_file_size < 0) { error_setg_errno(errp, -old_file_size, @@ -3701,6 +3859,16 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, bs->total_sectors = offset / BDRV_SECTOR_SIZE; + if (has_data_file(bs)) { + if (prealloc == PREALLOC_MODE_METADATA) { + prealloc = PREALLOC_MODE_OFF; + } + ret = bdrv_co_truncate(s->data_file, offset, prealloc, errp); + if (ret < 0) { + goto fail; + } + } + /* write updated header.size */ offset = cpu_to_be64(offset); ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size), @@ -3901,17 +4069,20 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, int ret; size_t out_len; uint8_t *buf, *out_buf; - int64_t cluster_offset; + uint64_t cluster_offset; + + if (has_data_file(bs)) { + return -ENOTSUP; + } if (bytes == 0) { /* align end of file to a sector boundary to ease reading with sector based I/Os */ - cluster_offset = bdrv_getlength(bs->file->bs); - if (cluster_offset < 0) { - return cluster_offset; + int64_t len = bdrv_getlength(bs->file->bs); + if (len < 0) { + return len; } - return bdrv_co_truncate(bs->file, cluster_offset, PREALLOC_MODE_OFF, - NULL); + return bdrv_co_truncate(bs->file, len, PREALLOC_MODE_OFF, NULL); } if (offset_into_cluster(s, offset)) { @@ -3948,16 +4119,14 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, } qemu_co_mutex_lock(&s->lock); - cluster_offset = - qcow2_alloc_compressed_cluster_offset(bs, offset, out_len); - if (!cluster_offset) { + ret = qcow2_alloc_compressed_cluster_offset(bs, offset, out_len, + &cluster_offset); + if (ret < 0) { qemu_co_mutex_unlock(&s->lock); - ret = -EIO; goto fail; } - cluster_offset &= s->cluster_offset_mask; - ret = qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len); + ret = qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len, true); qemu_co_mutex_unlock(&s->lock); if (ret < 0) { goto fail; @@ -3965,8 +4134,8 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, qemu_iovec_init_buf(&hd_qiov, out_buf, out_len); - BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED); - ret = bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0); + BLKDBG_EVENT(s->data_file, BLKDBG_WRITE_COMPRESSED); + ret = bdrv_co_pwritev(s->data_file, cluster_offset, out_len, &hd_qiov, 0); if (ret < 0) { goto fail; } @@ -4479,6 +4648,10 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs, .refcount_bits = s->refcount_bits, .has_bitmaps = !!bitmaps, .bitmaps = bitmaps, + .has_data_file = !!s->image_data_file, + .data_file = g_strdup(s->image_data_file), + .has_data_file_raw = has_data_file(bs), + .data_file_raw = data_file_is_raw(bs), }; } else { /* if this assertion fails, this probably means a new version was @@ -4555,6 +4728,11 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version, return -ENOTSUP; } + if (has_data_file(bs)) { + error_setg(errp, "Cannot downgrade an image with a data file"); + return -ENOTSUP; + } + /* clear incompatible features */ if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) { ret = qcow2_mark_clean(bs); @@ -4676,8 +4854,9 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, BDRVQcow2State *s = bs->opaque; int old_version = s->qcow_version, new_version = old_version; uint64_t new_size = 0; - const char *backing_file = NULL, *backing_format = NULL; + const char *backing_file = NULL, *backing_format = NULL, *data_file = NULL; bool lazy_refcounts = s->use_lazy_refcounts; + bool data_file_raw = data_file_is_raw(bs); const char *compat = NULL; uint64_t cluster_size = s->cluster_size; bool encrypt; @@ -4758,6 +4937,21 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, "may not exceed 64 bits"); return -EINVAL; } + } else if (!strcmp(desc->name, BLOCK_OPT_DATA_FILE)) { + data_file = qemu_opt_get(opts, BLOCK_OPT_DATA_FILE); + if (data_file && !has_data_file(bs)) { + error_setg(errp, "data-file can only be set for images that " + "use an external data file"); + return -EINVAL; + } + } else if (!strcmp(desc->name, BLOCK_OPT_DATA_FILE_RAW)) { + data_file_raw = qemu_opt_get_bool(opts, BLOCK_OPT_DATA_FILE_RAW, + data_file_raw); + if (data_file_raw && !data_file_is_raw(bs)) { + error_setg(errp, "data-file-raw cannot be set on existing " + "images"); + return -EINVAL; + } } else { /* if this point is reached, this probably means a new option was * added without having it covered here */ @@ -4804,6 +4998,24 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, } } + /* data-file-raw blocks backing files, so clear it first if requested */ + if (data_file_raw) { + s->autoclear_features |= QCOW2_AUTOCLEAR_DATA_FILE_RAW; + } else { + s->autoclear_features &= ~QCOW2_AUTOCLEAR_DATA_FILE_RAW; + } + + if (data_file) { + g_free(s->image_data_file); + s->image_data_file = *data_file ? g_strdup(data_file) : NULL; + } + + ret = qcow2_update_header(bs); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to update the image header"); + return ret; + } + if (backing_file || backing_format) { ret = qcow2_change_backing_file(bs, backing_file ?: s->image_backing_file, @@ -4952,6 +5164,16 @@ static QemuOptsList qcow2_create_opts = { .help = "Image format of the base image" }, { + .name = BLOCK_OPT_DATA_FILE, + .type = QEMU_OPT_STRING, + .help = "File name of an external data file" + }, + { + .name = BLOCK_OPT_DATA_FILE_RAW, + .type = QEMU_OPT_BOOL, + .help = "The external data file must stay valid as a raw image" + }, + { .name = BLOCK_OPT_ENCRYPT, .type = QEMU_OPT_BOOL, .help = "Encrypt the image with format 'aes'. (Deprecated " diff --git a/block/qcow2.h b/block/qcow2.h index 9dd02df831..de2a3bdfc5 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -91,6 +91,7 @@ #define DEFAULT_CLUSTER_SIZE 65536 +#define QCOW2_OPT_DATA_FILE "data-file" #define QCOW2_OPT_LAZY_REFCOUNTS "lazy-refcounts" #define QCOW2_OPT_DISCARD_REQUEST "pass-discard-request" #define QCOW2_OPT_DISCARD_SNAPSHOT "pass-discard-snapshot" @@ -197,13 +198,16 @@ enum { /* Incompatible feature bits */ enum { - QCOW2_INCOMPAT_DIRTY_BITNR = 0, - QCOW2_INCOMPAT_CORRUPT_BITNR = 1, - QCOW2_INCOMPAT_DIRTY = 1 << QCOW2_INCOMPAT_DIRTY_BITNR, - QCOW2_INCOMPAT_CORRUPT = 1 << QCOW2_INCOMPAT_CORRUPT_BITNR, - - QCOW2_INCOMPAT_MASK = QCOW2_INCOMPAT_DIRTY - | QCOW2_INCOMPAT_CORRUPT, + QCOW2_INCOMPAT_DIRTY_BITNR = 0, + QCOW2_INCOMPAT_CORRUPT_BITNR = 1, + QCOW2_INCOMPAT_DATA_FILE_BITNR = 2, + QCOW2_INCOMPAT_DIRTY = 1 << QCOW2_INCOMPAT_DIRTY_BITNR, + QCOW2_INCOMPAT_CORRUPT = 1 << QCOW2_INCOMPAT_CORRUPT_BITNR, + QCOW2_INCOMPAT_DATA_FILE = 1 << QCOW2_INCOMPAT_DATA_FILE_BITNR, + + QCOW2_INCOMPAT_MASK = QCOW2_INCOMPAT_DIRTY + | QCOW2_INCOMPAT_CORRUPT + | QCOW2_INCOMPAT_DATA_FILE, }; /* Compatible feature bits */ @@ -216,10 +220,13 @@ enum { /* Autoclear feature bits */ enum { - QCOW2_AUTOCLEAR_BITMAPS_BITNR = 0, - QCOW2_AUTOCLEAR_BITMAPS = 1 << QCOW2_AUTOCLEAR_BITMAPS_BITNR, + QCOW2_AUTOCLEAR_BITMAPS_BITNR = 0, + QCOW2_AUTOCLEAR_DATA_FILE_RAW_BITNR = 1, + QCOW2_AUTOCLEAR_BITMAPS = 1 << QCOW2_AUTOCLEAR_BITMAPS_BITNR, + QCOW2_AUTOCLEAR_DATA_FILE_RAW = 1 << QCOW2_AUTOCLEAR_DATA_FILE_RAW_BITNR, - QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS, + QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS + | QCOW2_AUTOCLEAR_DATA_FILE_RAW, }; enum qcow2_discard_type { @@ -337,9 +344,12 @@ typedef struct BDRVQcow2State { * override) */ char *image_backing_file; char *image_backing_format; + char *image_data_file; CoQueue compress_wait_queue; int nb_compress_threads; + + BdrvChild *data_file; } BDRVQcow2State; typedef struct Qcow2COWRegion { @@ -457,6 +467,20 @@ typedef enum QCow2MetadataOverlap { #define REFT_OFFSET_MASK 0xfffffffffffffe00ULL +#define INV_OFFSET (-1ULL) + +static inline bool has_data_file(BlockDriverState *bs) +{ + BDRVQcow2State *s = bs->opaque; + return (s->data_file != bs->file); +} + +static inline bool data_file_is_raw(BlockDriverState *bs) +{ + BDRVQcow2State *s = bs->opaque; + return !!(s->autoclear_features & QCOW2_AUTOCLEAR_DATA_FILE_RAW); +} + static inline int64_t start_of_cluster(BDRVQcow2State *s, int64_t offset) { return offset & ~(s->cluster_size - 1); @@ -498,7 +522,8 @@ static inline int64_t qcow2_vm_state_offset(BDRVQcow2State *s) return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits); } -static inline QCow2ClusterType qcow2_get_cluster_type(uint64_t l2_entry) +static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs, + uint64_t l2_entry) { if (l2_entry & QCOW_OFLAG_COMPRESSED) { return QCOW2_CLUSTER_COMPRESSED; @@ -508,7 +533,15 @@ static inline QCow2ClusterType qcow2_get_cluster_type(uint64_t l2_entry) } return QCOW2_CLUSTER_ZERO_PLAIN; } else if (!(l2_entry & L2E_OFFSET_MASK)) { - return QCOW2_CLUSTER_UNALLOCATED; + /* Offset 0 generally means unallocated, but it is ambiguous with + * external data files because 0 is a valid offset there. However, all + * clusters in external data files always have refcount 1, so we can + * rely on QCOW_OFLAG_COPIED to disambiguate. */ + if (has_data_file(bs) && (l2_entry & QCOW_OFLAG_COPIED)) { + return QCOW2_CLUSTER_NORMAL; + } else { + return QCOW2_CLUSTER_UNALLOCATED; + } } else { return QCOW2_CLUSTER_NORMAL; } @@ -599,7 +632,7 @@ void qcow2_process_discards(BlockDriverState *bs, int ret); int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset, int64_t size); int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset, - int64_t size); + int64_t size, bool data_file); int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res, void **refcount_table, int64_t *refcount_table_size, @@ -624,9 +657,10 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, unsigned int *bytes, uint64_t *host_offset, QCowL2Meta **m); -uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, - uint64_t offset, - int compressed_size); +int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, + uint64_t offset, + int compressed_size, + uint64_t *host_offset); int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); diff --git a/blockdev.c b/blockdev.c index 7e6bf9955c..871966ca13 100644 --- a/blockdev.c +++ b/blockdev.c @@ -531,7 +531,9 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, if ((buf = qemu_opt_get(opts, "format")) != NULL) { if (is_help_option(buf)) { error_printf("Supported formats:"); - bdrv_iterate_format(bdrv_format_print, NULL); + bdrv_iterate_format(bdrv_format_print, NULL, false); + error_printf("\nSupported formats (read-only):"); + bdrv_iterate_format(bdrv_format_print, NULL, true); error_printf("\n"); goto early_err; } diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index fb5cb47245..8c3098d8d9 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -97,7 +97,19 @@ in the description of a field. be written to (unless for regaining consistency). - Bits 2-63: Reserved (set to 0) + Bit 2: External data file bit. If this bit is set, an + external data file is used. Guest clusters are + then stored in the external data file. For such + images, clusters in the external data file are + not refcounted. The offset field in the + Standard Cluster Descriptor must match the + guest offset and neither compressed clusters + nor internal snapshots are supported. + + An External Data File Name header extension may + be present if this bit is set. + + Bits 3-63: Reserved (set to 0) 80 - 87: compatible_features Bitmask of compatible features. An implementation can @@ -126,7 +138,21 @@ in the description of a field. bit is unset, the bitmaps extension data must be considered inconsistent. - Bits 1-63: Reserved (set to 0) + Bit 1: If this bit is set, the external data file can + be read as a consistent standalone raw image + without looking at the qcow2 metadata. + + Setting this bit has a performance impact for + some operations on the image (e.g. writing + zeros requires writing to the data file instead + of only setting the zero flag in the L2 table + entry) and conflicts with backing files. + + This bit may only be set if the External Data + File bit (incompatible feature bit 1) is also + set. + + Bits 2-63: Reserved (set to 0) 96 - 99: refcount_order Describes the width of a reference count block entry (width @@ -144,10 +170,11 @@ be stored. Each extension has a structure like the following: Byte 0 - 3: Header extension type: 0x00000000 - End of the header extension area - 0xE2792ACA - Backing file format name + 0xE2792ACA - Backing file format name string 0x6803f857 - Feature name table 0x23852875 - Bitmaps extension 0x0537be77 - Full disk encryption header pointer + 0x44415441 - External data file name string other - Unknown header extension, can be safely ignored @@ -169,6 +196,16 @@ data of compatible features that it doesn't support. Compatible features that need space for additional data can use a header extension. +== String header extensions == + +Some header extensions (such as the backing file format name and the external +data file name) are just a single string. In this case, the header extension +length is the string length and the string is not '\0' terminated. (The header +extension padding can make it look like a string is '\0' terminated, but +neither is padding always necessary nor is there a guarantee that zero bytes +are used for padding.) + + == Feature name table == The feature name table is an optional header extension that contains the name @@ -437,6 +474,11 @@ L2 table entry: This information is only accurate in L2 tables that are reachable from the active L1 table. + With external data files, all guest clusters have an + implicit refcount of 1 (because of the fixed host = guest + mapping for guest cluster offsets), so this bit should be 1 + for all allocated clusters. + Standard Cluster Descriptor: Bit 0: If set to 1, the cluster reads as all zeros. The host @@ -450,8 +492,10 @@ Standard Cluster Descriptor: 1 - 8: Reserved (set to 0) 9 - 55: Bits 9-55 of host cluster offset. Must be aligned to a - cluster boundary. If the offset is 0, the cluster is - unallocated. + cluster boundary. If the offset is 0 and bit 63 is clear, + the cluster is unallocated. The offset may only be 0 with + bit 63 set (indicating a host cluster offset of 0) when an + external data file is used. 56 - 61: Reserved (set to 0) diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt index c1e7751fea..d57f409861 100644 --- a/docs/qcow2-cache.txt +++ b/docs/qcow2-cache.txt @@ -158,10 +158,10 @@ refcount cache is as small as possible unless overridden by the user. Using smaller cache entries --------------------------- -The qcow2 L2 cache stores complete tables by default. This means that -if QEMU needs an entry from an L2 table then the whole table is read -from disk and is kept in the cache. If the cache is full then a -complete table needs to be evicted first. +The qcow2 L2 cache can store complete tables. This means that if QEMU +needs an entry from an L2 table then the whole table is read from disk +and is kept in the cache. If the cache is full then a complete table +needs to be evicted first. This can be inefficient with large cluster sizes since it results in more disk I/O and wastes more cache memory. @@ -172,6 +172,9 @@ it smaller than the cluster size. This can be configured using the -drive file=hd.qcow2,l2-cache-size=2097152,l2-cache-entry-size=4096 +Since QEMU 4.0 the value of l2-cache-entry-size defaults to 4KB (or +the cluster size if it's smaller). + Some things to take into account: - The L2 cache entry size has the same restrictions as the cluster @@ -185,7 +188,8 @@ Some things to take into account: - Try different entry sizes to see which one gives faster performance in your case. The block size of the host filesystem is generally a - good default (usually 4096 bytes in the case of ext4). + good default (usually 4096 bytes in the case of ext4, hence the + default). - Only the L2 cache can be configured this way. The refcount cache always uses the cluster size as the entry size. @@ -194,7 +198,8 @@ Some things to take into account: (as explained in the "Choosing the right cache sizes" and "How to configure the cache sizes" sections in this document) then none of this is necessary and you can omit the "l2-cache-entry-size" - parameter altogether. + parameter altogether. In this case QEMU makes the entry size + equal to the cluster size by default. Reducing the memory usage diff --git a/include/block/block.h b/include/block/block.h index 5b5cf868df..6a758a76f8 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -472,7 +472,7 @@ void bdrv_next_cleanup(BdrvNextIterator *it); BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs); bool bdrv_is_encrypted(BlockDriverState *bs); void bdrv_iterate_format(void (*it)(void *opaque, const char *name), - void *opaque); + void *opaque, bool read_only); const char *bdrv_get_node_name(const BlockDriverState *bs); const char *bdrv_get_device_name(const BlockDriverState *bs); const char *bdrv_get_device_or_node_name(const BlockDriverState *bs); diff --git a/include/block/block_int.h b/include/block/block_int.h index 836d67c1ae..a23cabaddd 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -56,6 +56,8 @@ #define BLOCK_OPT_NOCOW "nocow" #define BLOCK_OPT_OBJECT_SIZE "object_size" #define BLOCK_OPT_REFCOUNT_BITS "refcount_bits" +#define BLOCK_OPT_DATA_FILE "data_file" +#define BLOCK_OPT_DATA_FILE_RAW "data_file_raw" #define BLOCK_PROBE_BUF_SIZE 512 diff --git a/qapi/block-core.json b/qapi/block-core.json index 2b8afbb924..919d0530b2 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -59,6 +59,13 @@ # # @compat: compatibility level # +# @data-file: the filename of the external data file that is stored in the +# image and used as a default for opening the image (since: 4.0) +# +# @data-file-raw: True if the external data file must stay valid as a +# standalone (read-only) raw image without looking at qcow2 +# metadata (since: 4.0) +# # @lazy-refcounts: on or off; only valid for compat >= 1.1 # # @corrupt: true if the image has been marked corrupt; only valid for @@ -76,6 +83,8 @@ { 'struct': 'ImageInfoSpecificQCow2', 'data': { 'compat': 'str', + '*data-file': 'str', + '*data-file-raw': 'bool', '*lazy-refcounts': 'bool', '*corrupt': 'bool', 'refcount-bits': 'int', @@ -3080,6 +3089,12 @@ # encrypted images, except when doing a metadata-only # probe of the image. (since 2.10) # +# @data-file: reference to or definition of the external data file. +# This may only be specified for images that require an +# external data file. If it is not specified for such +# an image, the data file name is loaded from the image +# file. (since 4.0) +# # Since: 2.9 ## { 'struct': 'BlockdevOptionsQcow2', @@ -3094,7 +3109,8 @@ '*l2-cache-entry-size': 'int', '*refcount-cache-size': 'int', '*cache-clean-interval': 'int', - '*encrypt': 'BlockdevQcow2Encryption' } } + '*encrypt': 'BlockdevQcow2Encryption', + '*data-file': 'BlockdevRef' } } ## # @SshHostKeyCheckMode: @@ -4130,6 +4146,12 @@ # Driver specific image creation options for qcow2. # # @file Node to create the image format on +# @data-file Node to use as an external data file in which all guest +# data is stored so that only metadata remains in the qcow2 +# file (since: 4.0) +# @data-file-raw True if the external data file must stay valid as a +# standalone (read-only) raw image without looking at qcow2 +# metadata (default: false; since: 4.0) # @size Size of the virtual disk in bytes # @version Compatibility level (default: v3) # @backing-file File name of the backing file if a backing file @@ -4145,6 +4167,8 @@ ## { 'struct': 'BlockdevCreateOptionsQcow2', 'data': { 'file': 'BlockdevRef', + '*data-file': 'BlockdevRef', + '*data-file-raw': 'bool', 'size': 'size', '*version': 'BlockdevQcow2Version', '*backing-file': 'str', diff --git a/qemu-img.c b/qemu-img.c index 660c01898e..5fac840742 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -198,7 +198,7 @@ static void QEMU_NORETURN help(void) " 'skip=N' skip N bs-sized blocks at the start of input\n"; printf("%s\nSupported formats:", help_msg); - bdrv_iterate_format(format_print, NULL); + bdrv_iterate_format(format_print, NULL, false); printf("\n\n" QEMU_HELP_BOTTOM "\n"); exit(EXIT_SUCCESS); } diff --git a/tests/Makefile.include b/tests/Makefile.include index 44af41515b..a5719551dd 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -780,7 +780,7 @@ tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y) tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y) tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) -tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) +tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) qemu-img$(EXESUF) tests/ipmi-kcs-test$(EXESUF): tests/ipmi-kcs-test.o tests/ipmi-bt-test$(EXESUF): tests/ipmi-bt-test.o tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o @@ -1101,7 +1101,7 @@ clean-tcg: $(CLEAN_TCG_TARGET_RULES) QEMU_IOTESTS_HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) = tests/qemu-iotests/socket_scm_helper$(EXESUF) .PHONY: check-tests/qemu-iotests-quick.sh -check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF) $(QEMU_IOTESTS_HELPERS-y) +check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF) qemu-nbd$(EXESUF) $(QEMU_IOTESTS_HELPERS-y) $< .PHONY: $(patsubst %, check-%, $(check-qapi-schema-y)) diff --git a/tests/multiboot/run_test.sh b/tests/multiboot/run_test.sh index 6c33003e71..98df91e6af 100755 --- a/tests/multiboot/run_test.sh +++ b/tests/multiboot/run_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com> # diff --git a/tests/qemu-iotests/001 b/tests/qemu-iotests/001 index 55dcbb71d9..5d266e170a 100755 --- a/tests/qemu-iotests/001 +++ b/tests/qemu-iotests/001 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test simple read/write using plain bdrv_read/bdrv_write # diff --git a/tests/qemu-iotests/002 b/tests/qemu-iotests/002 index 74572b4711..7fb85084a1 100755 --- a/tests/qemu-iotests/002 +++ b/tests/qemu-iotests/002 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test simple read/write using plain bdrv_pread/bdrv_pwrite # diff --git a/tests/qemu-iotests/003 b/tests/qemu-iotests/003 index bf2595559b..f008c57cdc 100755 --- a/tests/qemu-iotests/003 +++ b/tests/qemu-iotests/003 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test simple read/write using bdrv_aio_readv/bdrv_aio_writev # diff --git a/tests/qemu-iotests/004 b/tests/qemu-iotests/004 index 841b15dfac..64fab3e714 100755 --- a/tests/qemu-iotests/004 +++ b/tests/qemu-iotests/004 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Make sure we can't read and write outside of the image size. # diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005 index 8aa4283a4d..2fef63af88 100755 --- a/tests/qemu-iotests/005 +++ b/tests/qemu-iotests/005 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Make sure qemu-img can create 5TB images # diff --git a/tests/qemu-iotests/007 b/tests/qemu-iotests/007 index b983022a7f..3ab5490db3 100755 --- a/tests/qemu-iotests/007 +++ b/tests/qemu-iotests/007 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Check for one possible case of qcow2 refcount corruption. # diff --git a/tests/qemu-iotests/008 b/tests/qemu-iotests/008 index 8dfa10bcb8..75067e36ad 100755 --- a/tests/qemu-iotests/008 +++ b/tests/qemu-iotests/008 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test simple asynchronous read/write operations. # diff --git a/tests/qemu-iotests/009 b/tests/qemu-iotests/009 index 73ae09db69..bc4b461122 100755 --- a/tests/qemu-iotests/009 +++ b/tests/qemu-iotests/009 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Nolan I qcow2 corruption - incorrectly reports free clusters # diff --git a/tests/qemu-iotests/010 b/tests/qemu-iotests/010 index 751aca9813..6920408d28 100755 --- a/tests/qemu-iotests/010 +++ b/tests/qemu-iotests/010 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Nolan II qcow2 corruption - wrong used cluster # diff --git a/tests/qemu-iotests/011 b/tests/qemu-iotests/011 index 35909564a9..b4c7e8f799 100755 --- a/tests/qemu-iotests/011 +++ b/tests/qemu-iotests/011 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for AIO allocation on the same cluster # diff --git a/tests/qemu-iotests/012 b/tests/qemu-iotests/012 index de9a5fb4d5..2c3b42d9dd 100755 --- a/tests/qemu-iotests/012 +++ b/tests/qemu-iotests/012 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Make sure we can open read-only images # diff --git a/tests/qemu-iotests/013 b/tests/qemu-iotests/013 index 5e1efcee28..5cb9032f16 100755 --- a/tests/qemu-iotests/013 +++ b/tests/qemu-iotests/013 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 pattern test, empty and compressed image - 4k cluster patterns # diff --git a/tests/qemu-iotests/014 b/tests/qemu-iotests/014 index 9ade571a95..2f728a1956 100755 --- a/tests/qemu-iotests/014 +++ b/tests/qemu-iotests/014 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 pattern test, complex patterns including compression and snapshots # Using patterns for 4k cluster size. diff --git a/tests/qemu-iotests/015 b/tests/qemu-iotests/015 index 21f7d42c84..5a4063e4f5 100755 --- a/tests/qemu-iotests/015 +++ b/tests/qemu-iotests/015 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Combined test to grow the refcount table and test snapshots. # diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017 index 1ac6f74502..83744f29a3 100755 --- a/tests/qemu-iotests/017 +++ b/tests/qemu-iotests/017 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Simple backing file reads # diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018 index bba30a1be2..78169838ba 100755 --- a/tests/qemu-iotests/018 +++ b/tests/qemu-iotests/018 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Merge backing file into test image when converting the image # diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019 index 8f911a79c1..a56dd30bed 100755 --- a/tests/qemu-iotests/019 +++ b/tests/qemu-iotests/019 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # When using a backing file for the output image in qemu-img convert, # the backing file clusters must not copied. The data must still be diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020 index 6b972d082f..71fa753b4e 100755 --- a/tests/qemu-iotests/020 +++ b/tests/qemu-iotests/020 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Commit changes to backing file # diff --git a/tests/qemu-iotests/021 b/tests/qemu-iotests/021 index c15ebf9eb8..f6555f3b74 100755 --- a/tests/qemu-iotests/021 +++ b/tests/qemu-iotests/021 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test handling of invalid patterns arguments to qemu-io # diff --git a/tests/qemu-iotests/022 b/tests/qemu-iotests/022 index 44765c7b7a..b68cd64b33 100755 --- a/tests/qemu-iotests/022 +++ b/tests/qemu-iotests/022 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test bdrv_load/save_vmstate using the usual patterns # diff --git a/tests/qemu-iotests/023 b/tests/qemu-iotests/023 index c8e1b9a761..02ed047820 100755 --- a/tests/qemu-iotests/023 +++ b/tests/qemu-iotests/023 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 pattern test with various cluster sizes # diff --git a/tests/qemu-iotests/024 b/tests/qemu-iotests/024 index 428b5c815d..23298c6f59 100755 --- a/tests/qemu-iotests/024 +++ b/tests/qemu-iotests/024 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Rebasing COW images # diff --git a/tests/qemu-iotests/025 b/tests/qemu-iotests/025 index fcd4d97c17..d9a4ebc5e7 100755 --- a/tests/qemu-iotests/025 +++ b/tests/qemu-iotests/025 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Resizing images # diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026 index 31276d9027..ca89ad7048 100755 --- a/tests/qemu-iotests/026 +++ b/tests/qemu-iotests/026 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 error path testing # diff --git a/tests/qemu-iotests/027 b/tests/qemu-iotests/027 index 2c46ae1457..b7df9701f7 100755 --- a/tests/qemu-iotests/027 +++ b/tests/qemu-iotests/027 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that sub-cluster allocating writes zero the rest of the cluster # diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028 index a2a7c93bcd..01f495912f 100755 --- a/tests/qemu-iotests/028 +++ b/tests/qemu-iotests/028 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that backing files can be smaller than the image # diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029 index cf0fe0f6a6..5f42f76cc6 100755 --- a/tests/qemu-iotests/029 +++ b/tests/qemu-iotests/029 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 internal snapshots/VM state tests # diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031 index ac0dfaed7d..ef92d8eee3 100755 --- a/tests/qemu-iotests/031 +++ b/tests/qemu-iotests/031 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that all qcow2 header extensions survive a header rewrite # diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out index 7f5050b816..68a74d03b9 100644 --- a/tests/qemu-iotests/031.out +++ b/tests/qemu-iotests/031.out @@ -117,7 +117,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data <binary> Header extension: @@ -150,7 +150,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data <binary> Header extension: @@ -164,7 +164,7 @@ No errors were found on the image. magic 0x514649fb version 3 -backing_file_offset 0x148 +backing_file_offset 0x178 backing_file_size 0x17 cluster_bits 16 size 67108864 @@ -188,7 +188,7 @@ data 'host_device' Header extension: magic 0x6803f857 -length 144 +length 192 data <binary> Header extension: diff --git a/tests/qemu-iotests/032 b/tests/qemu-iotests/032 index 3e86bb0111..a1757bb15e 100755 --- a/tests/qemu-iotests/032 +++ b/tests/qemu-iotests/032 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that AIO requests are drained before an image is closed. This used # to segfault because the request coroutine kept running even after the diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033 index 46b91388ef..cfdf1ec2ba 100755 --- a/tests/qemu-iotests/033 +++ b/tests/qemu-iotests/033 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test aligned and misaligned write zeroes operations. # diff --git a/tests/qemu-iotests/034 b/tests/qemu-iotests/034 index 62812cd53c..324bed28c6 100755 --- a/tests/qemu-iotests/034 +++ b/tests/qemu-iotests/034 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test bdrv_pwrite_zeroes with backing files (see also 154) # diff --git a/tests/qemu-iotests/035 b/tests/qemu-iotests/035 index 85d9ef7f8e..46aa835936 100755 --- a/tests/qemu-iotests/035 +++ b/tests/qemu-iotests/035 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Let a few AIO requests run in parallel and have them access different L2 # tables so that the cache has a chance to get used up. diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036 index 4e76602a93..1b56394129 100755 --- a/tests/qemu-iotests/036 +++ b/tests/qemu-iotests/036 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qcow2 feature bits # diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out index 9b009b8c15..e489b44386 100644 --- a/tests/qemu-iotests/036.out +++ b/tests/qemu-iotests/036.out @@ -58,7 +58,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data <binary> @@ -86,7 +86,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data <binary> *** done diff --git a/tests/qemu-iotests/037 b/tests/qemu-iotests/037 index a11992dad2..0781bebefe 100755 --- a/tests/qemu-iotests/037 +++ b/tests/qemu-iotests/037 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test COW from backing files # diff --git a/tests/qemu-iotests/038 b/tests/qemu-iotests/038 index 575093e8cf..707e2d72e9 100755 --- a/tests/qemu-iotests/038 +++ b/tests/qemu-iotests/038 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test COW from backing files with AIO # diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039 index b3c344cb27..0d4e963bd4 100755 --- a/tests/qemu-iotests/039 +++ b/tests/qemu-iotests/039 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qcow2 lazy refcounts # diff --git a/tests/qemu-iotests/042 b/tests/qemu-iotests/042 index beaa339000..a9a7fc3041 100755 --- a/tests/qemu-iotests/042 +++ b/tests/qemu-iotests/042 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qemu-img operation on zero size images # diff --git a/tests/qemu-iotests/043 b/tests/qemu-iotests/043 index fc9005b28f..9894b154ec 100755 --- a/tests/qemu-iotests/043 +++ b/tests/qemu-iotests/043 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that qemu-img info --backing-chain detects infinite loops # diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046 index 5e41d96daa..95160bea4c 100755 --- a/tests/qemu-iotests/046 +++ b/tests/qemu-iotests/046 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test concurrent cluster allocations # diff --git a/tests/qemu-iotests/047 b/tests/qemu-iotests/047 index 6e776d2ce5..ce81fc6fa7 100755 --- a/tests/qemu-iotests/047 +++ b/tests/qemu-iotests/047 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Regression test for commit b7ab0fea (which was a corruption fix, # despite the commit message claiming otherwise) diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048 index 9ed04a068d..bde408ca92 100755 --- a/tests/qemu-iotests/048 +++ b/tests/qemu-iotests/048 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash ## ## qemu-img compare test ## diff --git a/tests/qemu-iotests/049 b/tests/qemu-iotests/049 index 97d8a64697..bc09cd6717 100755 --- a/tests/qemu-iotests/049 +++ b/tests/qemu-iotests/049 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Check qemu-img option parsing # diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050 index 963a0db97f..dd7b2c72eb 100755 --- a/tests/qemu-iotests/050 +++ b/tests/qemu-iotests/050 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qemu-img rebase with zero clusters # diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 32741d7efd..3b50c7f188 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test command line configuration of block devices and driver-specific options # diff --git a/tests/qemu-iotests/052 b/tests/qemu-iotests/052 index b992adf4ff..b3a2dc1143 100755 --- a/tests/qemu-iotests/052 +++ b/tests/qemu-iotests/052 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test bdrv_read/bdrv_write using BDRV_O_SNAPSHOT # diff --git a/tests/qemu-iotests/053 b/tests/qemu-iotests/053 index afa109c950..50c62f0f56 100755 --- a/tests/qemu-iotests/053 +++ b/tests/qemu-iotests/053 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qemu-img convert when image length is not a multiple of cluster size # diff --git a/tests/qemu-iotests/054 b/tests/qemu-iotests/054 index cf88a7c76e..0d5e14f847 100755 --- a/tests/qemu-iotests/054 +++ b/tests/qemu-iotests/054 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test huge qcow2 images # diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058 index d6d4f94d5d..8c3212a72f 100755 --- a/tests/qemu-iotests/058 +++ b/tests/qemu-iotests/058 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test export internal snapshot by qemu-nbd, convert it by qemu-img. # diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 index 54d5567acc..279aee6815 100755 --- a/tests/qemu-iotests/059 +++ b/tests/qemu-iotests/059 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for vmdk # diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index af0588ae9a..89e911400c 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for image corruption (overlapping data structures) in qcow2 # diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061 index 1a50163419..d7dbd7e2c7 100755 --- a/tests/qemu-iotests/061 +++ b/tests/qemu-iotests/061 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for image option amendment in qcow2. # @@ -28,7 +28,8 @@ status=1 # failure is the default! _cleanup() { - _cleanup_test_img + _cleanup_test_img + rm -f $TEST_IMG.data } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -250,6 +251,48 @@ $QEMU_IMG snapshot -c foo "$TEST_IMG" $QEMU_IMG amend -p -o "compat=0.10" "$TEST_IMG" _check_test_img +echo +echo "=== Testing version downgrade with external data file ===" +echo +IMGOPTS="compat=1.1,data_file=$TEST_IMG.data" _make_test_img 64M +$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG" +_img_info --format-specific +_check_test_img + +echo +echo "=== Try changing the external data file ===" +echo +IMGOPTS="compat=1.1" _make_test_img 64M +$QEMU_IMG amend -o "data_file=foo" "$TEST_IMG" + +echo +IMGOPTS="compat=1.1,data_file=$TEST_IMG.data" _make_test_img 64M +$QEMU_IMG amend -o "data_file=foo" "$TEST_IMG" +_img_info --format-specific +TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts + +echo +$QEMU_IMG amend -o "data_file=" --image-opts "data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" +_img_info --format-specific +TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts + +echo +echo "=== Clearing and setting data-file-raw ===" +echo +IMGOPTS="compat=1.1,data_file=$TEST_IMG.data,data_file_raw=on" _make_test_img 64M +$QEMU_IMG amend -o "data_file_raw=on" "$TEST_IMG" +_img_info --format-specific +_check_test_img + +$QEMU_IMG amend -o "data_file_raw=off" "$TEST_IMG" +_img_info --format-specific +_check_test_img + +$QEMU_IMG amend -o "data_file_raw=on" "$TEST_IMG" +_img_info --format-specific +_check_test_img + + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index 183f7dd690..9fe1ec702f 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -26,7 +26,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data <binary> magic 0x514649fb @@ -84,7 +84,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data <binary> magic 0x514649fb @@ -144,7 +144,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data <binary> ERROR cluster 5 refcount=0 reference=1 @@ -199,7 +199,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data <binary> magic 0x514649fb @@ -268,7 +268,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data <binary> read 65536/65536 bytes at offset 44040192 @@ -306,7 +306,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data <binary> ERROR cluster 5 refcount=0 reference=1 @@ -335,7 +335,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data <binary> read 131072/131072 bytes at offset 0 @@ -488,4 +488,93 @@ wrote 65536/65536 bytes at offset 3221225472 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (0.00/100%)
(6.25/100%)
(12.50/100%)
(18.75/100%)
(25.00/100%)
(31.25/100%)
(37.50/100%)
(43.75/100%)
(50.00/100%)
(56.25/100%)
(62.50/100%)
(68.75/100%)
(75.00/100%)
(81.25/100%)
(87.50/100%)
(93.75/100%)
(100.00/100%)
(100.00/100%) No errors were found on the image. + +=== Testing version downgrade with external data file === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data +qemu-img: Cannot downgrade an image with a data file +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + data file: TEST_DIR/t.IMGFMT.data + data file raw: false + corrupt: false +No errors were found on the image. + +=== Try changing the external data file === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qemu-img: data-file can only be set for images that use an external data file + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Could not open 'foo': No such file or directory +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + data file: foo + data file raw: false + corrupt: false + +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'data-file' is required for this image +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + data file raw: false + corrupt: false + +=== Clearing and setting data-file-raw === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=on +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + data file: TEST_DIR/t.IMGFMT.data + data file raw: true + corrupt: false +No errors were found on the image. +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + data file: TEST_DIR/t.IMGFMT.data + data file raw: false + corrupt: false +No errors were found on the image. +qemu-img: data-file-raw cannot be set on existing images +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + data file: TEST_DIR/t.IMGFMT.data + data file raw: false + corrupt: false +No errors were found on the image. *** done diff --git a/tests/qemu-iotests/062 b/tests/qemu-iotests/062 index 985fbef41e..ed7400fed2 100755 --- a/tests/qemu-iotests/062 +++ b/tests/qemu-iotests/062 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for snapshotting images with unallocated zero clusters in # qcow2 diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063 index 041fb5c1ac..2d5c0ce9fb 100755 --- a/tests/qemu-iotests/063 +++ b/tests/qemu-iotests/063 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # test of qemu-img convert -n - convert without creation # diff --git a/tests/qemu-iotests/064 b/tests/qemu-iotests/064 index f55ff37ca7..90673186ec 100755 --- a/tests/qemu-iotests/064 +++ b/tests/qemu-iotests/064 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test VHDX read/write from a sample image created with Hyper-V # diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066 index 26c043711b..f480986e35 100755 --- a/tests/qemu-iotests/066 +++ b/tests/qemu-iotests/066 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for preallocated zero clusters in qcow2 # diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067 index 342b2b0a30..fda16a6b0d 100755 --- a/tests/qemu-iotests/067 +++ b/tests/qemu-iotests/067 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test automatic deletion of BDSes created by -drive/drive_add # diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068 index f0583d52ae..881a022107 100755 --- a/tests/qemu-iotests/068 +++ b/tests/qemu-iotests/068 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for loading a saved VM state from a qcow2 image # diff --git a/tests/qemu-iotests/069 b/tests/qemu-iotests/069 index fdee121f43..6a8e4aa22e 100755 --- a/tests/qemu-iotests/069 +++ b/tests/qemu-iotests/069 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for deleting a backing file # diff --git a/tests/qemu-iotests/070 b/tests/qemu-iotests/070 index 78e0390f5f..cb0f927c16 100755 --- a/tests/qemu-iotests/070 +++ b/tests/qemu-iotests/070 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test VHDX log replay from an image with a journal that needs to be # replayed diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071 index 6e467dc1da..7f3e5abd57 100755 --- a/tests/qemu-iotests/071 +++ b/tests/qemu-iotests/071 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for the QMP blkdebug and blkverify interfaces # diff --git a/tests/qemu-iotests/072 b/tests/qemu-iotests/072 index 08ef29f5b4..6f9f247fa5 100755 --- a/tests/qemu-iotests/072 +++ b/tests/qemu-iotests/072 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for nested image formats # diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073 index 5e7f76cb7f..990f90acbd 100755 --- a/tests/qemu-iotests/073 +++ b/tests/qemu-iotests/073 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test count_contiguous_clusters in qcow2 # diff --git a/tests/qemu-iotests/074 b/tests/qemu-iotests/074 index b17866bd34..bb4ad1cc08 100755 --- a/tests/qemu-iotests/074 +++ b/tests/qemu-iotests/074 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash ## ## qemu-img compare test (qcow2 only ones) ## diff --git a/tests/qemu-iotests/075 b/tests/qemu-iotests/075 index 45b8901ef0..389d5675fa 100755 --- a/tests/qemu-iotests/075 +++ b/tests/qemu-iotests/075 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # cloop format input validation tests # diff --git a/tests/qemu-iotests/076 b/tests/qemu-iotests/076 index 3b5ab3fd08..0d405ef3f2 100755 --- a/tests/qemu-iotests/076 +++ b/tests/qemu-iotests/076 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # parallels format input validation tests # diff --git a/tests/qemu-iotests/077 b/tests/qemu-iotests/077 index 58fe8932b3..c284952082 100755 --- a/tests/qemu-iotests/077 +++ b/tests/qemu-iotests/077 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test concurrent pread/pwrite # diff --git a/tests/qemu-iotests/078 b/tests/qemu-iotests/078 index 68d0ea8802..54fc654d8e 100755 --- a/tests/qemu-iotests/078 +++ b/tests/qemu-iotests/078 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # bochs format input validation tests # diff --git a/tests/qemu-iotests/079 b/tests/qemu-iotests/079 index fca2f77d37..1b6594ebef 100755 --- a/tests/qemu-iotests/079 +++ b/tests/qemu-iotests/079 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qcow2 preallocation with different cluster_sizes # diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080 index cec2376f59..4bcb5021e8 100755 --- a/tests/qemu-iotests/080 +++ b/tests/qemu-iotests/080 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 format input validation tests # diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081 index edf6e6172a..c418bab093 100755 --- a/tests/qemu-iotests/081 +++ b/tests/qemu-iotests/081 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test Quorum block driver # diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082 index 61eec63797..d0afa46e9a 100755 --- a/tests/qemu-iotests/082 +++ b/tests/qemu-iotests/082 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qemu-img command line parsing # diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index 0ce18c075b..915640613f 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -48,6 +48,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -69,6 +71,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -90,6 +94,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -111,6 +117,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -132,6 +140,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -153,6 +163,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -174,6 +186,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -195,6 +209,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -231,6 +247,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -304,6 +322,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -325,6 +345,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -346,6 +368,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -367,6 +391,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -388,6 +414,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -409,6 +437,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -430,6 +460,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -451,6 +483,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -487,6 +521,8 @@ Supported options: backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -568,6 +604,8 @@ Creation options for 'qcow2': backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -590,6 +628,8 @@ Creation options for 'qcow2': backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -612,6 +652,8 @@ Creation options for 'qcow2': backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -634,6 +676,8 @@ Creation options for 'qcow2': backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -656,6 +700,8 @@ Creation options for 'qcow2': backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -678,6 +724,8 @@ Creation options for 'qcow2': backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -700,6 +748,8 @@ Creation options for 'qcow2': backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -722,6 +772,8 @@ Creation options for 'qcow2': backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' @@ -761,6 +813,8 @@ Creation options for 'qcow2': backing_fmt=<str> - Image format of the base image cluster_size=<size> - qcow2 cluster size compat=<str> - Compatibility level (0.10 or 1.1) + data_file=<str> - File name of an external data file + data_file_raw=<bool (on/off)> - The external data file must stay valid as a raw image encrypt.cipher-alg=<str> - Name of encryption cipher algorithm encrypt.cipher-mode=<str> - Name of encryption cipher mode encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks' diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083 index 89f67db70f..b270550d3e 100755 --- a/tests/qemu-iotests/083 +++ b/tests/qemu-iotests/083 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test NBD client unexpected disconnect # diff --git a/tests/qemu-iotests/084 b/tests/qemu-iotests/084 index e131fa9642..c29d7395e9 100755 --- a/tests/qemu-iotests/084 +++ b/tests/qemu-iotests/084 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for VDI header corruption; image too large, and too many blocks. # Also simple test for creating dynamic and static VDI images. diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085 index ade68ef853..68cb665987 100755 --- a/tests/qemu-iotests/085 +++ b/tests/qemu-iotests/085 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Live snapshot tests # diff --git a/tests/qemu-iotests/086 b/tests/qemu-iotests/086 index 3cca3687ea..fea1a7bd8a 100755 --- a/tests/qemu-iotests/086 +++ b/tests/qemu-iotests/086 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qemu-img progress output # diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 index f625887082..d6c8613419 100755 --- a/tests/qemu-iotests/087 +++ b/tests/qemu-iotests/087 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test unsupported blockdev-add cases # diff --git a/tests/qemu-iotests/088 b/tests/qemu-iotests/088 index c5e9ab42c7..b44edd0cf9 100755 --- a/tests/qemu-iotests/088 +++ b/tests/qemu-iotests/088 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # vpc (VHD) format input validation tests # diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089 index 3165d79e2a..6609954908 100755 --- a/tests/qemu-iotests/089 +++ b/tests/qemu-iotests/089 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for support of JSON filenames # diff --git a/tests/qemu-iotests/090 b/tests/qemu-iotests/090 index 1450993e15..193bae7d77 100755 --- a/tests/qemu-iotests/090 +++ b/tests/qemu-iotests/090 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for discarding compressed clusters on qcow2 images # diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091 index 2f2f98ee64..d62ef18a02 100755 --- a/tests/qemu-iotests/091 +++ b/tests/qemu-iotests/091 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Live migration test # diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092 index 8e318f10b9..e2e0726de1 100755 --- a/tests/qemu-iotests/092 +++ b/tests/qemu-iotests/092 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow1 format input validation tests # diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094 index 7adc9b9138..0bcca77261 100755 --- a/tests/qemu-iotests/094 +++ b/tests/qemu-iotests/094 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for drive-mirror to NBD # diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095 index 9fc47f6b87..18505b7181 100755 --- a/tests/qemu-iotests/095 +++ b/tests/qemu-iotests/095 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for commit of larger active layer # diff --git a/tests/qemu-iotests/097 b/tests/qemu-iotests/097 index 7234b16053..690f3d3ce1 100755 --- a/tests/qemu-iotests/097 +++ b/tests/qemu-iotests/097 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Commit changes into backing chains and empty the top image if the # backing image is not explicitly specified diff --git a/tests/qemu-iotests/098 b/tests/qemu-iotests/098 index c7977da99a..461144c831 100755 --- a/tests/qemu-iotests/098 +++ b/tests/qemu-iotests/098 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qcow2's bdrv_make_empty for images without internal snapshots # diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099 index 578808b747..ae02f27afe 100755 --- a/tests/qemu-iotests/099 +++ b/tests/qemu-iotests/099 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test valid filenames for blkdebug and blkverify representatively for # other protocols (such as NBD) when queried diff --git a/tests/qemu-iotests/101 b/tests/qemu-iotests/101 index 3001ba3c0a..a4c1b6366a 100755 --- a/tests/qemu-iotests/101 +++ b/tests/qemu-iotests/101 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test short file I/O # diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102 index 29a6a940e2..cedd2b25dc 100755 --- a/tests/qemu-iotests/102 +++ b/tests/qemu-iotests/102 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for qemu-io -c map and qemu-img map # diff --git a/tests/qemu-iotests/103 b/tests/qemu-iotests/103 index 66f8167f02..6773e94d9f 100755 --- a/tests/qemu-iotests/103 +++ b/tests/qemu-iotests/103 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for qcow2 metadata cache size specification # diff --git a/tests/qemu-iotests/104 b/tests/qemu-iotests/104 index 34bb0d23ba..390167bad4 100755 --- a/tests/qemu-iotests/104 +++ b/tests/qemu-iotests/104 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test image creation with aligned and unaligned sizes # diff --git a/tests/qemu-iotests/105 b/tests/qemu-iotests/105 index 943bda2f4f..3b5a596844 100755 --- a/tests/qemu-iotests/105 +++ b/tests/qemu-iotests/105 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Create, read, write big image # diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106 index 4129fee6bc..ac47eaa0f5 100755 --- a/tests/qemu-iotests/106 +++ b/tests/qemu-iotests/106 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test preallocated resize of raw images # diff --git a/tests/qemu-iotests/107 b/tests/qemu-iotests/107 index 5d70ad2007..fcd5a24dfe 100755 --- a/tests/qemu-iotests/107 +++ b/tests/qemu-iotests/107 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Tests updates of the qcow2 L1 table # diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108 index 58e8ad7636..9c08172237 100755 --- a/tests/qemu-iotests/108 +++ b/tests/qemu-iotests/108 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for repairing qcow2 images which cannot be repaired using # the on-disk refcount structures diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109 index b51e4616c6..9897ceb6cd 100755 --- a/tests/qemu-iotests/109 +++ b/tests/qemu-iotests/109 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test writing image headers of other formats into raw images # diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110 index 185ad5437e..fad672c1ae 100755 --- a/tests/qemu-iotests/110 +++ b/tests/qemu-iotests/110 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for relative backing file names in complex BDS trees # diff --git a/tests/qemu-iotests/111 b/tests/qemu-iotests/111 index e15e66ac5d..57395be64c 100755 --- a/tests/qemu-iotests/111 +++ b/tests/qemu-iotests/111 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for non-existing backing file when creating a qcow2 image # and not specifying the size diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112 index d67e6ebe9c..6d81c75a9c 100755 --- a/tests/qemu-iotests/112 +++ b/tests/qemu-iotests/112 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test cases for different refcount_bits values # diff --git a/tests/qemu-iotests/113 b/tests/qemu-iotests/113 index d8d78c46dc..f2703a2c50 100755 --- a/tests/qemu-iotests/113 +++ b/tests/qemu-iotests/113 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for accessing creation options on image formats and # protocols not supporting image creation diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114 index e17fb514cb..f36b88f3f3 100755 --- a/tests/qemu-iotests/114 +++ b/tests/qemu-iotests/114 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test invalid backing file format in qcow2 images # diff --git a/tests/qemu-iotests/115 b/tests/qemu-iotests/115 index 0581e03c26..7ed347010f 100755 --- a/tests/qemu-iotests/115 +++ b/tests/qemu-iotests/115 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for non-self-referential qcow2 refcount blocks # diff --git a/tests/qemu-iotests/116 b/tests/qemu-iotests/116 index f8a27b9c02..941b07a1a9 100755 --- a/tests/qemu-iotests/116 +++ b/tests/qemu-iotests/116 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test error code paths for invalid QED images # diff --git a/tests/qemu-iotests/117 b/tests/qemu-iotests/117 index e533e230a3..0af0f31c5a 100755 --- a/tests/qemu-iotests/117 +++ b/tests/qemu-iotests/117 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for shared BDS between backend trees # diff --git a/tests/qemu-iotests/119 b/tests/qemu-iotests/119 index 32810d52c9..ea6770a484 100755 --- a/tests/qemu-iotests/119 +++ b/tests/qemu-iotests/119 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # NBD test case for overriding BDRV_O_PROTOCOL by explicitly specifying # a driver diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120 index 76afdf449b..ca95b9276e 100755 --- a/tests/qemu-iotests/120 +++ b/tests/qemu-iotests/120 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Non-NBD test cases for overriding BDRV_O_PROTOCOL by explicitly # specifying a driver diff --git a/tests/qemu-iotests/121 b/tests/qemu-iotests/121 index d2885c700f..90a0424edb 100755 --- a/tests/qemu-iotests/121 +++ b/tests/qemu-iotests/121 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test cases for qcow2 refcount table growth # diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 index eab3399dd6..85c3a8d047 100755 --- a/tests/qemu-iotests/122 +++ b/tests/qemu-iotests/122 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test some qemu-img convert cases # diff --git a/tests/qemu-iotests/123 b/tests/qemu-iotests/123 index 168b985c8b..d33950eb54 100755 --- a/tests/qemu-iotests/123 +++ b/tests/qemu-iotests/123 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for qemu-img convert to NBD # diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125 index 778c874933..212dcd8f0d 100755 --- a/tests/qemu-iotests/125 +++ b/tests/qemu-iotests/125 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test preallocated growth of qcow2 images # diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126 index 91148383ad..96dc048d59 100755 --- a/tests/qemu-iotests/126 +++ b/tests/qemu-iotests/126 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Tests handling of colons in filenames (which may be confused with protocol # prefixes) diff --git a/tests/qemu-iotests/127 b/tests/qemu-iotests/127 index c9139ed5e6..3e941f74d4 100755 --- a/tests/qemu-iotests/127 +++ b/tests/qemu-iotests/127 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for mirroring with dataplane # diff --git a/tests/qemu-iotests/128 b/tests/qemu-iotests/128 index 925f5c7e98..3606c41760 100755 --- a/tests/qemu-iotests/128 +++ b/tests/qemu-iotests/128 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that opening O_DIRECT succeeds when image file I/O produces EIO # diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130 index f2f2706b28..77ad2aa13a 100755 --- a/tests/qemu-iotests/130 +++ b/tests/qemu-iotests/130 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that temporary backing file overrides (on the command line or in # blockdev-add) don't replace the original path stored in the image during diff --git a/tests/qemu-iotests/131 b/tests/qemu-iotests/131 index 58c25f7abe..27870231cf 100755 --- a/tests/qemu-iotests/131 +++ b/tests/qemu-iotests/131 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # parallels format validation tests (created by QEMU) # diff --git a/tests/qemu-iotests/133 b/tests/qemu-iotests/133 index 565e0b1b6e..1f6056d144 100755 --- a/tests/qemu-iotests/133 +++ b/tests/qemu-iotests/133 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for reopen # diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134 index cacabcd28b..e9e3e84c2a 100755 --- a/tests/qemu-iotests/134 +++ b/tests/qemu-iotests/134 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test encrypted read/write using plain bdrv_read/bdrv_write # diff --git a/tests/qemu-iotests/135 b/tests/qemu-iotests/135 index a18a0c7230..3b3d1dc2a5 100755 --- a/tests/qemu-iotests/135 +++ b/tests/qemu-iotests/135 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test VPC open of image with large Max Table Entries value. # diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137 index 09cd4450ca..0c3d2a1cf0 100755 --- a/tests/qemu-iotests/137 +++ b/tests/qemu-iotests/137 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qcow2 reopen # diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138 index eccbcae3a6..f353ac8219 100755 --- a/tests/qemu-iotests/138 +++ b/tests/qemu-iotests/138 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # General test case for qcow2's image check # diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139 index 62402c1c35..933b45121a 100755 --- a/tests/qemu-iotests/139 +++ b/tests/qemu-iotests/139 @@ -325,6 +325,7 @@ class TestBlockdevDel(iotests.QMPTestCase): # FIXME mirror0 disappears, drive-mirror doesn't take a reference #self.delBlockDriverState('mirror0') + @iotests.skip_if_unsupported(['blkdebug']) def testBlkDebug(self): self.addBlkDebug('debug0', 'node0') # 'node0' is used by the blkdebug node @@ -333,6 +334,7 @@ class TestBlockdevDel(iotests.QMPTestCase): self.delBlockDriverState('debug0') self.checkBlockDriverState('node0', False) + @iotests.skip_if_unsupported(['blkverify']) def testBlkVerify(self): self.addBlkVerify('verify0', 'node0', 'node1') # We cannot remove the children of a blkverify device @@ -343,6 +345,7 @@ class TestBlockdevDel(iotests.QMPTestCase): self.checkBlockDriverState('node0', False) self.checkBlockDriverState('node1', False) + @iotests.skip_if_unsupported(['quorum']) def testQuorum(self): if not iotests.supports_quorum(): return diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140 index d4623b5a5d..b965b1dd5d 100755 --- a/tests/qemu-iotests/140 +++ b/tests/qemu-iotests/140 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for ejecting a BlockBackend with an NBD server attached to it # diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141 index e2408c7988..2197a82d45 100755 --- a/tests/qemu-iotests/141 +++ b/tests/qemu-iotests/141 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for ejecting BDSs with block jobs still running on them # diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142 index 5fc488f5d2..d9b98cf60a 100755 --- a/tests/qemu-iotests/142 +++ b/tests/qemu-iotests/142 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for configuring cache modes of arbitrary nodes (requires O_DIRECT) # diff --git a/tests/qemu-iotests/143 b/tests/qemu-iotests/143 index d6302cc06d..c223867cb3 100755 --- a/tests/qemu-iotests/143 +++ b/tests/qemu-iotests/143 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for connecting to a non-existing NBD export name # diff --git a/tests/qemu-iotests/144 b/tests/qemu-iotests/144 index 118c099994..15157f33d7 100755 --- a/tests/qemu-iotests/144 +++ b/tests/qemu-iotests/144 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Check live snapshot, followed by active commit, and another snapshot. # # This test is to catch the error case of BZ #1300209: diff --git a/tests/qemu-iotests/145 b/tests/qemu-iotests/145 index 6ce8a46f92..28878dc8a1 100755 --- a/tests/qemu-iotests/145 +++ b/tests/qemu-iotests/145 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test the combination of -incoming and snapshot=on # diff --git a/tests/qemu-iotests/146 b/tests/qemu-iotests/146 index 3f61351ffe..2e43abddfc 100755 --- a/tests/qemu-iotests/146 +++ b/tests/qemu-iotests/146 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test VHD image format creator detection and override # diff --git a/tests/qemu-iotests/150 b/tests/qemu-iotests/150 index 955b877efa..3b1f32197a 100755 --- a/tests/qemu-iotests/150 +++ b/tests/qemu-iotests/150 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that qemu-img convert -S 0 fully allocates the target image # diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153 index 3120a61da4..c989c2495f 100755 --- a/tests/qemu-iotests/153 +++ b/tests/qemu-iotests/153 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test image locking # diff --git a/tests/qemu-iotests/154 b/tests/qemu-iotests/154 index 4a4abf0589..d68f66b9e0 100755 --- a/tests/qemu-iotests/154 +++ b/tests/qemu-iotests/154 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 specific bdrv_pwrite_zeroes tests with backing files (complements 034) # diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156 index f97f96f666..8d134029c6 100755 --- a/tests/qemu-iotests/156 +++ b/tests/qemu-iotests/156 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Tests oVirt-like storage migration: # - Create snapshot diff --git a/tests/qemu-iotests/157 b/tests/qemu-iotests/157 index 6fb26596ad..69b25cab30 100755 --- a/tests/qemu-iotests/157 +++ b/tests/qemu-iotests/157 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test command line configuration of block devices with qdev # diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158 index d277ddcc94..8c0928a7f9 100755 --- a/tests/qemu-iotests/158 +++ b/tests/qemu-iotests/158 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test encrypted read/write using backing files # diff --git a/tests/qemu-iotests/159 b/tests/qemu-iotests/159 index e74b2739de..29066eebde 100755 --- a/tests/qemu-iotests/159 +++ b/tests/qemu-iotests/159 @@ -1,4 +1,4 @@ -#! /bin/bash +#!/usr/bin/env bash # # qemu-img dd test with different block sizes # diff --git a/tests/qemu-iotests/160 b/tests/qemu-iotests/160 index 92fff45d10..df89d3864b 100755 --- a/tests/qemu-iotests/160 +++ b/tests/qemu-iotests/160 @@ -1,4 +1,4 @@ -#! /bin/bash +#!/usr/bin/env bash # # qemu-img dd test for the skip option # diff --git a/tests/qemu-iotests/161 b/tests/qemu-iotests/161 index 180df17ad6..456a4bd8c4 100755 --- a/tests/qemu-iotests/161 +++ b/tests/qemu-iotests/161 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test reopening a backing image after block-stream and block-commit # diff --git a/tests/qemu-iotests/162 b/tests/qemu-iotests/162 index ef02d844a2..2e9947fd9a 100755 --- a/tests/qemu-iotests/162 +++ b/tests/qemu-iotests/162 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for specifying runtime options of the wrong type to some # block drivers diff --git a/tests/qemu-iotests/170 b/tests/qemu-iotests/170 index 861eabf5cc..7deb7563c9 100755 --- a/tests/qemu-iotests/170 +++ b/tests/qemu-iotests/170 @@ -1,4 +1,4 @@ -#! /bin/bash +#!/usr/bin/env bash # # qemu-img dd test # diff --git a/tests/qemu-iotests/171 b/tests/qemu-iotests/171 index 5b46069fde..341064a1c6 100755 --- a/tests/qemu-iotests/171 +++ b/tests/qemu-iotests/171 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test 'offset' and 'size' options of the raw driver. Make sure we can't # (or can) read and write outside of the image size. diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172 index 1e60a7e3d6..ba7dad9057 100755 --- a/tests/qemu-iotests/172 +++ b/tests/qemu-iotests/172 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test floppy configuration # diff --git a/tests/qemu-iotests/173 b/tests/qemu-iotests/173 index 1fe8c5d738..47036a5564 100755 --- a/tests/qemu-iotests/173 +++ b/tests/qemu-iotests/173 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test QAPI commands looking up protocol based images with relative # filename backing strings diff --git a/tests/qemu-iotests/174 b/tests/qemu-iotests/174 index d8bb05c4e2..0a952a73fd 100755 --- a/tests/qemu-iotests/174 +++ b/tests/qemu-iotests/174 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that qemu-io fail with non-zero exit code # diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175 index ebbeb6e74c..d0ffc495c2 100755 --- a/tests/qemu-iotests/175 +++ b/tests/qemu-iotests/175 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test creating raw image preallocation mode # diff --git a/tests/qemu-iotests/176 b/tests/qemu-iotests/176 index 4ecd5894a3..50df4c00fa 100755 --- a/tests/qemu-iotests/176 +++ b/tests/qemu-iotests/176 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Commit changes into backing chains and empty the top image if the # backing image is not explicitly specified. diff --git a/tests/qemu-iotests/177 b/tests/qemu-iotests/177 index f0c1155e80..752d29f8ad 100755 --- a/tests/qemu-iotests/177 +++ b/tests/qemu-iotests/177 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test corner cases with unusual block geometries # diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178 index 927bf06e4d..21231cadd3 100755 --- a/tests/qemu-iotests/178 +++ b/tests/qemu-iotests/178 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qemu-img measure sub-command tests # diff --git a/tests/qemu-iotests/179 b/tests/qemu-iotests/179 index 3040631636..9372dc30ef 100755 --- a/tests/qemu-iotests/179 +++ b/tests/qemu-iotests/179 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for write zeroes with unmap # diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181 index 0c44108dac..e317e63422 100755 --- a/tests/qemu-iotests/181 +++ b/tests/qemu-iotests/181 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test postcopy live migration with shared storage # diff --git a/tests/qemu-iotests/182 b/tests/qemu-iotests/182 index 9e078c5484..ff3d7e7ec1 100755 --- a/tests/qemu-iotests/182 +++ b/tests/qemu-iotests/182 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test image locking for POSIX locks # diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183 index ebb5e304ac..93b7bd798a 100755 --- a/tests/qemu-iotests/183 +++ b/tests/qemu-iotests/183 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test old-style block migration (migrate -b) # diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184 index 0af7a73aca..cb0c181228 100755 --- a/tests/qemu-iotests/184 +++ b/tests/qemu-iotests/184 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test I/O throttle block filter driver interface # diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185 index d8f1505cd8..454ff600cc 100755 --- a/tests/qemu-iotests/185 +++ b/tests/qemu-iotests/185 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test exiting qemu while jobs are still running # diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186 index c27dc953b6..5dd2177b89 100755 --- a/tests/qemu-iotests/186 +++ b/tests/qemu-iotests/186 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test 'info block' with all kinds of configurations # diff --git a/tests/qemu-iotests/187 b/tests/qemu-iotests/187 index 1feddca508..a45addde09 100755 --- a/tests/qemu-iotests/187 +++ b/tests/qemu-iotests/187 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test switching between read-only and read-write # diff --git a/tests/qemu-iotests/188 b/tests/qemu-iotests/188 index af40e496ee..be7278aa65 100755 --- a/tests/qemu-iotests/188 +++ b/tests/qemu-iotests/188 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test encrypted read/write using plain bdrv_read/bdrv_write # diff --git a/tests/qemu-iotests/189 b/tests/qemu-iotests/189 index 222bec133b..c9ce9d3bed 100755 --- a/tests/qemu-iotests/189 +++ b/tests/qemu-iotests/189 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test encrypted read/write using backing files # diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190 index 95ba06d8f4..e1c1d407f0 100755 --- a/tests/qemu-iotests/190 +++ b/tests/qemu-iotests/190 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qemu-img measure sub-command tests on huge qcow2 files # diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191 index 198272ea3b..1ea908ce3d 100755 --- a/tests/qemu-iotests/191 +++ b/tests/qemu-iotests/191 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test commit block job where top has two parents # diff --git a/tests/qemu-iotests/192 b/tests/qemu-iotests/192 index 415c706db5..158086f9d2 100755 --- a/tests/qemu-iotests/192 +++ b/tests/qemu-iotests/192 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test NBD export with -incoming (non-shared storage migration use case from # libvirt) diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195 index a977c9798e..bd1b71ae5e 100755 --- a/tests/qemu-iotests/195 +++ b/tests/qemu-iotests/195 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test change-backing-file command # diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197 index 8170f5d4ab..2c664793f4 100755 --- a/tests/qemu-iotests/197 +++ b/tests/qemu-iotests/197 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for copy-on-read into qcow2 # diff --git a/tests/qemu-iotests/198 b/tests/qemu-iotests/198 index 4d961f4f3a..c8f824cfae 100755 --- a/tests/qemu-iotests/198 +++ b/tests/qemu-iotests/198 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test commit of encrypted qcow2 files # diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200 index b9ebd5a8c7..12d25f4a1c 100755 --- a/tests/qemu-iotests/200 +++ b/tests/qemu-iotests/200 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Block job co-routine race condition test. # diff --git a/tests/qemu-iotests/201 b/tests/qemu-iotests/201 index c1a1e00077..7abf740fe4 100755 --- a/tests/qemu-iotests/201 +++ b/tests/qemu-iotests/201 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test savevm and loadvm after live migration with postcopy flag # diff --git a/tests/qemu-iotests/204 b/tests/qemu-iotests/204 index 30f0653ce9..abb73dc381 100755 --- a/tests/qemu-iotests/204 +++ b/tests/qemu-iotests/204 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test corner cases with unusual block geometries # diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214 index 7a2d5391bb..c1a452ff9a 100755 --- a/tests/qemu-iotests/214 +++ b/tests/qemu-iotests/214 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qcow2 image compression # diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215 index 230fd2551a..7b063d7cfa 100755 --- a/tests/qemu-iotests/215 +++ b/tests/qemu-iotests/215 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for copy-on-read into qcow2, using the COR filter driver # diff --git a/tests/qemu-iotests/217 b/tests/qemu-iotests/217 index d3ab5d72be..f5482bb669 100755 --- a/tests/qemu-iotests/217 +++ b/tests/qemu-iotests/217 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # I/O errors when working with internal qcow2 snapshots, and repairing # the result diff --git a/tests/qemu-iotests/220 b/tests/qemu-iotests/220 index 0c5682bda0..2d62c5dcac 100755 --- a/tests/qemu-iotests/220 +++ b/tests/qemu-iotests/220 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # max limits on compression in huge qcow2 files # diff --git a/tests/qemu-iotests/220.out b/tests/qemu-iotests/220.out index af3021fd88..33b994b8a1 100644 --- a/tests/qemu-iotests/220.out +++ b/tests/qemu-iotests/220.out @@ -38,7 +38,7 @@ wrote 2097152/2097152 bytes at offset 37748736 No errors were found on the image. image size 39845888 == Trying to write compressed cluster == -write failed: Input/output error +write failed: File too large image size 562949957615616 == Writing normal cluster == wrote 2097152/2097152 bytes at offset 0 diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221 index 06f48f1f23..808cd9a289 100755 --- a/tests/qemu-iotests/221 +++ b/tests/qemu-iotests/221 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qemu-img vs. unaligned images # diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 index f120a01646..98b6cc73af 100755 --- a/tests/qemu-iotests/223 +++ b/tests/qemu-iotests/223 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test reading dirty bitmap over NBD # diff --git a/tests/qemu-iotests/225 b/tests/qemu-iotests/225 index e42ee94ff0..fbd7404791 100755 --- a/tests/qemu-iotests/225 +++ b/tests/qemu-iotests/225 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test vmdk backing file correlation # diff --git a/tests/qemu-iotests/226 b/tests/qemu-iotests/226 index aec413b23c..c1e1fb2b1c 100755 --- a/tests/qemu-iotests/226 +++ b/tests/qemu-iotests/226 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # This test covers expected filetypes for the file, host_cdrom and # host_device drivers. diff --git a/tests/qemu-iotests/227 b/tests/qemu-iotests/227 index be1b636af0..10cf144eb0 100755 --- a/tests/qemu-iotests/227 +++ b/tests/qemu-iotests/227 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test query-blockstats with different ways to create a BB # diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229 index b0d4885fa6..e18a464fe0 100755 --- a/tests/qemu-iotests/229 +++ b/tests/qemu-iotests/229 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for force canceling a running blockjob that is paused in # an error state. diff --git a/tests/qemu-iotests/231 b/tests/qemu-iotests/231 index e9f8aaacd3..5b2cbab9ac 100755 --- a/tests/qemu-iotests/231 +++ b/tests/qemu-iotests/231 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test legacy and modern option parsing for rbd/ceph. This will not # actually connect to a ceph server, but rather looks for the appropriate diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232 index e48bc8f5db..71fd48eff0 100755 --- a/tests/qemu-iotests/232 +++ b/tests/qemu-iotests/232 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for auto-read-only # diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233 index adb742fafb..876cd5997b 100755 --- a/tests/qemu-iotests/233 +++ b/tests/qemu-iotests/233 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test NBD TLS certificate / authorization integration # diff --git a/tests/qemu-iotests/238 b/tests/qemu-iotests/238 index 688abc9acb..1c0a46fa90 100755 --- a/tests/qemu-iotests/238 +++ b/tests/qemu-iotests/238 @@ -23,17 +23,12 @@ import os import iotests from iotests import log -sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) - -from qemu import QEMUMachine - if iotests.qemu_default_machine == 's390-ccw-virtio': virtio_scsi_device = 'virtio-scsi-ccw' else: virtio_scsi_device = 'virtio-scsi-pci' -vm = QEMUMachine(iotests.qemu_prog) -vm.add_args('-machine', 'accel=kvm') +vm = iotests.VM() vm.launch() log(vm.qmp('blockdev-add', node_name='hd0', driver='null-co')) diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243 new file mode 100755 index 0000000000..5838c6e89c --- /dev/null +++ b/tests/qemu-iotests/243 @@ -0,0 +1,85 @@ +#!/bin/bash +# +# Test qcow2 preallocation +# +# Copyright (C) 2019 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" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + rm -f $TEST_IMG.data +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +for mode in off metadata falloc full; do + + echo + echo "=== preallocation=$mode ===" + echo + + IMGOPTS="preallocation=$mode" _make_test_img 64M + + printf "File size: " + du -b $TEST_IMG | cut -f1 + + # Can't use precise numbers here because they differ between filesystems + printf "Disk usage: " + [ $(du -B1 $TEST_IMG | cut -f1) -lt 1048576 ] && echo "low" || echo "high" + +done + +for mode in off metadata falloc full; do + + echo + echo "=== External data file: preallocation=$mode ===" + echo + + IMGOPTS="data_file=$TEST_IMG.data,preallocation=$mode" _make_test_img 64M + + echo -n "qcow2 file size: " + du -b $TEST_IMG | cut -f1 + echo -n "data file size: " + du -b $TEST_IMG.data | cut -f1 + + # Can't use precise numbers here because they differ between filesystems + echo -n "qcow2 disk usage: " + [ $(du -B1 $TEST_IMG | cut -f1) -lt 1048576 ] && echo "low" || echo "high" + echo -n "data disk usage: " + [ $(du -B1 $TEST_IMG.data | cut -f1) -lt 1048576 ] && echo "low" || echo "high" + +done + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/243.out b/tests/qemu-iotests/243.out new file mode 100644 index 0000000000..dcb33fac32 --- /dev/null +++ b/tests/qemu-iotests/243.out @@ -0,0 +1,58 @@ +QA output created by 243 + +=== preallocation=off === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=off +File size: 196616 +Disk usage: low + +=== preallocation=metadata === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=metadata +File size: 67436544 +Disk usage: low + +=== preallocation=falloc === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=falloc +File size: 67436544 +Disk usage: high + +=== preallocation=full === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=full +File size: 67436544 +Disk usage: high + +=== External data file: preallocation=off === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data preallocation=off +qcow2 file size: 196616 +data file size: 67108864 +qcow2 disk usage: low +data disk usage: low + +=== External data file: preallocation=metadata === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data preallocation=metadata +qcow2 file size: 327680 +data file size: 67108864 +qcow2 disk usage: low +data disk usage: low + +=== External data file: preallocation=falloc === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data preallocation=falloc +qcow2 file size: 327680 +data file size: 67108864 +qcow2 disk usage: low +data disk usage: high + +=== External data file: preallocation=full === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data preallocation=full +qcow2 file size: 327680 +data file size: 67108864 +qcow2 disk usage: low +data disk usage: high +*** done diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244 new file mode 100755 index 0000000000..d8e7122305 --- /dev/null +++ b/tests/qemu-iotests/244 @@ -0,0 +1,200 @@ +#!/bin/bash +# +# Test qcow2 with external data files +# +# Copyright (C) 2019 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" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + rm -f $TEST_IMG.data + rm -f $TEST_IMG.src +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +echo +echo "=== Create and open image with external data file ===" +echo + +echo "With data file name in the image:" +IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M +_check_test_img + +$QEMU_IO -c "open $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir +$QEMU_IO -c "open -odata-file.filename=$TEST_IMG.data $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir +$QEMU_IO -c "open -odata-file.filename=inexistent $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir + +echo +echo "Data file required, but without data file name in the image:" +$QEMU_IMG amend -odata_file= $TEST_IMG + +$QEMU_IO -c "open $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir +$QEMU_IO -c "open -odata-file.filename=$TEST_IMG.data $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir +$QEMU_IO -c "open -odata-file.filename=inexistent $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir + +echo +echo "Setting data-file for an image with internal data:" +_make_test_img 64M + +$QEMU_IO -c "open -odata-file.filename=$TEST_IMG.data $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir +$QEMU_IO -c "open -odata-file.filename=inexistent $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir + +echo +echo "=== Conflicting features ===" +echo + +echo "Convert to compressed target with data file:" +TEST_IMG="$TEST_IMG.src" _make_test_img 64M + +$QEMU_IO -c 'write -P 0x11 0 1M' \ + -f $IMGFMT "$TEST_IMG.src" | + _filter_qemu_io + +$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -c -odata_file="$TEST_IMG.data" \ + "$TEST_IMG.src" "$TEST_IMG" + +echo +echo "Convert uncompressed, then write compressed data manually:" +$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -odata_file="$TEST_IMG.data" \ + "$TEST_IMG.src" "$TEST_IMG" +$QEMU_IMG compare "$TEST_IMG.src" "$TEST_IMG" + +$QEMU_IO -c 'write -c -P 0x22 0 1M' \ + -f $IMGFMT "$TEST_IMG" | + _filter_qemu_io +_check_test_img + +echo +echo "Take an internal snapshot:" + +$QEMU_IMG snapshot -c test "$TEST_IMG" +_check_test_img + +echo +echo "=== Standalone image with external data file (efficient) ===" +echo + +IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M + +echo -n "qcow2 file size before I/O: " +du -b $TEST_IMG | cut -f1 + +# Create image with the following layout +# 0-1 MB: Unallocated +# 1-2 MB: Written (pattern 0x11) +# 2-3 MB: Discarded +# 3-4 MB: Zero write over discarded space +# 4-5 MB: Zero write over written space +# 5-6 MB: Zero write over unallocated space + +echo +$QEMU_IO -c 'write -P 0x11 1M 4M' \ + -c 'discard 2M 2M' \ + -c 'write -z 3M 3M' \ + -f $IMGFMT "$TEST_IMG" | + _filter_qemu_io +_check_test_img + +echo +$QEMU_IMG map --output=json "$TEST_IMG" + +echo +$QEMU_IO -c 'read -P 0 0 1M' \ + -c 'read -P 0x11 1M 1M' \ + -c 'read -P 0 2M 4M' \ + -f $IMGFMT "$TEST_IMG" | + _filter_qemu_io + +# Zero clusters are only marked as such in the qcow2 metadata, but contain +# stale data in the external data file +echo +$QEMU_IO -c 'read -P 0 0 1M' \ + -c 'read -P 0x11 1M 1M' \ + -c 'read -P 0 2M 2M' \ + -c 'read -P 0x11 4M 1M' \ + -c 'read -P 0 5M 1M' \ + -f raw "$TEST_IMG.data" | + _filter_qemu_io + + +echo -n "qcow2 file size after I/O: " +du -b $TEST_IMG | cut -f1 + +echo +echo "=== Standalone image with external data file (valid raw) ===" +echo + +IMGOPTS="data_file=$TEST_IMG.data,data_file_raw=on" _make_test_img 64M + +echo -n "qcow2 file size before I/O: " +du -b $TEST_IMG | cut -f1 + +echo +$QEMU_IO -c 'write -P 0x11 1M 4M' \ + -c 'discard 2M 2M' \ + -c 'write -z 3M 3M' \ + -f $IMGFMT "$TEST_IMG" | + _filter_qemu_io +_check_test_img + +echo +$QEMU_IMG map --output=json "$TEST_IMG" + +echo +$QEMU_IO -c 'read -P 0 0 1M' \ + -c 'read -P 0x11 1M 1M' \ + -c 'read -P 0 2M 4M' \ + -f $IMGFMT "$TEST_IMG" | + _filter_qemu_io + +echo +$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.data" + +echo -n "qcow2 file size after I/O: " +du -b $TEST_IMG | cut -f1 + +echo +echo "=== bdrv_co_block_status test for file and offset=0 ===" +echo + +IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M + +$QEMU_IO -c 'write -P 0x11 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c 'read -P 0x11 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io +$QEMU_IMG map --output=human "$TEST_IMG" | _filter_testdir +$QEMU_IMG map --output=json "$TEST_IMG" + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out new file mode 100644 index 0000000000..98e5946976 --- /dev/null +++ b/tests/qemu-iotests/244.out @@ -0,0 +1,125 @@ +QA output created by 244 + +=== Create and open image with external data file === + +With data file name in the image: +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data +No errors were found on the image. +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory +no file open, try 'help open' + +Data file required, but without data file name in the image: +can't open device TEST_DIR/t.qcow2: 'data-file' is required for this image +no file open, try 'help open' +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory +no file open, try 'help open' + +Setting data-file for an image with internal data: +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +can't open device TEST_DIR/t.qcow2: 'data-file' can only be set for images with an external data file +no file open, try 'help open' +can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory +no file open, try 'help open' + +=== Conflicting features === + +Convert to compressed target with data file: +Formatting 'TEST_DIR/t.IMGFMT.src', fmt=IMGFMT size=67108864 +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-img: error while writing sector 0: Operation not supported + +Convert uncompressed, then write compressed data manually: +Images are identical. +write failed: Operation not supported +No errors were found on the image. + +Take an internal snapshot: +qemu-img: Could not create snapshot 'test': -95 (Operation not supported) +No errors were found on the image. + +=== Standalone image with external data file (efficient) === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data +qcow2 file size before I/O: 196616 + +wrote 4194304/4194304 bytes at offset 1048576 +4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 2097152/2097152 bytes at offset 2097152 +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 3145728/3145728 bytes at offset 3145728 +3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +No errors were found on the image. + +[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false}, +{ "start": 1048576, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": 1048576}, +{ "start": 2097152, "length": 2097152, "depth": 0, "zero": true, "data": false}, +{ "start": 4194304, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": 4194304}, +{ "start": 5242880, "length": 61865984, "depth": 0, "zero": true, "data": false}] + +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4194304/4194304 bytes at offset 2097152 +4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 2097152/2097152 bytes at offset 2097152 +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 4194304 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 5242880 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qcow2 file size after I/O: 327680 + +=== Standalone image with external data file (valid raw) === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=on +qcow2 file size before I/O: 196616 + +wrote 4194304/4194304 bytes at offset 1048576 +4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 2097152/2097152 bytes at offset 2097152 +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 3145728/3145728 bytes at offset 3145728 +3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +No errors were found on the image. + +[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false}, +{ "start": 1048576, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": 1048576}, +{ "start": 2097152, "length": 2097152, "depth": 0, "zero": true, "data": false}, +{ "start": 4194304, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": 4194304}, +{ "start": 5242880, "length": 61865984, "depth": 0, "zero": true, "data": false}] + +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4194304/4194304 bytes at offset 2097152 +4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +Images are identical. +qcow2 file size after I/O: 327680 + +=== bdrv_co_block_status test for file and offset=0 === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Offset Length Mapped to File +0 0x100000 0 TEST_DIR/t.qcow2.data +[{ "start": 0, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": 0}, +{ "start": 1048576, "length": 66060288, "depth": 0, "zero": true, "data": false}] +*** done diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index 895e1e3dcb..f9c24b6753 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright (C) 2009 Red Hat, Inc. # Copyright (c) 2000-2002,2006 Silicon Graphics, Inc. All Rights Reserved. @@ -25,6 +25,7 @@ try=0 n_bad=0 bad="" notrun="" +casenotrun="" interrupt=true # by default don't output timestamps @@ -664,6 +665,11 @@ END { if (NR > 0) { echo "Not run:$notrun" echo "Not run:$notrun" >>check.log fi + if [ ! -z "$casenotrun" ] + then + echo "Some cases not run in:$casenotrun" + echo "Some cases not run in:$casenotrun" >>check.log + fi if [ ! -z "$n_bad" -a $n_bad != 0 ] then echo "Failures:$bad" @@ -743,6 +749,7 @@ do printf " " # prettier output with timestamps. fi rm -f core $seq.notrun + rm -f $seq.casenotrun start=$(_wallclock) $timestamp && printf %s " [$(date "+%T")]" @@ -823,7 +830,11 @@ do fi fi fi - + if [ -f $seq.casenotrun ] + then + cat $seq.casenotrun + casenotrun="$casenotrun $seq" + fi fi # come here for each test, except when $showme is true diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config index 9f460f203d..9bd1a5a6fc 100644 --- a/tests/qemu-iotests/common.config +++ b/tests/qemu-iotests/common.config @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright (C) 2009 Red Hat, Inc. # Copyright (c) 2000-2003,2006 Silicon Graphics, Inc. All Rights Reserved. diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 1aa7d57140..35fddc746f 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright (C) 2009 Red Hat, Inc. # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. @@ -23,37 +23,37 @@ # _filter_date() { - sed \ + $SED \ -e 's/[A-Z][a-z][a-z] [A-z][a-z][a-z] *[0-9][0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]$/DATE/' } _filter_generated_node_ids() { - sed -re 's/\#block[0-9]{3,}/NODE_NAME/' + $SED -re 's/\#block[0-9]{3,}/NODE_NAME/' } _filter_qom_path() { - sed -e 's#\(Attached to: *\) /.*#\1 PATH#' + $SED -e 's#\(Attached to: *\) /.*#\1 PATH#' } # replace occurrences of the actual TEST_DIR value with TEST_DIR _filter_testdir() { - sed -e "s#$TEST_DIR/#TEST_DIR/#g" + $SED -e "s#$TEST_DIR/#TEST_DIR/#g" } # replace occurrences of the actual IMGFMT value with IMGFMT _filter_imgfmt() { - sed -e "s#$IMGFMT#IMGFMT#g" + $SED -e "s#$IMGFMT#IMGFMT#g" } # Replace error message when the format is not supported and delete # the output lines after the first one _filter_qemu_img_check() { - sed -e '/allocated.*fragmented.*compressed clusters/d' \ + $SED -e '/allocated.*fragmented.*compressed clusters/d' \ -e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \ -e '/Image end offset: [0-9]\+/d' } @@ -61,13 +61,13 @@ _filter_qemu_img_check() # Removes \r from messages _filter_win32() { - sed -e 's/\r//g' + $SED -e 's/\r//g' } # sanitize qemu-io output _filter_qemu_io() { - _filter_win32 | sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \ + _filter_win32 | $SED -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \ -e "s/: line [0-9][0-9]*: *[0-9][0-9]*\( Aborted\| Killed\)/:\1/" \ -e "s/qemu-io> //g" } @@ -75,7 +75,7 @@ _filter_qemu_io() # replace occurrences of QEMU_PROG with "qemu" _filter_qemu() { - sed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \ + $SED -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \ -e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#' \ -e $'s#\r##' # QEMU monitor uses \r\n line endings } @@ -84,7 +84,7 @@ _filter_qemu() _filter_qmp() { _filter_win32 | \ - sed -e 's#\("\(micro\)\?seconds": \)[0-9]\+#\1 TIMESTAMP#g' \ + $SED -e 's#\("\(micro\)\?seconds": \)[0-9]\+#\1 TIMESTAMP#g' \ -e 's#^{"QMP":.*}$#QMP_VERSION#' \ -e '/^ "QMP": {\s*$/, /^ }\s*$/ c\' \ -e ' QMP_VERSION' @@ -93,32 +93,32 @@ _filter_qmp() # readline makes HMP command strings so long that git complains _filter_hmp() { - sed -e $'s/^\\((qemu) \\)\\?.*\e\\[D/\\1/g' \ + $SED -e $'s/^\\((qemu) \\)\\?.*\e\\[D/\\1/g' \ -e $'s/\e\\[K//g' } # replace block job offset _filter_block_job_offset() { - sed -e 's/, "offset": [0-9]\+,/, "offset": OFFSET,/' + $SED -e 's/, "offset": [0-9]\+,/, "offset": OFFSET,/' } # replace block job len _filter_block_job_len() { - sed -e 's/, "len": [0-9]\+,/, "len": LEN,/g' + $SED -e 's/, "len": [0-9]\+,/, "len": LEN,/g' } # replace actual image size (depends on the host filesystem) _filter_actual_image_size() { - sed -s 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' + $SED -s 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' } # replace driver-specific options in the "Formatting..." line _filter_img_create() { - sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ + $SED -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ -e "s#$TEST_DIR#TEST_DIR#g" \ -e "s#$IMGFMT#IMGFMT#g" \ @@ -154,7 +154,7 @@ _filter_img_info() discard=0 regex_json_spec_start='^ *"format-specific": \{' - sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ + $SED -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ -e "s#$TEST_DIR#TEST_DIR#g" \ -e "s#$IMGFMT#IMGFMT#g" \ @@ -201,7 +201,7 @@ _filter_img_info() # human and json output _filter_qemu_img_map() { - sed -e 's/\([0-9a-fx]* *[0-9a-fx]* *\)[0-9a-fx]* */\1/g' \ + $SED -e 's/\([0-9a-fx]* *[0-9a-fx]* *\)[0-9a-fx]* */\1/g' \ -e 's/"offset": [0-9]\+/"offset": OFFSET/g' \ -e 's/Mapped to *//' | _filter_testdir | _filter_imgfmt } @@ -213,7 +213,7 @@ _filter_nbd() # receive callbacks sometimes, making them unreliable. # # Filter out the TCP port number since this changes between runs. - sed -e '/nbd\/.*\.c:/d' \ + $SED -e '/nbd\/.*\.c:/d' \ -e 's#127\.0\.0\.1:[0-9]*#127.0.0.1:PORT#g' \ -e "s#?socket=$TEST_DIR#?socket=TEST_DIR#g" \ -e 's#\(foo\|PORT/\?\|.sock\): Failed to .*$#\1#' diff --git a/tests/qemu-iotests/common.nbd b/tests/qemu-iotests/common.nbd index 233187a25c..25fc9ffaa4 100644 --- a/tests/qemu-iotests/common.nbd +++ b/tests/qemu-iotests/common.nbd @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # -*- shell-script-mode -*- # # Helpers for NBD server related config diff --git a/tests/qemu-iotests/common.pattern b/tests/qemu-iotests/common.pattern index b67bb34136..25aa0d01c1 100644 --- a/tests/qemu-iotests/common.pattern +++ b/tests/qemu-iotests/common.pattern @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright (C) 2009 Red Hat, Inc. # diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu index 7c87b897fa..8d2021a7eb 100644 --- a/tests/qemu-iotests/common.qemu +++ b/tests/qemu-iotests/common.qemu @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # This allows for launching of multiple QEMU instances, with independent # communication possible to each instance. diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 09a27f02d0..a543e546c2 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright (C) 2009 Red Hat, Inc. # Copyright (c) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. @@ -17,6 +17,19 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # +SED= +for sed in sed gsed; do + ($sed --version | grep 'GNU sed') > /dev/null 2>&1 + if [ "$?" -eq 0 ]; then + SED=$sed + break + fi +done +if [ -z "$SED" ]; then + echo "$0: GNU sed not found" + exit 1 +fi + dd() { if [ "$HOSTOS" == "Linux" ] diff --git a/tests/qemu-iotests/common.tls b/tests/qemu-iotests/common.tls index 3caf989d28..54c331d7a5 100644 --- a/tests/qemu-iotests/common.tls +++ b/tests/qemu-iotests/common.tls @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Helpers for TLS related config # diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index b5ca63cf72..36100b803c 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -241,3 +241,5 @@ 239 rw auto quick 240 auto quick 242 rw auto quick +243 rw auto quick +244 rw auto quick diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 3d15571688..997dc910cb 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -712,10 +712,18 @@ def notrun(reason): # Each test in qemu-iotests has a number ("seq") seq = os.path.basename(sys.argv[0]) - open('%s/%s.notrun' % (output_dir, seq), 'wb').write(reason + '\n') + open('%s/%s.notrun' % (output_dir, seq), 'w').write(reason + '\n') print('%s not run: %s' % (seq, reason)) sys.exit(0) +def case_notrun(reason): + '''Skip this test case''' + # Each test in qemu-iotests has a number ("seq") + seq = os.path.basename(sys.argv[0]) + + open('%s/%s.casenotrun' % (output_dir, seq), 'a').write( + ' [case not run] ' + reason + '\n') + def verify_image_format(supported_fmts=[], unsupported_fmts=[]): assert not (supported_fmts and unsupported_fmts) @@ -756,6 +764,41 @@ def verify_quorum(): if not supports_quorum(): notrun('quorum support missing') +def qemu_pipe(*args): + '''Run qemu with an option to print something and exit (e.g. a help option), + and return its output''' + args = [qemu_prog] + qemu_opts + list(args) + subp = subprocess.Popen(args, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True) + exitcode = subp.wait() + if exitcode < 0: + sys.stderr.write('qemu received signal %i: %s\n' % (-exitcode, + ' '.join(args))) + return subp.communicate()[0] + +def supported_formats(read_only=False): + '''Set 'read_only' to True to check ro-whitelist + Otherwise, rw-whitelist is checked''' + format_message = qemu_pipe("-drive", "format=help") + line = 1 if read_only else 0 + return format_message.splitlines()[line].split(":")[1].split() + +def skip_if_unsupported(required_formats=[], read_only=False): + '''Skip Test Decorator + Runs the test if all the required formats are whitelisted''' + def skip_test_decorator(func): + def func_wrapper(*args, **kwargs): + usf_list = list(set(required_formats) - + set(supported_formats(read_only))) + if usf_list: + case_notrun('{}: formats {} are not whitelisted'.format( + args[0], usf_list)) + else: + return func(*args, **kwargs) + return func_wrapper + return skip_test_decorator + def main(supported_fmts=[], supported_oses=['linux'], supported_cache_modes=[], unsupported_fmts=[]): '''Run tests''' |