diff options
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 3ee524d..9d968bd 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 d9dafa3..df02e7b 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 179aa2c..974a4e8 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 6f13d47..e0fe322 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 20e8472..a6ffae8 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 7fb2730..c4dd876 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 9dd02df..de2a3bd 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); @@ -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 fb5cb47..8c3098d 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 c1e7751..d57f409 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 5b5cf86..6a758a7 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 836d67c..a23caba 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 2b8afbb..919d053 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', @@ -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 44af415..a571955 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 6c33003..98df91e 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 55dcbb7..5d266e1 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 74572b4..7fb8508 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 bf25955..f008c57 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 841b15d..64fab3e 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 8aa4283..2fef63a 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 b983022..3ab5490 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 8dfa10b..75067e3 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 73ae09d..bc4b461 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 751aca9..6920408 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 3590956..b4c7e8f 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 de9a5fb..2c3b42d 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 5e1efce..5cb9032 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 9ade571..2f728a1 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 21f7d42..5a4063e 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 1ac6f74..83744f2 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 bba30a1..7816983 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 8f911a7..a56dd30 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 6b972d0..71fa753 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 c15ebf9..f6555f3 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 44765c7..b68cd64 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 c8e1b9a..02ed047 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 428b5c8..23298c6 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 fcd4d97..d9a4ebc 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 31276d9..ca89ad7 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 2c46ae1..b7df970 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 a2a7c93..01f4959 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 cf0fe0f..5f42f76 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 ac0dfae..ef92d8e 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 7f5050b..68a74d0 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 3e86bb0..a1757bb 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 46b9138..cfdf1ec 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 62812cd..324bed2 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 85d9ef7..46aa835 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 4e76602..1b56394 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 9b009b8..e489b44 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 a11992d..0781beb 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 575093e..707e2d7 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 b3c344c..0d4e963 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 beaa339..a9a7fc3 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 fc9005b..9894b15 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 5e41d96..95160be 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 6e776d2..ce81fc6 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 9ed04a0..bde408c 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 97d8a64..bc09cd6 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 963a0db..dd7b2c7 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 32741d7..3b50c7f 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 b992adf..b3a2dc1 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 afa109c..50c62f0 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 cf88a7c..0d5e14f 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 d6d4f94..8c3212a 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 54d5567..279aee6 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 af0588a..89e9114 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 1a50163..d7dbd7e 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 183f7dd..9fe1ec7 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 985fbef..ed7400f 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 041fb5c..2d5c0ce 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 f55ff37..9067318 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 26c0437..f480986 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 342b2b0..fda16a6 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 f0583d5..881a022 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 fdee121..6a8e4aa 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 78e0390..cb0f927 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 6e467dc..7f3e5abd 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 08ef29f..6f9f247 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 5e7f76c..990f90a 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 b17866b..bb4ad1c 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 45b8901..389d567 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 3b5ab3f..0d405ef 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 58fe893..c284952 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 68d0ea8..54fc654 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 fca2f77..1b6594e 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 cec2376..4bcb502 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 edf6e61..c418bab 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 61eec63..d0afa46 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 0ce18c0..9156406 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 89f67db..b270550 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 e131fa9..c29d739 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 ade68ef..68cb665 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 3cca368..fea1a7b 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 f625887..d6c8613 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 c5e9ab4..b44edd0 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 3165d79..6609954 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 1450993..193bae7 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 2f2f98e..d62ef18 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 8e318f1..e2e0726 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 7adc9b9..0bcca77 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 9fc47f6..18505b7 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 7234b16..690f3d3 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 c7977da..461144c 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 578808b..ae02f27 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 3001ba3..a4c1b63 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 29a6a94..cedd2b2 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 66f8167..6773e94 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 34bb0d2..390167b 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 943bda2..3b5a596 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 4129fee..ac47eaa 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 5d70ad2..fcd5a24 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 58e8ad7..9c08172 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 b51e461..9897ceb 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 185ad54..fad672c 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 e15e66a..57395be 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 d67e6eb..6d81c75 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 d8d78c4..f2703a2 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 e17fb51..f36b88f 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 0581e03..7ed3470 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 f8a27b9..941b07a 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 e533e23..0af0f31 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 32810d5..ea6770a 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 76afdf4..ca95b92 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 d2885c7..90a0424 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 eab3399..85c3a8d 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 168b985..d33950e 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 778c874..212dcd8 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 9114838..96dc048 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 c9139ed..3e941f7 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 925f5c7..3606c41 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 f2f2706..77ad2aa 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 58c25f7..2787023 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 565e0b1..1f6056d 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 cacabcd..e9e3e84 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 a18a0c7..3b3d1dc 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 09cd445..0c3d2a1 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 eccbcae..f353ac8 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 62402c1..933b451 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 d4623b5..b965b1d 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 e2408c7..2197a82 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 5fc488f..d9b98cf 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 d6302cc..c223867 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 118c099..15157f3 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 6ce8a46..28878dc 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 3f61351..2e43abd 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 955b877..3b1f321 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 3120a61..c989c24 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 4a4abf0..d68f66b 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 f97f96f..8d13402 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 6fb2659..69b25ca 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 d277ddc..8c0928a 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 e74b273..29066ee 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 92fff45..df89d38 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 180df17..456a4bd 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 ef02d84..2e9947f 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 861eabf..7deb756 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 5b46069..341064a 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 1e60a7e..ba7dad9 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 1fe8c5d..47036a5 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 d8bb05c..0a952a7 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 ebbeb6e..d0ffc49 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 4ecd589..50df4c0 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 f0c1155..752d29f 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 927bf06..21231ca 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 3040631..9372dc3 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 0c44108..e317e63 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 9e078c5..ff3d7e7 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 ebb5e30..93b7bd7 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 0af7a73..cb0c181 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 d8f1505..454ff60 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 c27dc95..5dd2177 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 1feddca..a45addd 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 af40e49..be7278a 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 222bec1..c9ce9d3 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 95ba06d..e1c1d40 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 198272e..1ea908c 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 415c706..158086f 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 a977c97..bd1b71a 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 8170f5d..2c66479 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 4d961f4..c8f824c 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 b9ebd5a..12d25f4 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 c1a1e00..7abf740 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 30f0653..abb73dc 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 7a2d539..c1a452f 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 230fd25..7b063d7 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 d3ab5d7..f5482bb 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 0c5682b..2d62c5d 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 af3021f..33b994b 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 06f48f1..808cd9a 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 f120a01..98b6cc7 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 e42ee94..fbd7404 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 aec413b..c1e1fb2 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 be1b636..10cf144 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 b0d4885..e18a464 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 e9f8aaa..5b2cbab 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 e48bc8f..71fd48e 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 adb742f..876cd59 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 688abc9..1c0a46f 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 0000000..5838c6e --- /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 0000000..dcb33fa --- /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 0000000..d8e7122 --- /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 0000000..98e5946 --- /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 895e1e3..f9c24b6 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 9f460f2..9bd1a5a 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 1aa7d57..35fddc7 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 233187a..25fc9ff 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 b67bb34..25aa0d0 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 7c87b89..8d2021a 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 09a27f0..a543e54 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 3caf989..54c331d 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 b5ca63c..36100b8 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 3d15571..997dc91 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''' |