1 | The following changes since commit 672f9d0df10a68a5c5f2b32cbc8284abf9f5ee18: | 1 | The following changes since commit 754f756cc4c6d9d14b7230c62b5bb20f9d655888: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging (2020-02-18 14:23:43 +0000) | 3 | Merge tag 'pull-target-arm-20220422-1' of https://git.linaro.org/people/pmaydell/qemu-arm into staging (2022-04-22 08:03:18 -0700) |
4 | 4 | ||
5 | are available in the Git repository at: | 5 | are available in the Git repository at: |
6 | 6 | ||
7 | https://github.com/XanClic/qemu.git tags/pull-block-2020-02-20 | 7 | https://gitlab.com/hreitz/qemu.git tags/pull-block-2022-04-25 |
8 | 8 | ||
9 | for you to fetch changes up to dff8d44c96f128480430b0c59ed8760917dbd427: | 9 | for you to fetch changes up to 348a0740afc5b313599533eb69bbb2b95d2f1bba: |
10 | 10 | ||
11 | iotests: Test snapshot -l field separation (2020-02-20 16:43:42 +0100) | 11 | iotests/108: Fix when missing user_allow_other (2022-04-25 14:46:45 +0200) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | Block patches: | 14 | Block patches: |
15 | - qemu-img convert: New --target-is-zero parameter | 15 | - New @force parameter for blockdev-change-medium |
16 | - qcow2: Specify non-default compression type flag | 16 | - Improvements to the iotests to help with debugging |
17 | - optionally flat output for query-named-block-nodes | 17 | - Fix iotest 108 on systems without user_allow_other in fuse.conf |
18 | - some fixes | ||
19 | - pseudo-creation of images on block devices is now done by a generic | ||
20 | block layer function | ||
21 | 18 | ||
22 | ---------------------------------------------------------------- | 19 | ---------------------------------------------------------------- |
23 | Daniel P. Berrangé (1): | 20 | Denis V. Lunev (1): |
24 | block: always fill entire LUKS header space with zeros | 21 | block: add 'force' parameter to 'blockdev-change-medium' command |
25 | 22 | ||
26 | David Edmondson (1): | 23 | Hanna Reitz (1): |
27 | qemu-img: Add --target-is-zero to convert | 24 | iotests/108: Fix when missing user_allow_other |
28 | 25 | ||
29 | Max Reitz (11): | 26 | John Snow (12): |
30 | iotests/147: Fix drive parameters | 27 | iotests: replace calls to log(qemu_io(...)) with qemu_io_log() |
31 | iotests/279: Fix for non-qcow2 formats | 28 | iotests/163: Fix broken qemu-io invocation |
32 | block/nbd: Fix hang in .bdrv_close() | 29 | iotests: Don't check qemu_io() output for specific error strings |
33 | block: Generic file creation fallback | 30 | iotests/040: Don't check image pattern on zero-length image |
34 | file-posix: Drop hdev_co_create_opts() | 31 | iotests/040: Fix TestCommitWithFilters test |
35 | iscsi: Drop iscsi_co_create_opts() | 32 | iotests: create generic qemu_tool() function |
36 | iotests: Add test for image creation fallback | 33 | iotests: rebase qemu_io() on top of qemu_tool() |
37 | qemu-img: Fix convert -n -B for backing-less targets | 34 | iotests/migration-permissions: use assertRaises() for qemu_io() |
38 | iotests: Test convert -n -B to backing-less target | 35 | negative test |
39 | block: Fix VM size field width in snapshot dump | 36 | iotests/image-fleecing: switch to qemu_io() |
40 | iotests: Test snapshot -l field separation | 37 | iotests: remove qemu_io_pipe_and_status() |
38 | iotests: remove qemu_io_silent() and qemu_io_silent_check(). | ||
39 | iotests: make qemu_io_log() check return codes by default | ||
41 | 40 | ||
42 | Peter Krempa (1): | 41 | qapi/block.json | 6 ++ |
43 | qapi: Allow getting flat output from 'query-named-block-nodes' | 42 | block/qapi-sysemu.c | 3 +- |
44 | 43 | monitor/hmp-cmds.c | 4 +- | |
45 | Thomas Huth (1): | 44 | hmp-commands.hx | 11 ++- |
46 | iotests: Remove the superfluous 2nd check for the availability of | 45 | tests/qemu-iotests/030 | 85 +++++++++++-------- |
47 | quorum | 46 | tests/qemu-iotests/040 | 53 +++++++----- |
48 | 47 | tests/qemu-iotests/056 | 2 +- | |
49 | Vladimir Sementsov-Ogievskiy (3): | 48 | tests/qemu-iotests/108 | 2 +- |
50 | docs: improve qcow2 spec about extending image header | 49 | tests/qemu-iotests/149 | 6 +- |
51 | docs: qcow2: introduce compression type feature | 50 | tests/qemu-iotests/163 | 5 +- |
52 | block/backup-top: fix flags handling | 51 | tests/qemu-iotests/205 | 4 +- |
53 | 52 | tests/qemu-iotests/216 | 12 +-- | |
54 | block.c | 164 +++++++++++++++++++++++++++++++++---- | 53 | tests/qemu-iotests/218 | 5 +- |
55 | block/backup-top.c | 31 ++++--- | 54 | tests/qemu-iotests/224 | 4 +- |
56 | block/file-posix.c | 67 --------------- | 55 | tests/qemu-iotests/242 | 6 +- |
57 | block/iscsi.c | 56 ------------- | 56 | tests/qemu-iotests/245 | 17 ++-- |
58 | block/nbd.c | 14 +++- | 57 | tests/qemu-iotests/255 | 4 +- |
59 | block/qapi.c | 15 +++- | 58 | tests/qemu-iotests/258 | 11 ++- |
60 | block/qcow2.c | 11 ++- | 59 | tests/qemu-iotests/298 | 17 ++-- |
61 | blockdev.c | 8 +- | 60 | tests/qemu-iotests/303 | 4 +- |
62 | docs/interop/qcow2.txt | 64 ++++++++++++++- | 61 | tests/qemu-iotests/310 | 22 ++--- |
63 | docs/interop/qemu-img.rst | 9 +- | 62 | tests/qemu-iotests/iotests.py | 69 ++++++++------- |
64 | include/block/block.h | 2 +- | 63 | tests/qemu-iotests/tests/image-fleecing | 30 ++++--- |
65 | include/block/qapi.h | 4 +- | 64 | .../qemu-iotests/tests/migration-permissions | 28 +++--- |
66 | monitor/hmp-cmds.c | 2 +- | 65 | .../tests/mirror-ready-cancel-error | 2 +- |
67 | qapi/block-core.json | 7 +- | 66 | .../qemu-iotests/tests/nbd-reconnect-on-open | 2 +- |
68 | qemu-img-cmds.hx | 4 +- | 67 | .../qemu-iotests/tests/stream-error-on-reset | 4 +- |
69 | qemu-img.c | 28 ++++++- | 68 | ui/cocoa.m | 1 + |
70 | tests/qemu-iotests/122 | 14 ++++ | 69 | 28 files changed, 231 insertions(+), 188 deletions(-) |
71 | tests/qemu-iotests/122.out | 5 ++ | ||
72 | tests/qemu-iotests/139 | 3 - | ||
73 | tests/qemu-iotests/147 | 2 +- | ||
74 | tests/qemu-iotests/259 | 62 ++++++++++++++ | ||
75 | tests/qemu-iotests/259.out | 14 ++++ | ||
76 | tests/qemu-iotests/279 | 7 +- | ||
77 | tests/qemu-iotests/284 | 97 ++++++++++++++++++++++ | ||
78 | tests/qemu-iotests/284.out | 62 ++++++++++++++ | ||
79 | tests/qemu-iotests/286 | 76 +++++++++++++++++ | ||
80 | tests/qemu-iotests/286.out | 8 ++ | ||
81 | tests/qemu-iotests/group | 3 + | ||
82 | 28 files changed, 659 insertions(+), 180 deletions(-) | ||
83 | create mode 100755 tests/qemu-iotests/259 | ||
84 | create mode 100644 tests/qemu-iotests/259.out | ||
85 | create mode 100755 tests/qemu-iotests/284 | ||
86 | create mode 100644 tests/qemu-iotests/284.out | ||
87 | create mode 100755 tests/qemu-iotests/286 | ||
88 | create mode 100644 tests/qemu-iotests/286.out | ||
89 | 70 | ||
90 | -- | 71 | -- |
91 | 2.24.1 | 72 | 2.35.1 |
92 | |||
93 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | Make it more obvious how to add new fields to the version 3 header and | ||
4 | how to interpret them. | ||
5 | |||
6 | The specification is adjusted so that for new defined optional fields: | ||
7 | |||
8 | 1. Software may support some of these optional fields and ignore the | ||
9 | others, which means that features may be backported to downstream | ||
10 | Qemu independently. | ||
11 | 2. If we want to add incompatible field (or a field, for which some of | ||
12 | its values would be incompatible), it must be accompanied by | ||
13 | incompatible feature bit. | ||
14 | |||
15 | Also the concept of "default is zero" is clarified, as it's strange to | ||
16 | say that the value of the field is assumed to be zero for the software | ||
17 | version which don't know about the field at all and don't know how to | ||
18 | treat it be it zero or not. | ||
19 | |||
20 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
21 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
22 | Message-Id: <20200131142219.3264-2-vsementsov@virtuozzo.com> | ||
23 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
24 | [mreitz: s/some its/some of its/] | ||
25 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
26 | --- | ||
27 | docs/interop/qcow2.txt | 45 +++++++++++++++++++++++++++++++++++++++--- | ||
28 | 1 file changed, 42 insertions(+), 3 deletions(-) | ||
29 | |||
30 | diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/docs/interop/qcow2.txt | ||
33 | +++ b/docs/interop/qcow2.txt | ||
34 | @@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header: | ||
35 | Offset into the image file at which the snapshot table | ||
36 | starts. Must be aligned to a cluster boundary. | ||
37 | |||
38 | -If the version is 3 or higher, the header has the following additional fields. | ||
39 | -For version 2, the values are assumed to be zero, unless specified otherwise | ||
40 | -in the description of a field. | ||
41 | +For version 2, the header is exactly 72 bytes in length, and finishes here. | ||
42 | +For version 3 or higher, the header length is at least 104 bytes, including | ||
43 | +the next fields through header_length. | ||
44 | |||
45 | 72 - 79: incompatible_features | ||
46 | Bitmask of incompatible features. An implementation must | ||
47 | @@ -XXX,XX +XXX,XX @@ in the description of a field. | ||
48 | 100 - 103: header_length | ||
49 | Length of the header structure in bytes. For version 2 | ||
50 | images, the length is always assumed to be 72 bytes. | ||
51 | + For version 3 it's at least 104 bytes and must be a multiple | ||
52 | + of 8. | ||
53 | + | ||
54 | + | ||
55 | +=== Additional fields (version 3 and higher) === | ||
56 | + | ||
57 | +In general, these fields are optional and may be safely ignored by the software, | ||
58 | +as well as filled by zeros (which is equal to field absence), if software needs | ||
59 | +to set field B, but does not care about field A which precedes B. More | ||
60 | +formally, additional fields have the following compatibility rules: | ||
61 | + | ||
62 | +1. If the value of the additional field must not be ignored for correct | ||
63 | +handling of the file, it will be accompanied by a corresponding incompatible | ||
64 | +feature bit. | ||
65 | + | ||
66 | +2. If there are no unrecognized incompatible feature bits set, an unknown | ||
67 | +additional field may be safely ignored other than preserving its value when | ||
68 | +rewriting the image header. | ||
69 | + | ||
70 | +3. An explicit value of 0 will have the same behavior as when the field is not | ||
71 | +present*, if not altered by a specific incompatible bit. | ||
72 | + | ||
73 | +*. A field is considered not present when header_length is less than or equal | ||
74 | +to the field's offset. Also, all additional fields are not present for | ||
75 | +version 2. | ||
76 | + | ||
77 | + < ... No additional fields in the header currently ... > | ||
78 | + | ||
79 | + | ||
80 | +=== Header padding === | ||
81 | + | ||
82 | +@header_length must be a multiple of 8, which means that if the end of the last | ||
83 | +additional field is not aligned, some padding is needed. This padding must be | ||
84 | +zeroed, so that if some existing (or future) additional field will fall into | ||
85 | +the padding, it will be interpreted accordingly to point [3.] of the previous | ||
86 | +paragraph, i.e. in the same manner as when this field is not present. | ||
87 | + | ||
88 | + | ||
89 | +=== Header extensions === | ||
90 | |||
91 | Directly after the image header, optional sections called header extensions can | ||
92 | be stored. Each extension has a structure like the following: | ||
93 | -- | ||
94 | 2.24.1 | ||
95 | |||
96 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | The patch adds a new additional field to the qcow2 header: compression_type, | ||
4 | which specifies compression type. If field is absent or zero, default | ||
5 | compression type is set: ZLIB, which corresponds to current behavior. | ||
6 | |||
7 | New compression type (ZSTD) is to be added in further commit. | ||
8 | |||
9 | Suggested-by: Denis Plotnikov <dplotnikov@virtuozzo.com> | ||
10 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
11 | Message-Id: <20200131142219.3264-3-vsementsov@virtuozzo.com> | ||
12 | [mreitz: s/Bits 3-63: Reserved/Bits 4-63: Reserved/] | ||
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
14 | --- | ||
15 | docs/interop/qcow2.txt | 21 +++++++++++++++++++-- | ||
16 | 1 file changed, 19 insertions(+), 2 deletions(-) | ||
17 | |||
18 | diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/docs/interop/qcow2.txt | ||
21 | +++ b/docs/interop/qcow2.txt | ||
22 | @@ -XXX,XX +XXX,XX @@ the next fields through header_length. | ||
23 | An External Data File Name header extension may | ||
24 | be present if this bit is set. | ||
25 | |||
26 | - Bits 3-63: Reserved (set to 0) | ||
27 | + Bit 3: Compression type bit. If this bit is set, | ||
28 | + a non-default compression is used for compressed | ||
29 | + clusters. The compression_type field must be | ||
30 | + present and not zero. | ||
31 | + | ||
32 | + Bits 4-63: Reserved (set to 0) | ||
33 | |||
34 | 80 - 87: compatible_features | ||
35 | Bitmask of compatible features. An implementation can | ||
36 | @@ -XXX,XX +XXX,XX @@ present*, if not altered by a specific incompatible bit. | ||
37 | to the field's offset. Also, all additional fields are not present for | ||
38 | version 2. | ||
39 | |||
40 | - < ... No additional fields in the header currently ... > | ||
41 | + 104: compression_type | ||
42 | + | ||
43 | + Defines the compression method used for compressed clusters. | ||
44 | + All compressed clusters in an image use the same compression | ||
45 | + type. | ||
46 | + | ||
47 | + If the incompatible bit "Compression type" is set: the field | ||
48 | + must be present and non-zero (which means non-zlib | ||
49 | + compression type). Otherwise, this field must not be present | ||
50 | + or must be zero (which means zlib). | ||
51 | + | ||
52 | + Available compression type values: | ||
53 | + 0: zlib <https://www.zlib.net/> | ||
54 | |||
55 | |||
56 | === Header padding === | ||
57 | -- | ||
58 | 2.24.1 | ||
59 | |||
60 | diff view generated by jsdifflib |
1 | From: Peter Krempa <pkrempa@redhat.com> | 1 | From: "Denis V. Lunev" <den@openvz.org> |
---|---|---|---|
2 | 2 | ||
3 | When a management application manages node names there's no reason to | 3 | 'blockdev-change-medium' is a convinient wrapper for the following |
4 | recurse into backing images in the output of query-named-block-nodes. | 4 | sequence of commands: |
5 | * blockdev-open-tray | ||
6 | * blockdev-remove-medium | ||
7 | * blockdev-insert-medium | ||
8 | * blockdev-close-tray | ||
9 | and should be used f.e. to change ISO image inside the CD-ROM tray. | ||
10 | Though the guest could lock the tray and some linux guests like | ||
11 | CentOS 8.5 actually does that. In this case the execution if this | ||
12 | command results in the error like the following: | ||
13 | Device 'scsi0-0-1-0' is locked and force was not specified, | ||
14 | wait for tray to open and try again. | ||
5 | 15 | ||
6 | Add a parameter to the command which will return just the top level | 16 | This situation is could be resolved 'blockdev-open-tray' by passing |
7 | structs. | 17 | flag 'force' inside. Thus is seems reasonable to add the same |
18 | capability for 'blockdev-change-medium' too. | ||
8 | 19 | ||
9 | Signed-off-by: Peter Krempa <pkrempa@redhat.com> | 20 | Signed-off-by: Denis V. Lunev <den@openvz.org> |
10 | Message-Id: <4470f8c779abc404dcf65e375db195cd91a80651.1579509782.git.pkrempa@redhat.com> | 21 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@openvz.org> |
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | 22 | Acked-by: "Dr. David Alan Gilbert" <dgilbert@redhat.com> |
12 | [mreitz: Fixed coding style] | 23 | CC: Kevin Wolf <kwolf@redhat.com> |
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 24 | CC: Hanna Reitz <hreitz@redhat.com> |
25 | CC: Eric Blake <eblake@redhat.com> | ||
26 | CC: Markus Armbruster <armbru@redhat.com> | ||
27 | Message-Id: <20220412221846.280723-1-den@openvz.org> | ||
28 | Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> | ||
29 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
14 | --- | 30 | --- |
15 | block.c | 5 +++-- | 31 | qapi/block.json | 6 ++++++ |
16 | block/qapi.c | 11 +++++++++-- | 32 | block/qapi-sysemu.c | 3 ++- |
17 | blockdev.c | 8 ++++++-- | 33 | monitor/hmp-cmds.c | 4 +++- |
18 | include/block/block.h | 2 +- | 34 | hmp-commands.hx | 11 +++++++---- |
19 | include/block/qapi.h | 4 +++- | 35 | ui/cocoa.m | 1 + |
20 | monitor/hmp-cmds.c | 2 +- | 36 | 5 files changed, 19 insertions(+), 6 deletions(-) |
21 | qapi/block-core.json | 7 ++++++- | ||
22 | 7 files changed, 29 insertions(+), 10 deletions(-) | ||
23 | 37 | ||
24 | diff --git a/block.c b/block.c | 38 | diff --git a/qapi/block.json b/qapi/block.json |
25 | index XXXXXXX..XXXXXXX 100644 | 39 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/block.c | 40 | --- a/qapi/block.json |
27 | +++ b/block.c | 41 | +++ b/qapi/block.json |
28 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_node(const char *node_name) | 42 | @@ -XXX,XX +XXX,XX @@ |
29 | } | 43 | # @read-only-mode: change the read-only mode of the device; defaults |
30 | 44 | # to 'retain' | |
31 | /* Put this QMP function here so it can access the static graph_bdrv_states. */ | 45 | # |
32 | -BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp) | 46 | +# @force: if false (the default), an eject request through blockdev-open-tray |
33 | +BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, | 47 | +# will be sent to the guest if it has locked the tray (and the tray |
34 | + Error **errp) | 48 | +# will not be opened immediately); if true, the tray will be opened |
35 | { | 49 | +# regardless of whether it is locked. (since 7.1) |
36 | BlockDeviceInfoList *list, *entry; | 50 | +# |
37 | BlockDriverState *bs; | 51 | # Features: |
38 | 52 | # @deprecated: Member @device is deprecated. Use @id instead. | |
39 | list = NULL; | 53 | # |
40 | QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) { | 54 | @@ -XXX,XX +XXX,XX @@ |
41 | - BlockDeviceInfo *info = bdrv_block_device_info(NULL, bs, errp); | 55 | '*id': 'str', |
42 | + BlockDeviceInfo *info = bdrv_block_device_info(NULL, bs, flat, errp); | 56 | 'filename': 'str', |
43 | if (!info) { | 57 | '*format': 'str', |
44 | qapi_free_BlockDeviceInfoList(list); | 58 | + '*force': 'bool', |
45 | return NULL; | 59 | '*read-only-mode': 'BlockdevChangeReadOnlyMode' } } |
46 | diff --git a/block/qapi.c b/block/qapi.c | 60 | |
61 | |||
62 | diff --git a/block/qapi-sysemu.c b/block/qapi-sysemu.c | ||
47 | index XXXXXXX..XXXXXXX 100644 | 63 | index XXXXXXX..XXXXXXX 100644 |
48 | --- a/block/qapi.c | 64 | --- a/block/qapi-sysemu.c |
49 | +++ b/block/qapi.c | 65 | +++ b/block/qapi-sysemu.c |
50 | @@ -XXX,XX +XXX,XX @@ | 66 | @@ -XXX,XX +XXX,XX @@ void qmp_blockdev_change_medium(bool has_device, const char *device, |
51 | #include "qemu/cutils.h" | 67 | bool has_id, const char *id, |
52 | 68 | const char *filename, | |
53 | BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, | 69 | bool has_format, const char *format, |
54 | - BlockDriverState *bs, Error **errp) | 70 | + bool has_force, bool force, |
55 | + BlockDriverState *bs, | 71 | bool has_read_only, |
56 | + bool flat, | 72 | BlockdevChangeReadOnlyMode read_only, |
57 | + Error **errp) | 73 | Error **errp) |
58 | { | 74 | @@ -XXX,XX +XXX,XX @@ void qmp_blockdev_change_medium(bool has_device, const char *device, |
59 | ImageInfo **p_image_info; | 75 | |
60 | BlockDriverState *bs0; | 76 | rc = do_open_tray(has_device ? device : NULL, |
61 | @@ -XXX,XX +XXX,XX @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, | 77 | has_id ? id : NULL, |
62 | return NULL; | 78 | - false, &err); |
63 | } | 79 | + force, &err); |
64 | 80 | if (rc && rc != -ENOSYS) { | |
65 | + /* stop gathering data for flat output */ | 81 | error_propagate(errp, err); |
66 | + if (flat) { | 82 | goto fail; |
67 | + break; | ||
68 | + } | ||
69 | + | ||
70 | if (bs0->drv && bs0->backing) { | ||
71 | info->backing_file_depth++; | ||
72 | bs0 = bs0->backing->bs; | ||
73 | @@ -XXX,XX +XXX,XX @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, | ||
74 | |||
75 | if (bs && bs->drv) { | ||
76 | info->has_inserted = true; | ||
77 | - info->inserted = bdrv_block_device_info(blk, bs, errp); | ||
78 | + info->inserted = bdrv_block_device_info(blk, bs, false, errp); | ||
79 | if (info->inserted == NULL) { | ||
80 | goto err; | ||
81 | } | ||
82 | diff --git a/blockdev.c b/blockdev.c | ||
83 | index XXXXXXX..XXXXXXX 100644 | ||
84 | --- a/blockdev.c | ||
85 | +++ b/blockdev.c | ||
86 | @@ -XXX,XX +XXX,XX @@ void qmp_drive_backup(DriveBackup *backup, Error **errp) | ||
87 | blockdev_do_action(&action, errp); | ||
88 | } | ||
89 | |||
90 | -BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp) | ||
91 | +BlockDeviceInfoList *qmp_query_named_block_nodes(bool has_flat, | ||
92 | + bool flat, | ||
93 | + Error **errp) | ||
94 | { | ||
95 | - return bdrv_named_nodes_list(errp); | ||
96 | + bool return_flat = has_flat && flat; | ||
97 | + | ||
98 | + return bdrv_named_nodes_list(return_flat, errp); | ||
99 | } | ||
100 | |||
101 | XDbgBlockGraph *qmp_x_debug_query_block_graph(Error **errp) | ||
102 | diff --git a/include/block/block.h b/include/block/block.h | ||
103 | index XXXXXXX..XXXXXXX 100644 | ||
104 | --- a/include/block/block.h | ||
105 | +++ b/include/block/block.h | ||
106 | @@ -XXX,XX +XXX,XX @@ void bdrv_lock_medium(BlockDriverState *bs, bool locked); | ||
107 | void bdrv_eject(BlockDriverState *bs, bool eject_flag); | ||
108 | const char *bdrv_get_format_name(BlockDriverState *bs); | ||
109 | BlockDriverState *bdrv_find_node(const char *node_name); | ||
110 | -BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp); | ||
111 | +BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, Error **errp); | ||
112 | XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp); | ||
113 | BlockDriverState *bdrv_lookup_bs(const char *device, | ||
114 | const char *node_name, | ||
115 | diff --git a/include/block/qapi.h b/include/block/qapi.h | ||
116 | index XXXXXXX..XXXXXXX 100644 | ||
117 | --- a/include/block/qapi.h | ||
118 | +++ b/include/block/qapi.h | ||
119 | @@ -XXX,XX +XXX,XX @@ | ||
120 | #include "block/snapshot.h" | ||
121 | |||
122 | BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, | ||
123 | - BlockDriverState *bs, Error **errp); | ||
124 | + BlockDriverState *bs, | ||
125 | + bool flat, | ||
126 | + Error **errp); | ||
127 | int bdrv_query_snapshot_info_list(BlockDriverState *bs, | ||
128 | SnapshotInfoList **p_list, | ||
129 | Error **errp); | ||
130 | diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c | 83 | diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c |
131 | index XXXXXXX..XXXXXXX 100644 | 84 | index XXXXXXX..XXXXXXX 100644 |
132 | --- a/monitor/hmp-cmds.c | 85 | --- a/monitor/hmp-cmds.c |
133 | +++ b/monitor/hmp-cmds.c | 86 | +++ b/monitor/hmp-cmds.c |
134 | @@ -XXX,XX +XXX,XX @@ void hmp_info_block(Monitor *mon, const QDict *qdict) | 87 | @@ -XXX,XX +XXX,XX @@ void hmp_change(Monitor *mon, const QDict *qdict) |
88 | const char *target = qdict_get_str(qdict, "target"); | ||
89 | const char *arg = qdict_get_try_str(qdict, "arg"); | ||
90 | const char *read_only = qdict_get_try_str(qdict, "read-only-mode"); | ||
91 | + bool force = qdict_get_try_bool(qdict, "force", false); | ||
92 | BlockdevChangeReadOnlyMode read_only_mode = 0; | ||
93 | Error *err = NULL; | ||
94 | |||
95 | @@ -XXX,XX +XXX,XX @@ void hmp_change(Monitor *mon, const QDict *qdict) | ||
96 | } | ||
97 | |||
98 | qmp_blockdev_change_medium(true, device, false, NULL, target, | ||
99 | - !!arg, arg, !!read_only, read_only_mode, | ||
100 | + !!arg, arg, true, force, | ||
101 | + !!read_only, read_only_mode, | ||
102 | &err); | ||
135 | } | 103 | } |
136 | 104 | ||
137 | /* Print node information */ | 105 | diff --git a/hmp-commands.hx b/hmp-commands.hx |
138 | - blockdev_list = qmp_query_named_block_nodes(NULL); | ||
139 | + blockdev_list = qmp_query_named_block_nodes(false, false, NULL); | ||
140 | for (blockdev = blockdev_list; blockdev; blockdev = blockdev->next) { | ||
141 | assert(blockdev->value->has_node_name); | ||
142 | if (device && strcmp(device, blockdev->value->node_name)) { | ||
143 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
144 | index XXXXXXX..XXXXXXX 100644 | 106 | index XXXXXXX..XXXXXXX 100644 |
145 | --- a/qapi/block-core.json | 107 | --- a/hmp-commands.hx |
146 | +++ b/qapi/block-core.json | 108 | +++ b/hmp-commands.hx |
147 | @@ -XXX,XX +XXX,XX @@ | 109 | @@ -XXX,XX +XXX,XX @@ ERST |
148 | # | 110 | |
149 | # Get the named block driver list | 111 | { |
150 | # | 112 | .name = "change", |
151 | +# @flat: Omit the nested data about backing image ("backing-image" key) if true. | 113 | - .args_type = "device:B,target:F,arg:s?,read-only-mode:s?", |
152 | +# Default is false (Since 5.0) | 114 | - .params = "device filename [format [read-only-mode]]", |
153 | +# | 115 | - .help = "change a removable medium, optional format", |
154 | # Returns: the list of BlockDeviceInfo | 116 | + .args_type = "device:B,force:-f,target:F,arg:s?,read-only-mode:s?", |
155 | # | 117 | + .params = "device [-f] filename [format [read-only-mode]]", |
156 | # Since: 2.0 | 118 | + .help = "change a removable medium, optional format, use -f to force the operation", |
157 | @@ -XXX,XX +XXX,XX @@ | 119 | .cmd = hmp_change, |
158 | # } } ] } | 120 | }, |
159 | # | 121 | |
160 | ## | 122 | @@ -XXX,XX +XXX,XX @@ SRST |
161 | -{ 'command': 'query-named-block-nodes', 'returns': [ 'BlockDeviceInfo' ] } | 123 | ``change`` *device* *setting* |
162 | +{ 'command': 'query-named-block-nodes', | 124 | Change the configuration of a device. |
163 | + 'returns': [ 'BlockDeviceInfo' ], | 125 | |
164 | + 'data': { '*flat': 'bool' } } | 126 | - ``change`` *diskdevice* *filename* [*format* [*read-only-mode*]] |
165 | 127 | + ``change`` *diskdevice* [-f] *filename* [*format* [*read-only-mode*]] | |
166 | ## | 128 | Change the medium for a removable disk device to point to *filename*. eg:: |
167 | # @XDbgBlockGraphNodeType: | 129 | |
130 | (qemu) change ide1-cd0 /path/to/some.iso | ||
131 | |||
132 | + ``-f`` | ||
133 | + forces the operation even if the guest has locked the tray. | ||
134 | + | ||
135 | *format* is optional. | ||
136 | |||
137 | *read-only-mode* may be used to change the read-only status of the device. | ||
138 | diff --git a/ui/cocoa.m b/ui/cocoa.m | ||
139 | index XXXXXXX..XXXXXXX 100644 | ||
140 | --- a/ui/cocoa.m | ||
141 | +++ b/ui/cocoa.m | ||
142 | @@ -XXX,XX +XXX,XX @@ - (void)changeDeviceMedia:(id)sender | ||
143 | [file cStringUsingEncoding: | ||
144 | NSASCIIStringEncoding], | ||
145 | true, "raw", | ||
146 | + true, false, | ||
147 | false, 0, | ||
148 | &err); | ||
149 | }); | ||
168 | -- | 150 | -- |
169 | 2.24.1 | 151 | 2.35.1 |
170 | 152 | ||
171 | 153 | diff view generated by jsdifflib |
1 | Add a test that all fields in "qemu-img snapshot -l"s output are | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | separated by spaces. | ||
3 | 2 | ||
4 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 3 | This makes these callsites a little simpler, but the real motivation is |
5 | Message-Id: <20200117105859.241818-3-mreitz@redhat.com> | 4 | a forthcoming commit will change the return type of qemu_io(), so removing |
5 | users of the return value now is helpful. | ||
6 | |||
7 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
6 | Reviewed-by: Eric Blake <eblake@redhat.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
7 | [mreitz: Renamed test from 284 to 286] | 9 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> |
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 10 | Message-Id: <20220418211504.943969-2-jsnow@redhat.com> |
11 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
9 | --- | 12 | --- |
10 | tests/qemu-iotests/286 | 76 ++++++++++++++++++++++++++++++++++++++ | 13 | tests/qemu-iotests/242 | 6 +++--- |
11 | tests/qemu-iotests/286.out | 8 ++++ | 14 | tests/qemu-iotests/255 | 4 +--- |
12 | tests/qemu-iotests/group | 1 + | 15 | tests/qemu-iotests/303 | 4 ++-- |
13 | 3 files changed, 85 insertions(+) | 16 | 3 files changed, 6 insertions(+), 8 deletions(-) |
14 | create mode 100755 tests/qemu-iotests/286 | ||
15 | create mode 100644 tests/qemu-iotests/286.out | ||
16 | 17 | ||
17 | diff --git a/tests/qemu-iotests/286 b/tests/qemu-iotests/286 | 18 | diff --git a/tests/qemu-iotests/242 b/tests/qemu-iotests/242 |
18 | new file mode 100755 | 19 | index XXXXXXX..XXXXXXX 100755 |
19 | index XXXXXXX..XXXXXXX | 20 | --- a/tests/qemu-iotests/242 |
20 | --- /dev/null | 21 | +++ b/tests/qemu-iotests/242 |
21 | +++ b/tests/qemu-iotests/286 | ||
22 | @@ -XXX,XX +XXX,XX @@ | 22 | @@ -XXX,XX +XXX,XX @@ |
23 | +#!/usr/bin/env bash | 23 | import iotests |
24 | +# | 24 | import json |
25 | +# Test qemu-img snapshot -l | 25 | import struct |
26 | +# | 26 | -from iotests import qemu_img_create, qemu_io, qemu_img_info, \ |
27 | +# Copyright (C) 2019 Red Hat, Inc. | 27 | - file_path, img_info_log, log, filter_qemu_io |
28 | +# | 28 | +from iotests import qemu_img_create, qemu_io_log, qemu_img_info, \ |
29 | +# This program is free software; you can redistribute it and/or modify | 29 | + file_path, img_info_log, log |
30 | +# it under the terms of the GNU General Public License as published by | 30 | |
31 | +# the Free Software Foundation; either version 2 of the License, or | 31 | iotests.script_initialize(supported_fmts=['qcow2'], |
32 | +# (at your option) any later version. | 32 | supported_protocols=['file'], |
33 | +# | 33 | @@ -XXX,XX +XXX,XX @@ def add_bitmap(bitmap_number, persistent, disabled): |
34 | +# This program is distributed in the hope that it will be useful, | 34 | |
35 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | 35 | def write_to_disk(offset, size): |
36 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 36 | write = 'write {} {}'.format(offset, size) |
37 | +# GNU General Public License for more details. | 37 | - log(qemu_io('-c', write, disk), filters=[filter_qemu_io]) |
38 | +# | 38 | + qemu_io_log('-c', write, disk) |
39 | +# You should have received a copy of the GNU General Public License | 39 | |
40 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | 40 | |
41 | +# | 41 | def toggle_flag(offset): |
42 | + | 42 | diff --git a/tests/qemu-iotests/255 b/tests/qemu-iotests/255 |
43 | +seq=$(basename "$0") | 43 | index XXXXXXX..XXXXXXX 100755 |
44 | +echo "QA output created by $seq" | 44 | --- a/tests/qemu-iotests/255 |
45 | + | 45 | +++ b/tests/qemu-iotests/255 |
46 | +status=1 # failure is the default! | 46 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('src.qcow2') as src_path, \ |
47 | + | 47 | iotests.qemu_img_create('-f', iotests.imgfmt, src_path, size_str) |
48 | +_cleanup() | 48 | iotests.qemu_img_create('-f', iotests.imgfmt, dst_path, size_str) |
49 | +{ | 49 | |
50 | + _cleanup_test_img | 50 | - iotests.log(iotests.qemu_io('-f', iotests.imgfmt, '-c', 'write 0 1M', |
51 | +} | 51 | - src_path), |
52 | +trap "_cleanup; exit \$status" 0 1 2 3 15 | 52 | - filters=[iotests.filter_test_dir, iotests.filter_qemu_io]) |
53 | + | 53 | + iotests.qemu_io_log('-f', iotests.imgfmt, '-c', 'write 0 1M', src_path), |
54 | +# get standard environment, filters and checks | 54 | |
55 | +. ./common.rc | 55 | vm.add_object('throttle-group,x-bps-read=4096,id=throttle0') |
56 | +. ./common.filter | 56 | |
57 | +. ./common.qemu | 57 | diff --git a/tests/qemu-iotests/303 b/tests/qemu-iotests/303 |
58 | + | 58 | index XXXXXXX..XXXXXXX 100755 |
59 | +_supported_fmt qcow2 | 59 | --- a/tests/qemu-iotests/303 |
60 | +_supported_proto file | 60 | +++ b/tests/qemu-iotests/303 |
61 | +# Internal snapshots are (currently) impossible with refcount_bits=1, | ||
62 | +# and generally impossible with external data files | ||
63 | +_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file | ||
64 | + | ||
65 | +_make_test_img 64M | ||
66 | + | ||
67 | +# Should be so long as to take up the whole field width | ||
68 | +sn_name=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz | ||
69 | + | ||
70 | +# More memory will give us a larger VM state, i.e. one above 1 MB. | ||
71 | +# This way, we get a number with a decimal point. | ||
72 | +qemu_comm_method=monitor _launch_qemu -m 512 "$TEST_IMG" | ||
73 | + | ||
74 | +_send_qemu_cmd $QEMU_HANDLE "savevm $sn_name" '(qemu)' | ||
75 | +_send_qemu_cmd $QEMU_HANDLE 'quit' '(qemu)' | ||
76 | +wait=yes _cleanup_qemu | ||
77 | + | ||
78 | +# Check that all fields are separated by spaces. | ||
79 | +# We first collapse all space sequences into one space each; | ||
80 | +# then we turn every space-separated field into a '.'; | ||
81 | +# and finally, we name the '.'s so the output is not just a confusing | ||
82 | +# sequence of dots. | ||
83 | + | ||
84 | +echo 'Output structure:' | ||
85 | +$QEMU_IMG snapshot -l "$TEST_IMG" | tail -n 1 | tr -s ' ' \ | ||
86 | + | sed -e 's/\S\+/./g' \ | ||
87 | + | sed -e 's/\./(snapshot ID)/' \ | ||
88 | + -e 's/\./(snapshot name)/' \ | ||
89 | + -e 's/\./(VM state size value)/' \ | ||
90 | + -e 's/\./(VM state size unit)/' \ | ||
91 | + -e 's/\./(snapshot date)/' \ | ||
92 | + -e 's/\./(snapshot time)/' \ | ||
93 | + -e 's/\./(VM clock)/' | ||
94 | + | ||
95 | +# success, all done | ||
96 | +echo "*** done" | ||
97 | +rm -f $seq.full | ||
98 | +status=0 | ||
99 | diff --git a/tests/qemu-iotests/286.out b/tests/qemu-iotests/286.out | ||
100 | new file mode 100644 | ||
101 | index XXXXXXX..XXXXXXX | ||
102 | --- /dev/null | ||
103 | +++ b/tests/qemu-iotests/286.out | ||
104 | @@ -XXX,XX +XXX,XX @@ | 61 | @@ -XXX,XX +XXX,XX @@ |
105 | +QA output created by 286 | 62 | |
106 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | 63 | import iotests |
107 | +QEMU X.Y.Z monitor - type 'help' for more information | 64 | import subprocess |
108 | +(qemu) savevm abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz | 65 | -from iotests import qemu_img_create, qemu_io, file_path, log, filter_qemu_io, \ |
109 | +(qemu) quit | 66 | +from iotests import qemu_img_create, qemu_io_log, file_path, log, \ |
110 | +Output structure: | 67 | verify_qcow2_zstd_compression |
111 | +(snapshot ID) (snapshot name) (VM state size value) (VM state size unit) (snapshot date) (snapshot time) (VM clock) | 68 | |
112 | +*** done | 69 | iotests.script_initialize(supported_fmts=['qcow2'], |
113 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | 70 | @@ -XXX,XX +XXX,XX @@ def create_bitmap(bitmap_number, disabled): |
114 | index XXXXXXX..XXXXXXX 100644 | 71 | |
115 | --- a/tests/qemu-iotests/group | 72 | def write_to_disk(offset, size): |
116 | +++ b/tests/qemu-iotests/group | 73 | write = f'write {offset} {size}' |
117 | @@ -XXX,XX +XXX,XX @@ | 74 | - log(qemu_io('-c', write, disk), filters=[filter_qemu_io]) |
118 | 281 rw quick | 75 | + qemu_io_log('-c', write, disk) |
119 | 283 auto quick | 76 | |
120 | 284 rw | 77 | |
121 | +286 rw quick | 78 | def add_bitmap(num, begin, end, disabled): |
122 | -- | 79 | -- |
123 | 2.24.1 | 80 | 2.35.1 |
124 | |||
125 | diff view generated by jsdifflib |
1 | When printing the snapshot list (e.g. with qemu-img snapshot -l), the VM | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | size field is only seven characters wide. As of de38b5005e9, this is | ||
3 | not necessarily sufficient: We generally print three digits, and this | ||
4 | may require a decimal point. Also, the unit field grew from something | ||
5 | as plain as "M" to " MiB". This means that number and unit may take up | ||
6 | eight characters in total; but we also want spaces in front. | ||
7 | 2 | ||
8 | Considering previously the maximum width was four characters and the | 3 | The 'read' commands to qemu-io were malformed, and this invocation only |
9 | field width was chosen to be three characters wider, let us adjust the | 4 | worked by coincidence because the error messages were identical. Oops. |
10 | field width to be eleven now. | ||
11 | 5 | ||
12 | Fixes: de38b5005e946aa3714963ea4c501e279e7d3666 | 6 | There's no point in checking the patterning of the reference image, so |
13 | Buglink: https://bugs.launchpad.net/qemu/+bug/1859989 | 7 | just check the empty image by itself instead. |
14 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 8 | |
15 | Message-Id: <20200117105859.241818-2-mreitz@redhat.com> | 9 | (Note: as of this commit, nothing actually enforces that this command |
10 | completes successfully, but a forthcoming commit in this series will | ||
11 | enforce that qemu_io() must have a zero status code.) | ||
12 | |||
13 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
16 | Reviewed-by: Eric Blake <eblake@redhat.com> | 14 | Reviewed-by: Eric Blake <eblake@redhat.com> |
17 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 15 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> |
16 | Message-Id: <20220418211504.943969-3-jsnow@redhat.com> | ||
17 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
18 | --- | 18 | --- |
19 | block/qapi.c | 4 ++-- | 19 | tests/qemu-iotests/163 | 5 +---- |
20 | 1 file changed, 2 insertions(+), 2 deletions(-) | 20 | 1 file changed, 1 insertion(+), 4 deletions(-) |
21 | 21 | ||
22 | diff --git a/block/qapi.c b/block/qapi.c | 22 | diff --git a/tests/qemu-iotests/163 b/tests/qemu-iotests/163 |
23 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100755 |
24 | --- a/block/qapi.c | 24 | --- a/tests/qemu-iotests/163 |
25 | +++ b/block/qapi.c | 25 | +++ b/tests/qemu-iotests/163 |
26 | @@ -XXX,XX +XXX,XX @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn) | 26 | @@ -XXX,XX +XXX,XX @@ class ShrinkBaseClass(iotests.QMPTestCase): |
27 | char *sizing = NULL; | 27 | qemu_img('resize', '-f', iotests.imgfmt, '--shrink', test_img, |
28 | 28 | self.shrink_size) | |
29 | if (!sn) { | 29 | |
30 | - qemu_printf("%-10s%-20s%7s%20s%15s", | 30 | - self.assertEqual( |
31 | + qemu_printf("%-10s%-20s%11s%20s%15s", | 31 | - qemu_io('-c', 'read -P 0x00 %s'%self.shrink_size, test_img), |
32 | "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); | 32 | - qemu_io('-c', 'read -P 0x00 %s'%self.shrink_size, check_img), |
33 | } else { | 33 | - "Verifying image content") |
34 | ti = sn->date_sec; | 34 | + qemu_io('-c', f"read -P 0x00 0 {self.shrink_size}", test_img) |
35 | @@ -XXX,XX +XXX,XX @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn) | 35 | |
36 | (int)(secs % 60), | 36 | self.image_verify() |
37 | (int)((sn->vm_clock_nsec / 1000000) % 1000)); | 37 | |
38 | sizing = size_to_str(sn->vm_state_size); | ||
39 | - qemu_printf("%-10s%-20s%7s%20s%15s", | ||
40 | + qemu_printf("%-10s%-20s%11s%20s%15s", | ||
41 | sn->id_str, sn->name, | ||
42 | sizing, | ||
43 | date_buf, | ||
44 | -- | 38 | -- |
45 | 2.24.1 | 39 | 2.35.1 |
46 | |||
47 | diff view generated by jsdifflib |
1 | This must not crash. | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 3 | A forthcoming commit updates qemu_io() to raise an exception on non-zero |
4 | Message-Id: <20200121155915.98232-3-mreitz@redhat.com> | 4 | return by default, and changes its return type. |
5 | Reviewed-by: John Snow <jsnow@redhat.com> | 5 | |
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 6 | In preparation, simplify some calls to qemu_io() that assert that |
7 | specific error message strings do not appear in qemu-io's | ||
8 | output. Asserting that all of these calls return a status code of zero | ||
9 | will be a more robust way to guard against failure. | ||
10 | |||
11 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
12 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
13 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
14 | Message-Id: <20220418211504.943969-4-jsnow@redhat.com> | ||
15 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
7 | --- | 16 | --- |
8 | tests/qemu-iotests/122 | 14 ++++++++++++++ | 17 | tests/qemu-iotests/040 | 33 ++++++++++++++++----------------- |
9 | tests/qemu-iotests/122.out | 5 +++++ | 18 | tests/qemu-iotests/056 | 2 +- |
10 | 2 files changed, 19 insertions(+) | 19 | 2 files changed, 17 insertions(+), 18 deletions(-) |
11 | 20 | ||
12 | diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 | 21 | diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 |
13 | index XXXXXXX..XXXXXXX 100755 | 22 | index XXXXXXX..XXXXXXX 100755 |
14 | --- a/tests/qemu-iotests/122 | 23 | --- a/tests/qemu-iotests/040 |
15 | +++ b/tests/qemu-iotests/122 | 24 | +++ b/tests/qemu-iotests/040 |
16 | @@ -XXX,XX +XXX,XX @@ $QEMU_IMG convert -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG".orig | 25 | @@ -XXX,XX +XXX,XX @@ class TestSingleDrive(ImageCommitTestCase): |
17 | 26 | ||
18 | $QEMU_IMG compare "$TEST_IMG" "$TEST_IMG".orig | 27 | def test_commit(self): |
19 | 28 | self.run_commit_test(mid_img, backing_img) | |
20 | +echo | 29 | - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) |
21 | +echo '=== -n -B to an image without a backing file ===' | 30 | - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) |
22 | +echo | 31 | + qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img) |
23 | + | 32 | + qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img) |
24 | +# Base for the output | 33 | |
25 | +TEST_IMG="$TEST_IMG".base _make_test_img 64M | 34 | def test_commit_node(self): |
26 | + | 35 | self.run_commit_test("mid", "base", node_names=True) |
27 | +# Output that does have $TEST_IMG.base set as its (implicit) backing file | 36 | - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) |
28 | +TEST_IMG="$TEST_IMG".orig _make_test_img 64M | 37 | - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) |
29 | + | 38 | + qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img) |
30 | +# Convert with -n, which should not confuse -B with "target BDS has a | 39 | + qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img) |
31 | +# backing file" | 40 | |
32 | +$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -n "$TEST_IMG" "$TEST_IMG".orig | 41 | @iotests.skip_if_unsupported(['throttle']) |
33 | + | 42 | def test_commit_with_filter_and_quit(self): |
34 | # success, all done | 43 | @@ -XXX,XX +XXX,XX @@ class TestSingleDrive(ImageCommitTestCase): |
35 | echo '*** done' | 44 | |
36 | rm -f $seq.full | 45 | def test_top_is_active(self): |
37 | diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out | 46 | self.run_commit_test(test_img, backing_img, need_ready=True) |
38 | index XXXXXXX..XXXXXXX 100644 | 47 | - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) |
39 | --- a/tests/qemu-iotests/122.out | 48 | - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) |
40 | +++ b/tests/qemu-iotests/122.out | 49 | + qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img) |
41 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864 | 50 | + qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img) |
42 | wrote 65536/65536 bytes at offset 0 | 51 | |
43 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | 52 | def test_top_is_default_active(self): |
44 | Images are identical. | 53 | self.run_default_commit_test() |
45 | + | 54 | - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed")) |
46 | +=== -n -B to an image without a backing file === | 55 | - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed")) |
47 | + | 56 | + qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img) |
48 | +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 | 57 | + qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img) |
49 | +Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864 | 58 | |
50 | *** done | 59 | def test_top_and_base_reversed(self): |
60 | self.assert_no_active_block_jobs() | ||
61 | @@ -XXX,XX +XXX,XX @@ class TestRelativePaths(ImageCommitTestCase): | ||
62 | |||
63 | def test_commit(self): | ||
64 | self.run_commit_test(self.mid_img, self.backing_img) | ||
65 | - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', self.backing_img_abs).find("verification failed")) | ||
66 | - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed")) | ||
67 | + qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', self.backing_img_abs) | ||
68 | + qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', self.backing_img_abs) | ||
69 | |||
70 | def test_device_not_found(self): | ||
71 | result = self.vm.qmp('block-commit', device='nonexistent', top='%s' % self.mid_img) | ||
72 | @@ -XXX,XX +XXX,XX @@ class TestRelativePaths(ImageCommitTestCase): | ||
73 | |||
74 | def test_top_is_active(self): | ||
75 | self.run_commit_test(self.test_img, self.backing_img) | ||
76 | - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', self.backing_img_abs).find("verification failed")) | ||
77 | - self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed")) | ||
78 | + qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', self.backing_img_abs) | ||
79 | + qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', self.backing_img_abs) | ||
80 | |||
81 | def test_top_and_base_reversed(self): | ||
82 | self.assert_no_active_block_jobs() | ||
83 | @@ -XXX,XX +XXX,XX @@ class TestCommitWithFilters(iotests.QMPTestCase): | ||
84 | |||
85 | def do_test_io(self, read_or_write): | ||
86 | for index, pattern_file in enumerate(self.pattern_files): | ||
87 | - result = qemu_io('-f', iotests.imgfmt, | ||
88 | - '-c', | ||
89 | - f'{read_or_write} -P {index + 1} {index}M 1M', | ||
90 | - pattern_file) | ||
91 | - self.assertFalse('Pattern verification failed' in result) | ||
92 | + qemu_io('-f', iotests.imgfmt, | ||
93 | + '-c', | ||
94 | + f'{read_or_write} -P {index + 1} {index}M 1M', | ||
95 | + pattern_file) | ||
96 | |||
97 | @iotests.skip_if_unsupported(['throttle']) | ||
98 | def setUp(self): | ||
99 | diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056 | ||
100 | index XXXXXXX..XXXXXXX 100755 | ||
101 | --- a/tests/qemu-iotests/056 | ||
102 | +++ b/tests/qemu-iotests/056 | ||
103 | @@ -XXX,XX +XXX,XX @@ class TestSyncModesNoneAndTop(iotests.QMPTestCase): | ||
104 | |||
105 | self.vm.shutdown() | ||
106 | time.sleep(1) | ||
107 | - self.assertEqual(-1, qemu_io('-c', 'read -P0x41 0 512', target_img).find("verification failed")) | ||
108 | + qemu_io('-c', 'read -P0x41 0 512', target_img) | ||
109 | |||
110 | class TestBeforeWriteNotifier(iotests.QMPTestCase): | ||
111 | def setUp(self): | ||
51 | -- | 112 | -- |
52 | 2.24.1 | 113 | 2.35.1 |
53 | |||
54 | diff view generated by jsdifflib |
1 | If a protocol driver does not support image creation, we can see whether | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | maybe the file exists already. If so, just truncating it will be | ||
3 | sufficient. | ||
4 | 2 | ||
5 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 3 | qemu-io fails on read/write beyond end-of-file on raw images, so skip |
6 | Message-Id: <20200122164532.178040-3-mreitz@redhat.com> | 4 | these invocations when running the zero-length image tests. |
7 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 5 | |
6 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
7 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
8 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
9 | Message-Id: <20220418211504.943969-5-jsnow@redhat.com> | ||
10 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
8 | --- | 11 | --- |
9 | block.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++----- | 12 | tests/qemu-iotests/040 | 14 ++++++++++++-- |
10 | 1 file changed, 147 insertions(+), 12 deletions(-) | 13 | 1 file changed, 12 insertions(+), 2 deletions(-) |
11 | 14 | ||
12 | diff --git a/block.c b/block.c | 15 | diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 |
13 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100755 |
14 | --- a/block.c | 17 | --- a/tests/qemu-iotests/040 |
15 | +++ b/block.c | 18 | +++ b/tests/qemu-iotests/040 |
16 | @@ -XXX,XX +XXX,XX @@ out: | 19 | @@ -XXX,XX +XXX,XX @@ class TestSingleDrive(ImageCommitTestCase): |
17 | return ret; | 20 | qemu_img('create', '-f', iotests.imgfmt, |
18 | } | 21 | '-o', 'backing_file=%s' % mid_img, |
19 | 22 | '-F', iotests.imgfmt, test_img) | |
20 | -int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp) | 23 | - qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', backing_img) |
21 | +/** | 24 | - qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', mid_img) |
22 | + * Helper function for bdrv_create_file_fallback(): Resize @blk to at | 25 | + if self.image_len: |
23 | + * least the given @minimum_size. | 26 | + qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', backing_img) |
24 | + * | 27 | + qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', |
25 | + * On success, return @blk's actual length. | 28 | + mid_img) |
26 | + * Otherwise, return -errno. | 29 | self.vm = iotests.VM().add_drive(test_img, "node-name=top,backing.node-name=mid,backing.backing.node-name=base", interface="none") |
27 | + */ | 30 | self.vm.add_device('virtio-scsi') |
28 | +static int64_t create_file_fallback_truncate(BlockBackend *blk, | 31 | self.vm.add_device("scsi-hd,id=scsi0,drive=drive0") |
29 | + int64_t minimum_size, Error **errp) | 32 | @@ -XXX,XX +XXX,XX @@ class TestSingleDrive(ImageCommitTestCase): |
30 | { | 33 | |
31 | - BlockDriver *drv; | 34 | def test_commit(self): |
32 | + Error *local_err = NULL; | 35 | self.run_commit_test(mid_img, backing_img) |
33 | + int64_t size; | 36 | + if not self.image_len: |
34 | + int ret; | 37 | + return |
35 | + | 38 | qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img) |
36 | + ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err); | 39 | qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img) |
37 | + if (ret < 0 && ret != -ENOTSUP) { | 40 | |
38 | + error_propagate(errp, local_err); | 41 | def test_commit_node(self): |
39 | + return ret; | 42 | self.run_commit_test("mid", "base", node_names=True) |
40 | + } | 43 | + if not self.image_len: |
41 | + | 44 | + return |
42 | + size = blk_getlength(blk); | 45 | qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img) |
43 | + if (size < 0) { | 46 | qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img) |
44 | + error_free(local_err); | 47 | |
45 | + error_setg_errno(errp, -size, | 48 | @@ -XXX,XX +XXX,XX @@ class TestSingleDrive(ImageCommitTestCase): |
46 | + "Failed to inquire the new image file's length"); | 49 | |
47 | + return size; | 50 | def test_top_is_active(self): |
48 | + } | 51 | self.run_commit_test(test_img, backing_img, need_ready=True) |
49 | + | 52 | + if not self.image_len: |
50 | + if (size < minimum_size) { | 53 | + return |
51 | + /* Need to grow the image, but we failed to do that */ | 54 | qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img) |
52 | + error_propagate(errp, local_err); | 55 | qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img) |
53 | + return -ENOTSUP; | 56 | |
54 | + } | 57 | def test_top_is_default_active(self): |
55 | + | 58 | self.run_default_commit_test() |
56 | + error_free(local_err); | 59 | + if not self.image_len: |
57 | + local_err = NULL; | 60 | + return |
58 | + | 61 | qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img) |
59 | + return size; | 62 | qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img) |
60 | +} | ||
61 | + | ||
62 | +/** | ||
63 | + * Helper function for bdrv_create_file_fallback(): Zero the first | ||
64 | + * sector to remove any potentially pre-existing image header. | ||
65 | + */ | ||
66 | +static int create_file_fallback_zero_first_sector(BlockBackend *blk, | ||
67 | + int64_t current_size, | ||
68 | + Error **errp) | ||
69 | +{ | ||
70 | + int64_t bytes_to_clear; | ||
71 | + int ret; | ||
72 | + | ||
73 | + bytes_to_clear = MIN(current_size, BDRV_SECTOR_SIZE); | ||
74 | + if (bytes_to_clear) { | ||
75 | + ret = blk_pwrite_zeroes(blk, 0, bytes_to_clear, BDRV_REQ_MAY_UNMAP); | ||
76 | + if (ret < 0) { | ||
77 | + error_setg_errno(errp, -ret, | ||
78 | + "Failed to clear the new image's first sector"); | ||
79 | + return ret; | ||
80 | + } | ||
81 | + } | ||
82 | + | ||
83 | + return 0; | ||
84 | +} | ||
85 | + | ||
86 | +static int bdrv_create_file_fallback(const char *filename, BlockDriver *drv, | ||
87 | + QemuOpts *opts, Error **errp) | ||
88 | +{ | ||
89 | + BlockBackend *blk; | ||
90 | + QDict *options = qdict_new(); | ||
91 | + int64_t size = 0; | ||
92 | + char *buf = NULL; | ||
93 | + PreallocMode prealloc; | ||
94 | Error *local_err = NULL; | ||
95 | int ret; | ||
96 | |||
97 | + size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); | ||
98 | + buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); | ||
99 | + prealloc = qapi_enum_parse(&PreallocMode_lookup, buf, | ||
100 | + PREALLOC_MODE_OFF, &local_err); | ||
101 | + g_free(buf); | ||
102 | + if (local_err) { | ||
103 | + error_propagate(errp, local_err); | ||
104 | + return -EINVAL; | ||
105 | + } | ||
106 | + | ||
107 | + if (prealloc != PREALLOC_MODE_OFF) { | ||
108 | + error_setg(errp, "Unsupported preallocation mode '%s'", | ||
109 | + PreallocMode_str(prealloc)); | ||
110 | + return -ENOTSUP; | ||
111 | + } | ||
112 | + | ||
113 | + qdict_put_str(options, "driver", drv->format_name); | ||
114 | + | ||
115 | + blk = blk_new_open(filename, NULL, options, | ||
116 | + BDRV_O_RDWR | BDRV_O_RESIZE, errp); | ||
117 | + if (!blk) { | ||
118 | + error_prepend(errp, "Protocol driver '%s' does not support image " | ||
119 | + "creation, and opening the image failed: ", | ||
120 | + drv->format_name); | ||
121 | + return -EINVAL; | ||
122 | + } | ||
123 | + | ||
124 | + size = create_file_fallback_truncate(blk, size, errp); | ||
125 | + if (size < 0) { | ||
126 | + ret = size; | ||
127 | + goto out; | ||
128 | + } | ||
129 | + | ||
130 | + ret = create_file_fallback_zero_first_sector(blk, size, errp); | ||
131 | + if (ret < 0) { | ||
132 | + goto out; | ||
133 | + } | ||
134 | + | ||
135 | + ret = 0; | ||
136 | +out: | ||
137 | + blk_unref(blk); | ||
138 | + return ret; | ||
139 | +} | ||
140 | + | ||
141 | +int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp) | ||
142 | +{ | ||
143 | + BlockDriver *drv; | ||
144 | + | ||
145 | drv = bdrv_find_protocol(filename, true, errp); | ||
146 | if (drv == NULL) { | ||
147 | return -ENOENT; | ||
148 | } | ||
149 | |||
150 | - ret = bdrv_create(drv, filename, opts, &local_err); | ||
151 | - error_propagate(errp, local_err); | ||
152 | - return ret; | ||
153 | + if (drv->bdrv_co_create_opts) { | ||
154 | + return bdrv_create(drv, filename, opts, errp); | ||
155 | + } else { | ||
156 | + return bdrv_create_file_fallback(filename, drv, opts, errp); | ||
157 | + } | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | @@ -XXX,XX +XXX,XX @@ QemuOptsList bdrv_runtime_opts = { | ||
162 | }, | ||
163 | }; | ||
164 | |||
165 | +static QemuOptsList fallback_create_opts = { | ||
166 | + .name = "fallback-create-opts", | ||
167 | + .head = QTAILQ_HEAD_INITIALIZER(fallback_create_opts.head), | ||
168 | + .desc = { | ||
169 | + { | ||
170 | + .name = BLOCK_OPT_SIZE, | ||
171 | + .type = QEMU_OPT_SIZE, | ||
172 | + .help = "Virtual disk size" | ||
173 | + }, | ||
174 | + { | ||
175 | + .name = BLOCK_OPT_PREALLOC, | ||
176 | + .type = QEMU_OPT_STRING, | ||
177 | + .help = "Preallocation mode (allowed values: off)" | ||
178 | + }, | ||
179 | + { /* end of list */ } | ||
180 | + } | ||
181 | +}; | ||
182 | + | ||
183 | /* | ||
184 | * Common part for opening disk images and files | ||
185 | * | ||
186 | @@ -XXX,XX +XXX,XX @@ void bdrv_img_create(const char *filename, const char *fmt, | ||
187 | return; | ||
188 | } | ||
189 | |||
190 | - if (!proto_drv->create_opts) { | ||
191 | - error_setg(errp, "Protocol driver '%s' does not support image creation", | ||
192 | - proto_drv->format_name); | ||
193 | - return; | ||
194 | - } | ||
195 | - | ||
196 | /* Create parameter list */ | ||
197 | create_opts = qemu_opts_append(create_opts, drv->create_opts); | ||
198 | - create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); | ||
199 | + if (proto_drv->create_opts) { | ||
200 | + create_opts = qemu_opts_append(create_opts, proto_drv->create_opts); | ||
201 | + } else { | ||
202 | + create_opts = qemu_opts_append(create_opts, &fallback_create_opts); | ||
203 | + } | ||
204 | |||
205 | opts = qemu_opts_create(create_opts, NULL, 0, &error_abort); | ||
206 | 63 | ||
207 | -- | 64 | -- |
208 | 2.24.1 | 65 | 2.35.1 |
209 | |||
210 | diff view generated by jsdifflib |
1 | When nbd_close() is called from a coroutine, the connection_co never | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | gets to run, and thus nbd_teardown_connection() hangs. | ||
3 | 2 | ||
4 | This is because aio_co_enter() only puts the connection_co into the main | 3 | Without this change, asserting that qemu_io always returns 0 causes this |
5 | coroutine's wake-up queue, so this main coroutine needs to yield and | 4 | test to fail in a way we happened not to be catching previously: |
6 | wait for connection_co to terminate. | ||
7 | 5 | ||
8 | Suggested-by: Kevin Wolf <kwolf@redhat.com> | 6 | qemu.utils.VerboseProcessError: Command |
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 7 | '('/home/jsnow/src/qemu/bin/git/tests/qemu-iotests/../../qemu-io', |
10 | Message-Id: <20200122164532.178040-2-mreitz@redhat.com> | 8 | '--cache', 'writeback', '--aio', 'threads', '-f', 'qcow2', '-c', |
9 | 'read -P 4 3M 1M', | ||
10 | '/home/jsnow/src/qemu/bin/git/tests/qemu-iotests/scratch/3.img')' | ||
11 | returned non-zero exit status 1. | ||
12 | ┏━ output ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
13 | ┃ qemu-io: can't open device | ||
14 | ┃ /home/jsnow/src/qemu/bin/git/tests/qemu-iotests/scratch/3.img: | ||
15 | ┃ Could not open backing file: Could not open backing file: Throttle | ||
16 | ┃ group 'tg' does not exist | ||
17 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ | ||
18 | |||
19 | The commit jobs changes the backing file string stored in the image file | ||
20 | header belonging to the node above the commit’s top node to point to the | ||
21 | commit target (the base node). QEMU tries to be as accurate as | ||
22 | possible, and so in these test cases will include the filter that is | ||
23 | part of the block graph in that backing file string (by virtue of making | ||
24 | it a json:{} description of the post-commit subgraph). This makes | ||
25 | little sense outside of QEMU, though: Specifically, the throttle node in | ||
26 | that subgraph will dearly miss its supposedly associated throttle group | ||
27 | object. | ||
28 | |||
29 | When starting the commit job, we can specify a custom backing file | ||
30 | string to write into said image file, so let’s use that feature to write | ||
31 | the plain filename of the backing chain’s next actual image file there. | ||
32 | |||
33 | Explicitly provide the backing file so that opening the file outside of | ||
34 | QEMU (Where we will not have throttle groups) will succeed. | ||
35 | |||
36 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
37 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | 38 | Reviewed-by: Eric Blake <eblake@redhat.com> |
12 | Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> | 39 | Message-Id: <20220418211504.943969-6-jsnow@redhat.com> |
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
14 | --- | 40 | --- |
15 | block/nbd.c | 14 +++++++++++++- | 41 | tests/qemu-iotests/040 | 6 ++++-- |
16 | 1 file changed, 13 insertions(+), 1 deletion(-) | 42 | 1 file changed, 4 insertions(+), 2 deletions(-) |
17 | 43 | ||
18 | diff --git a/block/nbd.c b/block/nbd.c | 44 | diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040 |
19 | index XXXXXXX..XXXXXXX 100644 | 45 | index XXXXXXX..XXXXXXX 100755 |
20 | --- a/block/nbd.c | 46 | --- a/tests/qemu-iotests/040 |
21 | +++ b/block/nbd.c | 47 | +++ b/tests/qemu-iotests/040 |
22 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVNBDState { | 48 | @@ -XXX,XX +XXX,XX @@ class TestCommitWithFilters(iotests.QMPTestCase): |
23 | CoMutex send_mutex; | 49 | job_id='commit', |
24 | CoQueue free_sema; | 50 | device='top-filter', |
25 | Coroutine *connection_co; | 51 | top_node='cow-2', |
26 | + Coroutine *teardown_co; | 52 | - base_node='cow-1') |
27 | QemuCoSleepState *connection_co_sleep_ns_state; | 53 | + base_node='cow-1', |
28 | bool drained; | 54 | + backing_file=self.img1) |
29 | bool wait_drained_end; | 55 | self.assert_qmp(result, 'return', {}) |
30 | @@ -XXX,XX +XXX,XX @@ static void nbd_teardown_connection(BlockDriverState *bs) | 56 | self.wait_until_completed(drive='commit') |
31 | qemu_co_sleep_wake(s->connection_co_sleep_ns_state); | 57 | |
32 | } | 58 | @@ -XXX,XX +XXX,XX @@ class TestCommitWithFilters(iotests.QMPTestCase): |
33 | } | 59 | job_id='commit', |
34 | - BDRV_POLL_WHILE(bs, s->connection_co); | 60 | device='top-filter', |
35 | + if (qemu_in_coroutine()) { | 61 | top_node='cow-1', |
36 | + s->teardown_co = qemu_coroutine_self(); | 62 | - base_node='cow-0') |
37 | + /* connection_co resumes us when it terminates */ | 63 | + base_node='cow-0', |
38 | + qemu_coroutine_yield(); | 64 | + backing_file=self.img0) |
39 | + s->teardown_co = NULL; | 65 | self.assert_qmp(result, 'return', {}) |
40 | + } else { | 66 | self.wait_until_completed(drive='commit') |
41 | + BDRV_POLL_WHILE(bs, s->connection_co); | ||
42 | + } | ||
43 | + assert(!s->connection_co); | ||
44 | } | ||
45 | |||
46 | static bool nbd_client_connecting(BDRVNBDState *s) | ||
47 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_connection_entry(void *opaque) | ||
48 | s->ioc = NULL; | ||
49 | } | ||
50 | |||
51 | + if (s->teardown_co) { | ||
52 | + aio_co_wake(s->teardown_co); | ||
53 | + } | ||
54 | aio_wait_kick(); | ||
55 | } | ||
56 | 67 | ||
57 | -- | 68 | -- |
58 | 2.24.1 | 69 | 2.35.1 |
59 | 70 | ||
60 | 71 | diff view generated by jsdifflib |
1 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | Message-Id: <20200122164532.178040-6-mreitz@redhat.com> | 2 | |
3 | reimplement qemu_img() in terms of qemu_tool() in preparation for doing | ||
4 | the same with qemu_io(). | ||
5 | |||
6 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
3 | Reviewed-by: Eric Blake <eblake@redhat.com> | 7 | Reviewed-by: Eric Blake <eblake@redhat.com> |
4 | Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> | 8 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> |
5 | [mreitz: Added a note that NBD does not support resizing, which is why | 9 | Message-Id: <20220418211504.943969-7-jsnow@redhat.com> |
6 | the second case is expected to fail] | 10 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> |
7 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
8 | --- | 11 | --- |
9 | tests/qemu-iotests/259 | 62 ++++++++++++++++++++++++++++++++++++++ | 12 | tests/qemu-iotests/iotests.py | 32 +++++++++++++++++++++----------- |
10 | tests/qemu-iotests/259.out | 14 +++++++++ | 13 | 1 file changed, 21 insertions(+), 11 deletions(-) |
11 | tests/qemu-iotests/group | 1 + | ||
12 | 3 files changed, 77 insertions(+) | ||
13 | create mode 100755 tests/qemu-iotests/259 | ||
14 | create mode 100644 tests/qemu-iotests/259.out | ||
15 | 14 | ||
16 | diff --git a/tests/qemu-iotests/259 b/tests/qemu-iotests/259 | 15 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py |
17 | new file mode 100755 | 16 | index XXXXXXX..XXXXXXX 100644 |
18 | index XXXXXXX..XXXXXXX | 17 | --- a/tests/qemu-iotests/iotests.py |
19 | --- /dev/null | 18 | +++ b/tests/qemu-iotests/iotests.py |
20 | +++ b/tests/qemu-iotests/259 | 19 | @@ -XXX,XX +XXX,XX @@ def qemu_img_create_prepare_args(args: List[str]) -> List[str]: |
21 | @@ -XXX,XX +XXX,XX @@ | 20 | |
22 | +#!/usr/bin/env bash | 21 | return result |
23 | +# | 22 | |
24 | +# Test generic image creation fallback (by using NBD) | 23 | -def qemu_img(*args: str, check: bool = True, combine_stdio: bool = True |
25 | +# | 24 | - ) -> 'subprocess.CompletedProcess[str]': |
26 | +# Copyright (C) 2019 Red Hat, Inc. | 25 | - """ |
27 | +# | 26 | - Run qemu_img and return the status code and console output. |
28 | +# This program is free software; you can redistribute it and/or modify | 27 | |
29 | +# it under the terms of the GNU General Public License as published by | 28 | - This function always prepends QEMU_IMG_OPTIONS and may further alter |
30 | +# the Free Software Foundation; either version 2 of the License, or | 29 | - the args for 'create' commands. |
31 | +# (at your option) any later version. | 30 | +def qemu_tool(*args: str, check: bool = True, combine_stdio: bool = True |
32 | +# | 31 | + ) -> 'subprocess.CompletedProcess[str]': |
33 | +# This program is distributed in the hope that it will be useful, | 32 | + """ |
34 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | 33 | + Run a qemu tool and return its status code and console output. |
35 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 34 | |
36 | +# GNU General Public License for more details. | 35 | - :param args: command-line arguments to qemu-img. |
37 | +# | 36 | + :param args: full command line to run. |
38 | +# You should have received a copy of the GNU General Public License | 37 | :param check: Enforce a return code of zero. |
39 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | 38 | :param combine_stdio: set to False to keep stdout/stderr separated. |
40 | +# | 39 | |
40 | @@ -XXX,XX +XXX,XX @@ def qemu_img(*args: str, check: bool = True, combine_stdio: bool = True | ||
41 | properties. If streams are not combined, it will also have a | ||
42 | stderr property. | ||
43 | """ | ||
44 | - full_args = qemu_img_args + qemu_img_create_prepare_args(list(args)) | ||
45 | - | ||
46 | subp = subprocess.run( | ||
47 | - full_args, | ||
48 | + args, | ||
49 | stdout=subprocess.PIPE, | ||
50 | stderr=subprocess.STDOUT if combine_stdio else subprocess.PIPE, | ||
51 | universal_newlines=True, | ||
52 | @@ -XXX,XX +XXX,XX @@ def qemu_img(*args: str, check: bool = True, combine_stdio: bool = True | ||
53 | |||
54 | if check and subp.returncode or (subp.returncode < 0): | ||
55 | raise VerboseProcessError( | ||
56 | - subp.returncode, full_args, | ||
57 | + subp.returncode, args, | ||
58 | output=subp.stdout, | ||
59 | stderr=subp.stderr, | ||
60 | ) | ||
61 | @@ -XXX,XX +XXX,XX @@ def qemu_img(*args: str, check: bool = True, combine_stdio: bool = True | ||
62 | return subp | ||
63 | |||
64 | |||
65 | +def qemu_img(*args: str, check: bool = True, combine_stdio: bool = True | ||
66 | + ) -> 'subprocess.CompletedProcess[str]': | ||
67 | + """ | ||
68 | + Run QEMU_IMG_PROG and return its status code and console output. | ||
41 | + | 69 | + |
42 | +# creator | 70 | + This function always prepends QEMU_IMG_OPTIONS and may further alter |
43 | +owner=mreitz@redhat.com | 71 | + the args for 'create' commands. |
44 | + | 72 | + |
45 | +seq=$(basename $0) | 73 | + See `qemu_tool()` for greater detail. |
46 | +echo "QA output created by $seq" | 74 | + """ |
47 | + | 75 | + full_args = qemu_img_args + qemu_img_create_prepare_args(list(args)) |
48 | +status=1 # failure is the default! | 76 | + return qemu_tool(*full_args, check=check, combine_stdio=combine_stdio) |
49 | + | ||
50 | +_cleanup() | ||
51 | +{ | ||
52 | + _cleanup_test_img | ||
53 | +} | ||
54 | +trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
55 | + | ||
56 | +# get standard environment, filters and checks | ||
57 | +. ./common.rc | ||
58 | +. ./common.filter | ||
59 | + | ||
60 | +_supported_fmt raw | ||
61 | +_supported_proto nbd | ||
62 | +_supported_os Linux | ||
63 | + | 77 | + |
64 | + | 78 | + |
65 | +_make_test_img 64M | 79 | def ordered_qmp(qmsg, conv_keys=True): |
66 | + | 80 | # Dictionaries are not ordered prior to 3.6, therefore: |
67 | +echo | 81 | if isinstance(qmsg, list): |
68 | +echo '--- Testing creation ---' | ||
69 | + | ||
70 | +$QEMU_IMG create -f qcow2 "$TEST_IMG" 64M | _filter_img_create | ||
71 | +$QEMU_IMG info "$TEST_IMG" | _filter_img_info | ||
72 | + | ||
73 | +echo | ||
74 | +echo '--- Testing creation for which the node would need to grow ---' | ||
75 | + | ||
76 | +# NBD does not support resizing, so this will fail | ||
77 | +$QEMU_IMG create -f qcow2 -o preallocation=metadata "$TEST_IMG" 64M 2>&1 \ | ||
78 | + | _filter_img_create | ||
79 | + | ||
80 | +# success, all done | ||
81 | +echo "*** done" | ||
82 | +rm -f $seq.full | ||
83 | +status=0 | ||
84 | diff --git a/tests/qemu-iotests/259.out b/tests/qemu-iotests/259.out | ||
85 | new file mode 100644 | ||
86 | index XXXXXXX..XXXXXXX | ||
87 | --- /dev/null | ||
88 | +++ b/tests/qemu-iotests/259.out | ||
89 | @@ -XXX,XX +XXX,XX @@ | ||
90 | +QA output created by 259 | ||
91 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
92 | + | ||
93 | +--- Testing creation --- | ||
94 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=qcow2 size=67108864 | ||
95 | +image: TEST_DIR/t.IMGFMT | ||
96 | +file format: qcow2 | ||
97 | +virtual size: 64 MiB (67108864 bytes) | ||
98 | +disk size: unavailable | ||
99 | + | ||
100 | +--- Testing creation for which the node would need to grow --- | ||
101 | +qemu-img: TEST_DIR/t.IMGFMT: Could not resize image: Image format driver does not support resize | ||
102 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=qcow2 size=67108864 preallocation=metadata | ||
103 | +*** done | ||
104 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
105 | index XXXXXXX..XXXXXXX 100644 | ||
106 | --- a/tests/qemu-iotests/group | ||
107 | +++ b/tests/qemu-iotests/group | ||
108 | @@ -XXX,XX +XXX,XX @@ | ||
109 | 256 rw auto quick | ||
110 | 257 rw | ||
111 | 258 rw quick | ||
112 | +259 rw auto quick | ||
113 | 260 rw quick | ||
114 | 261 rw | ||
115 | 262 rw quick migration | ||
116 | -- | 82 | -- |
117 | 2.24.1 | 83 | 2.35.1 |
118 | |||
119 | diff view generated by jsdifflib |
1 | From: Daniel P. Berrangé <berrange@redhat.com> | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | When initializing the LUKS header the size with default encryption | 3 | Rework qemu_io() to be analogous to qemu_img(); a function that requires |
4 | parameters will currently be 2068480 bytes. This is rounded up to | 4 | a return code of zero by default unless disabled explicitly. |
5 | a multiple of the cluster size, 2081792, with 64k sectors. If the | 5 | |
6 | end of the header is not the same as the end of the cluster we fill | 6 | Tests that use qemu_io(): |
7 | the extra space with zeros. This was forgetting that not even the | 7 | 030 040 041 044 055 056 093 124 129 132 136 148 149 151 152 163 165 205 |
8 | space allocated for the header will be fully initialized, as we | 8 | 209 219 236 245 248 254 255 257 260 264 280 298 300 302 304 |
9 | only write key material for the first key slot. The space left | 9 | image-fleecing migrate-bitmaps-postcopy-test migrate-bitmaps-test |
10 | for the other 7 slots is never written to. | 10 | migrate-during-backup migration-permissions |
11 | 11 | ||
12 | An optimization to the ref count checking code: | 12 | Test that use qemu_io_log(): |
13 | 13 | 242 245 255 274 303 307 nbd-reconnect-on-open | |
14 | commit a5fff8d4b4d928311a5005efa12d0991fe3b66f9 (refs/bisect/bad) | 14 | |
15 | Author: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 15 | Copy-pastables for testing/verification: |
16 | Date: Wed Feb 27 16:14:30 2019 +0300 | 16 | |
17 | 17 | ./check -qcow2 030 040 041 044 055 056 124 129 132 151 152 163 165 209 \ | |
18 | qcow2-refcount: avoid eating RAM | 18 | 219 236 242 245 248 254 255 257 260 264 274 \ |
19 | 19 | 280 298 300 302 303 304 307 image-fleecing \ | |
20 | made the assumption that every cluster which was allocated would | 20 | migrate-bitmaps-postcopy-test migrate-bitmaps-test \ |
21 | have at least some data written to it. This was violated by way | 21 | migrate-during-backup nbd-reconnect-on-open |
22 | the LUKS header is only partially written, with much space simply | 22 | ./check -raw 093 136 148 migration-permissions |
23 | reserved for future use. | 23 | ./check -nbd 205 |
24 | 24 | ||
25 | Depending on the cluster size this problem was masked by the | 25 | # ./configure configure --disable-gnutls --enable-gcrypt |
26 | logic which wrote zeros between the end of the LUKS header and | 26 | # this ALSO requires passwordless sudo. |
27 | the end of the cluster. | 27 | ./check -luks 149 |
28 | 28 | ||
29 | $ qemu-img create --object secret,id=cluster_encrypt0,data=123456 \ | 29 | # Just the tests that were edited in this commit: |
30 | -f qcow2 -o cluster_size=2k,encrypt.iter-time=1,\ | 30 | ./check -qcow2 030 040 242 245 |
31 | encrypt.format=luks,encrypt.key-secret=cluster_encrypt0 \ | 31 | ./check -raw migration-permissions |
32 | cluster_size_check.qcow2 100M | 32 | ./check -nbd 205 |
33 | Formatting 'cluster_size_check.qcow2', fmt=qcow2 size=104857600 | 33 | ./check -luks 149 |
34 | encrypt.format=luks encrypt.key-secret=cluster_encrypt0 | 34 | |
35 | encrypt.iter-time=1 cluster_size=2048 lazy_refcounts=off refcount_bits=16 | 35 | Signed-off-by: John Snow <jsnow@redhat.com> |
36 | 36 | Message-Id: <20220418211504.943969-8-jsnow@redhat.com> | |
37 | $ qemu-img check --object secret,id=cluster_encrypt0,data=redhat \ | ||
38 | 'json:{"driver": "qcow2", "encrypt.format": "luks", \ | ||
39 | "encrypt.key-secret": "cluster_encrypt0", \ | ||
40 | "file.driver": "file", "file.filename": "cluster_size_check.qcow2"}' | ||
41 | ERROR: counting reference for region exceeding the end of the file by one cluster or more: offset 0x2000 size 0x1f9000 | ||
42 | Leaked cluster 4 refcount=1 reference=0 | ||
43 | ...snip... | ||
44 | Leaked cluster 130 refcount=1 reference=0 | ||
45 | |||
46 | 1 errors were found on the image. | ||
47 | Data may be corrupted, or further writes to the image may corrupt it. | ||
48 | |||
49 | 127 leaked clusters were found on the image. | ||
50 | This means waste of disk space, but no harm to data. | ||
51 | Image end offset: 268288 | ||
52 | |||
53 | The problem only exists when the disk image is entirely empty. Writing | ||
54 | data to the disk image payload will solve the problem by causing the | ||
55 | end of the file to be extended further. | ||
56 | |||
57 | The change fixes it by ensuring that the entire allocated LUKS header | ||
58 | region is fully initialized with zeros. The qemu-img check will still | ||
59 | fail for any pre-existing disk images created prior to this change, | ||
60 | unless at least 1 byte of the payload is written to. | ||
61 | |||
62 | Fully writing zeros to the entire LUKS header is a good idea regardless | ||
63 | as it ensures that space has been allocated on the host filesystem (or | ||
64 | whatever block storage backend is used). | ||
65 | |||
66 | Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> | ||
67 | Message-Id: <20200207135520.2669430-1-berrange@redhat.com> | ||
68 | Reviewed-by: Eric Blake <eblake@redhat.com> | 37 | Reviewed-by: Eric Blake <eblake@redhat.com> |
69 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 38 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> |
70 | --- | 39 | --- |
71 | block/qcow2.c | 11 +++-- | 40 | tests/qemu-iotests/030 | 85 +++++++++++-------- |
72 | tests/qemu-iotests/284 | 97 ++++++++++++++++++++++++++++++++++++++ | 41 | tests/qemu-iotests/149 | 6 +- |
73 | tests/qemu-iotests/284.out | 62 ++++++++++++++++++++++++ | 42 | tests/qemu-iotests/205 | 4 +- |
74 | tests/qemu-iotests/group | 1 + | 43 | tests/qemu-iotests/245 | 17 ++-- |
75 | 4 files changed, 167 insertions(+), 4 deletions(-) | 44 | tests/qemu-iotests/iotests.py | 19 +++-- |
76 | create mode 100755 tests/qemu-iotests/284 | 45 | .../qemu-iotests/tests/migration-permissions | 4 +- |
77 | create mode 100644 tests/qemu-iotests/284.out | 46 | 6 files changed, 81 insertions(+), 54 deletions(-) |
78 | 47 | ||
79 | diff --git a/block/qcow2.c b/block/qcow2.c | 48 | diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030 |
49 | index XXXXXXX..XXXXXXX 100755 | ||
50 | --- a/tests/qemu-iotests/030 | ||
51 | +++ b/tests/qemu-iotests/030 | ||
52 | @@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase): | ||
53 | self.assert_no_active_block_jobs() | ||
54 | self.vm.shutdown() | ||
55 | |||
56 | - self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), | ||
57 | - qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), | ||
58 | - 'image file map does not match backing file after streaming') | ||
59 | + self.assertEqual( | ||
60 | + qemu_io('-f', 'raw', '-c', 'map', backing_img).stdout, | ||
61 | + qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img).stdout, | ||
62 | + 'image file map does not match backing file after streaming') | ||
63 | |||
64 | def test_stream_intermediate(self): | ||
65 | self.assert_no_active_block_jobs() | ||
66 | |||
67 | - self.assertNotEqual(qemu_io('-f', 'raw', '-rU', '-c', 'map', backing_img), | ||
68 | - qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', mid_img), | ||
69 | - 'image file map matches backing file before streaming') | ||
70 | + self.assertNotEqual( | ||
71 | + qemu_io('-f', 'raw', '-rU', '-c', 'map', backing_img).stdout, | ||
72 | + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', mid_img).stdout, | ||
73 | + 'image file map matches backing file before streaming') | ||
74 | |||
75 | result = self.vm.qmp('block-stream', device='mid', job_id='stream-mid') | ||
76 | self.assert_qmp(result, 'return', {}) | ||
77 | @@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase): | ||
78 | self.assert_no_active_block_jobs() | ||
79 | self.vm.shutdown() | ||
80 | |||
81 | - self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), | ||
82 | - qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img), | ||
83 | - 'image file map does not match backing file after streaming') | ||
84 | + self.assertEqual( | ||
85 | + qemu_io('-f', 'raw', '-c', 'map', backing_img).stdout, | ||
86 | + qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img).stdout, | ||
87 | + 'image file map does not match backing file after streaming') | ||
88 | |||
89 | def test_stream_pause(self): | ||
90 | self.assert_no_active_block_jobs() | ||
91 | @@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase): | ||
92 | self.assert_no_active_block_jobs() | ||
93 | self.vm.shutdown() | ||
94 | |||
95 | - self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img), | ||
96 | - qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), | ||
97 | - 'image file map does not match backing file after streaming') | ||
98 | + self.assertEqual( | ||
99 | + qemu_io('-f', 'raw', '-c', 'map', backing_img).stdout, | ||
100 | + qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img).stdout, | ||
101 | + 'image file map does not match backing file after streaming') | ||
102 | |||
103 | def test_stream_no_op(self): | ||
104 | self.assert_no_active_block_jobs() | ||
105 | |||
106 | # The image map is empty before the operation | ||
107 | - empty_map = qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', test_img) | ||
108 | + empty_map = qemu_io( | ||
109 | + '-f', iotests.imgfmt, '-rU', '-c', 'map', test_img).stdout | ||
110 | |||
111 | # This is a no-op: no data should ever be copied from the base image | ||
112 | result = self.vm.qmp('block-stream', device='drive0', base=mid_img) | ||
113 | @@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase): | ||
114 | self.assert_no_active_block_jobs() | ||
115 | self.vm.shutdown() | ||
116 | |||
117 | - self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), | ||
118 | - empty_map, 'image file map changed after a no-op') | ||
119 | + self.assertEqual( | ||
120 | + qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img).stdout, | ||
121 | + empty_map, 'image file map changed after a no-op') | ||
122 | |||
123 | def test_stream_partial(self): | ||
124 | self.assert_no_active_block_jobs() | ||
125 | @@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase): | ||
126 | self.assert_no_active_block_jobs() | ||
127 | self.vm.shutdown() | ||
128 | |||
129 | - self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img), | ||
130 | - qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), | ||
131 | - 'image file map does not match backing file after streaming') | ||
132 | + self.assertEqual( | ||
133 | + qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img).stdout, | ||
134 | + qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img).stdout, | ||
135 | + 'image file map does not match backing file after streaming') | ||
136 | |||
137 | def test_device_not_found(self): | ||
138 | result = self.vm.qmp('block-stream', device='nonexistent') | ||
139 | @@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase): | ||
140 | |||
141 | # Check that the maps don't match before the streaming operations | ||
142 | for i in range(2, self.num_imgs, 2): | ||
143 | - self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[i]), | ||
144 | - qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[i-1]), | ||
145 | - 'image file map matches backing file before streaming') | ||
146 | + self.assertNotEqual( | ||
147 | + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[i]).stdout, | ||
148 | + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[i-1]).stdout, | ||
149 | + 'image file map matches backing file before streaming') | ||
150 | |||
151 | # Create all streaming jobs | ||
152 | pending_jobs = [] | ||
153 | @@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase): | ||
154 | |||
155 | # Check that all maps match now | ||
156 | for i in range(2, self.num_imgs, 2): | ||
157 | - self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i]), | ||
158 | - qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i-1]), | ||
159 | - 'image file map does not match backing file after streaming') | ||
160 | + self.assertEqual( | ||
161 | + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i]).stdout, | ||
162 | + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i-1]).stdout, | ||
163 | + 'image file map does not match backing file after streaming') | ||
164 | |||
165 | # Test that it's not possible to perform two block-stream | ||
166 | # operations if there are nodes involved in both. | ||
167 | @@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase): | ||
168 | def test_stream_base_node_name(self): | ||
169 | self.assert_no_active_block_jobs() | ||
170 | |||
171 | - self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[4]), | ||
172 | - qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[3]), | ||
173 | - 'image file map matches backing file before streaming') | ||
174 | + self.assertNotEqual( | ||
175 | + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[4]).stdout, | ||
176 | + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.imgs[3]).stdout, | ||
177 | + 'image file map matches backing file before streaming') | ||
178 | |||
179 | # Error: the base node does not exist | ||
180 | result = self.vm.qmp('block-stream', device='node4', base_node='none', job_id='stream') | ||
181 | @@ -XXX,XX +XXX,XX @@ class TestParallelOps(iotests.QMPTestCase): | ||
182 | self.assert_no_active_block_jobs() | ||
183 | self.vm.shutdown() | ||
184 | |||
185 | - self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[4]), | ||
186 | - qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[3]), | ||
187 | - 'image file map matches backing file after streaming') | ||
188 | + self.assertEqual( | ||
189 | + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[4]).stdout, | ||
190 | + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[3]).stdout, | ||
191 | + 'image file map matches backing file after streaming') | ||
192 | |||
193 | class TestQuorum(iotests.QMPTestCase): | ||
194 | num_children = 3 | ||
195 | @@ -XXX,XX +XXX,XX @@ class TestQuorum(iotests.QMPTestCase): | ||
196 | os.remove(img) | ||
197 | |||
198 | def test_stream_quorum(self): | ||
199 | - self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.children[0]), | ||
200 | - qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.backing[0]), | ||
201 | - 'image file map matches backing file before streaming') | ||
202 | + self.assertNotEqual( | ||
203 | + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.children[0]).stdout, | ||
204 | + qemu_io('-f', iotests.imgfmt, '-rU', '-c', 'map', self.backing[0]).stdout, | ||
205 | + 'image file map matches backing file before streaming') | ||
206 | |||
207 | self.assert_no_active_block_jobs() | ||
208 | |||
209 | @@ -XXX,XX +XXX,XX @@ class TestQuorum(iotests.QMPTestCase): | ||
210 | self.assert_no_active_block_jobs() | ||
211 | self.vm.shutdown() | ||
212 | |||
213 | - self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.children[0]), | ||
214 | - qemu_io('-f', iotests.imgfmt, '-c', 'map', self.backing[0]), | ||
215 | - 'image file map does not match backing file after streaming') | ||
216 | + self.assertEqual( | ||
217 | + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.children[0]).stdout, | ||
218 | + qemu_io('-f', iotests.imgfmt, '-c', 'map', self.backing[0]).stdout, | ||
219 | + 'image file map does not match backing file after streaming') | ||
220 | |||
221 | class TestSmallerBackingFile(iotests.QMPTestCase): | ||
222 | backing_len = 1 * 1024 * 1024 # MB | ||
223 | diff --git a/tests/qemu-iotests/149 b/tests/qemu-iotests/149 | ||
224 | index XXXXXXX..XXXXXXX 100755 | ||
225 | --- a/tests/qemu-iotests/149 | ||
226 | +++ b/tests/qemu-iotests/149 | ||
227 | @@ -XXX,XX +XXX,XX @@ def qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False): | ||
228 | args = ["-c", "write -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] | ||
229 | args.extend(qemu_io_image_args(config, dev)) | ||
230 | iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) | ||
231 | - iotests.log(check_cipher_support(config, iotests.qemu_io(*args)), | ||
232 | + output = iotests.qemu_io(*args, check=False).stdout | ||
233 | + iotests.log(check_cipher_support(config, output), | ||
234 | filters=[iotests.filter_test_dir, iotests.filter_qemu_io]) | ||
235 | |||
236 | |||
237 | @@ -XXX,XX +XXX,XX @@ def qemu_io_read_pattern(config, pattern, offset_mb, size_mb, dev=False): | ||
238 | args = ["-c", "read -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] | ||
239 | args.extend(qemu_io_image_args(config, dev)) | ||
240 | iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) | ||
241 | - iotests.log(check_cipher_support(config, iotests.qemu_io(*args)), | ||
242 | + output = iotests.qemu_io(*args, check=False).stdout | ||
243 | + iotests.log(check_cipher_support(config, output), | ||
244 | filters=[iotests.filter_test_dir, iotests.filter_qemu_io]) | ||
245 | |||
246 | |||
247 | diff --git a/tests/qemu-iotests/205 b/tests/qemu-iotests/205 | ||
248 | index XXXXXXX..XXXXXXX 100755 | ||
249 | --- a/tests/qemu-iotests/205 | ||
250 | +++ b/tests/qemu-iotests/205 | ||
251 | @@ -XXX,XX +XXX,XX @@ class TestNbdServerRemove(iotests.QMPTestCase): | ||
252 | |||
253 | def do_test_connect_after_remove(self, mode=None): | ||
254 | args = ('-r', '-f', 'raw', '-c', 'read 0 512', nbd_uri) | ||
255 | - self.assertReadOk(qemu_io(*args)) | ||
256 | + self.assertReadOk(qemu_io(*args).stdout) | ||
257 | |||
258 | result = self.remove_export('exp', mode) | ||
259 | self.assert_qmp(result, 'return', {}) | ||
260 | |||
261 | self.assertExportNotFound('exp') | ||
262 | - self.assertConnectFailed(qemu_io(*args)) | ||
263 | + self.assertConnectFailed(qemu_io(*args, check=False).stdout) | ||
264 | |||
265 | def test_connect_after_remove_default(self): | ||
266 | self.do_test_connect_after_remove() | ||
267 | diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245 | ||
268 | index XXXXXXX..XXXXXXX 100755 | ||
269 | --- a/tests/qemu-iotests/245 | ||
270 | +++ b/tests/qemu-iotests/245 | ||
271 | @@ -XXX,XX +XXX,XX @@ | ||
272 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
273 | # | ||
274 | |||
275 | +import copy | ||
276 | +import json | ||
277 | import os | ||
278 | import re | ||
279 | +from subprocess import CalledProcessError | ||
280 | + | ||
281 | import iotests | ||
282 | -import copy | ||
283 | -import json | ||
284 | from iotests import qemu_img, qemu_io | ||
285 | |||
286 | hd_path = [ | ||
287 | @@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase): | ||
288 | |||
289 | # Reopen an image several times changing some of its options | ||
290 | def test_reopen(self): | ||
291 | - # Check whether the filesystem supports O_DIRECT | ||
292 | - if 'O_DIRECT' in qemu_io('-f', 'raw', '-t', 'none', '-c', 'quit', hd_path[0]): | ||
293 | - supports_direct = False | ||
294 | - else: | ||
295 | + try: | ||
296 | + qemu_io('-f', 'raw', '-t', 'none', '-c', 'quit', hd_path[0]) | ||
297 | supports_direct = True | ||
298 | + except CalledProcessError as exc: | ||
299 | + if 'O_DIRECT' in exc.stdout: | ||
300 | + supports_direct = False | ||
301 | + else: | ||
302 | + raise | ||
303 | |||
304 | # Open the hd1 image passing all backing options | ||
305 | opts = hd_opts(1) | ||
306 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
80 | index XXXXXXX..XXXXXXX 100644 | 307 | index XXXXXXX..XXXXXXX 100644 |
81 | --- a/block/qcow2.c | 308 | --- a/tests/qemu-iotests/iotests.py |
82 | +++ b/block/qcow2.c | 309 | +++ b/tests/qemu-iotests/iotests.py |
83 | @@ -XXX,XX +XXX,XX @@ static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, | 310 | @@ -XXX,XX +XXX,XX @@ def qemu_io_wrap_args(args: Sequence[str]) -> List[str]: |
84 | s->crypto_header.length = headerlen; | 311 | def qemu_io_popen(*args): |
85 | s->crypto_header.offset = ret; | 312 | return qemu_tool_popen(qemu_io_wrap_args(args)) |
86 | 313 | ||
87 | - /* Zero fill remaining space in cluster so it has predictable | 314 | -def qemu_io(*args): |
88 | - * content in case of future spec changes */ | 315 | - '''Run qemu-io and return the stdout data''' |
89 | + /* | 316 | - return qemu_tool_pipe_and_status('qemu-io', qemu_io_wrap_args(args))[0] |
90 | + * Zero fill all space in cluster so it has predictable | 317 | +def qemu_io(*args: str, check: bool = True, combine_stdio: bool = True |
91 | + * content, as we may not initialize some regions of the | 318 | + ) -> 'subprocess.CompletedProcess[str]': |
92 | + * header (eg only 1 out of 8 key slots will be initialized) | 319 | + """ |
93 | + */ | 320 | + Run QEMU_IO_PROG and return the status code and console output. |
94 | clusterlen = size_to_clusters(s, headerlen) * s->cluster_size; | ||
95 | assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen, false) == 0); | ||
96 | ret = bdrv_pwrite_zeroes(bs->file, | ||
97 | - ret + headerlen, | ||
98 | - clusterlen - headerlen, 0); | ||
99 | + ret, | ||
100 | + clusterlen, 0); | ||
101 | if (ret < 0) { | ||
102 | error_setg_errno(errp, -ret, "Could not zero fill encryption header"); | ||
103 | return -1; | ||
104 | diff --git a/tests/qemu-iotests/284 b/tests/qemu-iotests/284 | ||
105 | new file mode 100755 | ||
106 | index XXXXXXX..XXXXXXX | ||
107 | --- /dev/null | ||
108 | +++ b/tests/qemu-iotests/284 | ||
109 | @@ -XXX,XX +XXX,XX @@ | ||
110 | +#!/usr/bin/env bash | ||
111 | +# | ||
112 | +# Test ref count checks on encrypted images | ||
113 | +# | ||
114 | +# Copyright (C) 2019 Red Hat, Inc. | ||
115 | +# | ||
116 | +# This program is free software; you can redistribute it and/or modify | ||
117 | +# it under the terms of the GNU General Public License as published by | ||
118 | +# the Free Software Foundation; either version 2 of the License, or | ||
119 | +# (at your option) any later version. | ||
120 | +# | ||
121 | +# This program is distributed in the hope that it will be useful, | ||
122 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
123 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
124 | +# GNU General Public License for more details. | ||
125 | +# | ||
126 | +# You should have received a copy of the GNU General Public License | ||
127 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
128 | +# | ||
129 | + | 321 | + |
130 | +# creator | 322 | + This function always prepends either QEMU_IO_OPTIONS or |
131 | +owner=berrange@redhat.com | 323 | + QEMU_IO_OPTIONS_NO_FMT. |
132 | + | 324 | + """ |
133 | +seq=`basename $0` | 325 | + return qemu_tool(*qemu_io_wrap_args(args), |
134 | +echo "QA output created by $seq" | 326 | + check=check, combine_stdio=combine_stdio) |
135 | + | 327 | |
136 | +status=1 # failure is the default! | 328 | def qemu_io_pipe_and_status(*args): |
137 | + | 329 | return qemu_tool_pipe_and_status('qemu-io', qemu_io_wrap_args(args)) |
138 | +_cleanup() | 330 | |
139 | +{ | 331 | -def qemu_io_log(*args): |
140 | + _cleanup_test_img | 332 | - result = qemu_io(*args) |
141 | +} | 333 | - log(result, filters=[filter_testfiles, filter_qemu_io]) |
142 | +trap "_cleanup; exit \$status" 0 1 2 3 15 | 334 | +def qemu_io_log(*args: str) -> 'subprocess.CompletedProcess[str]': |
143 | + | 335 | + result = qemu_io(*args, check=False) |
144 | +# get standard environment, filters and checks | 336 | + log(result.stdout, filters=[filter_testfiles, filter_qemu_io]) |
145 | +. ./common.rc | 337 | return result |
146 | +. ./common.filter | 338 | |
147 | + | 339 | def qemu_io_silent(*args): |
148 | +_supported_fmt qcow2 | 340 | diff --git a/tests/qemu-iotests/tests/migration-permissions b/tests/qemu-iotests/tests/migration-permissions |
149 | +_supported_proto generic | 341 | index XXXXXXX..XXXXXXX 100755 |
150 | +_supported_os Linux | 342 | --- a/tests/qemu-iotests/tests/migration-permissions |
151 | + | 343 | +++ b/tests/qemu-iotests/tests/migration-permissions |
152 | + | 344 | @@ -XXX,XX +XXX,XX @@ class TestMigrationPermissions(iotests.QMPTestCase): |
153 | +size=1M | 345 | def test_post_migration_permissions(self): |
154 | + | 346 | # Try to access the image R/W, which should fail because virtio-blk |
155 | +SECRET="secret,id=sec0,data=astrochicken" | 347 | # has not been configured with share-rw=on |
156 | + | 348 | - log = qemu_io('-f', imgfmt, '-c', 'quit', test_img) |
157 | +IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0" | 349 | + log = qemu_io('-f', imgfmt, '-c', 'quit', test_img, check=False).stdout |
158 | +QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT | 350 | if not log.strip(): |
159 | + | 351 | print('ERROR (pre-migration): qemu-io should not be able to ' |
160 | +_run_test() | 352 | 'access this image, but it reported no error') |
161 | +{ | 353 | @@ -XXX,XX +XXX,XX @@ class TestMigrationPermissions(iotests.QMPTestCase): |
162 | + IMGOPTSSYNTAX=true | 354 | |
163 | + OLD_TEST_IMG="$TEST_IMG" | 355 | # Try the same qemu-io access again, verifying that the WRITE |
164 | + TEST_IMG="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0" | 356 | # permission remains unshared |
165 | + QEMU_IMG_EXTRA_ARGS="--image-opts --object $SECRET" | 357 | - log = qemu_io('-f', imgfmt, '-c', 'quit', test_img) |
166 | + | 358 | + log = qemu_io('-f', imgfmt, '-c', 'quit', test_img, check=False).stdout |
167 | + echo | 359 | if not log.strip(): |
168 | + echo "== cluster size $csize" | 360 | print('ERROR (post-migration): qemu-io should not be able to ' |
169 | + echo "== checking image refcounts ==" | 361 | 'access this image, but it reported no error') |
170 | + _check_test_img | ||
171 | + | ||
172 | + echo | ||
173 | + echo "== writing some data ==" | ||
174 | + $QEMU_IO -c "write -P 0x9 0 1" $QEMU_IMG_EXTRA_ARGS $TEST_IMG | _filter_qemu_io | _filter_testdir | ||
175 | + echo | ||
176 | + echo "== rechecking image refcounts ==" | ||
177 | + _check_test_img | ||
178 | + | ||
179 | + echo | ||
180 | + echo "== writing some more data ==" | ||
181 | + $QEMU_IO -c "write -P 0x9 $csize 1" $QEMU_IMG_EXTRA_ARGS $TEST_IMG | _filter_qemu_io | _filter_testdir | ||
182 | + echo | ||
183 | + echo "== rechecking image refcounts ==" | ||
184 | + _check_test_img | ||
185 | + | ||
186 | + TEST_IMG="$OLD_TEST_IMG" | ||
187 | + QEMU_IMG_EXTRA_ARGS= | ||
188 | + IMGOPTSSYNTAX= | ||
189 | +} | ||
190 | + | ||
191 | + | ||
192 | +echo | ||
193 | +echo "testing LUKS qcow2 encryption" | ||
194 | +echo | ||
195 | + | ||
196 | +for csize in 512 2048 32768 | ||
197 | +do | ||
198 | + _make_test_img --object $SECRET -o "encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10,cluster_size=$csize" $size | ||
199 | + _run_test | ||
200 | + _cleanup_test_img | ||
201 | +done | ||
202 | + | ||
203 | +# success, all done | ||
204 | +echo "*** done" | ||
205 | +rm -f $seq.full | ||
206 | +status=0 | ||
207 | diff --git a/tests/qemu-iotests/284.out b/tests/qemu-iotests/284.out | ||
208 | new file mode 100644 | ||
209 | index XXXXXXX..XXXXXXX | ||
210 | --- /dev/null | ||
211 | +++ b/tests/qemu-iotests/284.out | ||
212 | @@ -XXX,XX +XXX,XX @@ | ||
213 | +QA output created by 284 | ||
214 | + | ||
215 | +testing LUKS qcow2 encryption | ||
216 | + | ||
217 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 | ||
218 | + | ||
219 | +== cluster size 512 | ||
220 | +== checking image refcounts == | ||
221 | +No errors were found on the image. | ||
222 | + | ||
223 | +== writing some data == | ||
224 | +wrote 1/1 bytes at offset 0 | ||
225 | +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
226 | + | ||
227 | +== rechecking image refcounts == | ||
228 | +No errors were found on the image. | ||
229 | + | ||
230 | +== writing some more data == | ||
231 | +wrote 1/1 bytes at offset 512 | ||
232 | +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
233 | + | ||
234 | +== rechecking image refcounts == | ||
235 | +No errors were found on the image. | ||
236 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 | ||
237 | + | ||
238 | +== cluster size 2048 | ||
239 | +== checking image refcounts == | ||
240 | +No errors were found on the image. | ||
241 | + | ||
242 | +== writing some data == | ||
243 | +wrote 1/1 bytes at offset 0 | ||
244 | +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
245 | + | ||
246 | +== rechecking image refcounts == | ||
247 | +No errors were found on the image. | ||
248 | + | ||
249 | +== writing some more data == | ||
250 | +wrote 1/1 bytes at offset 2048 | ||
251 | +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
252 | + | ||
253 | +== rechecking image refcounts == | ||
254 | +No errors were found on the image. | ||
255 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 encrypt.format=luks encrypt.key-secret=sec0 encrypt.iter-time=10 | ||
256 | + | ||
257 | +== cluster size 32768 | ||
258 | +== checking image refcounts == | ||
259 | +No errors were found on the image. | ||
260 | + | ||
261 | +== writing some data == | ||
262 | +wrote 1/1 bytes at offset 0 | ||
263 | +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
264 | + | ||
265 | +== rechecking image refcounts == | ||
266 | +No errors were found on the image. | ||
267 | + | ||
268 | +== writing some more data == | ||
269 | +wrote 1/1 bytes at offset 32768 | ||
270 | +1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
271 | + | ||
272 | +== rechecking image refcounts == | ||
273 | +No errors were found on the image. | ||
274 | +*** done | ||
275 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
276 | index XXXXXXX..XXXXXXX 100644 | ||
277 | --- a/tests/qemu-iotests/group | ||
278 | +++ b/tests/qemu-iotests/group | ||
279 | @@ -XXX,XX +XXX,XX @@ | ||
280 | 280 rw migration quick | ||
281 | 281 rw quick | ||
282 | 283 auto quick | ||
283 | +284 rw | ||
284 | -- | 362 | -- |
285 | 2.24.1 | 363 | 2.35.1 |
286 | |||
287 | diff view generated by jsdifflib |
1 | 8dff69b94 added an aio parameter to the drive parameter but forgot to | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | add a comma before, thus breaking the test. Fix it again. | ||
3 | 2 | ||
4 | Fixes: 8dff69b9415b4287e900358744b732195e1ab2e2 | 3 | Modify this test to use assertRaises for its negative testing of |
5 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 4 | qemu_io. If the exception raised does not match the one we tell it to |
6 | Message-Id: <20200206130812.612960-1-mreitz@redhat.com> | 5 | expect, we get *that* exception unhandled. If we get no exception, we |
6 | get a unittest assertion failure and the provided emsg printed to | ||
7 | screen. | ||
8 | |||
9 | If we get the CalledProcessError exception but the output is not what we | ||
10 | expect, we re-raise the original CalledProcessError. | ||
11 | |||
12 | Tidy. | ||
13 | |||
14 | (Note: Yes, you can reference "with" objects after that block ends; it | ||
15 | just means that ctx.__exit__(...) will have been called on it. It does | ||
16 | not *actually* go out of scope. unittests expects you to want to inspect | ||
17 | the Exception object, so they leave it defined post-exit.) | ||
18 | |||
19 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
7 | Reviewed-by: Eric Blake <eblake@redhat.com> | 20 | Reviewed-by: Eric Blake <eblake@redhat.com> |
8 | Tested-by: Eric Blake <eblake@redhat.com> | 21 | Tested-by: Eric Blake <eblake@redhat.com> |
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 22 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> |
23 | Message-Id: <20220418211504.943969-9-jsnow@redhat.com> | ||
24 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
10 | --- | 25 | --- |
11 | tests/qemu-iotests/147 | 2 +- | 26 | .../qemu-iotests/tests/migration-permissions | 28 +++++++++---------- |
12 | 1 file changed, 1 insertion(+), 1 deletion(-) | 27 | 1 file changed, 14 insertions(+), 14 deletions(-) |
13 | 28 | ||
14 | diff --git a/tests/qemu-iotests/147 b/tests/qemu-iotests/147 | 29 | diff --git a/tests/qemu-iotests/tests/migration-permissions b/tests/qemu-iotests/tests/migration-permissions |
15 | index XXXXXXX..XXXXXXX 100755 | 30 | index XXXXXXX..XXXXXXX 100755 |
16 | --- a/tests/qemu-iotests/147 | 31 | --- a/tests/qemu-iotests/tests/migration-permissions |
17 | +++ b/tests/qemu-iotests/147 | 32 | +++ b/tests/qemu-iotests/tests/migration-permissions |
18 | @@ -XXX,XX +XXX,XX @@ class BuiltinNBD(NBDBlockdevAddBase): | 33 | @@ -XXX,XX +XXX,XX @@ |
19 | self.server.add_drive_raw('if=none,id=nbd-export,' + | 34 | # |
20 | 'file=%s,' % test_img + | 35 | |
21 | 'format=%s,' % imgfmt + | 36 | import os |
22 | - 'cache=%s' % cachemode + | 37 | +from subprocess import CalledProcessError |
23 | + 'cache=%s,' % cachemode + | 38 | + |
24 | 'aio=%s' % aiomode) | 39 | import iotests |
25 | self.server.launch() | 40 | from iotests import imgfmt, qemu_img_create, qemu_io |
26 | 41 | ||
42 | @@ -XXX,XX +XXX,XX @@ class TestMigrationPermissions(iotests.QMPTestCase): | ||
43 | def test_post_migration_permissions(self): | ||
44 | # Try to access the image R/W, which should fail because virtio-blk | ||
45 | # has not been configured with share-rw=on | ||
46 | - log = qemu_io('-f', imgfmt, '-c', 'quit', test_img, check=False).stdout | ||
47 | - if not log.strip(): | ||
48 | - print('ERROR (pre-migration): qemu-io should not be able to ' | ||
49 | - 'access this image, but it reported no error') | ||
50 | - else: | ||
51 | - # This is the expected output | ||
52 | - assert 'Is another process using the image' in log | ||
53 | + emsg = ('ERROR (pre-migration): qemu-io should not be able to ' | ||
54 | + 'access this image, but it reported no error') | ||
55 | + with self.assertRaises(CalledProcessError, msg=emsg) as ctx: | ||
56 | + qemu_io('-f', imgfmt, '-c', 'quit', test_img) | ||
57 | + if 'Is another process using the image' not in ctx.exception.stdout: | ||
58 | + raise ctx.exception | ||
59 | |||
60 | # Now migrate the VM | ||
61 | self.vm_s.qmp('migrate', uri=f'unix:{mig_sock}') | ||
62 | @@ -XXX,XX +XXX,XX @@ class TestMigrationPermissions(iotests.QMPTestCase): | ||
63 | |||
64 | # Try the same qemu-io access again, verifying that the WRITE | ||
65 | # permission remains unshared | ||
66 | - log = qemu_io('-f', imgfmt, '-c', 'quit', test_img, check=False).stdout | ||
67 | - if not log.strip(): | ||
68 | - print('ERROR (post-migration): qemu-io should not be able to ' | ||
69 | - 'access this image, but it reported no error') | ||
70 | - else: | ||
71 | - # This is the expected output | ||
72 | - assert 'Is another process using the image' in log | ||
73 | + emsg = ('ERROR (post-migration): qemu-io should not be able to ' | ||
74 | + 'access this image, but it reported no error') | ||
75 | + with self.assertRaises(CalledProcessError, msg=emsg) as ctx: | ||
76 | + qemu_io('-f', imgfmt, '-c', 'quit', test_img) | ||
77 | + if 'Is another process using the image' not in ctx.exception.stdout: | ||
78 | + raise ctx.exception | ||
79 | |||
80 | |||
81 | if __name__ == '__main__': | ||
27 | -- | 82 | -- |
28 | 2.24.1 | 83 | 2.35.1 |
29 | |||
30 | diff view generated by jsdifflib |
1 | The generic fallback implementation effectively does the same. | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> | 3 | This test expects failure ... but only sometimes. When? Why? |
4 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 4 | |
5 | Message-Id: <20200122164532.178040-5-mreitz@redhat.com> | 5 | It's for reads of a region not defined by a bitmap. Adjust the test to |
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 6 | be more explicit about what it expects to fail and why. |
7 | |||
8 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
9 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
10 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
11 | Message-Id: <20220418211504.943969-10-jsnow@redhat.com> | ||
12 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
7 | --- | 13 | --- |
8 | block/iscsi.c | 56 --------------------------------------------------- | 14 | tests/qemu-iotests/tests/image-fleecing | 28 +++++++++++++++++-------- |
9 | 1 file changed, 56 deletions(-) | 15 | 1 file changed, 19 insertions(+), 9 deletions(-) |
10 | 16 | ||
11 | diff --git a/block/iscsi.c b/block/iscsi.c | 17 | diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing |
12 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100755 |
13 | --- a/block/iscsi.c | 19 | --- a/tests/qemu-iotests/tests/image-fleecing |
14 | +++ b/block/iscsi.c | 20 | +++ b/tests/qemu-iotests/tests/image-fleecing |
15 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset, | 21 | @@ -XXX,XX +XXX,XX @@ |
16 | return 0; | 22 | # |
17 | } | 23 | # Creator/Owner: John Snow <jsnow@redhat.com> |
18 | 24 | ||
19 | -static int coroutine_fn iscsi_co_create_opts(const char *filename, QemuOpts *opts, | 25 | +from subprocess import CalledProcessError |
20 | - Error **errp) | 26 | + |
21 | -{ | 27 | import iotests |
22 | - int ret = 0; | 28 | -from iotests import log, qemu_img, qemu_io, qemu_io_silent, \ |
23 | - int64_t total_size = 0; | 29 | - qemu_io_pipe_and_status |
24 | - BlockDriverState *bs; | 30 | +from iotests import log, qemu_img, qemu_io, qemu_io_silent |
25 | - IscsiLun *iscsilun = NULL; | 31 | |
26 | - QDict *bs_options; | 32 | iotests.script_initialize( |
27 | - Error *local_err = NULL; | 33 | supported_fmts=['qcow2'], |
28 | - | 34 | @@ -XXX,XX +XXX,XX @@ def do_test(vm, use_cbw, use_snapshot_access_filter, base_img_path, |
29 | - bs = bdrv_new(); | 35 | for p in patterns + zeroes: |
30 | - | 36 | cmd = 'read -P%s %s %s' % p |
31 | - /* Read out options */ | 37 | log(cmd) |
32 | - total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), | 38 | - out, ret = qemu_io_pipe_and_status('-r', '-f', 'raw', '-c', cmd, |
33 | - BDRV_SECTOR_SIZE); | 39 | - nbd_uri) |
34 | - bs->opaque = g_new0(struct IscsiLun, 1); | 40 | - if ret != 0: |
35 | - iscsilun = bs->opaque; | 41 | - print(out) |
36 | - | 42 | + |
37 | - bs_options = qdict_new(); | 43 | + try: |
38 | - iscsi_parse_filename(filename, bs_options, &local_err); | 44 | + qemu_io('-r', '-f', 'raw', '-c', cmd, nbd_uri) |
39 | - if (local_err) { | 45 | + except CalledProcessError as exc: |
40 | - error_propagate(errp, local_err); | 46 | + if bitmap and p in zeroes: |
41 | - ret = -EINVAL; | 47 | + log(exc.stdout) |
42 | - } else { | 48 | + else: |
43 | - ret = iscsi_open(bs, bs_options, 0, NULL); | 49 | + raise |
44 | - } | 50 | |
45 | - qobject_unref(bs_options); | 51 | log('') |
46 | - | 52 | log('--- Testing COW ---') |
47 | - if (ret != 0) { | 53 | @@ -XXX,XX +XXX,XX @@ def do_test(vm, use_cbw, use_snapshot_access_filter, base_img_path, |
48 | - goto out; | 54 | args += [target_img_path] |
49 | - } | 55 | else: |
50 | - iscsi_detach_aio_context(bs); | 56 | args += ['-f', 'raw', nbd_uri] |
51 | - if (iscsilun->type != TYPE_DISK) { | 57 | - out, ret = qemu_io_pipe_and_status(*args) |
52 | - ret = -ENODEV; | 58 | - if ret != 0: |
53 | - goto out; | 59 | - print(out) |
54 | - } | 60 | + |
55 | - if (bs->total_sectors < total_size) { | 61 | + try: |
56 | - ret = -ENOSPC; | 62 | + qemu_io(*args) |
57 | - goto out; | 63 | + except CalledProcessError as exc: |
58 | - } | 64 | + if bitmap and p in zeroes: |
59 | - | 65 | + log(exc.stdout) |
60 | - ret = 0; | 66 | + else: |
61 | -out: | 67 | + raise |
62 | - if (iscsilun->iscsi != NULL) { | 68 | |
63 | - iscsi_destroy_context(iscsilun->iscsi); | 69 | log('') |
64 | - } | 70 | log('--- Cleanup ---') |
65 | - g_free(bs->opaque); | ||
66 | - bs->opaque = NULL; | ||
67 | - bdrv_unref(bs); | ||
68 | - return ret; | ||
69 | -} | ||
70 | - | ||
71 | static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) | ||
72 | { | ||
73 | IscsiLun *iscsilun = bs->opaque; | ||
74 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iscsi = { | ||
75 | .bdrv_parse_filename = iscsi_parse_filename, | ||
76 | .bdrv_file_open = iscsi_open, | ||
77 | .bdrv_close = iscsi_close, | ||
78 | - .bdrv_co_create_opts = iscsi_co_create_opts, | ||
79 | - .create_opts = &iscsi_create_opts, | ||
80 | .bdrv_reopen_prepare = iscsi_reopen_prepare, | ||
81 | .bdrv_reopen_commit = iscsi_reopen_commit, | ||
82 | .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache, | ||
83 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iser = { | ||
84 | .bdrv_parse_filename = iscsi_parse_filename, | ||
85 | .bdrv_file_open = iscsi_open, | ||
86 | .bdrv_close = iscsi_close, | ||
87 | - .bdrv_co_create_opts = iscsi_co_create_opts, | ||
88 | - .create_opts = &iscsi_create_opts, | ||
89 | .bdrv_reopen_prepare = iscsi_reopen_prepare, | ||
90 | .bdrv_reopen_commit = iscsi_reopen_commit, | ||
91 | .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache, | ||
92 | -- | 71 | -- |
93 | 2.24.1 | 72 | 2.35.1 |
94 | |||
95 | diff view generated by jsdifflib |
1 | From: Thomas Huth <thuth@redhat.com> | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Commit d9df28e7b07 ("iotests: check whitelisted formats") added the | 3 | I know we just added it, sorry. This is done in favor of qemu_io() which |
4 | modern @iotests.skip_if_unsupported() to the functions in this test, | 4 | *also* returns the console output and status, but with more robust error |
5 | so we don't need the old explicit test here anymore. | 5 | handling on failure. |
6 | 6 | ||
7 | Signed-off-by: Thomas Huth <thuth@redhat.com> | 7 | Signed-off-by: John Snow <jsnow@redhat.com> |
8 | Message-Id: <20200129141751.32652-1-thuth@redhat.com> | 8 | Reviewed-by: Eric Blake <eblake@redhat.com> |
9 | Reviewed-by: Alberto Garcia <berto@igalia.com> | 9 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> |
10 | Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com> | 10 | Message-Id: <20220418211504.943969-11-jsnow@redhat.com> |
11 | Tested-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com> | 11 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> |
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
13 | --- | 12 | --- |
14 | tests/qemu-iotests/139 | 3 --- | 13 | tests/qemu-iotests/iotests.py | 3 --- |
15 | 1 file changed, 3 deletions(-) | 14 | 1 file changed, 3 deletions(-) |
16 | 15 | ||
17 | diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139 | 16 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py |
18 | index XXXXXXX..XXXXXXX 100755 | 17 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/tests/qemu-iotests/139 | 18 | --- a/tests/qemu-iotests/iotests.py |
20 | +++ b/tests/qemu-iotests/139 | 19 | +++ b/tests/qemu-iotests/iotests.py |
21 | @@ -XXX,XX +XXX,XX @@ class TestBlockdevDel(iotests.QMPTestCase): | 20 | @@ -XXX,XX +XXX,XX @@ def qemu_io(*args: str, check: bool = True, combine_stdio: bool = True |
22 | 21 | return qemu_tool(*qemu_io_wrap_args(args), | |
23 | @iotests.skip_if_unsupported(['quorum']) | 22 | check=check, combine_stdio=combine_stdio) |
24 | def testQuorum(self): | 23 | |
25 | - if not iotests.supports_quorum(): | 24 | -def qemu_io_pipe_and_status(*args): |
26 | - return | 25 | - return qemu_tool_pipe_and_status('qemu-io', qemu_io_wrap_args(args)) |
27 | - | 26 | - |
28 | self.addQuorum('quorum0', 'node0', 'node1') | 27 | def qemu_io_log(*args: str) -> 'subprocess.CompletedProcess[str]': |
29 | # We cannot remove the children of a Quorum device | 28 | result = qemu_io(*args, check=False) |
30 | self.delBlockDriverState('node0', expect_error = True) | 29 | log(result.stdout, filters=[filter_testfiles, filter_qemu_io]) |
31 | -- | 30 | -- |
32 | 2.24.1 | 31 | 2.35.1 |
33 | |||
34 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: David Edmondson <david.edmondson@oracle.com> | ||
2 | 1 | ||
3 | In many cases the target of a convert operation is a newly provisioned | ||
4 | target that the user knows is blank (reads as zero). In this situation | ||
5 | there is no requirement for qemu-img to wastefully zero out the entire | ||
6 | device. | ||
7 | |||
8 | Add a new option, --target-is-zero, allowing the user to indicate that | ||
9 | an existing target device will return zeros for all reads. | ||
10 | |||
11 | Signed-off-by: David Edmondson <david.edmondson@oracle.com> | ||
12 | Message-Id: <20200205110248.2009589-2-david.edmondson@oracle.com> | ||
13 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
14 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
15 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
16 | --- | ||
17 | docs/interop/qemu-img.rst | 9 ++++++++- | ||
18 | qemu-img-cmds.hx | 4 ++-- | ||
19 | qemu-img.c | 26 +++++++++++++++++++++++--- | ||
20 | 3 files changed, 33 insertions(+), 6 deletions(-) | ||
21 | |||
22 | diff --git a/docs/interop/qemu-img.rst b/docs/interop/qemu-img.rst | ||
23 | index XXXXXXX..XXXXXXX 100644 | ||
24 | --- a/docs/interop/qemu-img.rst | ||
25 | +++ b/docs/interop/qemu-img.rst | ||
26 | @@ -XXX,XX +XXX,XX @@ Parameters to convert subcommand: | ||
27 | will still be printed. Areas that cannot be read from the source will be | ||
28 | treated as containing only zeroes. | ||
29 | |||
30 | +.. option:: --target-is-zero | ||
31 | + | ||
32 | + Assume that reading the destination image will always return | ||
33 | + zeros. This parameter is mutually exclusive with a destination image | ||
34 | + that has a backing file. It is required to also use the ``-n`` | ||
35 | + parameter to skip image creation. | ||
36 | + | ||
37 | Parameters to dd subcommand: | ||
38 | |||
39 | .. program:: qemu-img-dd | ||
40 | @@ -XXX,XX +XXX,XX @@ Command description: | ||
41 | 4 | ||
42 | Error on reading data | ||
43 | |||
44 | -.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME | ||
45 | +.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME | ||
46 | |||
47 | Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM* | ||
48 | to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can | ||
49 | diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx | ||
50 | index XXXXXXX..XXXXXXX 100644 | ||
51 | --- a/qemu-img-cmds.hx | ||
52 | +++ b/qemu-img-cmds.hx | ||
53 | @@ -XXX,XX +XXX,XX @@ SRST | ||
54 | ERST | ||
55 | |||
56 | DEF("convert", img_convert, | ||
57 | - "convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename") | ||
58 | + "convert [--object objectdef] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename") | ||
59 | SRST | ||
60 | -.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] [--salvage] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME | ||
61 | +.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-m NUM_COROUTINES] [-W] [--salvage] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME | ||
62 | ERST | ||
63 | |||
64 | DEF("create", img_create, | ||
65 | diff --git a/qemu-img.c b/qemu-img.c | ||
66 | index XXXXXXX..XXXXXXX 100644 | ||
67 | --- a/qemu-img.c | ||
68 | +++ b/qemu-img.c | ||
69 | @@ -XXX,XX +XXX,XX @@ enum { | ||
70 | OPTION_PREALLOCATION = 265, | ||
71 | OPTION_SHRINK = 266, | ||
72 | OPTION_SALVAGE = 267, | ||
73 | + OPTION_TARGET_IS_ZERO = 268, | ||
74 | }; | ||
75 | |||
76 | typedef enum OutputFormat { | ||
77 | @@ -XXX,XX +XXX,XX @@ static int convert_do_copy(ImgConvertState *s) | ||
78 | int64_t sector_num = 0; | ||
79 | |||
80 | /* Check whether we have zero initialisation or can get it efficiently */ | ||
81 | - if (s->target_is_new && s->min_sparse && !s->target_has_backing) { | ||
82 | + if (!s->has_zero_init && s->target_is_new && s->min_sparse && | ||
83 | + !s->target_has_backing) { | ||
84 | s->has_zero_init = bdrv_has_zero_init(blk_bs(s->target)); | ||
85 | - } else { | ||
86 | - s->has_zero_init = false; | ||
87 | } | ||
88 | |||
89 | if (!s->has_zero_init && !s->target_has_backing && | ||
90 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
91 | {"force-share", no_argument, 0, 'U'}, | ||
92 | {"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS}, | ||
93 | {"salvage", no_argument, 0, OPTION_SALVAGE}, | ||
94 | + {"target-is-zero", no_argument, 0, OPTION_TARGET_IS_ZERO}, | ||
95 | {0, 0, 0, 0} | ||
96 | }; | ||
97 | c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU", | ||
98 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
99 | case OPTION_TARGET_IMAGE_OPTS: | ||
100 | tgt_image_opts = true; | ||
101 | break; | ||
102 | + case OPTION_TARGET_IS_ZERO: | ||
103 | + /* | ||
104 | + * The user asserting that the target is blank has the | ||
105 | + * same effect as the target driver supporting zero | ||
106 | + * initialisation. | ||
107 | + */ | ||
108 | + s.has_zero_init = true; | ||
109 | + break; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
114 | warn_report("This will become an error in future QEMU versions."); | ||
115 | } | ||
116 | |||
117 | + if (s.has_zero_init && !skip_create) { | ||
118 | + error_report("--target-is-zero requires use of -n flag"); | ||
119 | + goto fail_getopt; | ||
120 | + } | ||
121 | + | ||
122 | s.src_num = argc - optind - 1; | ||
123 | out_filename = s.src_num >= 1 ? argv[argc - 1] : NULL; | ||
124 | |||
125 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
126 | } | ||
127 | s.target_has_backing = (bool) out_baseimg; | ||
128 | |||
129 | + if (s.has_zero_init && s.target_has_backing) { | ||
130 | + error_report("Cannot use --target-is-zero when the destination " | ||
131 | + "image has a backing file"); | ||
132 | + goto out; | ||
133 | + } | ||
134 | + | ||
135 | if (s.src_num > 1 && out_baseimg) { | ||
136 | error_report("Having a backing file for the target makes no sense when " | ||
137 | "concatenating multiple input images"); | ||
138 | -- | ||
139 | 2.24.1 | ||
140 | |||
141 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
2 | 1 | ||
3 | backup-top "supports" write-unchanged, by skipping CBW operation in | ||
4 | backup_top_co_pwritev. But it forgets to do the same in | ||
5 | backup_top_co_pwrite_zeroes, as well as declare support for | ||
6 | BDRV_REQ_WRITE_UNCHANGED. | ||
7 | |||
8 | Fix this, and, while being here, declare also support for flags | ||
9 | supported by source child. | ||
10 | |||
11 | Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
12 | Message-Id: <20200207161231.32707-1-vsementsov@virtuozzo.com> | ||
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
14 | --- | ||
15 | block/backup-top.c | 31 ++++++++++++++++++++----------- | ||
16 | 1 file changed, 20 insertions(+), 11 deletions(-) | ||
17 | |||
18 | diff --git a/block/backup-top.c b/block/backup-top.c | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/block/backup-top.c | ||
21 | +++ b/block/backup-top.c | ||
22 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int backup_top_co_preadv( | ||
23 | } | ||
24 | |||
25 | static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset, | ||
26 | - uint64_t bytes) | ||
27 | + uint64_t bytes, BdrvRequestFlags flags) | ||
28 | { | ||
29 | BDRVBackupTopState *s = bs->opaque; | ||
30 | - uint64_t end = QEMU_ALIGN_UP(offset + bytes, s->bcs->cluster_size); | ||
31 | - uint64_t off = QEMU_ALIGN_DOWN(offset, s->bcs->cluster_size); | ||
32 | + uint64_t off, end; | ||
33 | + | ||
34 | + if (flags & BDRV_REQ_WRITE_UNCHANGED) { | ||
35 | + return 0; | ||
36 | + } | ||
37 | + | ||
38 | + off = QEMU_ALIGN_DOWN(offset, s->bcs->cluster_size); | ||
39 | + end = QEMU_ALIGN_UP(offset + bytes, s->bcs->cluster_size); | ||
40 | |||
41 | return block_copy(s->bcs, off, end - off, NULL); | ||
42 | } | ||
43 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset, | ||
44 | static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs, | ||
45 | int64_t offset, int bytes) | ||
46 | { | ||
47 | - int ret = backup_top_cbw(bs, offset, bytes); | ||
48 | + int ret = backup_top_cbw(bs, offset, bytes, 0); | ||
49 | if (ret < 0) { | ||
50 | return ret; | ||
51 | } | ||
52 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs, | ||
53 | static int coroutine_fn backup_top_co_pwrite_zeroes(BlockDriverState *bs, | ||
54 | int64_t offset, int bytes, BdrvRequestFlags flags) | ||
55 | { | ||
56 | - int ret = backup_top_cbw(bs, offset, bytes); | ||
57 | + int ret = backup_top_cbw(bs, offset, bytes, flags); | ||
58 | if (ret < 0) { | ||
59 | return ret; | ||
60 | } | ||
61 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int backup_top_co_pwritev(BlockDriverState *bs, | ||
62 | uint64_t bytes, | ||
63 | QEMUIOVector *qiov, int flags) | ||
64 | { | ||
65 | - if (!(flags & BDRV_REQ_WRITE_UNCHANGED)) { | ||
66 | - int ret = backup_top_cbw(bs, offset, bytes); | ||
67 | - if (ret < 0) { | ||
68 | - return ret; | ||
69 | - } | ||
70 | + int ret = backup_top_cbw(bs, offset, bytes, flags); | ||
71 | + if (ret < 0) { | ||
72 | + return ret; | ||
73 | } | ||
74 | |||
75 | return bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags); | ||
76 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source, | ||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | - top->total_sectors = source->total_sectors; | ||
81 | state = top->opaque; | ||
82 | + top->total_sectors = source->total_sectors; | ||
83 | + top->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
84 | + (BDRV_REQ_FUA & source->supported_write_flags); | ||
85 | + top->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | | ||
86 | + ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) & | ||
87 | + source->supported_zero_flags); | ||
88 | |||
89 | bdrv_ref(target); | ||
90 | state->target = bdrv_attach_child(top, target, "target", &child_file, errp); | ||
91 | -- | ||
92 | 2.24.1 | ||
93 | |||
94 | diff view generated by jsdifflib |
1 | The generic fallback implementation effectively does the same. | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> | 3 | Like qemu-img, qemu-io returning 0 should be the norm and not the |
4 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 4 | exception. Remove all calls to qemu_io_silent that just assert the |
5 | Message-Id: <20200122164532.178040-4-mreitz@redhat.com> | 5 | return code is zero (That's every last call, as it turns out), and |
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 6 | replace them with a normal qemu_io() call. |
7 | |||
8 | qemu_io_silent_check() appeared to have been unused already. | ||
9 | |||
10 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
12 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> | ||
13 | Message-Id: <20220418211504.943969-12-jsnow@redhat.com> | ||
14 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
7 | --- | 15 | --- |
8 | block/file-posix.c | 67 ---------------------------------------------- | 16 | tests/qemu-iotests/216 | 12 +++++----- |
9 | 1 file changed, 67 deletions(-) | 17 | tests/qemu-iotests/218 | 5 ++--- |
18 | tests/qemu-iotests/224 | 4 ++-- | ||
19 | tests/qemu-iotests/258 | 11 +++++----- | ||
20 | tests/qemu-iotests/298 | 17 ++++++-------- | ||
21 | tests/qemu-iotests/310 | 22 +++++++++---------- | ||
22 | tests/qemu-iotests/iotests.py | 16 -------------- | ||
23 | tests/qemu-iotests/tests/image-fleecing | 4 ++-- | ||
24 | .../tests/mirror-ready-cancel-error | 2 +- | ||
25 | .../qemu-iotests/tests/stream-error-on-reset | 4 ++-- | ||
26 | 10 files changed, 38 insertions(+), 59 deletions(-) | ||
10 | 27 | ||
11 | diff --git a/block/file-posix.c b/block/file-posix.c | 28 | diff --git a/tests/qemu-iotests/216 b/tests/qemu-iotests/216 |
29 | index XXXXXXX..XXXXXXX 100755 | ||
30 | --- a/tests/qemu-iotests/216 | ||
31 | +++ b/tests/qemu-iotests/216 | ||
32 | @@ -XXX,XX +XXX,XX @@ | ||
33 | # Creator/Owner: Hanna Reitz <hreitz@redhat.com> | ||
34 | |||
35 | import iotests | ||
36 | -from iotests import log, qemu_img, qemu_io_silent | ||
37 | +from iotests import log, qemu_img, qemu_io | ||
38 | |||
39 | # Need backing file support | ||
40 | iotests.script_initialize(supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk'], | ||
41 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
42 | log('') | ||
43 | |||
44 | qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') | ||
45 | - assert qemu_io_silent(base_img_path, '-c', 'write -P 1 0M 1M') == 0 | ||
46 | + qemu_io(base_img_path, '-c', 'write -P 1 0M 1M') | ||
47 | qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path, | ||
48 | '-F', iotests.imgfmt, top_img_path) | ||
49 | - assert qemu_io_silent(top_img_path, '-c', 'write -P 2 1M 1M') == 0 | ||
50 | + qemu_io(top_img_path, '-c', 'write -P 2 1M 1M') | ||
51 | |||
52 | log('Done') | ||
53 | |||
54 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
55 | log('--- Checking COR result ---') | ||
56 | log('') | ||
57 | |||
58 | - assert qemu_io_silent(base_img_path, '-c', 'discard 0 64M') == 0 | ||
59 | - assert qemu_io_silent(top_img_path, '-c', 'read -P 1 0M 1M') == 0 | ||
60 | - assert qemu_io_silent(top_img_path, '-c', 'read -P 2 1M 1M') == 0 | ||
61 | + qemu_io(base_img_path, '-c', 'discard 0 64M') | ||
62 | + qemu_io(top_img_path, '-c', 'read -P 1 0M 1M') | ||
63 | + qemu_io(top_img_path, '-c', 'read -P 2 1M 1M') | ||
64 | |||
65 | log('Done') | ||
66 | diff --git a/tests/qemu-iotests/218 b/tests/qemu-iotests/218 | ||
67 | index XXXXXXX..XXXXXXX 100755 | ||
68 | --- a/tests/qemu-iotests/218 | ||
69 | +++ b/tests/qemu-iotests/218 | ||
70 | @@ -XXX,XX +XXX,XX @@ | ||
71 | # Creator/Owner: Hanna Reitz <hreitz@redhat.com> | ||
72 | |||
73 | import iotests | ||
74 | -from iotests import log, qemu_img, qemu_io_silent | ||
75 | +from iotests import log, qemu_img, qemu_io | ||
76 | |||
77 | iotests.script_initialize(supported_fmts=['qcow2', 'raw']) | ||
78 | |||
79 | @@ -XXX,XX +XXX,XX @@ with iotests.VM() as vm, \ | ||
80 | iotests.FilePath('src.img') as src_img_path: | ||
81 | |||
82 | qemu_img('create', '-f', iotests.imgfmt, src_img_path, '64M') | ||
83 | - assert qemu_io_silent('-f', iotests.imgfmt, src_img_path, | ||
84 | - '-c', 'write -P 42 0M 64M') == 0 | ||
85 | + qemu_io('-f', iotests.imgfmt, src_img_path, '-c', 'write -P 42 0M 64M') | ||
86 | |||
87 | vm.launch() | ||
88 | |||
89 | diff --git a/tests/qemu-iotests/224 b/tests/qemu-iotests/224 | ||
90 | index XXXXXXX..XXXXXXX 100755 | ||
91 | --- a/tests/qemu-iotests/224 | ||
92 | +++ b/tests/qemu-iotests/224 | ||
93 | @@ -XXX,XX +XXX,XX @@ | ||
94 | # Creator/Owner: Hanna Reitz <hreitz@redhat.com> | ||
95 | |||
96 | import iotests | ||
97 | -from iotests import log, qemu_img, qemu_io_silent, filter_qmp_testfiles, \ | ||
98 | +from iotests import log, qemu_img, qemu_io, filter_qmp_testfiles, \ | ||
99 | filter_qmp_imgfmt | ||
100 | import json | ||
101 | |||
102 | @@ -XXX,XX +XXX,XX @@ for filter_node_name in False, True: | ||
103 | '-F', iotests.imgfmt, top_img_path) | ||
104 | |||
105 | # Something to commit | ||
106 | - assert qemu_io_silent(mid_img_path, '-c', 'write -P 1 0 1M') == 0 | ||
107 | + qemu_io(mid_img_path, '-c', 'write -P 1 0 1M') | ||
108 | |||
109 | vm.launch() | ||
110 | |||
111 | diff --git a/tests/qemu-iotests/258 b/tests/qemu-iotests/258 | ||
112 | index XXXXXXX..XXXXXXX 100755 | ||
113 | --- a/tests/qemu-iotests/258 | ||
114 | +++ b/tests/qemu-iotests/258 | ||
115 | @@ -XXX,XX +XXX,XX @@ | ||
116 | # Creator/Owner: Hanna Reitz <hreitz@redhat.com> | ||
117 | |||
118 | import iotests | ||
119 | -from iotests import log, qemu_img, qemu_io_silent, \ | ||
120 | +from iotests import log, qemu_img, qemu_io, \ | ||
121 | filter_qmp_testfiles, filter_qmp_imgfmt | ||
122 | |||
123 | # Returns a node for blockdev-add | ||
124 | @@ -XXX,XX +XXX,XX @@ def test_concurrent_finish(write_to_stream_node): | ||
125 | if write_to_stream_node: | ||
126 | # This is what (most of the time) makes commit finish | ||
127 | # earlier and then pull in stream | ||
128 | - assert qemu_io_silent(node2_path, | ||
129 | - '-c', 'write %iK 64K' % (65536 - 192), | ||
130 | - '-c', 'write %iK 64K' % (65536 - 64)) == 0 | ||
131 | + qemu_io(node2_path, | ||
132 | + '-c', 'write %iK 64K' % (65536 - 192), | ||
133 | + '-c', 'write %iK 64K' % (65536 - 64)) | ||
134 | |||
135 | stream_throttle='tg' | ||
136 | else: | ||
137 | # And this makes stream finish earlier | ||
138 | - assert qemu_io_silent(node1_path, | ||
139 | - '-c', 'write %iK 64K' % (65536 - 64)) == 0 | ||
140 | + qemu_io(node1_path, '-c', 'write %iK 64K' % (65536 - 64)) | ||
141 | |||
142 | commit_throttle='tg' | ||
143 | |||
144 | diff --git a/tests/qemu-iotests/298 b/tests/qemu-iotests/298 | ||
145 | index XXXXXXX..XXXXXXX 100755 | ||
146 | --- a/tests/qemu-iotests/298 | ||
147 | +++ b/tests/qemu-iotests/298 | ||
148 | @@ -XXX,XX +XXX,XX @@ class TestTruncate(iotests.QMPTestCase): | ||
149 | os.remove(refdisk) | ||
150 | |||
151 | def do_test(self, prealloc_mode, new_size): | ||
152 | - ret = iotests.qemu_io_silent('--image-opts', '-c', 'write 0 10M', '-c', | ||
153 | - f'truncate -m {prealloc_mode} {new_size}', | ||
154 | - drive_opts) | ||
155 | - self.assertEqual(ret, 0) | ||
156 | - | ||
157 | - ret = iotests.qemu_io_silent('-f', iotests.imgfmt, '-c', 'write 0 10M', | ||
158 | - '-c', | ||
159 | - f'truncate -m {prealloc_mode} {new_size}', | ||
160 | - refdisk) | ||
161 | - self.assertEqual(ret, 0) | ||
162 | + iotests.qemu_io('--image-opts', '-c', 'write 0 10M', '-c', | ||
163 | + f'truncate -m {prealloc_mode} {new_size}', | ||
164 | + drive_opts) | ||
165 | + | ||
166 | + iotests.qemu_io('-f', iotests.imgfmt, '-c', 'write 0 10M', | ||
167 | + '-c', f'truncate -m {prealloc_mode} {new_size}', | ||
168 | + refdisk) | ||
169 | |||
170 | stat = os.stat(disk) | ||
171 | refstat = os.stat(refdisk) | ||
172 | diff --git a/tests/qemu-iotests/310 b/tests/qemu-iotests/310 | ||
173 | index XXXXXXX..XXXXXXX 100755 | ||
174 | --- a/tests/qemu-iotests/310 | ||
175 | +++ b/tests/qemu-iotests/310 | ||
176 | @@ -XXX,XX +XXX,XX @@ | ||
177 | # | ||
178 | |||
179 | import iotests | ||
180 | -from iotests import log, qemu_img, qemu_io_silent | ||
181 | +from iotests import log, qemu_img, qemu_io | ||
182 | |||
183 | # Need backing file support | ||
184 | iotests.script_initialize(supported_fmts=['qcow2'], | ||
185 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
186 | log('') | ||
187 | |||
188 | qemu_img('create', '-f', iotests.imgfmt, base_img_path, '64M') | ||
189 | - assert qemu_io_silent(base_img_path, '-c', 'write -P 1 0M 1M') == 0 | ||
190 | - assert qemu_io_silent(base_img_path, '-c', 'write -P 1 3M 1M') == 0 | ||
191 | + qemu_io(base_img_path, '-c', 'write -P 1 0M 1M') | ||
192 | + qemu_io(base_img_path, '-c', 'write -P 1 3M 1M') | ||
193 | qemu_img('create', '-f', iotests.imgfmt, '-b', base_img_path, | ||
194 | '-F', iotests.imgfmt, mid_img_path) | ||
195 | - assert qemu_io_silent(mid_img_path, '-c', 'write -P 3 2M 1M') == 0 | ||
196 | - assert qemu_io_silent(mid_img_path, '-c', 'write -P 3 4M 1M') == 0 | ||
197 | + qemu_io(mid_img_path, '-c', 'write -P 3 2M 1M') | ||
198 | + qemu_io(mid_img_path, '-c', 'write -P 3 4M 1M') | ||
199 | qemu_img('create', '-f', iotests.imgfmt, '-b', mid_img_path, | ||
200 | '-F', iotests.imgfmt, top_img_path) | ||
201 | - assert qemu_io_silent(top_img_path, '-c', 'write -P 2 1M 1M') == 0 | ||
202 | + qemu_io(top_img_path, '-c', 'write -P 2 1M 1M') | ||
203 | |||
204 | # 0 1 2 3 4 | ||
205 | # top 2 | ||
206 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base.img') as base_img_path, \ | ||
207 | # Detach backing to check that we can read the data from the top level now | ||
208 | qemu_img('rebase', '-u', '-b', '', '-f', iotests.imgfmt, top_img_path) | ||
209 | |||
210 | - assert qemu_io_silent(top_img_path, '-c', 'read -P 0 0 1M') == 0 | ||
211 | - assert qemu_io_silent(top_img_path, '-c', 'read -P 2 1M 1M') == 0 | ||
212 | - assert qemu_io_silent(top_img_path, '-c', 'read -P 3 2M 1M') == 0 | ||
213 | - assert qemu_io_silent(top_img_path, '-c', 'read -P 0 3M 1M') == 0 | ||
214 | - assert qemu_io_silent(top_img_path, '-c', 'read -P 3 4M 1M') == 0 | ||
215 | + qemu_io(top_img_path, '-c', 'read -P 0 0 1M') | ||
216 | + qemu_io(top_img_path, '-c', 'read -P 2 1M 1M') | ||
217 | + qemu_io(top_img_path, '-c', 'read -P 3 2M 1M') | ||
218 | + qemu_io(top_img_path, '-c', 'read -P 0 3M 1M') | ||
219 | + qemu_io(top_img_path, '-c', 'read -P 3 4M 1M') | ||
220 | |||
221 | log('Done') | ||
222 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
12 | index XXXXXXX..XXXXXXX 100644 | 223 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/block/file-posix.c | 224 | --- a/tests/qemu-iotests/iotests.py |
14 | +++ b/block/file-posix.c | 225 | +++ b/tests/qemu-iotests/iotests.py |
15 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int hdev_co_pwrite_zeroes(BlockDriverState *bs, | 226 | @@ -XXX,XX +XXX,XX @@ def qemu_io_log(*args: str) -> 'subprocess.CompletedProcess[str]': |
16 | return raw_do_pwrite_zeroes(bs, offset, bytes, flags, true); | 227 | log(result.stdout, filters=[filter_testfiles, filter_qemu_io]) |
17 | } | 228 | return result |
18 | 229 | ||
19 | -static int coroutine_fn hdev_co_create_opts(const char *filename, QemuOpts *opts, | 230 | -def qemu_io_silent(*args): |
20 | - Error **errp) | 231 | - '''Run qemu-io and return the exit code, suppressing stdout''' |
21 | -{ | 232 | - args = qemu_io_wrap_args(args) |
22 | - int fd; | 233 | - result = subprocess.run(args, stdout=subprocess.DEVNULL, check=False) |
23 | - int ret = 0; | 234 | - if result.returncode < 0: |
24 | - struct stat stat_buf; | 235 | - sys.stderr.write('qemu-io received signal %i: %s\n' % |
25 | - int64_t total_size = 0; | 236 | - (-result.returncode, ' '.join(args))) |
26 | - bool has_prefix; | 237 | - return result.returncode |
27 | - | 238 | - |
28 | - /* This function is used by both protocol block drivers and therefore either | 239 | -def qemu_io_silent_check(*args): |
29 | - * of these prefixes may be given. | 240 | - '''Run qemu-io and return the true if subprocess returned 0''' |
30 | - * The return value has to be stored somewhere, otherwise this is an error | 241 | - args = qemu_io_wrap_args(args) |
31 | - * due to -Werror=unused-value. */ | 242 | - result = subprocess.run(args, stdout=subprocess.DEVNULL, |
32 | - has_prefix = | 243 | - stderr=subprocess.STDOUT, check=False) |
33 | - strstart(filename, "host_device:", &filename) || | 244 | - return result.returncode == 0 |
34 | - strstart(filename, "host_cdrom:" , &filename); | ||
35 | - | 245 | - |
36 | - (void)has_prefix; | 246 | class QemuIoInteractive: |
37 | - | 247 | def __init__(self, *args): |
38 | - ret = raw_normalize_devicepath(&filename, errp); | 248 | self.args = qemu_io_wrap_args(args) |
39 | - if (ret < 0) { | 249 | diff --git a/tests/qemu-iotests/tests/image-fleecing b/tests/qemu-iotests/tests/image-fleecing |
40 | - return ret; | 250 | index XXXXXXX..XXXXXXX 100755 |
41 | - } | 251 | --- a/tests/qemu-iotests/tests/image-fleecing |
42 | - | 252 | +++ b/tests/qemu-iotests/tests/image-fleecing |
43 | - /* Read out options */ | 253 | @@ -XXX,XX +XXX,XX @@ |
44 | - total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), | 254 | from subprocess import CalledProcessError |
45 | - BDRV_SECTOR_SIZE); | 255 | |
46 | - | 256 | import iotests |
47 | - fd = qemu_open(filename, O_WRONLY | O_BINARY); | 257 | -from iotests import log, qemu_img, qemu_io, qemu_io_silent |
48 | - if (fd < 0) { | 258 | +from iotests import log, qemu_img, qemu_io |
49 | - ret = -errno; | 259 | |
50 | - error_setg_errno(errp, -ret, "Could not open device"); | 260 | iotests.script_initialize( |
51 | - return ret; | 261 | supported_fmts=['qcow2'], |
52 | - } | 262 | @@ -XXX,XX +XXX,XX @@ def do_test(vm, use_cbw, use_snapshot_access_filter, base_img_path, |
53 | - | 263 | for p in overwrite + remainder: |
54 | - if (fstat(fd, &stat_buf) < 0) { | 264 | cmd = 'read -P%s %s %s' % p |
55 | - ret = -errno; | 265 | log(cmd) |
56 | - error_setg_errno(errp, -ret, "Could not stat device"); | 266 | - assert qemu_io_silent(base_img_path, '-c', cmd) == 0 |
57 | - } else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode)) { | 267 | + qemu_io(base_img_path, '-c', cmd) |
58 | - error_setg(errp, | 268 | |
59 | - "The given file is neither a block nor a character device"); | 269 | log('') |
60 | - ret = -ENODEV; | 270 | log('Done') |
61 | - } else if (lseek(fd, 0, SEEK_END) < total_size) { | 271 | diff --git a/tests/qemu-iotests/tests/mirror-ready-cancel-error b/tests/qemu-iotests/tests/mirror-ready-cancel-error |
62 | - error_setg(errp, "Device is too small"); | 272 | index XXXXXXX..XXXXXXX 100755 |
63 | - ret = -ENOSPC; | 273 | --- a/tests/qemu-iotests/tests/mirror-ready-cancel-error |
64 | - } | 274 | +++ b/tests/qemu-iotests/tests/mirror-ready-cancel-error |
65 | - | 275 | @@ -XXX,XX +XXX,XX @@ class TestMirrorReadyCancelError(iotests.QMPTestCase): |
66 | - if (!ret && total_size) { | 276 | # Ensure that mirror will copy something before READY so the |
67 | - uint8_t buf[BDRV_SECTOR_SIZE] = { 0 }; | 277 | # target format layer will forward the pre-READY flush to its |
68 | - int64_t zero_size = MIN(BDRV_SECTOR_SIZE, total_size); | 278 | # file child |
69 | - if (lseek(fd, 0, SEEK_SET) == -1) { | 279 | - assert iotests.qemu_io_silent('-c', 'write -P 1 0 64k', source) == 0 |
70 | - ret = -errno; | 280 | + iotests.qemu_io('-c', 'write -P 1 0 64k', source) |
71 | - } else { | 281 | |
72 | - ret = qemu_write_full(fd, buf, zero_size); | 282 | self.vm = iotests.VM() |
73 | - ret = ret == zero_size ? 0 : -errno; | 283 | self.vm.launch() |
74 | - } | 284 | diff --git a/tests/qemu-iotests/tests/stream-error-on-reset b/tests/qemu-iotests/tests/stream-error-on-reset |
75 | - } | 285 | index XXXXXXX..XXXXXXX 100755 |
76 | - qemu_close(fd); | 286 | --- a/tests/qemu-iotests/tests/stream-error-on-reset |
77 | - return ret; | 287 | +++ b/tests/qemu-iotests/tests/stream-error-on-reset |
78 | -} | 288 | @@ -XXX,XX +XXX,XX @@ |
79 | - | 289 | |
80 | static BlockDriver bdrv_host_device = { | 290 | import os |
81 | .format_name = "host_device", | 291 | import iotests |
82 | .protocol_name = "host_device", | 292 | -from iotests import imgfmt, qemu_img_create, qemu_io_silent, QMPTestCase |
83 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_device = { | 293 | +from iotests import imgfmt, qemu_img_create, qemu_io, QMPTestCase |
84 | .bdrv_reopen_prepare = raw_reopen_prepare, | 294 | |
85 | .bdrv_reopen_commit = raw_reopen_commit, | 295 | |
86 | .bdrv_reopen_abort = raw_reopen_abort, | 296 | image_size = 1 * 1024 * 1024 |
87 | - .bdrv_co_create_opts = hdev_co_create_opts, | 297 | @@ -XXX,XX +XXX,XX @@ class TestStreamErrorOnReset(QMPTestCase): |
88 | - .create_opts = &raw_create_opts, | 298 | - top image is attached to a virtio-scsi device |
89 | .mutable_opts = mutable_opts, | 299 | """ |
90 | .bdrv_co_invalidate_cache = raw_co_invalidate_cache, | 300 | qemu_img_create('-f', imgfmt, base, str(image_size)) |
91 | .bdrv_co_pwrite_zeroes = hdev_co_pwrite_zeroes, | 301 | - assert qemu_io_silent('-c', f'write 0 {data_size}', base) == 0 |
92 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_cdrom = { | 302 | + qemu_io('-c', f'write 0 {data_size}', base) |
93 | .bdrv_reopen_prepare = raw_reopen_prepare, | 303 | qemu_img_create('-f', imgfmt, top, str(image_size)) |
94 | .bdrv_reopen_commit = raw_reopen_commit, | 304 | |
95 | .bdrv_reopen_abort = raw_reopen_abort, | 305 | self.vm = iotests.VM() |
96 | - .bdrv_co_create_opts = hdev_co_create_opts, | ||
97 | - .create_opts = &raw_create_opts, | ||
98 | .mutable_opts = mutable_opts, | ||
99 | .bdrv_co_invalidate_cache = raw_co_invalidate_cache, | ||
100 | |||
101 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_cdrom = { | ||
102 | .bdrv_reopen_prepare = raw_reopen_prepare, | ||
103 | .bdrv_reopen_commit = raw_reopen_commit, | ||
104 | .bdrv_reopen_abort = raw_reopen_abort, | ||
105 | - .bdrv_co_create_opts = hdev_co_create_opts, | ||
106 | - .create_opts = &raw_create_opts, | ||
107 | .mutable_opts = mutable_opts, | ||
108 | |||
109 | .bdrv_co_preadv = raw_co_preadv, | ||
110 | -- | 306 | -- |
111 | 2.24.1 | 307 | 2.35.1 |
112 | |||
113 | diff view generated by jsdifflib |
1 | First, driver=qcow2 will not work so well with non-qcow2 formats (and | 1 | From: John Snow <jsnow@redhat.com> |
---|---|---|---|
2 | this test claims to support qcow, qed, and vmdk). | ||
3 | 2 | ||
4 | Second, vmdk will always report the backing file format to be vmdk. | 3 | Just like qemu_img_log(), upgrade qemu_io_log() to enforce a return code |
5 | Filter that out so the output looks like for all other formats. | 4 | of zero by default. |
6 | 5 | ||
7 | Third, the flat vmdk subformats do not support backing files, so they | 6 | Tests that use qemu_io_log(): 242 245 255 274 303 307 nbd-reconnect-on-open |
8 | will not work with this test. | ||
9 | 7 | ||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 8 | Signed-off-by: John Snow <jsnow@redhat.com> |
11 | Message-Id: <20191219144243.1763246-1-mreitz@redhat.com> | 9 | Reviewed-by: Eric Blake <eblake@redhat.com> |
12 | Tested-by: Thomas Huth <thuth@redhat.com> | 10 | Reviewed-by: Hanna Reitz <hreitz@redhat.com> |
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 11 | Message-Id: <20220418211504.943969-13-jsnow@redhat.com> |
12 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> | ||
14 | --- | 13 | --- |
15 | tests/qemu-iotests/279 | 7 +++++-- | 14 | tests/qemu-iotests/iotests.py | 5 +++-- |
16 | 1 file changed, 5 insertions(+), 2 deletions(-) | 15 | tests/qemu-iotests/tests/nbd-reconnect-on-open | 2 +- |
16 | 2 files changed, 4 insertions(+), 3 deletions(-) | ||
17 | 17 | ||
18 | diff --git a/tests/qemu-iotests/279 b/tests/qemu-iotests/279 | 18 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py |
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/tests/qemu-iotests/iotests.py | ||
21 | +++ b/tests/qemu-iotests/iotests.py | ||
22 | @@ -XXX,XX +XXX,XX @@ def qemu_io(*args: str, check: bool = True, combine_stdio: bool = True | ||
23 | return qemu_tool(*qemu_io_wrap_args(args), | ||
24 | check=check, combine_stdio=combine_stdio) | ||
25 | |||
26 | -def qemu_io_log(*args: str) -> 'subprocess.CompletedProcess[str]': | ||
27 | - result = qemu_io(*args, check=False) | ||
28 | +def qemu_io_log(*args: str, check: bool = True | ||
29 | + ) -> 'subprocess.CompletedProcess[str]': | ||
30 | + result = qemu_io(*args, check=check) | ||
31 | log(result.stdout, filters=[filter_testfiles, filter_qemu_io]) | ||
32 | return result | ||
33 | |||
34 | diff --git a/tests/qemu-iotests/tests/nbd-reconnect-on-open b/tests/qemu-iotests/tests/nbd-reconnect-on-open | ||
19 | index XXXXXXX..XXXXXXX 100755 | 35 | index XXXXXXX..XXXXXXX 100755 |
20 | --- a/tests/qemu-iotests/279 | 36 | --- a/tests/qemu-iotests/tests/nbd-reconnect-on-open |
21 | +++ b/tests/qemu-iotests/279 | 37 | +++ b/tests/qemu-iotests/tests/nbd-reconnect-on-open |
22 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | 38 | @@ -XXX,XX +XXX,XX @@ def check_fail_to_connect(open_timeout): |
23 | _supported_fmt qcow qcow2 vmdk qed | 39 | log(f'Check fail to connect with {open_timeout} seconds of timeout') |
24 | _supported_proto file | 40 | |
25 | _supported_os Linux | 41 | start_t = time.time() |
26 | +_unsupported_imgopts "subformat=monolithicFlat" \ | 42 | - qemu_io_log(*create_args(open_timeout)) |
27 | + "subformat=twoGbMaxExtentFlat" \ | 43 | + qemu_io_log(*create_args(open_timeout), check=False) |
28 | 44 | delta_t = time.time() - start_t | |
29 | TEST_IMG="$TEST_IMG.base" _make_test_img 64M | 45 | |
30 | TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base" | 46 | max_delta = open_timeout + 0.2 |
31 | @@ -XXX,XX +XXX,XX @@ _make_test_img -b "$TEST_IMG.mid" | ||
32 | |||
33 | echo | ||
34 | echo '== qemu-img info --backing-chain ==' | ||
35 | -_img_info --backing-chain | _filter_img_info | ||
36 | +_img_info --backing-chain | _filter_img_info | grep -v 'backing file format' | ||
37 | |||
38 | echo | ||
39 | echo '== qemu-img info --backing-chain --image-opts ==' | ||
40 | -TEST_IMG="driver=qcow2,file.driver=file,file.filename=$TEST_IMG" _img_info --backing-chain --image-opts | _filter_img_info | ||
41 | +TEST_IMG="driver=$IMGFMT,file.driver=file,file.filename=$TEST_IMG" _img_info --backing-chain --image-opts \ | ||
42 | + | _filter_img_info | grep -v 'backing file format' | ||
43 | |||
44 | # success, all done | ||
45 | echo "*** done" | ||
46 | -- | 47 | -- |
47 | 2.24.1 | 48 | 2.35.1 |
48 | |||
49 | diff view generated by jsdifflib |
1 | s.target_has_backing does not reflect whether the target BDS has a | 1 | FUSE exports' allow-other option defaults to "auto", which means that it |
---|---|---|---|
2 | backing file; it only tells whether we should use a backing file during | 2 | will try passing allow_other as a mount option, and fall back to not |
3 | conversion (specified by -B). | 3 | using it when an error occurs. We make no effort to hide fusermount's |
4 | error message (because it would be difficult, and because users might | ||
5 | want to know about the fallback occurring), and so when allow_other does | ||
6 | not work (primarily when /etc/fuse.conf does not contain | ||
7 | user_allow_other), this error message will appear and break the | ||
8 | reference output. | ||
4 | 9 | ||
5 | As such, if you use convert -n, the target does not necessarily actually | 10 | We do not need allow_other here, though, so we can just pass |
6 | have a backing file, and then dereferencing out_bs->backing fails here. | 11 | allow-other=off to fix that. |
7 | 12 | ||
8 | When converting to an existing file, we should set | 13 | Reported-by: Markus Armbruster <armbru@redhat.com> |
9 | target_backing_sectors to a negative value, because first, as the | 14 | Signed-off-by: Hanna Reitz <hreitz@redhat.com> |
10 | comment explains, this value is only used for optimization, so it is | 15 | Message-Id: <20220421142435.569600-1-hreitz@redhat.com> |
11 | always fine to do that. | 16 | Tested-by: Markus Armbruster <armbru@redhat.com> |
12 | 17 | Tested-by: Eric Blake <eblake@redhat.com> | |
13 | Second, we use this value to determine where the target must be | ||
14 | initialized to zeroes (overlays are initialized to zero after the end of | ||
15 | their backing file). When converting to an existing file, we cannot | ||
16 | assume that to be true. | ||
17 | |||
18 | Cc: qemu-stable@nongnu.org | ||
19 | Fixes: 351c8efff9ad809c822d55620df54d575d536f68 | ||
20 | ("qemu-img: Special post-backing convert handling") | ||
21 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
22 | Message-Id: <20200121155915.98232-2-mreitz@redhat.com> | ||
23 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
24 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
25 | --- | 18 | --- |
26 | qemu-img.c | 2 +- | 19 | tests/qemu-iotests/108 | 2 +- |
27 | 1 file changed, 1 insertion(+), 1 deletion(-) | 20 | 1 file changed, 1 insertion(+), 1 deletion(-) |
28 | 21 | ||
29 | diff --git a/qemu-img.c b/qemu-img.c | 22 | diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108 |
30 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100755 |
31 | --- a/qemu-img.c | 24 | --- a/tests/qemu-iotests/108 |
32 | +++ b/qemu-img.c | 25 | +++ b/tests/qemu-iotests/108 |
33 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | 26 | @@ -XXX,XX +XXX,XX @@ else |
34 | } | 27 | |
35 | } | 28 | $QSD \ |
36 | 29 | --blockdev file,node-name=export-node,filename="$TEST_IMG" \ | |
37 | - if (s.target_has_backing) { | 30 | - --export fuse,id=fuse-export,node-name=export-node,mountpoint="$export_mp",writable=on,growable=off \ |
38 | + if (s.target_has_backing && s.target_is_new) { | 31 | + --export fuse,id=fuse-export,node-name=export-node,mountpoint="$export_mp",writable=on,growable=off,allow-other=off \ |
39 | /* Errors are treated as "backing length unknown" (which means | 32 | --pidfile "$TEST_DIR/qsd.pid" \ |
40 | * s.target_backing_sectors has to be negative, which it will | 33 | --daemonize |
41 | * be automatically). The backing file length is used only | 34 | fi |
42 | -- | 35 | -- |
43 | 2.24.1 | 36 | 2.35.1 |
44 | |||
45 | diff view generated by jsdifflib |