diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2021-03-30 14:06:54 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-03-30 14:06:54 +0100 |
commit | 4a0ba67c77a425436e867fcbb8c513b44d7e7d6e (patch) | |
tree | ad4e2dfd75e4e47b4c4959b1527daaab8016df7c | |
parent | 7993b0f83fe5c3f8555e79781d5d098f99751a94 (diff) | |
parent | 2ec7e8a94668efccf7f45634584cfa19a83fc553 (diff) |
Merge remote-tracking branch 'remotes/maxreitz/tags/pull-block-2021-03-30' into staging
Block patches for 6.0-rc1:
- Mark the qcow2 cache clean timer as external to fix record/replay
- Fix the mirror filter node's permissions so that an external process
cannot grab an image while it is used as the mirror source
- Add documentation about FUSE exports to the storage daemon
- When creating a qcow2 image with the data-file-raw option, all
metadata structures should be preallocated
- iotest fixes
# gpg: Signature made Tue 30 Mar 2021 13:38:40 BST
# gpg: using RSA key 91BEB60A30DB3E8857D11829F407DB0061D5CF40
# gpg: issuer "mreitz@redhat.com"
# gpg: Good signature from "Max Reitz <mreitz@redhat.com>" [full]
# Primary key fingerprint: 91BE B60A 30DB 3E88 57D1 1829 F407 DB00 61D5 CF40
* remotes/maxreitz/tags/pull-block-2021-03-30:
iotests/244: Test preallocation for data-file-raw
qcow2: Force preallocation with data-file-raw
qsd: Document FUSE exports
block/mirror: Fix mirror_top's permissions
iotests/046: Filter request length
qcow2: use external virtual timers
iotests/116: Fix reference output
iotests: fix 051.out expected output after error text touchups
iotests: Fix typo in iotest 051
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | block/mirror.c | 32 | ||||
-rw-r--r-- | block/qcow2.c | 41 | ||||
-rw-r--r-- | docs/tools/qemu-storage-daemon.rst | 19 | ||||
-rw-r--r-- | storage-daemon/qemu-storage-daemon.c | 4 | ||||
-rwxr-xr-x | tests/qemu-iotests/046 | 3 | ||||
-rw-r--r-- | tests/qemu-iotests/046.out | 104 | ||||
-rwxr-xr-x | tests/qemu-iotests/051 | 2 | ||||
-rw-r--r-- | tests/qemu-iotests/051.out | 6 | ||||
-rw-r--r-- | tests/qemu-iotests/051.pc.out | 4 | ||||
-rw-r--r-- | tests/qemu-iotests/116.out | 12 | ||||
-rwxr-xr-x | tests/qemu-iotests/244 | 104 | ||||
-rw-r--r-- | tests/qemu-iotests/244.out | 68 |
12 files changed, 319 insertions, 80 deletions
diff --git a/block/mirror.c b/block/mirror.c index 6af02a57c4..d7e54c0ff7 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -89,6 +89,7 @@ typedef struct MirrorBlockJob { typedef struct MirrorBDSOpaque { MirrorBlockJob *job; bool stop; + bool is_commit; } MirrorBDSOpaque; struct MirrorOp { @@ -1522,13 +1523,27 @@ static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c, return; } - /* Must be able to forward guest writes to the real image */ - *nperm = 0; - if (perm & BLK_PERM_WRITE) { - *nperm |= BLK_PERM_WRITE; - } + bdrv_default_perms(bs, c, role, reopen_queue, + perm, shared, nperm, nshared); - *nshared = BLK_PERM_ALL; + if (s->is_commit) { + /* + * For commit jobs, we cannot take CONSISTENT_READ, because + * that permission is unshared for everything above the base + * node (except for filters on the base node). + * We also have to force-share the WRITE permission, or + * otherwise we would block ourselves at the base node (if + * writes are blocked for a node, they are also blocked for + * its backing file). + * (We could also share RESIZE, because it may be needed for + * the target if its size is less than the top node's; but + * bdrv_default_perms_for_cow() automatically shares RESIZE + * for backing nodes if WRITE is shared, so there is no need + * to do it here.) + */ + *nperm &= ~BLK_PERM_CONSISTENT_READ; + *nshared |= BLK_PERM_WRITE; + } } /* Dummy node that provides consistent read to its users without requiring it @@ -1591,6 +1606,8 @@ static BlockJob *mirror_start_job( return NULL; } + target_is_backing = bdrv_chain_contains(bs, target); + /* In the case of active commit, add dummy driver to provide consistent * reads on the top, while disabling it in the intermediate nodes, and make * the backing chain writable. */ @@ -1613,6 +1630,8 @@ static BlockJob *mirror_start_job( bs_opaque = g_new0(MirrorBDSOpaque, 1); mirror_top_bs->opaque = bs_opaque; + bs_opaque->is_commit = target_is_backing; + /* bdrv_append takes ownership of the mirror_top_bs reference, need to keep * it alive until block_job_create() succeeds even if bs has no parent. */ bdrv_ref(mirror_top_bs); @@ -1653,7 +1672,6 @@ static BlockJob *mirror_start_job( target_perms = BLK_PERM_WRITE; target_shared_perms = BLK_PERM_WRITE_UNCHANGED; - target_is_backing = bdrv_chain_contains(bs, target); if (target_is_backing) { int64_t bs_size, target_size; bs_size = bdrv_getlength(bs); diff --git a/block/qcow2.c b/block/qcow2.c index 0db1227ac9..9727ae8fe3 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -840,9 +840,10 @@ static void cache_clean_timer_init(BlockDriverState *bs, AioContext *context) { BDRVQcow2State *s = bs->opaque; if (s->cache_clean_interval > 0) { - s->cache_clean_timer = aio_timer_new(context, QEMU_CLOCK_VIRTUAL, - SCALE_MS, cache_clean_timer_cb, - bs); + s->cache_clean_timer = + aio_timer_new_with_attrs(context, QEMU_CLOCK_VIRTUAL, + SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL, + cache_clean_timer_cb, bs); timer_mod(s->cache_clean_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + (int64_t) s->cache_clean_interval * 1000); } @@ -3502,6 +3503,28 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) ret = -EINVAL; goto out; } + if (qcow2_opts->data_file_raw && + qcow2_opts->preallocation == PREALLOC_MODE_OFF) + { + /* + * data-file-raw means that "the external data file can be + * read as a consistent standalone raw image without looking + * at the qcow2 metadata." It does not say that the metadata + * must be ignored, though (and the qcow2 driver in fact does + * not ignore it), so the L1/L2 tables must be present and + * give a 1:1 mapping, so you get the same result regardless + * of whether you look at the metadata or whether you ignore + * it. + */ + qcow2_opts->preallocation = PREALLOC_MODE_METADATA; + + /* + * Cannot use preallocation with backing files, but giving a + * backing file when specifying data_file_raw is an error + * anyway. + */ + assert(!qcow2_opts->has_backing_file); + } if (qcow2_opts->data_file) { if (version < 3) { @@ -4237,6 +4260,18 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, error_setg_errno(errp, -ret, "Failed to grow the L1 table"); goto fail; } + + if (data_file_is_raw(bs) && prealloc == PREALLOC_MODE_OFF) { + /* + * When creating a qcow2 image with data-file-raw, we enforce + * at least prealloc=metadata, so that the L1/L2 tables are + * fully allocated and reading from the data file will return + * the same data as reading from the qcow2 image. When the + * image is grown, we must consequently preallocate the + * metadata structures to cover the added area. + */ + prealloc = PREALLOC_MODE_METADATA; + } } switch (prealloc) { diff --git a/docs/tools/qemu-storage-daemon.rst b/docs/tools/qemu-storage-daemon.rst index 086493ebb3..3ec4bdd914 100644 --- a/docs/tools/qemu-storage-daemon.rst +++ b/docs/tools/qemu-storage-daemon.rst @@ -74,6 +74,7 @@ Standard options: .. option:: --export [type=]nbd,id=<id>,node-name=<node-name>[,name=<export-name>][,writable=on|off][,bitmap=<name>] --export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=unix,addr.path=<socket-path>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>] --export [type=]vhost-user-blk,id=<id>,node-name=<node-name>,addr.type=fd,addr.str=<fd>[,writable=on|off][,logical-block-size=<block-size>][,num-queues=<num-queues>] + --export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file>[,growable=on|off][,writable=on|off] is a block export definition. ``node-name`` is the block node that should be exported. ``writable`` determines whether or not the export allows write @@ -92,6 +93,16 @@ Standard options: ``logical-block-size`` sets the logical block size in bytes (the default is 512). ``num-queues`` sets the number of virtqueues (the default is 1). + The ``fuse`` export type takes a mount point, which must be a regular file, + on which to export the given block node. That file will not be changed, it + will just appear to have the block node's content while the export is active + (very much like mounting a filesystem on a directory does not change what the + directory contains, it only shows a different content while the filesystem is + mounted). Consequently, applications that have opened the given file before + the export became active will continue to see its original content. If + ``growable`` is set, writes after the end of the exported file will grow the + block node to fit. + .. option:: --monitor MONITORDEF is a QMP monitor definition. See the :manpage:`qemu(1)` manual page for @@ -196,6 +207,14 @@ domain socket ``vhost-user-blk.sock``:: --blockdev driver=qcow2,node-name=qcow2,file=file \ --export type=vhost-user-blk,id=export,addr.type=unix,addr.path=vhost-user-blk.sock,node-name=qcow2 +Export a qcow2 image file ``disk.qcow2`` via FUSE on itself, so the disk image +file will then appear as a raw image:: + + $ qemu-storage-daemon \ + --blockdev driver=file,node-name=file,filename=disk.qcow2 \ + --blockdev driver=qcow2,node-name=qcow2,file=file \ + --export type=fuse,id=export,node-name=qcow2,mountpoint=disk.qcow2,writable=on + See also -------- diff --git a/storage-daemon/qemu-storage-daemon.c b/storage-daemon/qemu-storage-daemon.c index 72900dc2ec..fc8b150629 100644 --- a/storage-daemon/qemu-storage-daemon.c +++ b/storage-daemon/qemu-storage-daemon.c @@ -98,6 +98,10 @@ static void help(void) " export the specified block node over NBD\n" " (requires --nbd-server)\n" "\n" +" --export [type=]fuse,id=<id>,node-name=<node-name>,mountpoint=<file>\n" +" [,growable=on|off][,writable=on|off]\n" +" export the specified block node over FUSE\n" +"\n" " --monitor [chardev=]name[,mode=control][,pretty[=on|off]]\n" " configure a QMP monitor\n" "\n" diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046 index 50b0678f60..517b162508 100755 --- a/tests/qemu-iotests/046 +++ b/tests/qemu-iotests/046 @@ -187,7 +187,8 @@ EOF } overlay_io | $QEMU_IO blkdebug::"$TEST_IMG" | _filter_qemu_io |\ - sed -e 's/bytes at offset [0-9]*/bytes at offset XXX/g' + sed -e 's/[0-9]*\/[0-9]* bytes at offset [0-9]*/XXX\/XXX bytes at offset XXX/g' \ + -e 's/^[0-9]* KiB/XXX KiB/g' echo echo "== Verify image content ==" diff --git a/tests/qemu-iotests/046.out b/tests/qemu-iotests/046.out index 66ad987ab3..b1a03f4041 100644 --- a/tests/qemu-iotests/046.out +++ b/tests/qemu-iotests/046.out @@ -71,74 +71,74 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR == Some concurrent requests touching the same cluster == blkdebug: Suspended request 'A' blkdebug: Resuming request 'A' -wrote 8192/8192 bytes at offset XXX -8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 8192/8192 bytes at offset XXX -8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 8192/8192 bytes at offset XXX -8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) blkdebug: Suspended request 'A' blkdebug: Resuming request 'A' -wrote 8192/8192 bytes at offset XXX -8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 65536/65536 bytes at offset XXX -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) blkdebug: Suspended request 'A' blkdebug: Resuming request 'A' -wrote 8192/8192 bytes at offset XXX -8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 65536/65536 bytes at offset XXX -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 32768/32768 bytes at offset XXX -32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) blkdebug: Suspended request 'A' blkdebug: Resuming request 'A' -wrote 8192/8192 bytes at offset XXX -8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 57344/57344 bytes at offset XXX -56 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 4096/4096 bytes at offset XXX -4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 32768/32768 bytes at offset XXX -32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -discard 65536/65536 bytes at offset XXX -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) blkdebug: Suspended request 'A' blkdebug: Resuming request 'A' -wrote 8192/8192 bytes at offset XXX -8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 57344/57344 bytes at offset XXX -56 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 4096/4096 bytes at offset XXX -4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 65536/65536 bytes at offset XXX -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -discard 65536/65536 bytes at offset XXX -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) blkdebug: Suspended request 'A' blkdebug: Resuming request 'A' -wrote 8192/8192 bytes at offset XXX -8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 57344/57344 bytes at offset XXX -56 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) blkdebug: Suspended request 'A' blkdebug: Resuming request 'A' -wrote 8192/8192 bytes at offset XXX -8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 98304/98304 bytes at offset XXX -96 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) blkdebug: Suspended request 'A' blkdebug: Resuming request 'A' -wrote 8192/8192 bytes at offset XXX -8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 81920/81920 bytes at offset XXX -80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) blkdebug: Suspended request 'A' blkdebug: Resuming request 'A' -wrote 32768/32768 bytes at offset XXX -32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -wrote 98304/98304 bytes at offset XXX -96 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote XXX/XXX bytes at offset XXX +XXX KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == Verify image content == read 65536/65536 bytes at offset 0 diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 333cc81818..7bf29343d7 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -199,7 +199,7 @@ case "$QEMU_DEFAULT_MACHINE" in # virtio-blk enables the iothread only when the driver initialises the # device, so a second virtio-blk device can't be added even with the # same iothread. virtio-scsi allows this. - run_qemu $iothread -device virtio-blk-pci,drive=disk,iohtread=iothread0,share-rw=on + run_qemu $iothread -device virtio-blk-pci,drive=disk,iothread=iothread0,share-rw=on run_qemu $iothread -device virtio-scsi,id=virtio-scsi1,iothread=thread0 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on ;; *) diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 437053c839..441f83e41a 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -61,13 +61,13 @@ QEMU X.Y.Z monitor - type 'help' for more information (qemu) quit Testing: -drive file=TEST_DIR/t.qcow2,node-name=123foo -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=123foo: Invalid node name +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=123foo: Invalid node-name: '123foo' Testing: -drive file=TEST_DIR/t.qcow2,node-name=_foo -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=_foo: Invalid node name +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=_foo: Invalid node-name: '_foo' Testing: -drive file=TEST_DIR/t.qcow2,node-name=foo#12 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=foo#12: Invalid node name +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,node-name=foo#12: Invalid node-name: 'foo#12' === Device without drive === diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out index e95bd42b8d..afe7632964 100644 --- a/tests/qemu-iotests/051.pc.out +++ b/tests/qemu-iotests/051.pc.out @@ -183,9 +183,9 @@ Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on: Cannot change iothread of active block backend -Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-blk-pci,drive=disk,iohtread=iothread0,share-rw=on +Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-blk-pci,drive=disk,iothread=iothread0,share-rw=on QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device virtio-blk-pci,drive=disk,iohtread=iothread0,share-rw=on: Cannot change iothread of active block backend +(qemu) QEMU_PROG: -device virtio-blk-pci,drive=disk,iothread=iothread0,share-rw=on: Cannot change iothread of active block backend Testing: -drive file=TEST_DIR/t.qcow2,if=none,node-name=disk -object iothread,id=thread0 -device virtio-scsi,iothread=thread0,id=virtio-scsi0 -device scsi-hd,bus=virtio-scsi0.0,drive=disk,share-rw=on -device virtio-scsi,id=virtio-scsi1,iothread=thread0 -device scsi-hd,bus=virtio-scsi1.0,drive=disk,share-rw=on QEMU X.Y.Z monitor - type 'help' for more information diff --git a/tests/qemu-iotests/116.out b/tests/qemu-iotests/116.out index 49f9a261a0..5f6c6fffca 100644 --- a/tests/qemu-iotests/116.out +++ b/tests/qemu-iotests/116.out @@ -2,7 +2,7 @@ QA output created by 116 == truncated header cluster == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -qemu-io: can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument +qemu-io: can't open device TEST_DIR/t.qed: QED table offset is invalid == invalid header magic == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 @@ -10,21 +10,21 @@ qemu-io: can't open device TEST_DIR/t.qed: Image not in QED format == invalid cluster size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -qemu-io: can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument +qemu-io: can't open device TEST_DIR/t.qed: QED cluster size is invalid == invalid table size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -qemu-io: can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument +qemu-io: can't open device TEST_DIR/t.qed: QED table size is invalid == invalid header size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -qemu-io: can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument +qemu-io: can't open device TEST_DIR/t.qed: QED table offset is invalid == invalid L1 table offset == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -qemu-io: can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument +qemu-io: can't open device TEST_DIR/t.qed: QED table offset is invalid == invalid image size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -qemu-io: can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument +qemu-io: can't open device TEST_DIR/t.qed: QED image size is invalid *** done diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244 index a46b441627..3e61fa25bb 100755 --- a/tests/qemu-iotests/244 +++ b/tests/qemu-iotests/244 @@ -38,6 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 # get standard environment, filters and checks . ./common.rc . ./common.filter +. ./common.qemu _supported_fmt qcow2 _supported_proto file @@ -267,6 +268,109 @@ case $result in ;; esac +echo +echo '=== Preallocation with data-file-raw ===' + +echo +echo '--- Using a non-zeroed data file ---' + +# Using data-file-raw must enforce at least metadata preallocation so +# that it does not matter whether one reads the raw file or the qcow2 +# file + +# Pre-create the data file, write some data. Real-world use cases for +# this are adding a qcow2 metadata file to a block device (i.e., using +# the device as the data file) or adding qcow2 features to pre-existing +# raw images (e.g. because the user now wants persistent dirty bitmaps). +truncate -s 1M "$TEST_IMG.data" +$QEMU_IO -f raw -c 'write -P 42 0 1M' "$TEST_IMG.data" | _filter_qemu_io + +# We cannot use qemu-img to create the qcow2 image, because it would +# clear the data file. Use the blockdev-create job instead, which will +# only format the qcow2 image file. +touch "$TEST_IMG" +_launch_qemu \ + -blockdev file,node-name=data,filename="$TEST_IMG.data" \ + -blockdev file,node-name=meta,filename="$TEST_IMG" + +_send_qemu_cmd $QEMU_HANDLE '{ "execute": "qmp_capabilities" }' 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + '{ "execute": "blockdev-create", + "arguments": { + "job-id": "create", + "options": { + "driver": "qcow2", + "size": '"$((1 * 1024 * 1024))"', + "file": "meta", + "data-file": "data", + "data-file-raw": true + } } }' \ + '"status": "concluded"' + +_send_qemu_cmd $QEMU_HANDLE \ + '{ "execute": "job-dismiss", "arguments": { "id": "create" } }' \ + 'return' + +_cleanup_qemu + +echo +echo 'Comparing pattern:' + +# Reading from either the qcow2 file or the data file should return +# the same result: +$QEMU_IO -f raw -c 'read -P 42 0 1M' "$TEST_IMG.data" | _filter_qemu_io +$QEMU_IO -f $IMGFMT -c 'read -P 42 0 1M' "$TEST_IMG" | _filter_qemu_io + +# For good measure +$QEMU_IMG compare -f raw "$TEST_IMG.data" "$TEST_IMG" + +echo +echo '--- Truncation (growing) ---' + +# Append some new data to the raw file, then resize the qcow2 image +# accordingly and see whether the new data is visible. Technically +# that is not allowed, but it is reasonable behavior, so test it. +truncate -s 2M "$TEST_IMG.data" +$QEMU_IO -f raw -c 'write -P 84 1M 1M' "$TEST_IMG.data" | _filter_qemu_io + +$QEMU_IMG resize "$TEST_IMG" 2M + +echo +echo 'Comparing pattern:' + +$QEMU_IO -f raw -c 'read -P 42 0 1M' -c 'read -P 84 1M 1M' "$TEST_IMG.data" \ + | _filter_qemu_io +$QEMU_IO -f $IMGFMT -c 'read -P 42 0 1M' -c 'read -P 84 1M 1M' "$TEST_IMG" \ + | _filter_qemu_io + +$QEMU_IMG compare -f raw "$TEST_IMG.data" "$TEST_IMG" + +echo +echo '--- Giving a backing file at runtime ---' + +# qcow2 files with data-file-raw cannot have backing files given by +# their image header, but qemu will allow you to set a backing node at +# runtime -- it should not have any effect, though (because reading +# from the qcow2 node should return the same data as reading from the +# raw node). + +_make_test_img -o "data_file=$TEST_IMG.data,data_file_raw=on" 1M +TEST_IMG="$TEST_IMG.base" _make_test_img 1M + +# Write something that is not zero into the base image +$QEMU_IO -c 'write -P 42 0 1M' "$TEST_IMG.base" | _filter_qemu_io + +echo +echo 'Comparing qcow2 image and raw data file:' + +# $TEST_IMG and $TEST_IMG.data must show the same data at all times; +# that is, the qcow2 node must not fall through to the backing image +# at any point +$QEMU_IMG compare --image-opts \ + "driver=raw,file.filename=$TEST_IMG.data" \ + "file.filename=$TEST_IMG,backing.file.filename=$TEST_IMG.base" + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out index 7269b4295a..99f56ac18c 100644 --- a/tests/qemu-iotests/244.out +++ b/tests/qemu-iotests/244.out @@ -83,7 +83,7 @@ qcow2 file size after I/O: 327680 === Standalone image with external data file (valid raw) === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=on -qcow2 file size before I/O: 196616 +qcow2 file size before I/O: 327680 wrote 4194304/4194304 bytes at offset 1048576 4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -93,11 +93,10 @@ wrote 3145728/3145728 bytes at offset 3145728 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) No errors were found on the image. -[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false}, -{ "start": 1048576, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": 1048576}, +[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 0}, { "start": 2097152, "length": 2097152, "depth": 0, "zero": true, "data": false}, -{ "start": 4194304, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": 4194304}, -{ "start": 5242880, "length": 61865984, "depth": 0, "zero": true, "data": false}] +{ "start": 4194304, "length": 2097152, "depth": 0, "zero": true, "data": false, "offset": 4194304}, +{ "start": 6291456, "length": 60817408, "depth": 0, "zero": false, "data": true, "offset": 6291456}] read 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -138,4 +137,63 @@ wrote 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) Success: qemu-io failed, so the data file was flushed + +=== Preallocation with data-file-raw === + +--- Using a non-zeroed data file --- +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{ "execute": "qmp_capabilities" } +{"return": {}} +{ "execute": "blockdev-create", + "arguments": { + "job-id": "create", + "options": { + "driver": "IMGFMT", + "size": 1048576, + "file": "meta", + "data-file": "data", + "data-file-raw": true + } } } +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "create"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "create"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "create"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "create"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "create"}} +{ "execute": "job-dismiss", "arguments": { "id": "create" } } +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "create"}} +{"return": {}} + +Comparing pattern: +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Images are identical. + +--- Truncation (growing) --- +wrote 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Image resized. + +Comparing pattern: +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Images are identical. + +--- Giving a backing file at runtime --- +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=on +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576 +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +Comparing qcow2 image and raw data file: +Images are identical. *** done |