mirror of https://gitee.com/openkylin/qemu.git
Block layer patches:
- qcow2: Support for external data files - qcow2: Default to 4KB for the qcow2 cache entry size - Apply block driver whitelist for -drive format=help - Several qemu-iotests improvements -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJcgmYDAAoJEH8JsnLIjy/WiEgP/jirn5n4bFHDSzpofRxgpcEG 2SoBpYtJQvAVgXmg8P1ZKeaX5yiiZpJS475ShuH6C3dnWuaHBBjvQfDkLLrh3v05 4KJyZQUFx0WQZqkEiHxtgmE3iIOAsWe8VzBCZjsFITdp+fN8HlRjKVofyYP0y48G k9PzMlEe30Wu2s+lq6PEIXgpwIZqOVl1V3C7wDF8Vg/1OOsv+rK0vKD8yra/oQAc mthM+hjkpa+ohjE5aTeCsDVxO56AStvXv0d3bE0aF/ZtCvQdbVh5coYj1ldNz6VY Bvx+UP7kPHJw0wesZJXLeVyZUMyHAuu9vW6zKlDYJ7PoIXSLXC7rYyoEofvkAzQL awSluFj4HpYU1dKseJ8LzrMyUqjJ2eLJ+K48iNIh0vNlVuvX8aR62dIv0Obo3rod Y7zgyd6mSgDGulDa3xVsD0+eAUUEbLaUDBV80+M7S2/V9YP4Bt7lKbm0SQB4dUxm eOJfnbMTpIYUUjYtpCkURED3MlTIA51fy28O87TMJwa11sJTXRscysE9oNQNsvwW 2UPhMPLykMI023glhV0vCwgXQ5kktOvpaB3U7LGQhhHd1ed9sdLEB1bO9eKWYr4N h6QPLBRLGUYd+BFMMIBLQtx8r+mAn1hUZoX4zxTn0lD50Rch3pRnCjMoC1iWqRkS J204Lzum5kgNPheyVxhy =GCRI -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block layer patches: - qcow2: Support for external data files - qcow2: Default to 4KB for the qcow2 cache entry size - Apply block driver whitelist for -drive format=help - Several qemu-iotests improvements # gpg: Signature made Fri 08 Mar 2019 12:54:27 GMT # gpg: using RSA key 7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full] # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: (33 commits) qcow2 spec: Describe string header extensions qemu-iotests: Add dependency to qemu-nbd tool ahci-test: Add dependency to qemu-img tool qemu-iotests: amend with external data file qemu-iotests: General tests for qcow2 with external data file qemu-iotests: Preallocation with external data file qcow2: Implement data-file-raw create option qcow2: Store data file name in the image qcow2: Creating images with external data file qcow2: Add basic data-file infrastructure qcow2: Support external data file in qemu-img check qcow2: Return error for snapshot operation with data file qcow2: External file I/O qcow2: Prepare qcow2_co_block_status() for data file qcow2: Return 0/-errno in qcow2_alloc_compressed_cluster_offset() qcow2: Don't assume 0 is an invalid cluster offset qcow2: Prepare count_contiguous_clusters() for external data file qcow2: Prepare qcow2_get_cluster_type() for external data file qcow2: Pass bs to qcow2_get_cluster_type() qcow2: Basic definitions for external data files ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
4c76137484
23
block.c
23
block.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
326
block/qcow2.c
326
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);
|
||||
|
@ -2428,6 +2519,11 @@ int qcow2_update_header(BlockDriverState *bs)
|
|||
.bit = QCOW2_INCOMPAT_CORRUPT_BITNR,
|
||||
.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,
|
||||
|
@ -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,
|
||||
|
@ -4951,6 +5163,16 @@ static QemuOptsList qcow2_create_opts = {
|
|||
.type = QEMU_OPT_STRING,
|
||||
.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,
|
||||
|
|
|
@ -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_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_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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com>
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test simple read/write using plain bdrv_read/bdrv_write
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test simple read/write using plain bdrv_pread/bdrv_pwrite
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test simple read/write using bdrv_aio_readv/bdrv_aio_writev
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Make sure we can't read and write outside of the image size.
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Make sure qemu-img can create 5TB images
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Check for one possible case of qcow2 refcount corruption.
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test simple asynchronous read/write operations.
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Nolan I qcow2 corruption - incorrectly reports free clusters
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Nolan II qcow2 corruption - wrong used cluster
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test for AIO allocation on the same cluster
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Make sure we can open read-only images
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# qcow2 pattern test, empty and compressed image - 4k cluster patterns
|
||||
#
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Combined test to grow the refcount table and test snapshots.
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Simple backing file reads
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Merge backing file into test image when converting the image
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Commit changes to backing file
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test handling of invalid patterns arguments to qemu-io
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test bdrv_load/save_vmstate using the usual patterns
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# qcow2 pattern test with various cluster sizes
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Rebasing COW images
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Resizing images
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# qcow2 error path testing
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test that sub-cluster allocating writes zero the rest of the cluster
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test that backing files can be smaller than the image
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# qcow2 internal snapshots/VM state tests
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test that all qcow2 header extensions survive a header rewrite
|
||||
#
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test aligned and misaligned write zeroes operations.
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test bdrv_pwrite_zeroes with backing files (see also 154)
|
||||
#
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test qcow2 feature bits
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test COW from backing files
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test COW from backing files with AIO
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test qcow2 lazy refcounts
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test qemu-img operation on zero size images
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test that qemu-img info --backing-chain detects infinite loops
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test concurrent cluster allocations
|
||||
#
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
##
|
||||
## qemu-img compare test
|
||||
##
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Check qemu-img option parsing
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test qemu-img rebase with zero clusters
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test command line configuration of block devices and driver-specific options
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test bdrv_read/bdrv_write using BDRV_O_SNAPSHOT
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test qemu-img convert when image length is not a multiple of cluster size
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test huge qcow2 images
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test export internal snapshot by qemu-nbd, convert it by qemu-img.
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test case for vmdk
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test case for image corruption (overlapping data structures) in qcow2
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test case for snapshotting images with unallocated zero clusters in
|
||||
# qcow2
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# test of qemu-img convert -n - convert without creation
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test VHDX read/write from a sample image created with Hyper-V
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test case for preallocated zero clusters in qcow2
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test automatic deletion of BDSes created by -drive/drive_add
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test case for loading a saved VM state from a qcow2 image
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test case for deleting a backing file
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test case for the QMP blkdebug and blkverify interfaces
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test case for nested image formats
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test count_contiguous_clusters in qcow2
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
##
|
||||
## qemu-img compare test (qcow2 only ones)
|
||||
##
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# cloop format input validation tests
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# parallels format input validation tests
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test concurrent pread/pwrite
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# bochs format input validation tests
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test qcow2 preallocation with different cluster_sizes
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# qcow2 format input validation tests
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test Quorum block driver
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test qemu-img command line parsing
|
||||
#
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test NBD client unexpected disconnect
|
||||
#
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Live snapshot tests
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test qemu-img progress output
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test unsupported blockdev-add cases
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# vpc (VHD) format input validation tests
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test case for support of JSON filenames
|
||||
#
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Test for discarding compressed clusters on qcow2 images
|
||||
#
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue