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:
Peter Maydell 2019-03-09 14:43:39 +00:00
commit 4c76137484
215 changed files with 1583 additions and 421 deletions

23
block.c
View file

@ -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);
}

View file

@ -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;

View file

@ -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) {

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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,

View file

@ -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);

View file

@ -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;
}

View file

@ -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)

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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',

View file

@ -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);
}

View file

@ -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))

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com>
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test simple read/write using plain bdrv_read/bdrv_write
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test simple read/write using plain bdrv_pread/bdrv_pwrite
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test simple read/write using bdrv_aio_readv/bdrv_aio_writev
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Make sure we can't read and write outside of the image size.
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Make sure qemu-img can create 5TB images
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Check for one possible case of qcow2 refcount corruption.
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test simple asynchronous read/write operations.
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Nolan I qcow2 corruption - incorrectly reports free clusters
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Nolan II qcow2 corruption - wrong used cluster
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test for AIO allocation on the same cluster
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Make sure we can open read-only images
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# qcow2 pattern test, empty and compressed image - 4k cluster patterns
#

View file

@ -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.

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Combined test to grow the refcount table and test snapshots.
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Simple backing file reads
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Merge backing file into test image when converting the image
#

View file

@ -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

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Commit changes to backing file
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test handling of invalid patterns arguments to qemu-io
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test bdrv_load/save_vmstate using the usual patterns
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# qcow2 pattern test with various cluster sizes
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Rebasing COW images
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Resizing images
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# qcow2 error path testing
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test that sub-cluster allocating writes zero the rest of the cluster
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test that backing files can be smaller than the image
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# qcow2 internal snapshots/VM state tests
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test that all qcow2 header extensions survive a header rewrite
#

View file

@ -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:

View file

@ -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

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test aligned and misaligned write zeroes operations.
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test bdrv_pwrite_zeroes with backing files (see also 154)
#

View file

@ -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.

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test qcow2 feature bits
#

View file

@ -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

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test COW from backing files
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test COW from backing files with AIO
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test qcow2 lazy refcounts
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test qemu-img operation on zero size images
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test that qemu-img info --backing-chain detects infinite loops
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test concurrent cluster allocations
#

View file

@ -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)

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
##
## qemu-img compare test
##

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Check qemu-img option parsing
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test qemu-img rebase with zero clusters
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test command line configuration of block devices and driver-specific options
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test bdrv_read/bdrv_write using BDRV_O_SNAPSHOT
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test qemu-img convert when image length is not a multiple of cluster size
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test huge qcow2 images
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test export internal snapshot by qemu-nbd, convert it by qemu-img.
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test case for vmdk
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test case for image corruption (overlapping data structures) in qcow2
#

View file

@ -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

View file

@ -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

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test case for snapshotting images with unallocated zero clusters in
# qcow2

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# test of qemu-img convert -n - convert without creation
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test VHDX read/write from a sample image created with Hyper-V
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test case for preallocated zero clusters in qcow2
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test automatic deletion of BDSes created by -drive/drive_add
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test case for loading a saved VM state from a qcow2 image
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test case for deleting a backing file
#

View 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

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test case for the QMP blkdebug and blkverify interfaces
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test case for nested image formats
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test count_contiguous_clusters in qcow2
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
##
## qemu-img compare test (qcow2 only ones)
##

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# cloop format input validation tests
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# parallels format input validation tests
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test concurrent pread/pwrite
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# bochs format input validation tests
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test qcow2 preallocation with different cluster_sizes
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# qcow2 format input validation tests
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test Quorum block driver
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test qemu-img command line parsing
#

View file

@ -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'

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test NBD client unexpected disconnect
#

View file

@ -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.

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Live snapshot tests
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test qemu-img progress output
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test unsupported blockdev-add cases
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# vpc (VHD) format input validation tests
#

View file

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Test case for support of JSON filenames
#

View file

@ -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