1 | The following changes since commit a395717cbd26e7593d3c3fe81faca121ec6d13e8: | 1 | The following changes since commit ba49d760eb04630e7b15f423ebecf6c871b8f77b: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/cody/tags/block-pull-request' into staging (2018-07-03 11:49:51 +0100) | 3 | Merge tag 'pull-maintainer-final-130324-1' of https://gitlab.com/stsquad/qemu into staging (2024-03-13 15:12:14 +0000) |
4 | 4 | ||
5 | are available in the git repository at: | 5 | are available in the Git repository at: |
6 | 6 | ||
7 | git://repo.or.cz/qemu/kevin.git tags/for-upstream | 7 | https://repo.or.cz/qemu/kevin.git tags/for-upstream |
8 | 8 | ||
9 | for you to fetch changes up to 59738025a1674bb7e07713c3c93ff4fb9c5079f5: | 9 | for you to fetch changes up to 39a94d7c34ce9d222fa9c0c99a14e20a567456d7: |
10 | 10 | ||
11 | block: Add blklogwrites (2018-07-03 16:09:48 +0200) | 11 | iotests: adapt to output change for recently introduced 'detached header' field (2024-03-18 13:33:54 +0100) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | Block layer patches: | 14 | Block layer patches |
15 | 15 | ||
16 | - qcow2: Use worker threads for compression to improve performance of | 16 | - mirror: Fix deadlock |
17 | 'qemu-img convert -W' and compressed backup jobs | 17 | - nbd/server: Fix race in draining the export |
18 | - blklogwrites: New filter driver to log write requests to an image in | 18 | - qemu-img snapshot: Fix formatting with large values |
19 | the dm-log-writes format | 19 | - Fix blockdev-snapshot-sync error reporting for no medium |
20 | - iotests fixes | ||
20 | 21 | ||
21 | ---------------------------------------------------------------- | 22 | ---------------------------------------------------------------- |
22 | Aapo Vienamo (1): | 23 | Abhiram Tilak (1): |
23 | block: Add blklogwrites | 24 | qemu-img: Fix Column Width and Improve Formatting in snapshot list |
24 | 25 | ||
25 | Ari Sundholm (1): | 26 | Fiona Ebner (1): |
26 | block: Move two block permission constants to the relevant enum | 27 | iotests: adapt to output change for recently introduced 'detached header' field |
27 | 28 | ||
28 | Vladimir Sementsov-Ogievskiy (3): | 29 | Kevin Wolf (3): |
29 | qemu-img: allow compressed not-in-order writes | 30 | mirror: Don't call job_pause_point() under graph lock |
30 | qcow2: refactor data compression | 31 | nbd/server: Fix race in draining the export |
31 | qcow2: add compress threads | 32 | iotests: Add test for reset/AioContext switches with NBD exports |
32 | 33 | ||
33 | qapi/block-core.json | 33 ++++- | 34 | Markus Armbruster (1): |
34 | block/qcow2.h | 3 + | 35 | blockdev: Fix blockdev-snapshot-sync error reporting for no medium |
35 | include/block/block.h | 7 + | ||
36 | block.c | 6 - | ||
37 | block/blklogwrites.c | 392 ++++++++++++++++++++++++++++++++++++++++++++++++++ | ||
38 | block/qcow2.c | 136 ++++++++++++++---- | ||
39 | qemu-img.c | 5 - | ||
40 | MAINTAINERS | 6 + | ||
41 | block/Makefile.objs | 1 + | ||
42 | 9 files changed, 545 insertions(+), 44 deletions(-) | ||
43 | create mode 100644 block/blklogwrites.c | ||
44 | 36 | ||
37 | Thomas Huth (9): | ||
38 | tests/qemu-iotests: Fix test 033 for running with non-file protocols | ||
39 | tests/qemu-iotests: Restrict test 066 to the 'file' protocol | ||
40 | tests/qemu-iotests: Restrict test 114 to the 'file' protocol | ||
41 | tests/qemu-iotests: Restrict test 130 to the 'file' protocol | ||
42 | tests/qemu-iotests: Restrict test 134 and 158 to the 'file' protocol | ||
43 | tests/qemu-iotests: Restrict test 156 to the 'file' protocol | ||
44 | tests/qemu-iotests: Restrict tests that use --image-opts to the 'file' protocol | ||
45 | tests/qemu-iotests: Fix some tests that use --image-opts for other protocols | ||
46 | tests/qemu-iotests: Restrict tests using "--blockdev file" to the file protocol | ||
47 | |||
48 | include/qemu/job.h | 2 +- | ||
49 | block/mirror.c | 10 ++-- | ||
50 | block/qapi.c | 10 ++-- | ||
51 | blockdev.c | 3 +- | ||
52 | nbd/server.c | 15 +++-- | ||
53 | tests/qemu-iotests/033 | 6 +- | ||
54 | tests/qemu-iotests/066 | 2 +- | ||
55 | tests/qemu-iotests/114 | 2 +- | ||
56 | tests/qemu-iotests/130 | 2 +- | ||
57 | tests/qemu-iotests/134 | 2 +- | ||
58 | tests/qemu-iotests/156 | 2 +- | ||
59 | tests/qemu-iotests/158 | 2 +- | ||
60 | tests/qemu-iotests/176.out | 16 +++--- | ||
61 | tests/qemu-iotests/188 | 2 +- | ||
62 | tests/qemu-iotests/189 | 2 +- | ||
63 | tests/qemu-iotests/198 | 2 +- | ||
64 | tests/qemu-iotests/198.out | 2 + | ||
65 | tests/qemu-iotests/206.out | 1 + | ||
66 | tests/qemu-iotests/261 | 4 +- | ||
67 | tests/qemu-iotests/263 | 6 +- | ||
68 | tests/qemu-iotests/267.out | 48 ++++++++-------- | ||
69 | tests/qemu-iotests/284 | 7 +-- | ||
70 | tests/qemu-iotests/286 | 3 +- | ||
71 | tests/qemu-iotests/286.out | 2 +- | ||
72 | .../tests/detect-zeroes-registered-buf | 4 +- | ||
73 | tests/qemu-iotests/tests/iothreads-nbd-export | 66 ++++++++++++++++++++++ | ||
74 | tests/qemu-iotests/tests/iothreads-nbd-export.out | 19 +++++++ | ||
75 | tests/qemu-iotests/tests/qcow2-internal-snapshots | 2 +- | ||
76 | .../tests/qcow2-internal-snapshots.out | 14 ++--- | ||
77 | tests/qemu-iotests/tests/qsd-jobs | 2 +- | ||
78 | 30 files changed, 178 insertions(+), 82 deletions(-) | ||
79 | create mode 100755 tests/qemu-iotests/tests/iothreads-nbd-export | ||
80 | create mode 100644 tests/qemu-iotests/tests/iothreads-nbd-export.out | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | Calling job_pause_point() while holding the graph reader lock | ||
2 | potentially results in a deadlock: bdrv_graph_wrlock() first drains | ||
3 | everything, including the mirror job, which pauses it. The job is only | ||
4 | unpaused at the end of the drain section, which is when the graph writer | ||
5 | lock has been successfully taken. However, if the job happens to be | ||
6 | paused at a pause point where it still holds the reader lock, the writer | ||
7 | lock can't be taken as long as the job is still paused. | ||
1 | 8 | ||
9 | Mark job_pause_point() as GRAPH_UNLOCKED and fix mirror accordingly. | ||
10 | |||
11 | Cc: qemu-stable@nongnu.org | ||
12 | Buglink: https://issues.redhat.com/browse/RHEL-28125 | ||
13 | Fixes: 004915a96a7a ("block: Protect bs->backing with graph_lock") | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | Message-ID: <20240313153000.33121-1-kwolf@redhat.com> | ||
16 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
18 | --- | ||
19 | include/qemu/job.h | 2 +- | ||
20 | block/mirror.c | 10 ++++++---- | ||
21 | 2 files changed, 7 insertions(+), 5 deletions(-) | ||
22 | |||
23 | diff --git a/include/qemu/job.h b/include/qemu/job.h | ||
24 | index XXXXXXX..XXXXXXX 100644 | ||
25 | --- a/include/qemu/job.h | ||
26 | +++ b/include/qemu/job.h | ||
27 | @@ -XXX,XX +XXX,XX @@ void job_enter(Job *job); | ||
28 | * | ||
29 | * Called with job_mutex *not* held. | ||
30 | */ | ||
31 | -void coroutine_fn job_pause_point(Job *job); | ||
32 | +void coroutine_fn GRAPH_UNLOCKED job_pause_point(Job *job); | ||
33 | |||
34 | /** | ||
35 | * @job: The job that calls the function. | ||
36 | diff --git a/block/mirror.c b/block/mirror.c | ||
37 | index XXXXXXX..XXXXXXX 100644 | ||
38 | --- a/block/mirror.c | ||
39 | +++ b/block/mirror.c | ||
40 | @@ -XXX,XX +XXX,XX @@ static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset, | ||
41 | return bytes_handled; | ||
42 | } | ||
43 | |||
44 | -static void coroutine_fn GRAPH_RDLOCK mirror_iteration(MirrorBlockJob *s) | ||
45 | +static void coroutine_fn GRAPH_UNLOCKED mirror_iteration(MirrorBlockJob *s) | ||
46 | { | ||
47 | - BlockDriverState *source = s->mirror_top_bs->backing->bs; | ||
48 | + BlockDriverState *source; | ||
49 | MirrorOp *pseudo_op; | ||
50 | int64_t offset; | ||
51 | /* At least the first dirty chunk is mirrored in one iteration. */ | ||
52 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn GRAPH_RDLOCK mirror_iteration(MirrorBlockJob *s) | ||
53 | bool write_zeroes_ok = bdrv_can_write_zeroes_with_unmap(blk_bs(s->target)); | ||
54 | int max_io_bytes = MAX(s->buf_size / MAX_IN_FLIGHT, MAX_IO_BYTES); | ||
55 | |||
56 | + bdrv_graph_co_rdlock(); | ||
57 | + source = s->mirror_top_bs->backing->bs; | ||
58 | + bdrv_graph_co_rdunlock(); | ||
59 | + | ||
60 | bdrv_dirty_bitmap_lock(s->dirty_bitmap); | ||
61 | offset = bdrv_dirty_iter_next(s->dbi); | ||
62 | if (offset < 0) { | ||
63 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp) | ||
64 | mirror_wait_for_free_in_flight_slot(s); | ||
65 | continue; | ||
66 | } else if (cnt != 0) { | ||
67 | - bdrv_graph_co_rdlock(); | ||
68 | mirror_iteration(s); | ||
69 | - bdrv_graph_co_rdunlock(); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | -- | ||
74 | 2.44.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | When draining an NBD export, nbd_drained_begin() first sets | ||
2 | client->quiescing so that nbd_client_receive_next_request() won't start | ||
3 | any new request coroutines. Then nbd_drained_poll() tries to makes sure | ||
4 | that we wait for any existing request coroutines by checking that | ||
5 | client->nb_requests has become 0. | ||
1 | 6 | ||
7 | However, there is a small window between creating a new request | ||
8 | coroutine and increasing client->nb_requests. If a coroutine is in this | ||
9 | state, it won't be waited for and drain returns too early. | ||
10 | |||
11 | In the context of switching to a different AioContext, this means that | ||
12 | blk_aio_attached() will see client->recv_coroutine != NULL and fail its | ||
13 | assertion. | ||
14 | |||
15 | Fix this by increasing client->nb_requests immediately when starting the | ||
16 | coroutine. Doing this after the checks if we should create a new | ||
17 | coroutine is okay because client->lock is held. | ||
18 | |||
19 | Cc: qemu-stable@nongnu.org | ||
20 | Fixes: fd6afc501a01 ("nbd/server: Use drained block ops to quiesce the server") | ||
21 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
22 | Message-ID: <20240314165825.40261-2-kwolf@redhat.com> | ||
23 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
24 | --- | ||
25 | nbd/server.c | 15 +++++++-------- | ||
26 | 1 file changed, 7 insertions(+), 8 deletions(-) | ||
27 | |||
28 | diff --git a/nbd/server.c b/nbd/server.c | ||
29 | index XXXXXXX..XXXXXXX 100644 | ||
30 | --- a/nbd/server.c | ||
31 | +++ b/nbd/server.c | ||
32 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int nbd_handle_request(NBDClient *client, | ||
33 | /* Owns a reference to the NBDClient passed as opaque. */ | ||
34 | static coroutine_fn void nbd_trip(void *opaque) | ||
35 | { | ||
36 | - NBDClient *client = opaque; | ||
37 | - NBDRequestData *req = NULL; | ||
38 | + NBDRequestData *req = opaque; | ||
39 | + NBDClient *client = req->client; | ||
40 | NBDRequest request = { 0 }; /* GCC thinks it can be used uninitialized */ | ||
41 | int ret; | ||
42 | Error *local_err = NULL; | ||
43 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_trip(void *opaque) | ||
44 | goto done; | ||
45 | } | ||
46 | |||
47 | - req = nbd_request_get(client); | ||
48 | - | ||
49 | /* | ||
50 | * nbd_co_receive_request() returns -EAGAIN when nbd_drained_begin() has | ||
51 | * set client->quiescing but by the time we get back nbd_drained_end() may | ||
52 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_trip(void *opaque) | ||
53 | } | ||
54 | |||
55 | done: | ||
56 | - if (req) { | ||
57 | - nbd_request_put(req); | ||
58 | - } | ||
59 | + nbd_request_put(req); | ||
60 | |||
61 | qemu_mutex_unlock(&client->lock); | ||
62 | |||
63 | @@ -XXX,XX +XXX,XX @@ disconnect: | ||
64 | */ | ||
65 | static void nbd_client_receive_next_request(NBDClient *client) | ||
66 | { | ||
67 | + NBDRequestData *req; | ||
68 | + | ||
69 | if (!client->recv_coroutine && client->nb_requests < MAX_NBD_REQUESTS && | ||
70 | !client->quiescing) { | ||
71 | nbd_client_get(client); | ||
72 | - client->recv_coroutine = qemu_coroutine_create(nbd_trip, client); | ||
73 | + req = nbd_request_get(client); | ||
74 | + client->recv_coroutine = qemu_coroutine_create(nbd_trip, req); | ||
75 | aio_co_schedule(client->exp->common.ctx, client->recv_coroutine); | ||
76 | } | ||
77 | } | ||
78 | -- | ||
79 | 2.44.0 | diff view generated by jsdifflib |
1 | From: Aapo Vienamo <aapo@tuxera.com> | 1 | This replicates the scenario in which the bug was reported. |
---|---|---|---|
2 | Unfortunately this relies on actually executing a guest (so that the | ||
3 | firmware initialises the virtio-blk device and moves it to its | ||
4 | configured iothread), so this can't make use of the qtest accelerator | ||
5 | like most other test cases. I tried to find a different easy way to | ||
6 | trigger the bug, but couldn't find one. | ||
2 | 7 | ||
3 | Implements a block device write logging system, similar to Linux kernel | 8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | device mapper dm-log-writes. The write operations that are performed | 9 | Message-ID: <20240314165825.40261-3-kwolf@redhat.com> |
5 | on a block device are logged to a file or another block device. The | ||
6 | write log format is identical to the dm-log-writes format. Currently, | ||
7 | log markers are not supported. | ||
8 | |||
9 | This functionality can be used for crash consistency and fs consistency | ||
10 | testing. By implementing it in qemu, tests utilizing write logs can be | ||
11 | be used to test non-Linux drivers and older kernels. | ||
12 | |||
13 | The driver accepts an optional parameter to set the sector size used | ||
14 | for logging. This makes the driver require all requests to be aligned | ||
15 | to this sector size and also makes offsets and sizes of writes in the | ||
16 | log metadata to be expressed in terms of this value (the log format has | ||
17 | a granularity of one sector for offsets and sizes). This allows | ||
18 | accurate logging of writes to guest block devices that have unusual | ||
19 | sector sizes. | ||
20 | |||
21 | The implementation is based on the blkverify and blkdebug block | ||
22 | drivers. | ||
23 | |||
24 | Signed-off-by: Aapo Vienamo <aapo@tuxera.com> | ||
25 | Signed-off-by: Ari Sundholm <ari@tuxera.com> | ||
26 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
27 | --- | 11 | --- |
28 | qapi/block-core.json | 33 ++++- | 12 | tests/qemu-iotests/tests/iothreads-nbd-export | 66 +++++++++++++++++++ |
29 | block/blklogwrites.c | 392 +++++++++++++++++++++++++++++++++++++++++++++++++++ | 13 | .../tests/iothreads-nbd-export.out | 19 ++++++ |
30 | MAINTAINERS | 6 + | 14 | 2 files changed, 85 insertions(+) |
31 | block/Makefile.objs | 1 + | 15 | create mode 100755 tests/qemu-iotests/tests/iothreads-nbd-export |
32 | 4 files changed, 426 insertions(+), 6 deletions(-) | 16 | create mode 100644 tests/qemu-iotests/tests/iothreads-nbd-export.out |
33 | create mode 100644 block/blklogwrites.c | ||
34 | 17 | ||
35 | diff --git a/qapi/block-core.json b/qapi/block-core.json | 18 | diff --git a/tests/qemu-iotests/tests/iothreads-nbd-export b/tests/qemu-iotests/tests/iothreads-nbd-export |
36 | index XXXXXXX..XXXXXXX 100644 | 19 | new file mode 100755 |
37 | --- a/qapi/block-core.json | 20 | index XXXXXXX..XXXXXXX |
38 | +++ b/qapi/block-core.json | 21 | --- /dev/null |
22 | +++ b/tests/qemu-iotests/tests/iothreads-nbd-export | ||
39 | @@ -XXX,XX +XXX,XX @@ | 23 | @@ -XXX,XX +XXX,XX @@ |
40 | # @throttle: Since 2.11 | 24 | +#!/usr/bin/env python3 |
41 | # @nvme: Since 2.12 | 25 | +# group: rw quick |
42 | # @copy-on-read: Since 3.0 | ||
43 | +# @blklogwrites: Since 3.0 | ||
44 | # | ||
45 | # Since: 2.9 | ||
46 | ## | ||
47 | { 'enum': 'BlockdevDriver', | ||
48 | - 'data': [ 'blkdebug', 'blkverify', 'bochs', 'cloop', 'copy-on-read', | ||
49 | - 'dmg', 'file', 'ftp', 'ftps', 'gluster', 'host_cdrom', | ||
50 | - 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs', | ||
51 | - 'null-aio', 'null-co', 'nvme', 'parallels', 'qcow', 'qcow2', 'qed', | ||
52 | - 'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh', | ||
53 | - 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] } | ||
54 | + 'data': [ 'blkdebug', 'blklogwrites', 'blkverify', 'bochs', 'cloop', | ||
55 | + 'copy-on-read', 'dmg', 'file', 'ftp', 'ftps', 'gluster', | ||
56 | + 'host_cdrom', 'host_device', 'http', 'https', 'iscsi', 'luks', | ||
57 | + 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels', 'qcow', | ||
58 | + 'qcow2', 'qed', 'quorum', 'raw', 'rbd', 'replication', 'sheepdog', | ||
59 | + 'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] } | ||
60 | |||
61 | ## | ||
62 | # @BlockdevOptionsFile: | ||
63 | @@ -XXX,XX +XXX,XX @@ | ||
64 | '*set-state': ['BlkdebugSetStateOptions'] } } | ||
65 | |||
66 | ## | ||
67 | +# @BlockdevOptionsBlklogwrites: | ||
68 | +# | 26 | +# |
69 | +# Driver specific block device options for blklogwrites. | 27 | +# Copyright (C) 2024 Red Hat, Inc. |
70 | +# | 28 | +# |
71 | +# @file: block device | 29 | +# This program is free software; you can redistribute it and/or modify |
30 | +# it under the terms of the GNU General Public License as published by | ||
31 | +# the Free Software Foundation; either version 2 of the License, or | ||
32 | +# (at your option) any later version. | ||
72 | +# | 33 | +# |
73 | +# @log: block device used to log writes to @file | 34 | +# This program is distributed in the hope that it will be useful, |
35 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
36 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
37 | +# GNU General Public License for more details. | ||
74 | +# | 38 | +# |
75 | +# @log-sector-size: sector size used in logging writes to @file, determines | 39 | +# You should have received a copy of the GNU General Public License |
76 | +# granularity of offsets and sizes of writes (default: 512) | 40 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
77 | +# | 41 | +# |
78 | +# Since: 3.0 | 42 | +# Creator/Owner: Kevin Wolf <kwolf@redhat.com> |
79 | +## | ||
80 | +{ 'struct': 'BlockdevOptionsBlklogwrites', | ||
81 | + 'data': { 'file': 'BlockdevRef', | ||
82 | + 'log': 'BlockdevRef', | ||
83 | + '*log-sector-size': 'uint32' } } | ||
84 | + | 43 | + |
85 | +## | 44 | +import time |
86 | # @BlockdevOptionsBlkverify: | 45 | +import qemu |
87 | # | 46 | +import iotests |
88 | # Driver specific block device options for blkverify. | 47 | + |
89 | @@ -XXX,XX +XXX,XX @@ | 48 | +iotests.script_initialize(supported_fmts=['qcow2'], |
90 | 'discriminator': 'driver', | 49 | + supported_platforms=['linux']) |
91 | 'data': { | 50 | + |
92 | 'blkdebug': 'BlockdevOptionsBlkdebug', | 51 | +with iotests.FilePath('disk1.img') as path, \ |
93 | + 'blklogwrites':'BlockdevOptionsBlklogwrites', | 52 | + iotests.FilePath('nbd.sock', base_dir=iotests.sock_dir) as nbd_sock, \ |
94 | 'blkverify': 'BlockdevOptionsBlkverify', | 53 | + qemu.machine.QEMUMachine(iotests.qemu_prog) as vm: |
95 | 'bochs': 'BlockdevOptionsGenericFormat', | 54 | + |
96 | 'cloop': 'BlockdevOptionsGenericFormat', | 55 | + img_size = '10M' |
97 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | 56 | + |
57 | + iotests.log('Preparing disk...') | ||
58 | + iotests.qemu_img_create('-f', iotests.imgfmt, path, img_size) | ||
59 | + vm.add_args('-blockdev', f'file,node-name=disk-file,filename={path}') | ||
60 | + vm.add_args('-blockdev', 'qcow2,node-name=disk,file=disk-file') | ||
61 | + vm.add_args('-object', 'iothread,id=iothread0') | ||
62 | + vm.add_args('-device', | ||
63 | + 'virtio-blk,drive=disk,iothread=iothread0,share-rw=on') | ||
64 | + | ||
65 | + iotests.log('Launching VM...') | ||
66 | + vm.add_args('-accel', 'kvm', '-accel', 'tcg') | ||
67 | + #vm.add_args('-accel', 'qtest') | ||
68 | + vm.launch() | ||
69 | + | ||
70 | + iotests.log('Exporting to NBD...') | ||
71 | + iotests.log(vm.qmp('nbd-server-start', | ||
72 | + addr={'type': 'unix', 'data': {'path': nbd_sock}})) | ||
73 | + iotests.log(vm.qmp('block-export-add', type='nbd', id='exp0', | ||
74 | + node_name='disk', writable=True)) | ||
75 | + | ||
76 | + iotests.log('Connecting qemu-img...') | ||
77 | + qemu_io = iotests.QemuIoInteractive('-f', 'raw', | ||
78 | + f'nbd+unix:///disk?socket={nbd_sock}') | ||
79 | + | ||
80 | + iotests.log('Moving the NBD export to a different iothread...') | ||
81 | + for i in range(0, 10): | ||
82 | + iotests.log(vm.qmp('system_reset')) | ||
83 | + time.sleep(0.1) | ||
84 | + | ||
85 | + iotests.log('Checking that it is still alive...') | ||
86 | + iotests.log(vm.qmp('query-status')) | ||
87 | + | ||
88 | + qemu_io.close() | ||
89 | + vm.shutdown() | ||
90 | diff --git a/tests/qemu-iotests/tests/iothreads-nbd-export.out b/tests/qemu-iotests/tests/iothreads-nbd-export.out | ||
98 | new file mode 100644 | 91 | new file mode 100644 |
99 | index XXXXXXX..XXXXXXX | 92 | index XXXXXXX..XXXXXXX |
100 | --- /dev/null | 93 | --- /dev/null |
101 | +++ b/block/blklogwrites.c | 94 | +++ b/tests/qemu-iotests/tests/iothreads-nbd-export.out |
102 | @@ -XXX,XX +XXX,XX @@ | 95 | @@ -XXX,XX +XXX,XX @@ |
103 | +/* | 96 | +Preparing disk... |
104 | + * Write logging blk driver based on blkverify and blkdebug. | 97 | +Launching VM... |
105 | + * | 98 | +Exporting to NBD... |
106 | + * Copyright (c) 2017 Tuomas Tynkkynen <tuomas@tuxera.com> | 99 | +{"return": {}} |
107 | + * Copyright (c) 2018 Aapo Vienamo <aapo@tuxera.com> | 100 | +{"return": {}} |
108 | + * Copyright (c) 2018 Ari Sundholm <ari@tuxera.com> | 101 | +Connecting qemu-img... |
109 | + * | 102 | +Moving the NBD export to a different iothread... |
110 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | 103 | +{"return": {}} |
111 | + * See the COPYING file in the top-level directory. | 104 | +{"return": {}} |
112 | + */ | 105 | +{"return": {}} |
113 | + | 106 | +{"return": {}} |
114 | +#include "qemu/osdep.h" | 107 | +{"return": {}} |
115 | +#include "qapi/error.h" | 108 | +{"return": {}} |
116 | +#include "qemu/sockets.h" /* for EINPROGRESS on Windows */ | 109 | +{"return": {}} |
117 | +#include "block/block_int.h" | 110 | +{"return": {}} |
118 | +#include "qapi/qmp/qdict.h" | 111 | +{"return": {}} |
119 | +#include "qapi/qmp/qstring.h" | 112 | +{"return": {}} |
120 | +#include "qemu/cutils.h" | 113 | +Checking that it is still alive... |
121 | +#include "qemu/option.h" | 114 | +{"return": {"running": true, "status": "running"}} |
122 | + | ||
123 | +/* Disk format stuff - taken from Linux drivers/md/dm-log-writes.c */ | ||
124 | + | ||
125 | +#define LOG_FLUSH_FLAG (1 << 0) | ||
126 | +#define LOG_FUA_FLAG (1 << 1) | ||
127 | +#define LOG_DISCARD_FLAG (1 << 2) | ||
128 | +#define LOG_MARK_FLAG (1 << 3) | ||
129 | + | ||
130 | +#define WRITE_LOG_VERSION 1ULL | ||
131 | +#define WRITE_LOG_MAGIC 0x6a736677736872ULL | ||
132 | + | ||
133 | +/* All fields are little-endian. */ | ||
134 | +struct log_write_super { | ||
135 | + uint64_t magic; | ||
136 | + uint64_t version; | ||
137 | + uint64_t nr_entries; | ||
138 | + uint32_t sectorsize; | ||
139 | +} QEMU_PACKED; | ||
140 | + | ||
141 | +struct log_write_entry { | ||
142 | + uint64_t sector; | ||
143 | + uint64_t nr_sectors; | ||
144 | + uint64_t flags; | ||
145 | + uint64_t data_len; | ||
146 | +} QEMU_PACKED; | ||
147 | + | ||
148 | +/* End of disk format structures. */ | ||
149 | + | ||
150 | +typedef struct { | ||
151 | + BdrvChild *log_file; | ||
152 | + uint32_t sectorsize; | ||
153 | + uint32_t sectorbits; | ||
154 | + uint64_t cur_log_sector; | ||
155 | + uint64_t nr_entries; | ||
156 | +} BDRVBlkLogWritesState; | ||
157 | + | ||
158 | +static inline uint32_t blk_log_writes_log2(uint32_t value) | ||
159 | +{ | ||
160 | + assert(value > 0); | ||
161 | + return 31 - clz32(value); | ||
162 | +} | ||
163 | + | ||
164 | +static int blk_log_writes_open(BlockDriverState *bs, QDict *options, int flags, | ||
165 | + Error **errp) | ||
166 | +{ | ||
167 | + BDRVBlkLogWritesState *s = bs->opaque; | ||
168 | + Error *local_err = NULL; | ||
169 | + int ret; | ||
170 | + int64_t log_sector_size = BDRV_SECTOR_SIZE; | ||
171 | + | ||
172 | + /* Open the file */ | ||
173 | + bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false, | ||
174 | + &local_err); | ||
175 | + if (local_err) { | ||
176 | + ret = -EINVAL; | ||
177 | + error_propagate(errp, local_err); | ||
178 | + goto fail; | ||
179 | + } | ||
180 | + | ||
181 | + if (qdict_haskey(options, "log-sector-size")) { | ||
182 | + log_sector_size = qdict_get_int(options, "log-sector-size"); | ||
183 | + qdict_del(options, "log-sector-size"); | ||
184 | + } | ||
185 | + | ||
186 | + if (log_sector_size < 0 || log_sector_size >= (1ull << 32) || | ||
187 | + !is_power_of_2(log_sector_size)) | ||
188 | + { | ||
189 | + ret = -EINVAL; | ||
190 | + error_setg(errp, "Invalid log sector size %"PRId64, log_sector_size); | ||
191 | + goto fail; | ||
192 | + } | ||
193 | + | ||
194 | + s->sectorsize = log_sector_size; | ||
195 | + s->sectorbits = blk_log_writes_log2(log_sector_size); | ||
196 | + s->cur_log_sector = 1; | ||
197 | + s->nr_entries = 0; | ||
198 | + | ||
199 | + /* Open the log file */ | ||
200 | + s->log_file = bdrv_open_child(NULL, options, "log", bs, &child_file, false, | ||
201 | + &local_err); | ||
202 | + if (local_err) { | ||
203 | + ret = -EINVAL; | ||
204 | + error_propagate(errp, local_err); | ||
205 | + goto fail; | ||
206 | + } | ||
207 | + | ||
208 | + ret = 0; | ||
209 | +fail: | ||
210 | + if (ret < 0) { | ||
211 | + bdrv_unref_child(bs, bs->file); | ||
212 | + bs->file = NULL; | ||
213 | + } | ||
214 | + return ret; | ||
215 | +} | ||
216 | + | ||
217 | +static void blk_log_writes_close(BlockDriverState *bs) | ||
218 | +{ | ||
219 | + BDRVBlkLogWritesState *s = bs->opaque; | ||
220 | + | ||
221 | + bdrv_unref_child(bs, s->log_file); | ||
222 | + s->log_file = NULL; | ||
223 | +} | ||
224 | + | ||
225 | +static int64_t blk_log_writes_getlength(BlockDriverState *bs) | ||
226 | +{ | ||
227 | + return bdrv_getlength(bs->file->bs); | ||
228 | +} | ||
229 | + | ||
230 | +static void blk_log_writes_refresh_filename(BlockDriverState *bs, | ||
231 | + QDict *options) | ||
232 | +{ | ||
233 | + BDRVBlkLogWritesState *s = bs->opaque; | ||
234 | + | ||
235 | + /* bs->file->bs has already been refreshed */ | ||
236 | + bdrv_refresh_filename(s->log_file->bs); | ||
237 | + | ||
238 | + if (bs->file->bs->full_open_options | ||
239 | + && s->log_file->bs->full_open_options) | ||
240 | + { | ||
241 | + QDict *opts = qdict_new(); | ||
242 | + qdict_put_str(opts, "driver", "blklogwrites"); | ||
243 | + | ||
244 | + qobject_ref(bs->file->bs->full_open_options); | ||
245 | + qdict_put_obj(opts, "file", QOBJECT(bs->file->bs->full_open_options)); | ||
246 | + qobject_ref(s->log_file->bs->full_open_options); | ||
247 | + qdict_put_obj(opts, "log", | ||
248 | + QOBJECT(s->log_file->bs->full_open_options)); | ||
249 | + | ||
250 | + bs->full_open_options = opts; | ||
251 | + } | ||
252 | +} | ||
253 | + | ||
254 | +static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
255 | + const BdrvChildRole *role, | ||
256 | + BlockReopenQueue *ro_q, | ||
257 | + uint64_t perm, uint64_t shrd, | ||
258 | + uint64_t *nperm, uint64_t *nshrd) | ||
259 | +{ | ||
260 | + if (!c) { | ||
261 | + *nperm = perm & DEFAULT_PERM_PASSTHROUGH; | ||
262 | + *nshrd = (shrd & DEFAULT_PERM_PASSTHROUGH) | DEFAULT_PERM_UNCHANGED; | ||
263 | + return; | ||
264 | + } | ||
265 | + | ||
266 | + if (!strcmp(c->name, "log")) { | ||
267 | + bdrv_format_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd); | ||
268 | + } else { | ||
269 | + bdrv_filter_default_perms(bs, c, role, ro_q, perm, shrd, nperm, nshrd); | ||
270 | + } | ||
271 | +} | ||
272 | + | ||
273 | +static void blk_log_writes_refresh_limits(BlockDriverState *bs, Error **errp) | ||
274 | +{ | ||
275 | + BDRVBlkLogWritesState *s = bs->opaque; | ||
276 | + bs->bl.request_alignment = s->sectorsize; | ||
277 | +} | ||
278 | + | ||
279 | +static int coroutine_fn | ||
280 | +blk_log_writes_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | ||
281 | + QEMUIOVector *qiov, int flags) | ||
282 | +{ | ||
283 | + return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); | ||
284 | +} | ||
285 | + | ||
286 | +typedef struct BlkLogWritesFileReq { | ||
287 | + BlockDriverState *bs; | ||
288 | + uint64_t offset; | ||
289 | + uint64_t bytes; | ||
290 | + int file_flags; | ||
291 | + QEMUIOVector *qiov; | ||
292 | + int (*func)(struct BlkLogWritesFileReq *r); | ||
293 | + int file_ret; | ||
294 | +} BlkLogWritesFileReq; | ||
295 | + | ||
296 | +typedef struct { | ||
297 | + BlockDriverState *bs; | ||
298 | + QEMUIOVector *qiov; | ||
299 | + struct log_write_entry entry; | ||
300 | + uint64_t zero_size; | ||
301 | + int log_ret; | ||
302 | +} BlkLogWritesLogReq; | ||
303 | + | ||
304 | +static void coroutine_fn blk_log_writes_co_do_log(BlkLogWritesLogReq *lr) | ||
305 | +{ | ||
306 | + BDRVBlkLogWritesState *s = lr->bs->opaque; | ||
307 | + uint64_t cur_log_offset = s->cur_log_sector << s->sectorbits; | ||
308 | + | ||
309 | + s->nr_entries++; | ||
310 | + s->cur_log_sector += | ||
311 | + ROUND_UP(lr->qiov->size, s->sectorsize) >> s->sectorbits; | ||
312 | + | ||
313 | + lr->log_ret = bdrv_co_pwritev(s->log_file, cur_log_offset, lr->qiov->size, | ||
314 | + lr->qiov, 0); | ||
315 | + | ||
316 | + /* Logging for the "write zeroes" operation */ | ||
317 | + if (lr->log_ret == 0 && lr->zero_size) { | ||
318 | + cur_log_offset = s->cur_log_sector << s->sectorbits; | ||
319 | + s->cur_log_sector += | ||
320 | + ROUND_UP(lr->zero_size, s->sectorsize) >> s->sectorbits; | ||
321 | + | ||
322 | + lr->log_ret = bdrv_co_pwrite_zeroes(s->log_file, cur_log_offset, | ||
323 | + lr->zero_size, 0); | ||
324 | + } | ||
325 | + | ||
326 | + /* Update super block on flush */ | ||
327 | + if (lr->log_ret == 0 && lr->entry.flags & LOG_FLUSH_FLAG) { | ||
328 | + struct log_write_super super = { | ||
329 | + .magic = cpu_to_le64(WRITE_LOG_MAGIC), | ||
330 | + .version = cpu_to_le64(WRITE_LOG_VERSION), | ||
331 | + .nr_entries = cpu_to_le64(s->nr_entries), | ||
332 | + .sectorsize = cpu_to_le32(s->sectorsize), | ||
333 | + }; | ||
334 | + void *zeroes = g_malloc0(s->sectorsize - sizeof(super)); | ||
335 | + QEMUIOVector qiov; | ||
336 | + | ||
337 | + qemu_iovec_init(&qiov, 2); | ||
338 | + qemu_iovec_add(&qiov, &super, sizeof(super)); | ||
339 | + qemu_iovec_add(&qiov, zeroes, s->sectorsize - sizeof(super)); | ||
340 | + | ||
341 | + lr->log_ret = | ||
342 | + bdrv_co_pwritev(s->log_file, 0, s->sectorsize, &qiov, 0); | ||
343 | + if (lr->log_ret == 0) { | ||
344 | + lr->log_ret = bdrv_co_flush(s->log_file->bs); | ||
345 | + } | ||
346 | + qemu_iovec_destroy(&qiov); | ||
347 | + g_free(zeroes); | ||
348 | + } | ||
349 | +} | ||
350 | + | ||
351 | +static void coroutine_fn blk_log_writes_co_do_file(BlkLogWritesFileReq *fr) | ||
352 | +{ | ||
353 | + fr->file_ret = fr->func(fr); | ||
354 | +} | ||
355 | + | ||
356 | +static int coroutine_fn | ||
357 | +blk_log_writes_co_log(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | ||
358 | + QEMUIOVector *qiov, int flags, | ||
359 | + int (*file_func)(BlkLogWritesFileReq *r), | ||
360 | + uint64_t entry_flags, bool is_zero_write) | ||
361 | +{ | ||
362 | + QEMUIOVector log_qiov; | ||
363 | + size_t niov = qiov ? qiov->niov : 0; | ||
364 | + BDRVBlkLogWritesState *s = bs->opaque; | ||
365 | + BlkLogWritesFileReq fr = { | ||
366 | + .bs = bs, | ||
367 | + .offset = offset, | ||
368 | + .bytes = bytes, | ||
369 | + .file_flags = flags, | ||
370 | + .qiov = qiov, | ||
371 | + .func = file_func, | ||
372 | + }; | ||
373 | + BlkLogWritesLogReq lr = { | ||
374 | + .bs = bs, | ||
375 | + .qiov = &log_qiov, | ||
376 | + .entry = { | ||
377 | + .sector = cpu_to_le64(offset >> s->sectorbits), | ||
378 | + .nr_sectors = cpu_to_le64(bytes >> s->sectorbits), | ||
379 | + .flags = cpu_to_le64(entry_flags), | ||
380 | + .data_len = 0, | ||
381 | + }, | ||
382 | + .zero_size = is_zero_write ? bytes : 0, | ||
383 | + }; | ||
384 | + void *zeroes = g_malloc0(s->sectorsize - sizeof(lr.entry)); | ||
385 | + | ||
386 | + assert((1 << s->sectorbits) == s->sectorsize); | ||
387 | + assert(bs->bl.request_alignment == s->sectorsize); | ||
388 | + assert(QEMU_IS_ALIGNED(offset, bs->bl.request_alignment)); | ||
389 | + assert(QEMU_IS_ALIGNED(bytes, bs->bl.request_alignment)); | ||
390 | + | ||
391 | + qemu_iovec_init(&log_qiov, niov + 2); | ||
392 | + qemu_iovec_add(&log_qiov, &lr.entry, sizeof(lr.entry)); | ||
393 | + qemu_iovec_add(&log_qiov, zeroes, s->sectorsize - sizeof(lr.entry)); | ||
394 | + if (qiov) { | ||
395 | + qemu_iovec_concat(&log_qiov, qiov, 0, qiov->size); | ||
396 | + } | ||
397 | + | ||
398 | + blk_log_writes_co_do_file(&fr); | ||
399 | + blk_log_writes_co_do_log(&lr); | ||
400 | + | ||
401 | + qemu_iovec_destroy(&log_qiov); | ||
402 | + g_free(zeroes); | ||
403 | + | ||
404 | + if (lr.log_ret < 0) { | ||
405 | + return lr.log_ret; | ||
406 | + } | ||
407 | + | ||
408 | + return fr.file_ret; | ||
409 | +} | ||
410 | + | ||
411 | +static int coroutine_fn | ||
412 | +blk_log_writes_co_do_file_pwritev(BlkLogWritesFileReq *fr) | ||
413 | +{ | ||
414 | + return bdrv_co_pwritev(fr->bs->file, fr->offset, fr->bytes, | ||
415 | + fr->qiov, fr->file_flags); | ||
416 | +} | ||
417 | + | ||
418 | +static int coroutine_fn | ||
419 | +blk_log_writes_co_do_file_pwrite_zeroes(BlkLogWritesFileReq *fr) | ||
420 | +{ | ||
421 | + return bdrv_co_pwrite_zeroes(fr->bs->file, fr->offset, fr->bytes, | ||
422 | + fr->file_flags); | ||
423 | +} | ||
424 | + | ||
425 | +static int coroutine_fn blk_log_writes_co_do_file_flush(BlkLogWritesFileReq *fr) | ||
426 | +{ | ||
427 | + return bdrv_co_flush(fr->bs->file->bs); | ||
428 | +} | ||
429 | + | ||
430 | +static int coroutine_fn | ||
431 | +blk_log_writes_co_do_file_pdiscard(BlkLogWritesFileReq *fr) | ||
432 | +{ | ||
433 | + return bdrv_co_pdiscard(fr->bs->file->bs, fr->offset, fr->bytes); | ||
434 | +} | ||
435 | + | ||
436 | +static int coroutine_fn | ||
437 | +blk_log_writes_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | ||
438 | + QEMUIOVector *qiov, int flags) | ||
439 | +{ | ||
440 | + return blk_log_writes_co_log(bs, offset, bytes, qiov, flags, | ||
441 | + blk_log_writes_co_do_file_pwritev, 0, false); | ||
442 | +} | ||
443 | + | ||
444 | +static int coroutine_fn | ||
445 | +blk_log_writes_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes, | ||
446 | + BdrvRequestFlags flags) | ||
447 | +{ | ||
448 | + return blk_log_writes_co_log(bs, offset, bytes, NULL, flags, | ||
449 | + blk_log_writes_co_do_file_pwrite_zeroes, 0, | ||
450 | + true); | ||
451 | +} | ||
452 | + | ||
453 | +static int coroutine_fn blk_log_writes_co_flush_to_disk(BlockDriverState *bs) | ||
454 | +{ | ||
455 | + return blk_log_writes_co_log(bs, 0, 0, NULL, 0, | ||
456 | + blk_log_writes_co_do_file_flush, | ||
457 | + LOG_FLUSH_FLAG, false); | ||
458 | +} | ||
459 | + | ||
460 | +static int coroutine_fn | ||
461 | +blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int count) | ||
462 | +{ | ||
463 | + return blk_log_writes_co_log(bs, offset, count, NULL, 0, | ||
464 | + blk_log_writes_co_do_file_pdiscard, | ||
465 | + LOG_DISCARD_FLAG, false); | ||
466 | +} | ||
467 | + | ||
468 | +static BlockDriver bdrv_blk_log_writes = { | ||
469 | + .format_name = "blklogwrites", | ||
470 | + .instance_size = sizeof(BDRVBlkLogWritesState), | ||
471 | + | ||
472 | + .bdrv_open = blk_log_writes_open, | ||
473 | + .bdrv_close = blk_log_writes_close, | ||
474 | + .bdrv_getlength = blk_log_writes_getlength, | ||
475 | + .bdrv_refresh_filename = blk_log_writes_refresh_filename, | ||
476 | + .bdrv_child_perm = blk_log_writes_child_perm, | ||
477 | + .bdrv_refresh_limits = blk_log_writes_refresh_limits, | ||
478 | + | ||
479 | + .bdrv_co_preadv = blk_log_writes_co_preadv, | ||
480 | + .bdrv_co_pwritev = blk_log_writes_co_pwritev, | ||
481 | + .bdrv_co_pwrite_zeroes = blk_log_writes_co_pwrite_zeroes, | ||
482 | + .bdrv_co_flush_to_disk = blk_log_writes_co_flush_to_disk, | ||
483 | + .bdrv_co_pdiscard = blk_log_writes_co_pdiscard, | ||
484 | + .bdrv_co_block_status = bdrv_co_block_status_from_file, | ||
485 | + | ||
486 | + .is_filter = true, | ||
487 | +}; | ||
488 | + | ||
489 | +static void bdrv_blk_log_writes_init(void) | ||
490 | +{ | ||
491 | + bdrv_register(&bdrv_blk_log_writes); | ||
492 | +} | ||
493 | + | ||
494 | +block_init(bdrv_blk_log_writes_init); | ||
495 | diff --git a/MAINTAINERS b/MAINTAINERS | ||
496 | index XXXXXXX..XXXXXXX 100644 | ||
497 | --- a/MAINTAINERS | ||
498 | +++ b/MAINTAINERS | ||
499 | @@ -XXX,XX +XXX,XX @@ S: Supported | ||
500 | F: block/quorum.c | ||
501 | L: qemu-block@nongnu.org | ||
502 | |||
503 | +blklogwrites | ||
504 | +M: Ari Sundholm <ari@tuxera.com> | ||
505 | +L: qemu-block@nongnu.org | ||
506 | +S: Supported | ||
507 | +F: block/blklogwrites.c | ||
508 | + | ||
509 | blkverify | ||
510 | M: Stefan Hajnoczi <stefanha@redhat.com> | ||
511 | L: qemu-block@nongnu.org | ||
512 | diff --git a/block/Makefile.objs b/block/Makefile.objs | ||
513 | index XXXXXXX..XXXXXXX 100644 | ||
514 | --- a/block/Makefile.objs | ||
515 | +++ b/block/Makefile.objs | ||
516 | @@ -XXX,XX +XXX,XX @@ block-obj-y += qed-check.o | ||
517 | block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o | ||
518 | block-obj-y += quorum.o | ||
519 | block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o | ||
520 | +block-obj-y += blklogwrites.o | ||
521 | block-obj-y += block-backend.o snapshot.o qapi.o | ||
522 | block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o | ||
523 | block-obj-$(CONFIG_POSIX) += file-posix.o | ||
524 | -- | 115 | -- |
525 | 2.13.6 | 116 | 2.44.0 |
526 | |||
527 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Markus Armbruster <armbru@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | No reason to forbid them, and they are needed to improve performance | 3 | When external_snapshot_abort() rejects a BlockDriverState without a |
4 | with compress-threads in further patches. | 4 | medium, it creates an error like this: |
5 | 5 | ||
6 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 6 | error_setg(errp, "Device '%s' has no medium", device); |
7 | |||
8 | Trouble is @device can be null. My system formats null as "(null)", | ||
9 | but other systems might crash. Reproducer: | ||
10 | |||
11 | 1. Create a block device without a medium | ||
12 | |||
13 | -> {"execute": "blockdev-add", "arguments": {"driver": "host_cdrom", "node-name": "blk0", "filename": "/dev/sr0"}} | ||
14 | <- {"return": {}} | ||
15 | |||
16 | 3. Attempt to snapshot it | ||
17 | |||
18 | -> {"execute":"blockdev-snapshot-sync", "arguments": { "node-name": "blk0", "snapshot-file":"/tmp/foo.qcow2","format":"qcow2"}} | ||
19 | <- {"error": {"class": "GenericError", "desc": "Device '(null)' has no medium"}} | ||
20 | |||
21 | Broken when commit 0901f67ecdb made @device optional. | ||
22 | |||
23 | Use bdrv_get_device_or_node_name() instead. Now it fails as it | ||
24 | should: | ||
25 | |||
26 | <- {"error": {"class": "GenericError", "desc": "Device 'blk0' has no medium"}} | ||
27 | |||
28 | Fixes: 0901f67ecdb7 ("qmp: Allow to take external snapshots on bs graphs node.") | ||
29 | Signed-off-by: Markus Armbruster <armbru@redhat.com> | ||
30 | Message-ID: <20240306142831.2514431-1-armbru@redhat.com> | ||
31 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 32 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | --- | 33 | --- |
9 | qemu-img.c | 5 ----- | 34 | blockdev.c | 3 ++- |
10 | 1 file changed, 5 deletions(-) | 35 | 1 file changed, 2 insertions(+), 1 deletion(-) |
11 | 36 | ||
12 | diff --git a/qemu-img.c b/qemu-img.c | 37 | diff --git a/blockdev.c b/blockdev.c |
13 | index XXXXXXX..XXXXXXX 100644 | 38 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/qemu-img.c | 39 | --- a/blockdev.c |
15 | +++ b/qemu-img.c | 40 | +++ b/blockdev.c |
16 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | 41 | @@ -XXX,XX +XXX,XX @@ static void external_snapshot_action(TransactionAction *action, |
17 | goto fail_getopt; | 42 | bdrv_drained_begin(state->old_bs); |
43 | |||
44 | if (!bdrv_is_inserted(state->old_bs)) { | ||
45 | - error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); | ||
46 | + error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, | ||
47 | + bdrv_get_device_or_node_name(state->old_bs)); | ||
48 | return; | ||
18 | } | 49 | } |
19 | 50 | ||
20 | - if (!s.wr_in_order && s.compressed) { | ||
21 | - error_report("Out of order write and compress are mutually exclusive"); | ||
22 | - goto fail_getopt; | ||
23 | - } | ||
24 | - | ||
25 | if (tgt_image_opts && !skip_create) { | ||
26 | error_report("--target-image-opts requires use of -n flag"); | ||
27 | goto fail_getopt; | ||
28 | -- | 51 | -- |
29 | 2.13.6 | 52 | 2.44.0 |
30 | |||
31 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | From: Abhiram Tilak <atp.exp@gmail.com> | |
2 | |||
3 | When running the command `qemu-img snapshot -l SNAPSHOT` the output of | ||
4 | VM_CLOCK (measures the offset between host and VM clock) cannot to | ||
5 | accommodate values in the order of thousands (4-digit). | ||
6 | |||
7 | This line [1] hints on the problem. Additionally, the column width for | ||
8 | the VM_CLOCK field was reduced from 15 to 13 spaces in commit b39847a5 | ||
9 | in line [2], resulting in a shortage of space. | ||
10 | |||
11 | [1]: | ||
12 | https://gitlab.com/qemu-project/qemu/-/blob/master/block/qapi.c?ref_type=heads#L753 | ||
13 | [2]: | ||
14 | https://gitlab.com/qemu-project/qemu/-/blob/master/block/qapi.c?ref_type=heads#L763 | ||
15 | |||
16 | This patch restores the column width to 15 spaces and makes adjustments | ||
17 | to the affected iotests accordingly. Furthermore, addresses a potential | ||
18 | source | ||
19 | of confusion by removing whitespace in column headers. Example, VM CLOCK | ||
20 | is modified to VM_CLOCK. Additionally a '--' symbol is introduced when | ||
21 | ICOUNT returns no output for clarity. | ||
22 | |||
23 | Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2062 | ||
24 | Fixes: b39847a50553 ("migration: introduce icount field for snapshots") | ||
25 | Signed-off-by: Abhiram Tilak <atp.exp@gmail.com> | ||
26 | Message-ID: <20240123050354.22152-2-atp.exp@gmail.com> | ||
27 | [kwolf: Fixed up qemu-iotests 261 and 286] | ||
28 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
29 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
30 | --- | ||
31 | block/qapi.c | 10 ++-- | ||
32 | tests/qemu-iotests/176.out | 16 +++---- | ||
33 | tests/qemu-iotests/261 | 4 +- | ||
34 | tests/qemu-iotests/267.out | 48 +++++++++---------- | ||
35 | tests/qemu-iotests/286 | 3 +- | ||
36 | tests/qemu-iotests/286.out | 2 +- | ||
37 | .../tests/qcow2-internal-snapshots.out | 14 +++--- | ||
38 | 7 files changed, 50 insertions(+), 47 deletions(-) | ||
39 | |||
40 | diff --git a/block/qapi.c b/block/qapi.c | ||
41 | index XXXXXXX..XXXXXXX 100644 | ||
42 | --- a/block/qapi.c | ||
43 | +++ b/block/qapi.c | ||
44 | @@ -XXX,XX +XXX,XX @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn) | ||
45 | char *sizing = NULL; | ||
46 | |||
47 | if (!sn) { | ||
48 | - qemu_printf("%-10s%-17s%8s%20s%13s%11s", | ||
49 | - "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK", "ICOUNT"); | ||
50 | + qemu_printf("%-7s %-16s %8s %19s %15s %10s", | ||
51 | + "ID", "TAG", "VM_SIZE", "DATE", "VM_CLOCK", "ICOUNT"); | ||
52 | } else { | ||
53 | g_autoptr(GDateTime) date = g_date_time_new_from_unix_local(sn->date_sec); | ||
54 | g_autofree char *date_buf = g_date_time_format(date, "%Y-%m-%d %H:%M:%S"); | ||
55 | |||
56 | secs = sn->vm_clock_nsec / 1000000000; | ||
57 | snprintf(clock_buf, sizeof(clock_buf), | ||
58 | - "%02d:%02d:%02d.%03d", | ||
59 | + "%04d:%02d:%02d.%03d", | ||
60 | (int)(secs / 3600), | ||
61 | (int)((secs / 60) % 60), | ||
62 | (int)(secs % 60), | ||
63 | @@ -XXX,XX +XXX,XX @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn) | ||
64 | if (sn->icount != -1ULL) { | ||
65 | snprintf(icount_buf, sizeof(icount_buf), | ||
66 | "%"PRId64, sn->icount); | ||
67 | + } else { | ||
68 | + snprintf(icount_buf, sizeof(icount_buf), "--"); | ||
69 | } | ||
70 | - qemu_printf("%-9s %-16s %8s%20s%13s%11s", | ||
71 | + qemu_printf("%-7s %-16s %8s %19s %15s %10s", | ||
72 | sn->id_str, sn->name, | ||
73 | sizing, | ||
74 | date_buf, | ||
75 | diff --git a/tests/qemu-iotests/176.out b/tests/qemu-iotests/176.out | ||
76 | index XXXXXXX..XXXXXXX 100644 | ||
77 | --- a/tests/qemu-iotests/176.out | ||
78 | +++ b/tests/qemu-iotests/176.out | ||
79 | @@ -XXX,XX +XXX,XX @@ Offset Length File | ||
80 | 0x7ffe0000 0x20000 TEST_DIR/t.IMGFMT.itmd | ||
81 | 0x83400000 0x200 TEST_DIR/t.IMGFMT.itmd | ||
82 | Snapshot list: | ||
83 | -ID TAG | ||
84 | -1 snap | ||
85 | +ID TAG | ||
86 | +1 snap | ||
87 | |||
88 | === Test pass snapshot.1 === | ||
89 | |||
90 | @@ -XXX,XX +XXX,XX @@ Offset Length File | ||
91 | 0x7fff0000 0x10000 TEST_DIR/t.IMGFMT | ||
92 | 0x83400000 0x200 TEST_DIR/t.IMGFMT | ||
93 | Snapshot list: | ||
94 | -ID TAG | ||
95 | -1 snap | ||
96 | +ID TAG | ||
97 | +1 snap | ||
98 | |||
99 | === Test pass snapshot.2 === | ||
100 | |||
101 | @@ -XXX,XX +XXX,XX @@ Offset Length File | ||
102 | 0x7fff0000 0x10000 TEST_DIR/t.IMGFMT | ||
103 | 0x83400000 0x200 TEST_DIR/t.IMGFMT | ||
104 | Snapshot list: | ||
105 | -ID TAG | ||
106 | -1 snap | ||
107 | +ID TAG | ||
108 | +1 snap | ||
109 | |||
110 | === Test pass snapshot.3 === | ||
111 | |||
112 | @@ -XXX,XX +XXX,XX @@ Offset Length File | ||
113 | 0x7fff0000 0x10000 TEST_DIR/t.IMGFMT | ||
114 | 0x83400000 0x200 TEST_DIR/t.IMGFMT | ||
115 | Snapshot list: | ||
116 | -ID TAG | ||
117 | -1 snap | ||
118 | +ID TAG | ||
119 | +1 snap | ||
120 | |||
121 | === Test pass bitmap.0 === | ||
122 | |||
123 | diff --git a/tests/qemu-iotests/261 b/tests/qemu-iotests/261 | ||
124 | index XXXXXXX..XXXXXXX 100755 | ||
125 | --- a/tests/qemu-iotests/261 | ||
126 | +++ b/tests/qemu-iotests/261 | ||
127 | @@ -XXX,XX +XXX,XX @@ _check_test_img -r all | ||
128 | |||
129 | echo | ||
130 | echo "$((sn_count - 1)) snapshots should remain:" | ||
131 | -echo " qemu-img info reports $(_img_info | grep -c '^ \{32\}') snapshots" | ||
132 | +echo " qemu-img info reports $(_img_info | grep -c '^ \{30\}') snapshots" | ||
133 | echo " Image header reports $(peek_file_be "$TEST_IMG" 60 4) snapshots" | ||
134 | |||
135 | echo | ||
136 | @@ -XXX,XX +XXX,XX @@ _check_test_img -r all | ||
137 | |||
138 | echo | ||
139 | echo '65536 snapshots should remain:' | ||
140 | -echo " qemu-img info reports $(_img_info | grep -c '^ \{32\}') snapshots" | ||
141 | +echo " qemu-img info reports $(_img_info | grep -c '^ \{30\}') snapshots" | ||
142 | echo " Image header reports $(peek_file_be "$TEST_IMG" 60 4) snapshots" | ||
143 | |||
144 | # success, all done | ||
145 | diff --git a/tests/qemu-iotests/267.out b/tests/qemu-iotests/267.out | ||
146 | index XXXXXXX..XXXXXXX 100644 | ||
147 | --- a/tests/qemu-iotests/267.out | ||
148 | +++ b/tests/qemu-iotests/267.out | ||
149 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
150 | (qemu) savevm snap0 | ||
151 | (qemu) info snapshots | ||
152 | List of snapshots present on all disks: | ||
153 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
154 | --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
155 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
156 | +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
157 | (qemu) loadvm snap0 | ||
158 | (qemu) quit | ||
159 | |||
160 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
161 | (qemu) savevm snap0 | ||
162 | (qemu) info snapshots | ||
163 | List of snapshots present on all disks: | ||
164 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
165 | --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
166 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
167 | +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
168 | (qemu) loadvm snap0 | ||
169 | (qemu) quit | ||
170 | |||
171 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
172 | (qemu) savevm snap0 | ||
173 | (qemu) info snapshots | ||
174 | List of snapshots present on all disks: | ||
175 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
176 | --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
177 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
178 | +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
179 | (qemu) loadvm snap0 | ||
180 | (qemu) quit | ||
181 | |||
182 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
183 | (qemu) savevm snap0 | ||
184 | (qemu) info snapshots | ||
185 | List of snapshots present on all disks: | ||
186 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
187 | --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
188 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
189 | +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
190 | (qemu) loadvm snap0 | ||
191 | (qemu) quit | ||
192 | |||
193 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
194 | (qemu) savevm snap0 | ||
195 | (qemu) info snapshots | ||
196 | List of snapshots present on all disks: | ||
197 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
198 | --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
199 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
200 | +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
201 | (qemu) loadvm snap0 | ||
202 | (qemu) quit | ||
203 | |||
204 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
205 | (qemu) savevm snap0 | ||
206 | (qemu) info snapshots | ||
207 | List of snapshots present on all disks: | ||
208 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
209 | --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
210 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
211 | +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
212 | (qemu) loadvm snap0 | ||
213 | (qemu) quit | ||
214 | |||
215 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
216 | (qemu) savevm snap0 | ||
217 | (qemu) info snapshots | ||
218 | List of snapshots present on all disks: | ||
219 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
220 | --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
221 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
222 | +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
223 | (qemu) loadvm snap0 | ||
224 | (qemu) quit | ||
225 | |||
226 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
227 | (qemu) savevm snap0 | ||
228 | (qemu) info snapshots | ||
229 | List of snapshots present on all disks: | ||
230 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
231 | --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
232 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
233 | +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
234 | (qemu) loadvm snap0 | ||
235 | (qemu) quit | ||
236 | |||
237 | Internal snapshots on overlay: | ||
238 | Snapshot list: | ||
239 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
240 | -1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
241 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
242 | +1 snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
243 | Internal snapshots on backing file: | ||
244 | |||
245 | === -blockdev with NBD server on the backing file === | ||
246 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
247 | (qemu) savevm snap0 | ||
248 | (qemu) info snapshots | ||
249 | List of snapshots present on all disks: | ||
250 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
251 | --- snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
252 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
253 | +-- snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
254 | (qemu) loadvm snap0 | ||
255 | (qemu) quit | ||
256 | |||
257 | Internal snapshots on overlay: | ||
258 | Snapshot list: | ||
259 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
260 | -1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
261 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
262 | +1 snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
263 | Internal snapshots on backing file: | ||
264 | Snapshot list: | ||
265 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
266 | -1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
267 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
268 | +1 snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
269 | *** done | ||
270 | diff --git a/tests/qemu-iotests/286 b/tests/qemu-iotests/286 | ||
271 | index XXXXXXX..XXXXXXX 100755 | ||
272 | --- a/tests/qemu-iotests/286 | ||
273 | +++ b/tests/qemu-iotests/286 | ||
274 | @@ -XXX,XX +XXX,XX @@ $QEMU_IMG snapshot -l "$TEST_IMG" | tail -n 1 | tr -s ' ' \ | ||
275 | -e 's/\./(VM state size unit)/' \ | ||
276 | -e 's/\./(snapshot date)/' \ | ||
277 | -e 's/\./(snapshot time)/' \ | ||
278 | - -e 's/\./(VM clock)/' | ||
279 | + -e 's/\./(VM clock)/' \ | ||
280 | + -e 's/\./(icount)/' | ||
281 | |||
282 | # success, all done | ||
283 | echo "*** done" | ||
284 | diff --git a/tests/qemu-iotests/286.out b/tests/qemu-iotests/286.out | ||
285 | index XXXXXXX..XXXXXXX 100644 | ||
286 | --- a/tests/qemu-iotests/286.out | ||
287 | +++ b/tests/qemu-iotests/286.out | ||
288 | @@ -XXX,XX +XXX,XX @@ QEMU X.Y.Z monitor - type 'help' for more information | ||
289 | (qemu) savevm abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz | ||
290 | (qemu) quit | ||
291 | Output structure: | ||
292 | -(snapshot ID) (snapshot name) (VM state size value) (VM state size unit) (snapshot date) (snapshot time) (VM clock) | ||
293 | +(snapshot ID) (snapshot name) (VM state size value) (VM state size unit) (snapshot date) (snapshot time) (VM clock) (icount) | ||
294 | *** done | ||
295 | diff --git a/tests/qemu-iotests/tests/qcow2-internal-snapshots.out b/tests/qemu-iotests/tests/qcow2-internal-snapshots.out | ||
296 | index XXXXXXX..XXXXXXX 100644 | ||
297 | --- a/tests/qemu-iotests/tests/qcow2-internal-snapshots.out | ||
298 | +++ b/tests/qemu-iotests/tests/qcow2-internal-snapshots.out | ||
299 | @@ -XXX,XX +XXX,XX @@ wrote 524288/524288 bytes at offset 0 | ||
300 | (qemu) quit | ||
301 | |||
302 | Snapshot list: | ||
303 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
304 | -1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
305 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
306 | +1 snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
307 | No errors were found on the image. | ||
308 | |||
309 | === Verify that loading the snapshot reverts to the old content === | ||
310 | @@ -XXX,XX +XXX,XX @@ read 64512/64512 bytes at offset 66560 | ||
311 | (qemu) quit | ||
312 | |||
313 | Snapshot list: | ||
314 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
315 | -1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
316 | -2 snap1 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
317 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
318 | +1 snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
319 | +2 snap1 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
320 | No errors were found on the image. | ||
321 | |||
322 | === qemu-img snapshot can revert to snapshots === | ||
323 | @@ -XXX,XX +XXX,XX @@ read 64512/64512 bytes at offset 66560 | ||
324 | (qemu) quit | ||
325 | |||
326 | Snapshot list: | ||
327 | -ID TAG VM SIZE DATE VM CLOCK ICOUNT | ||
328 | -1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000 | ||
329 | +ID TAG VM_SIZE DATE VM_CLOCK ICOUNT | ||
330 | +1 snap0 SIZE yyyy-mm-dd hh:mm:ss 0000:00:00.000 -- | ||
331 | No errors were found on the image. | ||
332 | |||
333 | === Error cases === | ||
334 | -- | ||
335 | 2.44.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Thomas Huth <thuth@redhat.com> | ||
1 | 2 | ||
3 | When running iotest 033 with the ssh protocol, it fails with: | ||
4 | |||
5 | 033 fail [14:48:31] [14:48:41] 10.2s output mismatch | ||
6 | --- /.../tests/qemu-iotests/033.out | ||
7 | +++ /.../tests/qemu-iotests/scratch/qcow2-ssh-033/033.out.bad | ||
8 | @@ -174,6 +174,7 @@ | ||
9 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
10 | wrote 512/512 bytes at offset 2097152 | ||
11 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
12 | +qemu-io: warning: Failed to truncate the tail of the image: ssh driver does not support shrinking files | ||
13 | read 512/512 bytes at offset 0 | ||
14 | 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
15 | |||
16 | We already check for the qcow2 format here, so let's simply also | ||
17 | add a check for the protocol here, too, to only test the truncation | ||
18 | with the file protocol. | ||
19 | |||
20 | Signed-off-by: Thomas Huth <thuth@redhat.com> | ||
21 | Message-ID: <20240315111108.153201-2-thuth@redhat.com> | ||
22 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
23 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
24 | --- | ||
25 | tests/qemu-iotests/033 | 6 +++--- | ||
26 | 1 file changed, 3 insertions(+), 3 deletions(-) | ||
27 | |||
28 | diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033 | ||
29 | index XXXXXXX..XXXXXXX 100755 | ||
30 | --- a/tests/qemu-iotests/033 | ||
31 | +++ b/tests/qemu-iotests/033 | ||
32 | @@ -XXX,XX +XXX,XX @@ do_test 512 "write -P 1 0 0x200" "$TEST_IMG" | _filter_qemu_io | ||
33 | # next L2 table | ||
34 | do_test 512 "write -P 1 $L2_COVERAGE 0x200" "$TEST_IMG" | _filter_qemu_io | ||
35 | |||
36 | -# only interested in qcow2 here; also other formats might respond with | ||
37 | -# "not supported" error message | ||
38 | -if [ $IMGFMT = "qcow2" ]; then | ||
39 | +# only interested in qcow2 with file protocol here; also other formats | ||
40 | +# might respond with "not supported" error message | ||
41 | +if [ $IMGFMT = "qcow2" ] && [ $IMGPROTO = "file" ]; then | ||
42 | do_test 512 "truncate $L2_COVERAGE" "$TEST_IMG" | _filter_qemu_io | ||
43 | fi | ||
44 | |||
45 | -- | ||
46 | 2.44.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Thomas Huth <thuth@redhat.com> | ||
1 | 2 | ||
3 | The hand-crafted json statement in this test only works if the test | ||
4 | is run with the "file" protocol, so mark this test accordingly. | ||
5 | |||
6 | Signed-off-by: Thomas Huth <thuth@redhat.com> | ||
7 | Message-ID: <20240315111108.153201-3-thuth@redhat.com> | ||
8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | ||
11 | tests/qemu-iotests/066 | 2 +- | ||
12 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
13 | |||
14 | diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066 | ||
15 | index XXXXXXX..XXXXXXX 100755 | ||
16 | --- a/tests/qemu-iotests/066 | ||
17 | +++ b/tests/qemu-iotests/066 | ||
18 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
19 | |||
20 | # This tests qcow2-specific low-level functionality | ||
21 | _supported_fmt qcow2 | ||
22 | -_supported_proto generic | ||
23 | +_supported_proto file | ||
24 | # We need zero clusters and snapshots | ||
25 | # (TODO: Consider splitting the snapshot part into a separate test | ||
26 | # file, so this one runs with refcount_bits=1 and data_file) | ||
27 | -- | ||
28 | 2.44.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Thomas Huth <thuth@redhat.com> | ||
1 | 2 | ||
3 | iotest 114 uses "truncate" and the qcow2.py script on the destination file, | ||
4 | which both cannot deal with URIs. Thus this test needs the "file" protocol, | ||
5 | otherwise it fails with an error message like this: | ||
6 | |||
7 | truncate: cannot open 'ssh://127.0.0.1/tmp/qemu-build/tests/qemu-iotests/scratch/qcow2-ssh-114/t.qcow2.orig' | ||
8 | for writing: No such file or directory | ||
9 | |||
10 | Thus mark this test for "file protocol only" accordingly. | ||
11 | |||
12 | Signed-off-by: Thomas Huth <thuth@redhat.com> | ||
13 | Message-ID: <20240315111108.153201-4-thuth@redhat.com> | ||
14 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
16 | --- | ||
17 | tests/qemu-iotests/114 | 2 +- | ||
18 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
19 | |||
20 | diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114 | ||
21 | index XXXXXXX..XXXXXXX 100755 | ||
22 | --- a/tests/qemu-iotests/114 | ||
23 | +++ b/tests/qemu-iotests/114 | ||
24 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
25 | . ./common.filter | ||
26 | |||
27 | _supported_fmt qcow2 | ||
28 | -_supported_proto generic | ||
29 | +_supported_proto file | ||
30 | # At least OpenBSD doesn't seem to have truncate | ||
31 | _supported_os Linux | ||
32 | # qcow2.py does not work too well with external data files | ||
33 | -- | ||
34 | 2.44.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Thomas Huth <thuth@redhat.com> | ||
1 | 2 | ||
3 | Using "-drive ...,backing.file.filename=..." only works with the | ||
4 | file protocol, but not with URIs, so mark this test accordingly. | ||
5 | |||
6 | Signed-off-by: Thomas Huth <thuth@redhat.com> | ||
7 | Message-ID: <20240315111108.153201-5-thuth@redhat.com> | ||
8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | --- | ||
11 | tests/qemu-iotests/130 | 2 +- | ||
12 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
13 | |||
14 | diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130 | ||
15 | index XXXXXXX..XXXXXXX 100755 | ||
16 | --- a/tests/qemu-iotests/130 | ||
17 | +++ b/tests/qemu-iotests/130 | ||
18 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
19 | . ./common.qemu | ||
20 | |||
21 | _supported_fmt qcow2 | ||
22 | -_supported_proto generic | ||
23 | +_supported_proto file | ||
24 | _supported_os Linux | ||
25 | # We are going to use lazy-refcounts | ||
26 | _unsupported_imgopts 'compat=0.10' | ||
27 | -- | ||
28 | 2.44.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Thomas Huth <thuth@redhat.com> | ||
1 | 2 | ||
3 | Commit b25b387fa592 updated the iotests 134 and 158 to use the --image-opts | ||
4 | parameter for qemu-io with file protocol related options, but forgot to | ||
5 | update the _supported_proto line accordingly. So let's do that now. | ||
6 | |||
7 | Fixes: b25b387fa5 ("qcow2: convert QCow2 to use QCryptoBlock for encryption") | ||
8 | Signed-off-by: Thomas Huth <thuth@redhat.com> | ||
9 | Message-ID: <20240315111108.153201-6-thuth@redhat.com> | ||
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | --- | ||
13 | tests/qemu-iotests/134 | 2 +- | ||
14 | tests/qemu-iotests/158 | 2 +- | ||
15 | 2 files changed, 2 insertions(+), 2 deletions(-) | ||
16 | |||
17 | diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134 | ||
18 | index XXXXXXX..XXXXXXX 100755 | ||
19 | --- a/tests/qemu-iotests/134 | ||
20 | +++ b/tests/qemu-iotests/134 | ||
21 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
22 | . ./common.filter | ||
23 | |||
24 | _supported_fmt qcow qcow2 | ||
25 | -_supported_proto generic | ||
26 | +_supported_proto file | ||
27 | |||
28 | |||
29 | size=128M | ||
30 | diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158 | ||
31 | index XXXXXXX..XXXXXXX 100755 | ||
32 | --- a/tests/qemu-iotests/158 | ||
33 | +++ b/tests/qemu-iotests/158 | ||
34 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
35 | . ./common.filter | ||
36 | |||
37 | _supported_fmt qcow qcow2 | ||
38 | -_supported_proto generic | ||
39 | +_supported_proto file | ||
40 | |||
41 | |||
42 | size=128M | ||
43 | -- | ||
44 | 2.44.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Thomas Huth <thuth@redhat.com> | ||
1 | 2 | ||
3 | The test fails completely when you try to use it with a different | ||
4 | protocol, e.g. with "./check -ssh -qcow2 156". | ||
5 | The test uses some hand-crafted JSON statements which cannot work with other | ||
6 | protocols, thus let's change this test to only support the 'file' protocol. | ||
7 | |||
8 | Signed-off-by: Thomas Huth <thuth@redhat.com> | ||
9 | Message-ID: <20240315111108.153201-7-thuth@redhat.com> | ||
10 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | --- | ||
13 | tests/qemu-iotests/156 | 2 +- | ||
14 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
15 | |||
16 | diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156 | ||
17 | index XXXXXXX..XXXXXXX 100755 | ||
18 | --- a/tests/qemu-iotests/156 | ||
19 | +++ b/tests/qemu-iotests/156 | ||
20 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
21 | . ./common.qemu | ||
22 | |||
23 | _supported_fmt qcow2 qed | ||
24 | -_supported_proto generic | ||
25 | +_supported_proto file | ||
26 | # Copying files around with cp does not work with external data files | ||
27 | _unsupported_imgopts data_file | ||
28 | |||
29 | -- | ||
30 | 2.44.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Thomas Huth <thuth@redhat.com> | ||
1 | 2 | ||
3 | These tests 188, 189 and 198 use qemu-io with --image-opts with additional | ||
4 | hard-coded parameters for the file protocol, so they cannot work for other | ||
5 | protocols. Thus we have to limit these tests to the file protocol only. | ||
6 | |||
7 | Signed-off-by: Thomas Huth <thuth@redhat.com> | ||
8 | Message-ID: <20240315111108.153201-8-thuth@redhat.com> | ||
9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | ||
12 | tests/qemu-iotests/188 | 2 +- | ||
13 | tests/qemu-iotests/189 | 2 +- | ||
14 | tests/qemu-iotests/198 | 2 +- | ||
15 | 3 files changed, 3 insertions(+), 3 deletions(-) | ||
16 | |||
17 | diff --git a/tests/qemu-iotests/188 b/tests/qemu-iotests/188 | ||
18 | index XXXXXXX..XXXXXXX 100755 | ||
19 | --- a/tests/qemu-iotests/188 | ||
20 | +++ b/tests/qemu-iotests/188 | ||
21 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
22 | . ./common.filter | ||
23 | |||
24 | _supported_fmt qcow2 | ||
25 | -_supported_proto generic | ||
26 | +_supported_proto file | ||
27 | _supported_os Linux | ||
28 | _require_working_luks | ||
29 | |||
30 | diff --git a/tests/qemu-iotests/189 b/tests/qemu-iotests/189 | ||
31 | index XXXXXXX..XXXXXXX 100755 | ||
32 | --- a/tests/qemu-iotests/189 | ||
33 | +++ b/tests/qemu-iotests/189 | ||
34 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
35 | . ./common.filter | ||
36 | |||
37 | _supported_fmt qcow2 | ||
38 | -_supported_proto generic | ||
39 | +_supported_proto file | ||
40 | _supported_os Linux | ||
41 | _require_working_luks | ||
42 | |||
43 | diff --git a/tests/qemu-iotests/198 b/tests/qemu-iotests/198 | ||
44 | index XXXXXXX..XXXXXXX 100755 | ||
45 | --- a/tests/qemu-iotests/198 | ||
46 | +++ b/tests/qemu-iotests/198 | ||
47 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
48 | . ./common.filter | ||
49 | |||
50 | _supported_fmt qcow2 | ||
51 | -_supported_proto generic | ||
52 | +_supported_proto file | ||
53 | _supported_os Linux | ||
54 | _require_working_luks | ||
55 | |||
56 | -- | ||
57 | 2.44.0 | diff view generated by jsdifflib |
1 | From: Ari Sundholm <ari@tuxera.com> | 1 | From: Thomas Huth <thuth@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This allows using the two constants outside of block.c, which will | 3 | Tests 263, 284 and detect-zeroes-registered-buf use qemu-io |
4 | happen in a subsequent patch. | 4 | with --image-opts so we have to enforce IMGOPTSSYNTAX=true here |
5 | to get $TEST_IMG in shape for other protocols than "file". | ||
5 | 6 | ||
6 | Signed-off-by: Ari Sundholm <ari@tuxera.com> | 7 | Signed-off-by: Thomas Huth <thuth@redhat.com> |
8 | Message-ID: <20240315111108.153201-9-thuth@redhat.com> | ||
9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | --- | 11 | --- |
9 | include/block/block.h | 7 +++++++ | 12 | tests/qemu-iotests/263 | 6 ++++-- |
10 | block.c | 6 ------ | 13 | tests/qemu-iotests/284 | 7 +++---- |
11 | 2 files changed, 7 insertions(+), 6 deletions(-) | 14 | tests/qemu-iotests/tests/detect-zeroes-registered-buf | 4 +++- |
15 | 3 files changed, 10 insertions(+), 7 deletions(-) | ||
12 | 16 | ||
13 | diff --git a/include/block/block.h b/include/block/block.h | 17 | diff --git a/tests/qemu-iotests/263 b/tests/qemu-iotests/263 |
14 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100755 |
15 | --- a/include/block/block.h | 19 | --- a/tests/qemu-iotests/263 |
16 | +++ b/include/block/block.h | 20 | +++ b/tests/qemu-iotests/263 |
17 | @@ -XXX,XX +XXX,XX @@ enum { | 21 | @@ -XXX,XX +XXX,XX @@ _cleanup() |
18 | BLK_PERM_GRAPH_MOD = 0x10, | 22 | } |
19 | 23 | trap "_cleanup; exit \$status" 0 1 2 3 15 | |
20 | BLK_PERM_ALL = 0x1f, | 24 | |
25 | +IMGOPTSSYNTAX=true | ||
21 | + | 26 | + |
22 | + DEFAULT_PERM_PASSTHROUGH = BLK_PERM_CONSISTENT_READ | 27 | # get standard environment, filters and checks |
23 | + | BLK_PERM_WRITE | 28 | . ./common.rc |
24 | + | BLK_PERM_WRITE_UNCHANGED | 29 | . ./common.filter |
25 | + | BLK_PERM_RESIZE, | 30 | @@ -XXX,XX +XXX,XX @@ echo "testing LUKS qcow2 encryption" |
31 | echo | ||
32 | |||
33 | _make_test_img --object $SECRET -o "encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10,cluster_size=64K" $size | ||
34 | -_run_test "driver=$IMGFMT,encrypt.key-secret=sec0,file.filename=$TEST_IMG" | ||
35 | +_run_test "$TEST_IMG,encrypt.key-secret=sec0" | ||
36 | _cleanup_test_img | ||
37 | |||
38 | echo | ||
39 | @@ -XXX,XX +XXX,XX @@ echo | ||
40 | |||
41 | |||
42 | _make_test_img --object $SECRET -o "encrypt.format=aes,encrypt.key-secret=sec0,cluster_size=64K" $size | ||
43 | -_run_test "driver=$IMGFMT,encrypt.key-secret=sec0,file.filename=$TEST_IMG" | ||
44 | +_run_test "$TEST_IMG,encrypt.key-secret=sec0" | ||
45 | _cleanup_test_img | ||
46 | |||
47 | |||
48 | diff --git a/tests/qemu-iotests/284 b/tests/qemu-iotests/284 | ||
49 | index XXXXXXX..XXXXXXX 100755 | ||
50 | --- a/tests/qemu-iotests/284 | ||
51 | +++ b/tests/qemu-iotests/284 | ||
52 | @@ -XXX,XX +XXX,XX @@ _cleanup() | ||
53 | } | ||
54 | trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
55 | |||
56 | +IMGOPTSSYNTAX=true | ||
26 | + | 57 | + |
27 | + DEFAULT_PERM_UNCHANGED = BLK_PERM_ALL & ~DEFAULT_PERM_PASSTHROUGH, | 58 | # get standard environment, filters and checks |
28 | }; | 59 | . ./common.rc |
29 | 60 | . ./common.filter | |
30 | char *bdrv_perm_names(uint64_t perm); | 61 | @@ -XXX,XX +XXX,XX @@ size=1M |
31 | diff --git a/block.c b/block.c | 62 | |
32 | index XXXXXXX..XXXXXXX 100644 | 63 | SECRET="secret,id=sec0,data=astrochicken" |
33 | --- a/block.c | 64 | |
34 | +++ b/block.c | 65 | -IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0" |
35 | @@ -XXX,XX +XXX,XX @@ int bdrv_child_try_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared, | 66 | QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT |
36 | return 0; | 67 | |
68 | _run_test() | ||
69 | { | ||
70 | - IMGOPTSSYNTAX=true | ||
71 | OLD_TEST_IMG="$TEST_IMG" | ||
72 | - TEST_IMG="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0" | ||
73 | + TEST_IMG="$TEST_IMG,encrypt.key-secret=sec0" | ||
74 | QEMU_IMG_EXTRA_ARGS="--image-opts --object $SECRET" | ||
75 | |||
76 | echo | ||
77 | @@ -XXX,XX +XXX,XX @@ _run_test() | ||
78 | |||
79 | TEST_IMG="$OLD_TEST_IMG" | ||
80 | QEMU_IMG_EXTRA_ARGS= | ||
81 | - IMGOPTSSYNTAX= | ||
37 | } | 82 | } |
38 | 83 | ||
39 | -#define DEFAULT_PERM_PASSTHROUGH (BLK_PERM_CONSISTENT_READ \ | 84 | |
40 | - | BLK_PERM_WRITE \ | 85 | diff --git a/tests/qemu-iotests/tests/detect-zeroes-registered-buf b/tests/qemu-iotests/tests/detect-zeroes-registered-buf |
41 | - | BLK_PERM_WRITE_UNCHANGED \ | 86 | index XXXXXXX..XXXXXXX 100755 |
42 | - | BLK_PERM_RESIZE) | 87 | --- a/tests/qemu-iotests/tests/detect-zeroes-registered-buf |
43 | -#define DEFAULT_PERM_UNCHANGED (BLK_PERM_ALL & ~DEFAULT_PERM_PASSTHROUGH) | 88 | +++ b/tests/qemu-iotests/tests/detect-zeroes-registered-buf |
44 | - | 89 | @@ -XXX,XX +XXX,XX @@ _cleanup() |
45 | void bdrv_filter_default_perms(BlockDriverState *bs, BdrvChild *c, | 90 | } |
46 | const BdrvChildRole *role, | 91 | trap "_cleanup; exit \$status" 0 1 2 3 15 |
47 | BlockReopenQueue *reopen_queue, | 92 | |
93 | +IMGOPTSSYNTAX=true | ||
94 | + | ||
95 | # get standard environment, filters and checks | ||
96 | cd .. | ||
97 | . ./common.rc | ||
98 | @@ -XXX,XX +XXX,XX @@ _supported_proto generic | ||
99 | |||
100 | size=128M | ||
101 | _make_test_img $size | ||
102 | -IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,discard=unmap,detect-zeroes=unmap" | ||
103 | +IMGSPEC="$TEST_IMG,discard=unmap,detect-zeroes=unmap" | ||
104 | |||
105 | echo | ||
106 | echo "== writing zero buffer to image ==" | ||
48 | -- | 107 | -- |
49 | 2.13.6 | 108 | 2.44.0 |
50 | |||
51 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Thomas Huth <thuth@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Do data compression in separate threads. This significantly improve | 3 | Tests that use "--blockdev" with the "file" driver cannot work with |
4 | performance for qemu-img convert with -W (allow async writes) and -c | 4 | other protocols, so we should mark them accordingly. |
5 | (compressed) options. | ||
6 | 5 | ||
7 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 6 | Signed-off-by: Thomas Huth <thuth@redhat.com> |
7 | Message-ID: <20240315111108.153201-10-thuth@redhat.com> | ||
8 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | --- | 10 | --- |
10 | block/qcow2.h | 3 +++ | 11 | tests/qemu-iotests/tests/qcow2-internal-snapshots | 2 +- |
11 | block/qcow2.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- | 12 | tests/qemu-iotests/tests/qsd-jobs | 2 +- |
12 | 2 files changed, 64 insertions(+), 1 deletion(-) | 13 | 2 files changed, 2 insertions(+), 2 deletions(-) |
13 | 14 | ||
14 | diff --git a/block/qcow2.h b/block/qcow2.h | 15 | diff --git a/tests/qemu-iotests/tests/qcow2-internal-snapshots b/tests/qemu-iotests/tests/qcow2-internal-snapshots |
15 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100755 |
16 | --- a/block/qcow2.h | 17 | --- a/tests/qemu-iotests/tests/qcow2-internal-snapshots |
17 | +++ b/block/qcow2.h | 18 | +++ b/tests/qemu-iotests/tests/qcow2-internal-snapshots |
18 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcow2State { | 19 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 |
19 | * override) */ | 20 | |
20 | char *image_backing_file; | 21 | # This tests qcow2-specific low-level functionality |
21 | char *image_backing_format; | 22 | _supported_fmt qcow2 |
22 | + | 23 | -_supported_proto generic |
23 | + CoQueue compress_wait_queue; | 24 | +_supported_proto file |
24 | + int nb_compress_threads; | 25 | # Internal snapshots are (currently) impossible with refcount_bits=1, |
25 | } BDRVQcow2State; | 26 | # and generally impossible with external data files |
26 | 27 | _unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file | |
27 | typedef struct Qcow2COWRegion { | 28 | diff --git a/tests/qemu-iotests/tests/qsd-jobs b/tests/qemu-iotests/tests/qsd-jobs |
28 | diff --git a/block/qcow2.c b/block/qcow2.c | 29 | index XXXXXXX..XXXXXXX 100755 |
29 | index XXXXXXX..XXXXXXX 100644 | 30 | --- a/tests/qemu-iotests/tests/qsd-jobs |
30 | --- a/block/qcow2.c | 31 | +++ b/tests/qemu-iotests/tests/qsd-jobs |
31 | +++ b/block/qcow2.c | 32 | @@ -XXX,XX +XXX,XX @@ cd .. |
32 | @@ -XXX,XX +XXX,XX @@ | 33 | . ./common.filter |
33 | #include "qapi/qobject-input-visitor.h" | 34 | |
34 | #include "qapi/qapi-visit-block-core.h" | 35 | _supported_fmt qcow2 |
35 | #include "crypto.h" | 36 | -_supported_proto generic |
36 | +#include "block/thread-pool.h" | 37 | +_supported_proto file |
37 | 38 | ||
38 | /* | 39 | size=128M |
39 | Differences with QCOW: | 40 | |
40 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, | ||
41 | qcow2_check_refcounts(bs, &result, 0); | ||
42 | } | ||
43 | #endif | ||
44 | + | ||
45 | + qemu_co_queue_init(&s->compress_wait_queue); | ||
46 | + | ||
47 | return ret; | ||
48 | |||
49 | fail: | ||
50 | @@ -XXX,XX +XXX,XX @@ static ssize_t qcow2_compress(void *dest, const void *src, size_t size) | ||
51 | return ret; | ||
52 | } | ||
53 | |||
54 | +#define MAX_COMPRESS_THREADS 4 | ||
55 | + | ||
56 | +typedef struct Qcow2CompressData { | ||
57 | + void *dest; | ||
58 | + const void *src; | ||
59 | + size_t size; | ||
60 | + ssize_t ret; | ||
61 | +} Qcow2CompressData; | ||
62 | + | ||
63 | +static int qcow2_compress_pool_func(void *opaque) | ||
64 | +{ | ||
65 | + Qcow2CompressData *data = opaque; | ||
66 | + | ||
67 | + data->ret = qcow2_compress(data->dest, data->src, data->size); | ||
68 | + | ||
69 | + return 0; | ||
70 | +} | ||
71 | + | ||
72 | +static void qcow2_compress_complete(void *opaque, int ret) | ||
73 | +{ | ||
74 | + qemu_coroutine_enter(opaque); | ||
75 | +} | ||
76 | + | ||
77 | +/* See qcow2_compress definition for parameters description */ | ||
78 | +static ssize_t qcow2_co_compress(BlockDriverState *bs, | ||
79 | + void *dest, const void *src, size_t size) | ||
80 | +{ | ||
81 | + BDRVQcow2State *s = bs->opaque; | ||
82 | + BlockAIOCB *acb; | ||
83 | + ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs)); | ||
84 | + Qcow2CompressData arg = { | ||
85 | + .dest = dest, | ||
86 | + .src = src, | ||
87 | + .size = size, | ||
88 | + }; | ||
89 | + | ||
90 | + while (s->nb_compress_threads >= MAX_COMPRESS_THREADS) { | ||
91 | + qemu_co_queue_wait(&s->compress_wait_queue, NULL); | ||
92 | + } | ||
93 | + | ||
94 | + s->nb_compress_threads++; | ||
95 | + acb = thread_pool_submit_aio(pool, qcow2_compress_pool_func, &arg, | ||
96 | + qcow2_compress_complete, | ||
97 | + qemu_coroutine_self()); | ||
98 | + | ||
99 | + if (!acb) { | ||
100 | + s->nb_compress_threads--; | ||
101 | + return -EINVAL; | ||
102 | + } | ||
103 | + qemu_coroutine_yield(); | ||
104 | + s->nb_compress_threads--; | ||
105 | + qemu_co_queue_next(&s->compress_wait_queue); | ||
106 | + | ||
107 | + return arg.ret; | ||
108 | +} | ||
109 | + | ||
110 | /* XXX: put compressed sectors first, then all the cluster aligned | ||
111 | tables to avoid losing bytes in alignment */ | ||
112 | static coroutine_fn int | ||
113 | @@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, | ||
114 | |||
115 | out_buf = g_malloc(s->cluster_size); | ||
116 | |||
117 | - out_len = qcow2_compress(out_buf, buf, s->cluster_size); | ||
118 | + out_len = qcow2_co_compress(bs, out_buf, buf, s->cluster_size); | ||
119 | if (out_len == -2) { | ||
120 | ret = -EINVAL; | ||
121 | goto fail; | ||
122 | -- | 41 | -- |
123 | 2.13.6 | 42 | 2.44.0 |
124 | |||
125 | diff view generated by jsdifflib |
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 1 | From: Fiona Ebner <f.ebner@proxmox.com> |
---|---|---|---|
2 | 2 | ||
3 | Make a separate function for compression to be parallelized later. | 3 | Failure was noticed when running the tests for the qcow2 image format. |
4 | - use .avail_out field instead of .next_out to calculate size of | ||
5 | compressed data. It looks more natural and it allows to keep dest to | ||
6 | be void pointer | ||
7 | - set avail_out to be at least one byte less than input, to be sure | ||
8 | avoid inefficient compression earlier | ||
9 | 4 | ||
10 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 5 | Fixes: 0bd779e27e ("crypto: Introduce 'detached-header' field in QCryptoBlockInfoLUKS") |
6 | Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> | ||
7 | Message-ID: <20240216101415.293769-1-f.ebner@proxmox.com> | ||
8 | Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> | ||
9 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 11 | --- |
13 | block/qcow2.c | 76 ++++++++++++++++++++++++++++++++++++++--------------------- | 12 | tests/qemu-iotests/198.out | 2 ++ |
14 | 1 file changed, 49 insertions(+), 27 deletions(-) | 13 | tests/qemu-iotests/206.out | 1 + |
14 | 2 files changed, 3 insertions(+) | ||
15 | 15 | ||
16 | diff --git a/block/qcow2.c b/block/qcow2.c | 16 | diff --git a/tests/qemu-iotests/198.out b/tests/qemu-iotests/198.out |
17 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/qcow2.c | 18 | --- a/tests/qemu-iotests/198.out |
19 | +++ b/block/qcow2.c | 19 | +++ b/tests/qemu-iotests/198.out |
20 | @@ -XXX,XX +XXX,XX @@ | 20 | @@ -XXX,XX +XXX,XX @@ Format specific information: |
21 | */ | 21 | compression type: COMPRESSION_TYPE |
22 | 22 | encrypt: | |
23 | #include "qemu/osdep.h" | 23 | ivgen alg: plain64 |
24 | + | 24 | + detached header: false |
25 | +#define ZLIB_CONST | 25 | hash alg: sha256 |
26 | +#include <zlib.h> | 26 | cipher alg: aes-256 |
27 | + | 27 | uuid: 00000000-0000-0000-0000-000000000000 |
28 | #include "block/block_int.h" | 28 | @@ -XXX,XX +XXX,XX @@ Format specific information: |
29 | #include "block/qdict.h" | 29 | compression type: COMPRESSION_TYPE |
30 | #include "sysemu/block-backend.h" | 30 | encrypt: |
31 | #include "qemu/module.h" | 31 | ivgen alg: plain64 |
32 | -#include <zlib.h> | 32 | + detached header: false |
33 | #include "qcow2.h" | 33 | hash alg: sha256 |
34 | #include "qemu/error-report.h" | 34 | cipher alg: aes-256 |
35 | #include "qapi/error.h" | 35 | uuid: 00000000-0000-0000-0000-000000000000 |
36 | @@ -XXX,XX +XXX,XX @@ fail: | 36 | diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out |
37 | return ret; | 37 | index XXXXXXX..XXXXXXX 100644 |
38 | } | 38 | --- a/tests/qemu-iotests/206.out |
39 | 39 | +++ b/tests/qemu-iotests/206.out | |
40 | +/* | 40 | @@ -XXX,XX +XXX,XX @@ Format specific information: |
41 | + * qcow2_compress() | 41 | refcount bits: 16 |
42 | + * | 42 | encrypt: |
43 | + * @dest - destination buffer, at least of @size-1 bytes | 43 | ivgen alg: plain64 |
44 | + * @src - source buffer, @size bytes | 44 | + detached header: false |
45 | + * | 45 | hash alg: sha1 |
46 | + * Returns: compressed size on success | 46 | cipher alg: aes-128 |
47 | + * -1 if compression is inefficient | 47 | uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX |
48 | + * -2 on any other error | ||
49 | + */ | ||
50 | +static ssize_t qcow2_compress(void *dest, const void *src, size_t size) | ||
51 | +{ | ||
52 | + ssize_t ret; | ||
53 | + z_stream strm; | ||
54 | + | ||
55 | + /* best compression, small window, no zlib header */ | ||
56 | + memset(&strm, 0, sizeof(strm)); | ||
57 | + ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, | ||
58 | + -12, 9, Z_DEFAULT_STRATEGY); | ||
59 | + if (ret != 0) { | ||
60 | + return -2; | ||
61 | + } | ||
62 | + | ||
63 | + strm.avail_in = size; | ||
64 | + strm.next_in = src; | ||
65 | + strm.avail_out = size - 1; | ||
66 | + strm.next_out = dest; | ||
67 | + | ||
68 | + ret = deflate(&strm, Z_FINISH); | ||
69 | + if (ret == Z_STREAM_END) { | ||
70 | + ret = size - 1 - strm.avail_out; | ||
71 | + } else { | ||
72 | + ret = (ret == Z_OK ? -1 : -2); | ||
73 | + } | ||
74 | + | ||
75 | + deflateEnd(&strm); | ||
76 | + | ||
77 | + return ret; | ||
78 | +} | ||
79 | + | ||
80 | /* XXX: put compressed sectors first, then all the cluster aligned | ||
81 | tables to avoid losing bytes in alignment */ | ||
82 | static coroutine_fn int | ||
83 | @@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, | ||
84 | BDRVQcow2State *s = bs->opaque; | ||
85 | QEMUIOVector hd_qiov; | ||
86 | struct iovec iov; | ||
87 | - z_stream strm; | ||
88 | - int ret, out_len; | ||
89 | + int ret; | ||
90 | + size_t out_len; | ||
91 | uint8_t *buf, *out_buf; | ||
92 | int64_t cluster_offset; | ||
93 | |||
94 | @@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, | ||
95 | |||
96 | out_buf = g_malloc(s->cluster_size); | ||
97 | |||
98 | - /* best compression, small window, no zlib header */ | ||
99 | - memset(&strm, 0, sizeof(strm)); | ||
100 | - ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, | ||
101 | - Z_DEFLATED, -12, | ||
102 | - 9, Z_DEFAULT_STRATEGY); | ||
103 | - if (ret != 0) { | ||
104 | + out_len = qcow2_compress(out_buf, buf, s->cluster_size); | ||
105 | + if (out_len == -2) { | ||
106 | ret = -EINVAL; | ||
107 | goto fail; | ||
108 | - } | ||
109 | - | ||
110 | - strm.avail_in = s->cluster_size; | ||
111 | - strm.next_in = (uint8_t *)buf; | ||
112 | - strm.avail_out = s->cluster_size; | ||
113 | - strm.next_out = out_buf; | ||
114 | - | ||
115 | - ret = deflate(&strm, Z_FINISH); | ||
116 | - if (ret != Z_STREAM_END && ret != Z_OK) { | ||
117 | - deflateEnd(&strm); | ||
118 | - ret = -EINVAL; | ||
119 | - goto fail; | ||
120 | - } | ||
121 | - out_len = strm.next_out - out_buf; | ||
122 | - | ||
123 | - deflateEnd(&strm); | ||
124 | - | ||
125 | - if (ret != Z_STREAM_END || out_len >= s->cluster_size) { | ||
126 | + } else if (out_len == -1) { | ||
127 | /* could not compress: write normal cluster */ | ||
128 | ret = qcow2_co_pwritev(bs, offset, bytes, qiov, 0); | ||
129 | if (ret < 0) { | ||
130 | -- | 48 | -- |
131 | 2.13.6 | 49 | 2.44.0 |
132 | 50 | ||
133 | 51 | diff view generated by jsdifflib |