1 | The following changes since commit 672f9d0df10a68a5c5f2b32cbc8284abf9f5ee18: | 1 | The following changes since commit 6d40ce00c1166c317e298ad82ecf10e650c4f87d: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging (2020-02-18 14:23:43 +0000) | 3 | Update version for v6.0.0-rc1 release (2021-03-30 18:19:07 +0100) |
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/stefanha/qemu.git tags/block-pull-request |
8 | 8 | ||
9 | for you to fetch changes up to dff8d44c96f128480430b0c59ed8760917dbd427: | 9 | for you to fetch changes up to b6489ac06695e257ea0a9841364577e247fdee30: |
10 | 10 | ||
11 | iotests: Test snapshot -l field separation (2020-02-20 16:43:42 +0100) | 11 | test-coroutine: Add rwlock downgrade test (2021-03-31 10:44:21 +0100) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | Block patches: | 14 | Pull request |
15 | - qemu-img convert: New --target-is-zero parameter | 15 | |
16 | - qcow2: Specify non-default compression type flag | 16 | A fix for VDI image files and more generally for CoRwlock. |
17 | - optionally flat output for query-named-block-nodes | ||
18 | - some fixes | ||
19 | - pseudo-creation of images on block devices is now done by a generic | ||
20 | block layer function | ||
21 | 17 | ||
22 | ---------------------------------------------------------------- | 18 | ---------------------------------------------------------------- |
23 | Daniel P. Berrangé (1): | ||
24 | block: always fill entire LUKS header space with zeros | ||
25 | 19 | ||
26 | David Edmondson (1): | 20 | David Edmondson (4): |
27 | qemu-img: Add --target-is-zero to convert | 21 | block/vdi: When writing new bmap entry fails, don't leak the buffer |
22 | block/vdi: Don't assume that blocks are larger than VdiHeader | ||
23 | coroutine-lock: Store the coroutine in the CoWaitRecord only once | ||
24 | test-coroutine: Add rwlock downgrade test | ||
28 | 25 | ||
29 | Max Reitz (11): | 26 | Paolo Bonzini (2): |
30 | iotests/147: Fix drive parameters | 27 | coroutine-lock: Reimplement CoRwlock to fix downgrade bug |
31 | iotests/279: Fix for non-qcow2 formats | 28 | test-coroutine: Add rwlock upgrade test |
32 | block/nbd: Fix hang in .bdrv_close() | ||
33 | block: Generic file creation fallback | ||
34 | file-posix: Drop hdev_co_create_opts() | ||
35 | iscsi: Drop iscsi_co_create_opts() | ||
36 | iotests: Add test for image creation fallback | ||
37 | qemu-img: Fix convert -n -B for backing-less targets | ||
38 | iotests: Test convert -n -B to backing-less target | ||
39 | block: Fix VM size field width in snapshot dump | ||
40 | iotests: Test snapshot -l field separation | ||
41 | 29 | ||
42 | Peter Krempa (1): | 30 | include/qemu/coroutine.h | 17 ++-- |
43 | qapi: Allow getting flat output from 'query-named-block-nodes' | 31 | block/vdi.c | 11 ++- |
44 | 32 | tests/unit/test-coroutine.c | 161 +++++++++++++++++++++++++++++++++++ | |
45 | Thomas Huth (1): | 33 | util/qemu-coroutine-lock.c | 165 +++++++++++++++++++++++------------- |
46 | iotests: Remove the superfluous 2nd check for the availability of | 34 | 4 files changed, 282 insertions(+), 72 deletions(-) |
47 | quorum | ||
48 | |||
49 | Vladimir Sementsov-Ogievskiy (3): | ||
50 | docs: improve qcow2 spec about extending image header | ||
51 | docs: qcow2: introduce compression type feature | ||
52 | block/backup-top: fix flags handling | ||
53 | |||
54 | block.c | 164 +++++++++++++++++++++++++++++++++---- | ||
55 | block/backup-top.c | 31 ++++--- | ||
56 | block/file-posix.c | 67 --------------- | ||
57 | block/iscsi.c | 56 ------------- | ||
58 | block/nbd.c | 14 +++- | ||
59 | block/qapi.c | 15 +++- | ||
60 | block/qcow2.c | 11 ++- | ||
61 | blockdev.c | 8 +- | ||
62 | docs/interop/qcow2.txt | 64 ++++++++++++++- | ||
63 | docs/interop/qemu-img.rst | 9 +- | ||
64 | include/block/block.h | 2 +- | ||
65 | include/block/qapi.h | 4 +- | ||
66 | monitor/hmp-cmds.c | 2 +- | ||
67 | qapi/block-core.json | 7 +- | ||
68 | qemu-img-cmds.hx | 4 +- | ||
69 | qemu-img.c | 28 ++++++- | ||
70 | tests/qemu-iotests/122 | 14 ++++ | ||
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 | 35 | ||
90 | -- | 36 | -- |
91 | 2.24.1 | 37 | 2.30.2 |
92 | 38 | ||
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 |
Deleted patch | |||
---|---|---|---|
1 | From: Thomas Huth <thuth@redhat.com> | ||
2 | 1 | ||
3 | Commit d9df28e7b07 ("iotests: check whitelisted formats") added the | ||
4 | modern @iotests.skip_if_unsupported() to the functions in this test, | ||
5 | so we don't need the old explicit test here anymore. | ||
6 | |||
7 | Signed-off-by: Thomas Huth <thuth@redhat.com> | ||
8 | Message-Id: <20200129141751.32652-1-thuth@redhat.com> | ||
9 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
10 | Reviewed-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com> | ||
11 | Tested-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com> | ||
12 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
13 | --- | ||
14 | tests/qemu-iotests/139 | 3 --- | ||
15 | 1 file changed, 3 deletions(-) | ||
16 | |||
17 | diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139 | ||
18 | index XXXXXXX..XXXXXXX 100755 | ||
19 | --- a/tests/qemu-iotests/139 | ||
20 | +++ b/tests/qemu-iotests/139 | ||
21 | @@ -XXX,XX +XXX,XX @@ class TestBlockdevDel(iotests.QMPTestCase): | ||
22 | |||
23 | @iotests.skip_if_unsupported(['quorum']) | ||
24 | def testQuorum(self): | ||
25 | - if not iotests.supports_quorum(): | ||
26 | - return | ||
27 | - | ||
28 | self.addQuorum('quorum0', 'node0', 'node1') | ||
29 | # We cannot remove the children of a Quorum device | ||
30 | self.delBlockDriverState('node0', expect_error = True) | ||
31 | -- | ||
32 | 2.24.1 | ||
33 | |||
34 | diff view generated by jsdifflib |
1 | 8dff69b94 added an aio parameter to the drive parameter but forgot to | 1 | From: David Edmondson <david.edmondson@oracle.com> |
---|---|---|---|
2 | add a comma before, thus breaking the test. Fix it again. | ||
3 | 2 | ||
4 | Fixes: 8dff69b9415b4287e900358744b732195e1ab2e2 | 3 | If a new bitmap entry is allocated, requiring the entire block to be |
5 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 4 | written, avoiding leaking the buffer allocated for the block should |
6 | Message-Id: <20200206130812.612960-1-mreitz@redhat.com> | 5 | the write fail. |
7 | Reviewed-by: Eric Blake <eblake@redhat.com> | 6 | |
8 | Tested-by: Eric Blake <eblake@redhat.com> | 7 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> |
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 8 | Signed-off-by: David Edmondson <david.edmondson@oracle.com> |
9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
10 | Acked-by: Max Reitz <mreitz@redhat.com> | ||
11 | Message-id: 20210325112941.365238-2-pbonzini@redhat.com | ||
12 | Message-Id: <20210309144015.557477-2-david.edmondson@oracle.com> | ||
13 | Acked-by: Max Reitz <mreitz@redhat.com> | ||
14 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
15 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
10 | --- | 16 | --- |
11 | tests/qemu-iotests/147 | 2 +- | 17 | block/vdi.c | 1 + |
12 | 1 file changed, 1 insertion(+), 1 deletion(-) | 18 | 1 file changed, 1 insertion(+) |
13 | 19 | ||
14 | diff --git a/tests/qemu-iotests/147 b/tests/qemu-iotests/147 | 20 | diff --git a/block/vdi.c b/block/vdi.c |
15 | index XXXXXXX..XXXXXXX 100755 | 21 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/tests/qemu-iotests/147 | 22 | --- a/block/vdi.c |
17 | +++ b/tests/qemu-iotests/147 | 23 | +++ b/block/vdi.c |
18 | @@ -XXX,XX +XXX,XX @@ class BuiltinNBD(NBDBlockdevAddBase): | 24 | @@ -XXX,XX +XXX,XX @@ nonallocating_write: |
19 | self.server.add_drive_raw('if=none,id=nbd-export,' + | 25 | |
20 | 'file=%s,' % test_img + | 26 | logout("finished data write\n"); |
21 | 'format=%s,' % imgfmt + | 27 | if (ret < 0) { |
22 | - 'cache=%s' % cachemode + | 28 | + g_free(block); |
23 | + 'cache=%s,' % cachemode + | 29 | return ret; |
24 | 'aio=%s' % aiomode) | 30 | } |
25 | self.server.launch() | ||
26 | 31 | ||
27 | -- | 32 | -- |
28 | 2.24.1 | 33 | 2.30.2 |
29 | 34 | ||
30 | diff view generated by jsdifflib |
1 | From: David Edmondson <david.edmondson@oracle.com> | 1 | From: David Edmondson <david.edmondson@oracle.com> |
---|---|---|---|
2 | 2 | ||
3 | In many cases the target of a convert operation is a newly provisioned | 3 | Given that the block size is read from the header of the VDI file, a |
4 | target that the user knows is blank (reads as zero). In this situation | 4 | wide variety of sizes might be seen. Rather than re-using a block |
5 | there is no requirement for qemu-img to wastefully zero out the entire | 5 | sized memory region when writing the VDI header, allocate an |
6 | device. | 6 | appropriately sized buffer. |
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 | 7 | ||
11 | Signed-off-by: David Edmondson <david.edmondson@oracle.com> | 8 | Signed-off-by: David Edmondson <david.edmondson@oracle.com> |
12 | Message-Id: <20200205110248.2009589-2-david.edmondson@oracle.com> | 9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
13 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | 10 | Acked-by: Max Reitz <mreitz@redhat.com> |
14 | Reviewed-by: Eric Blake <eblake@redhat.com> | 11 | Message-id: 20210325112941.365238-3-pbonzini@redhat.com |
15 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 12 | Message-Id: <20210309144015.557477-3-david.edmondson@oracle.com> |
13 | Acked-by: Max Reitz <mreitz@redhat.com> | ||
14 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
15 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
16 | --- | 16 | --- |
17 | docs/interop/qemu-img.rst | 9 ++++++++- | 17 | block/vdi.c | 10 ++++++---- |
18 | qemu-img-cmds.hx | 4 ++-- | 18 | 1 file changed, 6 insertions(+), 4 deletions(-) |
19 | qemu-img.c | 26 +++++++++++++++++++++++--- | ||
20 | 3 files changed, 33 insertions(+), 6 deletions(-) | ||
21 | 19 | ||
22 | diff --git a/docs/interop/qemu-img.rst b/docs/interop/qemu-img.rst | 20 | diff --git a/block/vdi.c b/block/vdi.c |
23 | index XXXXXXX..XXXXXXX 100644 | 21 | index XXXXXXX..XXXXXXX 100644 |
24 | --- a/docs/interop/qemu-img.rst | 22 | --- a/block/vdi.c |
25 | +++ b/docs/interop/qemu-img.rst | 23 | +++ b/block/vdi.c |
26 | @@ -XXX,XX +XXX,XX @@ Parameters to convert subcommand: | 24 | @@ -XXX,XX +XXX,XX @@ nonallocating_write: |
27 | will still be printed. Areas that cannot be read from the source will be | 25 | |
28 | treated as containing only zeroes. | 26 | if (block) { |
29 | 27 | /* One or more new blocks were allocated. */ | |
30 | +.. option:: --target-is-zero | 28 | - VdiHeader *header = (VdiHeader *) block; |
29 | + VdiHeader *header; | ||
30 | uint8_t *base; | ||
31 | uint64_t offset; | ||
32 | uint32_t n_sectors; | ||
33 | |||
34 | + g_free(block); | ||
35 | + header = g_malloc(sizeof(*header)); | ||
31 | + | 36 | + |
32 | + Assume that reading the destination image will always return | 37 | logout("now writing modified header\n"); |
33 | + zeros. This parameter is mutually exclusive with a destination image | 38 | assert(VDI_IS_ALLOCATED(bmap_first)); |
34 | + that has a backing file. It is required to also use the ``-n`` | 39 | *header = s->header; |
35 | + parameter to skip image creation. | 40 | vdi_header_to_le(header); |
36 | + | 41 | - ret = bdrv_pwrite(bs->file, 0, block, sizeof(VdiHeader)); |
37 | Parameters to dd subcommand: | 42 | - g_free(block); |
38 | 43 | - block = NULL; | |
39 | .. program:: qemu-img-dd | 44 | + ret = bdrv_pwrite(bs->file, 0, header, sizeof(*header)); |
40 | @@ -XXX,XX +XXX,XX @@ Command description: | 45 | + g_free(header); |
41 | 4 | 46 | |
42 | Error on reading data | 47 | if (ret < 0) { |
43 | 48 | return ret; | |
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 | -- | 49 | -- |
139 | 2.24.1 | 50 | 2.30.2 |
140 | 51 | ||
141 | diff view generated by jsdifflib |
1 | Add a test that all fields in "qemu-img snapshot -l"s output are | 1 | From: David Edmondson <david.edmondson@oracle.com> |
---|---|---|---|
2 | separated by spaces. | ||
3 | 2 | ||
4 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 3 | When taking the slow path for mutex acquisition, set the coroutine |
5 | Message-Id: <20200117105859.241818-3-mreitz@redhat.com> | 4 | value in the CoWaitRecord in push_waiter(), rather than both there and |
6 | Reviewed-by: Eric Blake <eblake@redhat.com> | 5 | in the caller. |
7 | [mreitz: Renamed test from 284 to 286] | 6 | |
8 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 7 | Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> |
8 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
9 | Signed-off-by: David Edmondson <david.edmondson@oracle.com> | ||
10 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
11 | Message-id: 20210325112941.365238-4-pbonzini@redhat.com | ||
12 | Message-Id: <20210309144015.557477-4-david.edmondson@oracle.com> | ||
13 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
14 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
9 | --- | 15 | --- |
10 | tests/qemu-iotests/286 | 76 ++++++++++++++++++++++++++++++++++++++ | 16 | util/qemu-coroutine-lock.c | 1 - |
11 | tests/qemu-iotests/286.out | 8 ++++ | 17 | 1 file changed, 1 deletion(-) |
12 | tests/qemu-iotests/group | 1 + | ||
13 | 3 files changed, 85 insertions(+) | ||
14 | create mode 100755 tests/qemu-iotests/286 | ||
15 | create mode 100644 tests/qemu-iotests/286.out | ||
16 | 18 | ||
17 | diff --git a/tests/qemu-iotests/286 b/tests/qemu-iotests/286 | 19 | diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c |
18 | new file mode 100755 | ||
19 | index XXXXXXX..XXXXXXX | ||
20 | --- /dev/null | ||
21 | +++ b/tests/qemu-iotests/286 | ||
22 | @@ -XXX,XX +XXX,XX @@ | ||
23 | +#!/usr/bin/env bash | ||
24 | +# | ||
25 | +# Test qemu-img snapshot -l | ||
26 | +# | ||
27 | +# Copyright (C) 2019 Red Hat, Inc. | ||
28 | +# | ||
29 | +# This program is free software; you can redistribute it and/or modify | ||
30 | +# it under the terms of the GNU General Public License as published by | ||
31 | +# the Free Software Foundation; either version 2 of the License, or | ||
32 | +# (at your option) any later version. | ||
33 | +# | ||
34 | +# This program is distributed in the hope that it will be useful, | ||
35 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
36 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
37 | +# GNU General Public License for more details. | ||
38 | +# | ||
39 | +# You should have received a copy of the GNU General Public License | ||
40 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
41 | +# | ||
42 | + | ||
43 | +seq=$(basename "$0") | ||
44 | +echo "QA output created by $seq" | ||
45 | + | ||
46 | +status=1 # failure is the default! | ||
47 | + | ||
48 | +_cleanup() | ||
49 | +{ | ||
50 | + _cleanup_test_img | ||
51 | +} | ||
52 | +trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
53 | + | ||
54 | +# get standard environment, filters and checks | ||
55 | +. ./common.rc | ||
56 | +. ./common.filter | ||
57 | +. ./common.qemu | ||
58 | + | ||
59 | +_supported_fmt qcow2 | ||
60 | +_supported_proto file | ||
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 @@ | ||
105 | +QA output created by 286 | ||
106 | +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 | ||
107 | +QEMU X.Y.Z monitor - type 'help' for more information | ||
108 | +(qemu) savevm abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz | ||
109 | +(qemu) quit | ||
110 | +Output structure: | ||
111 | +(snapshot ID) (snapshot name) (VM state size value) (VM state size unit) (snapshot date) (snapshot time) (VM clock) | ||
112 | +*** done | ||
113 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
114 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
115 | --- a/tests/qemu-iotests/group | 21 | --- a/util/qemu-coroutine-lock.c |
116 | +++ b/tests/qemu-iotests/group | 22 | +++ b/util/qemu-coroutine-lock.c |
117 | @@ -XXX,XX +XXX,XX @@ | 23 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn qemu_co_mutex_lock_slowpath(AioContext *ctx, |
118 | 281 rw quick | 24 | unsigned old_handoff; |
119 | 283 auto quick | 25 | |
120 | 284 rw | 26 | trace_qemu_co_mutex_lock_entry(mutex, self); |
121 | +286 rw quick | 27 | - w.co = self; |
28 | push_waiter(mutex, &w); | ||
29 | |||
30 | /* This is the "Responsibility Hand-Off" protocol; a lock() picks from | ||
122 | -- | 31 | -- |
123 | 2.24.1 | 32 | 2.30.2 |
124 | 33 | ||
125 | diff view generated by jsdifflib |
1 | If a protocol driver does not support image creation, we can see whether | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | maybe the file exists already. If so, just truncating it will be | 2 | |
3 | sufficient. | 3 | An invariant of the current rwlock is that if multiple coroutines hold a |
4 | 4 | reader lock, all must be runnable. The unlock implementation relies on | |
5 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 5 | this, choosing to wake a single coroutine when the final read lock |
6 | Message-Id: <20200122164532.178040-3-mreitz@redhat.com> | 6 | holder exits the critical section, assuming that it will wake a |
7 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 7 | coroutine attempting to acquire a write lock. |
8 | |||
9 | The downgrade implementation violates this assumption by creating a | ||
10 | read lock owning coroutine that is exclusively runnable - any other | ||
11 | coroutines that are waiting to acquire a read lock are *not* made | ||
12 | runnable when the write lock holder converts its ownership to read | ||
13 | only. | ||
14 | |||
15 | More in general, the old implementation had lots of other fairness bugs. | ||
16 | The root cause of the bugs was that CoQueue would wake up readers even | ||
17 | if there were pending writers, and would wake up writers even if there | ||
18 | were readers. In that case, the coroutine would go back to sleep *at | ||
19 | the end* of the CoQueue, losing its place at the head of the line. | ||
20 | |||
21 | To fix this, keep the queue of waiters explicitly in the CoRwlock | ||
22 | instead of using CoQueue, and store for each whether it is a | ||
23 | potential reader or a writer. This way, downgrade can look at the | ||
24 | first queued coroutines and wake it only if it is a reader, causing | ||
25 | all other readers in line to be released in turn. | ||
26 | |||
27 | Reported-by: David Edmondson <david.edmondson@oracle.com> | ||
28 | Reviewed-by: David Edmondson <david.edmondson@oracle.com> | ||
29 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
30 | Message-id: 20210325112941.365238-5-pbonzini@redhat.com | ||
31 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
8 | --- | 32 | --- |
9 | block.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++----- | 33 | include/qemu/coroutine.h | 17 ++-- |
10 | 1 file changed, 147 insertions(+), 12 deletions(-) | 34 | util/qemu-coroutine-lock.c | 164 +++++++++++++++++++++++-------------- |
11 | 35 | 2 files changed, 114 insertions(+), 67 deletions(-) | |
12 | diff --git a/block.c b/block.c | 36 | |
37 | diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h | ||
13 | index XXXXXXX..XXXXXXX 100644 | 38 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/block.c | 39 | --- a/include/qemu/coroutine.h |
15 | +++ b/block.c | 40 | +++ b/include/qemu/coroutine.h |
16 | @@ -XXX,XX +XXX,XX @@ out: | 41 | @@ -XXX,XX +XXX,XX @@ bool qemu_co_enter_next_impl(CoQueue *queue, QemuLockable *lock); |
17 | return ret; | 42 | bool qemu_co_queue_empty(CoQueue *queue); |
18 | } | 43 | |
19 | 44 | ||
20 | -int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp) | 45 | +typedef struct CoRwTicket CoRwTicket; |
21 | +/** | 46 | typedef struct CoRwlock { |
22 | + * Helper function for bdrv_create_file_fallback(): Resize @blk to at | 47 | - int pending_writer; |
23 | + * least the given @minimum_size. | 48 | - int reader; |
24 | + * | 49 | CoMutex mutex; |
25 | + * On success, return @blk's actual length. | 50 | - CoQueue queue; |
26 | + * Otherwise, return -errno. | 51 | + |
27 | + */ | 52 | + /* Number of readers, or -1 if owned for writing. */ |
28 | +static int64_t create_file_fallback_truncate(BlockBackend *blk, | 53 | + int owners; |
29 | + int64_t minimum_size, Error **errp) | 54 | + |
30 | { | 55 | + /* Waiting coroutines. */ |
31 | - BlockDriver *drv; | 56 | + QSIMPLEQ_HEAD(, CoRwTicket) tickets; |
32 | + Error *local_err = NULL; | 57 | } CoRwlock; |
33 | + int64_t size; | 58 | |
34 | + int ret; | 59 | /** |
35 | + | 60 | @@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_rdlock(CoRwlock *lock); |
36 | + ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err); | 61 | /** |
37 | + if (ret < 0 && ret != -ENOTSUP) { | 62 | * Write Locks the CoRwlock from a reader. This is a bit more efficient than |
38 | + error_propagate(errp, local_err); | 63 | * @qemu_co_rwlock_unlock followed by a separate @qemu_co_rwlock_wrlock. |
39 | + return ret; | 64 | - * However, if the lock cannot be upgraded immediately, control is transferred |
40 | + } | 65 | - * to the caller of the current coroutine. Also, @qemu_co_rwlock_upgrade |
41 | + | 66 | - * only overrides CoRwlock fairness if there are no concurrent readers, so |
42 | + size = blk_getlength(blk); | 67 | - * another writer might run while @qemu_co_rwlock_upgrade blocks. |
43 | + if (size < 0) { | 68 | + * Note that if the lock cannot be upgraded immediately, control is transferred |
44 | + error_free(local_err); | 69 | + * to the caller of the current coroutine; another writer might run while |
45 | + error_setg_errno(errp, -size, | 70 | + * @qemu_co_rwlock_upgrade blocks. |
46 | + "Failed to inquire the new image file's length"); | 71 | */ |
47 | + return size; | 72 | void qemu_co_rwlock_upgrade(CoRwlock *lock); |
48 | + } | 73 | |
49 | + | 74 | diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c |
50 | + if (size < minimum_size) { | 75 | index XXXXXXX..XXXXXXX 100644 |
51 | + /* Need to grow the image, but we failed to do that */ | 76 | --- a/util/qemu-coroutine-lock.c |
52 | + error_propagate(errp, local_err); | 77 | +++ b/util/qemu-coroutine-lock.c |
53 | + return -ENOTSUP; | 78 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex) |
54 | + } | 79 | trace_qemu_co_mutex_unlock_return(mutex, self); |
55 | + | 80 | } |
56 | + error_free(local_err); | 81 | |
57 | + local_err = NULL; | 82 | +struct CoRwTicket { |
58 | + | 83 | + bool read; |
59 | + return size; | 84 | + Coroutine *co; |
85 | + QSIMPLEQ_ENTRY(CoRwTicket) next; | ||
86 | +}; | ||
87 | + | ||
88 | void qemu_co_rwlock_init(CoRwlock *lock) | ||
89 | { | ||
90 | - memset(lock, 0, sizeof(*lock)); | ||
91 | - qemu_co_queue_init(&lock->queue); | ||
92 | qemu_co_mutex_init(&lock->mutex); | ||
93 | + lock->owners = 0; | ||
94 | + QSIMPLEQ_INIT(&lock->tickets); | ||
60 | +} | 95 | +} |
61 | + | 96 | + |
62 | +/** | 97 | +/* Releases the internal CoMutex. */ |
63 | + * Helper function for bdrv_create_file_fallback(): Zero the first | 98 | +static void qemu_co_rwlock_maybe_wake_one(CoRwlock *lock) |
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 | +{ | 99 | +{ |
70 | + int64_t bytes_to_clear; | 100 | + CoRwTicket *tkt = QSIMPLEQ_FIRST(&lock->tickets); |
71 | + int ret; | 101 | + Coroutine *co = NULL; |
72 | + | 102 | + |
73 | + bytes_to_clear = MIN(current_size, BDRV_SECTOR_SIZE); | 103 | + /* |
74 | + if (bytes_to_clear) { | 104 | + * Setting lock->owners here prevents rdlock and wrlock from |
75 | + ret = blk_pwrite_zeroes(blk, 0, bytes_to_clear, BDRV_REQ_MAY_UNMAP); | 105 | + * sneaking in between unlock and wake. |
76 | + if (ret < 0) { | 106 | + */ |
77 | + error_setg_errno(errp, -ret, | 107 | + |
78 | + "Failed to clear the new image's first sector"); | 108 | + if (tkt) { |
79 | + return ret; | 109 | + if (tkt->read) { |
110 | + if (lock->owners >= 0) { | ||
111 | + lock->owners++; | ||
112 | + co = tkt->co; | ||
113 | + } | ||
114 | + } else { | ||
115 | + if (lock->owners == 0) { | ||
116 | + lock->owners = -1; | ||
117 | + co = tkt->co; | ||
118 | + } | ||
80 | + } | 119 | + } |
81 | + } | 120 | + } |
82 | + | 121 | + |
83 | + return 0; | 122 | + if (co) { |
123 | + QSIMPLEQ_REMOVE_HEAD(&lock->tickets, next); | ||
124 | + qemu_co_mutex_unlock(&lock->mutex); | ||
125 | + aio_co_wake(co); | ||
126 | + } else { | ||
127 | + qemu_co_mutex_unlock(&lock->mutex); | ||
128 | + } | ||
129 | } | ||
130 | |||
131 | void qemu_co_rwlock_rdlock(CoRwlock *lock) | ||
132 | @@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_rdlock(CoRwlock *lock) | ||
133 | |||
134 | qemu_co_mutex_lock(&lock->mutex); | ||
135 | /* For fairness, wait if a writer is in line. */ | ||
136 | - while (lock->pending_writer) { | ||
137 | - qemu_co_queue_wait(&lock->queue, &lock->mutex); | ||
138 | - } | ||
139 | - lock->reader++; | ||
140 | - qemu_co_mutex_unlock(&lock->mutex); | ||
141 | - | ||
142 | - /* The rest of the read-side critical section is run without the mutex. */ | ||
143 | - self->locks_held++; | ||
144 | -} | ||
145 | - | ||
146 | -void qemu_co_rwlock_unlock(CoRwlock *lock) | ||
147 | -{ | ||
148 | - Coroutine *self = qemu_coroutine_self(); | ||
149 | - | ||
150 | - assert(qemu_in_coroutine()); | ||
151 | - if (!lock->reader) { | ||
152 | - /* The critical section started in qemu_co_rwlock_wrlock. */ | ||
153 | - qemu_co_queue_restart_all(&lock->queue); | ||
154 | + if (lock->owners == 0 || (lock->owners > 0 && QSIMPLEQ_EMPTY(&lock->tickets))) { | ||
155 | + lock->owners++; | ||
156 | + qemu_co_mutex_unlock(&lock->mutex); | ||
157 | } else { | ||
158 | - self->locks_held--; | ||
159 | + CoRwTicket my_ticket = { true, self }; | ||
160 | |||
161 | + QSIMPLEQ_INSERT_TAIL(&lock->tickets, &my_ticket, next); | ||
162 | + qemu_co_mutex_unlock(&lock->mutex); | ||
163 | + qemu_coroutine_yield(); | ||
164 | + assert(lock->owners >= 1); | ||
165 | + | ||
166 | + /* Possibly wake another reader, which will wake the next in line. */ | ||
167 | qemu_co_mutex_lock(&lock->mutex); | ||
168 | - lock->reader--; | ||
169 | - assert(lock->reader >= 0); | ||
170 | - /* Wakeup only one waiting writer */ | ||
171 | - if (!lock->reader) { | ||
172 | - qemu_co_queue_next(&lock->queue); | ||
173 | - } | ||
174 | + qemu_co_rwlock_maybe_wake_one(lock); | ||
175 | } | ||
176 | - qemu_co_mutex_unlock(&lock->mutex); | ||
177 | + | ||
178 | + self->locks_held++; | ||
84 | +} | 179 | +} |
85 | + | 180 | + |
86 | +static int bdrv_create_file_fallback(const char *filename, BlockDriver *drv, | 181 | +void qemu_co_rwlock_unlock(CoRwlock *lock) |
87 | + QemuOpts *opts, Error **errp) | ||
88 | +{ | 182 | +{ |
89 | + BlockBackend *blk; | 183 | + Coroutine *self = qemu_coroutine_self(); |
90 | + QDict *options = qdict_new(); | 184 | + |
91 | + int64_t size = 0; | 185 | + assert(qemu_in_coroutine()); |
92 | + char *buf = NULL; | 186 | + self->locks_held--; |
93 | + PreallocMode prealloc; | 187 | + |
94 | Error *local_err = NULL; | 188 | + qemu_co_mutex_lock(&lock->mutex); |
95 | int ret; | 189 | + if (lock->owners > 0) { |
96 | 190 | + lock->owners--; | |
97 | + size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); | 191 | + } else { |
98 | + buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); | 192 | + assert(lock->owners == -1); |
99 | + prealloc = qapi_enum_parse(&PreallocMode_lookup, buf, | 193 | + lock->owners = 0; |
100 | + PREALLOC_MODE_OFF, &local_err); | ||
101 | + g_free(buf); | ||
102 | + if (local_err) { | ||
103 | + error_propagate(errp, local_err); | ||
104 | + return -EINVAL; | ||
105 | + } | 194 | + } |
106 | + | 195 | + |
107 | + if (prealloc != PREALLOC_MODE_OFF) { | 196 | + qemu_co_rwlock_maybe_wake_one(lock); |
108 | + error_setg(errp, "Unsupported preallocation mode '%s'", | 197 | } |
109 | + PreallocMode_str(prealloc)); | 198 | |
110 | + return -ENOTSUP; | 199 | void qemu_co_rwlock_downgrade(CoRwlock *lock) |
111 | + } | 200 | { |
112 | + | 201 | - Coroutine *self = qemu_coroutine_self(); |
113 | + qdict_put_str(options, "driver", drv->format_name); | 202 | + qemu_co_mutex_lock(&lock->mutex); |
114 | + | 203 | + assert(lock->owners == -1); |
115 | + blk = blk_new_open(filename, NULL, options, | 204 | + lock->owners = 1; |
116 | + BDRV_O_RDWR | BDRV_O_RESIZE, errp); | 205 | |
117 | + if (!blk) { | 206 | - /* lock->mutex critical section started in qemu_co_rwlock_wrlock or |
118 | + error_prepend(errp, "Protocol driver '%s' does not support image " | 207 | - * qemu_co_rwlock_upgrade. |
119 | + "creation, and opening the image failed: ", | 208 | - */ |
120 | + drv->format_name); | 209 | - assert(lock->reader == 0); |
121 | + return -EINVAL; | 210 | - lock->reader++; |
122 | + } | 211 | - qemu_co_mutex_unlock(&lock->mutex); |
123 | + | 212 | - |
124 | + size = create_file_fallback_truncate(blk, size, errp); | 213 | - /* The rest of the read-side critical section is run without the mutex. */ |
125 | + if (size < 0) { | 214 | - self->locks_held++; |
126 | + ret = size; | 215 | + /* Possibly wake another reader, which will wake the next in line. */ |
127 | + goto out; | 216 | + qemu_co_rwlock_maybe_wake_one(lock); |
128 | + } | 217 | } |
129 | + | 218 | |
130 | + ret = create_file_fallback_zero_first_sector(blk, size, errp); | 219 | void qemu_co_rwlock_wrlock(CoRwlock *lock) |
131 | + if (ret < 0) { | 220 | { |
132 | + goto out; | 221 | + Coroutine *self = qemu_coroutine_self(); |
133 | + } | 222 | + |
134 | + | 223 | qemu_co_mutex_lock(&lock->mutex); |
135 | + ret = 0; | 224 | - lock->pending_writer++; |
136 | +out: | 225 | - while (lock->reader) { |
137 | + blk_unref(blk); | 226 | - qemu_co_queue_wait(&lock->queue, &lock->mutex); |
138 | + return ret; | 227 | + if (lock->owners == 0) { |
139 | +} | 228 | + lock->owners = -1; |
140 | + | 229 | + qemu_co_mutex_unlock(&lock->mutex); |
141 | +int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp) | 230 | + } else { |
142 | +{ | 231 | + CoRwTicket my_ticket = { false, qemu_coroutine_self() }; |
143 | + BlockDriver *drv; | 232 | + |
144 | + | 233 | + QSIMPLEQ_INSERT_TAIL(&lock->tickets, &my_ticket, next); |
145 | drv = bdrv_find_protocol(filename, true, errp); | 234 | + qemu_co_mutex_unlock(&lock->mutex); |
146 | if (drv == NULL) { | 235 | + qemu_coroutine_yield(); |
147 | return -ENOENT; | 236 | + assert(lock->owners == -1); |
148 | } | 237 | } |
149 | 238 | - lock->pending_writer--; | |
150 | - ret = bdrv_create(drv, filename, opts, &local_err); | 239 | |
151 | - error_propagate(errp, local_err); | 240 | - /* The rest of the write-side critical section is run with |
152 | - return ret; | 241 | - * the mutex taken, so that lock->reader remains zero. |
153 | + if (drv->bdrv_co_create_opts) { | 242 | - * There is no need to update self->locks_held. |
154 | + return bdrv_create(drv, filename, opts, errp); | 243 | - */ |
155 | + } else { | 244 | + self->locks_held++; |
156 | + return bdrv_create_file_fallback(filename, drv, opts, errp); | 245 | } |
157 | + } | 246 | |
158 | } | 247 | void qemu_co_rwlock_upgrade(CoRwlock *lock) |
159 | 248 | { | |
160 | /** | 249 | - Coroutine *self = qemu_coroutine_self(); |
161 | @@ -XXX,XX +XXX,XX @@ QemuOptsList bdrv_runtime_opts = { | 250 | - |
162 | }, | 251 | qemu_co_mutex_lock(&lock->mutex); |
163 | }; | 252 | - assert(lock->reader > 0); |
164 | 253 | - lock->reader--; | |
165 | +static QemuOptsList fallback_create_opts = { | 254 | - lock->pending_writer++; |
166 | + .name = "fallback-create-opts", | 255 | - while (lock->reader) { |
167 | + .head = QTAILQ_HEAD_INITIALIZER(fallback_create_opts.head), | 256 | - qemu_co_queue_wait(&lock->queue, &lock->mutex); |
168 | + .desc = { | 257 | + assert(lock->owners > 0); |
169 | + { | 258 | + /* For fairness, wait if a writer is in line. */ |
170 | + .name = BLOCK_OPT_SIZE, | 259 | + if (lock->owners == 1 && QSIMPLEQ_EMPTY(&lock->tickets)) { |
171 | + .type = QEMU_OPT_SIZE, | 260 | + lock->owners = -1; |
172 | + .help = "Virtual disk size" | 261 | + qemu_co_mutex_unlock(&lock->mutex); |
173 | + }, | 262 | + } else { |
174 | + { | 263 | + CoRwTicket my_ticket = { false, qemu_coroutine_self() }; |
175 | + .name = BLOCK_OPT_PREALLOC, | 264 | + |
176 | + .type = QEMU_OPT_STRING, | 265 | + lock->owners--; |
177 | + .help = "Preallocation mode (allowed values: off)" | 266 | + QSIMPLEQ_INSERT_TAIL(&lock->tickets, &my_ticket, next); |
178 | + }, | 267 | + qemu_co_rwlock_maybe_wake_one(lock); |
179 | + { /* end of list */ } | 268 | + qemu_coroutine_yield(); |
180 | + } | 269 | + assert(lock->owners == -1); |
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 | } | 270 | } |
189 | 271 | - lock->pending_writer--; | |
190 | - if (!proto_drv->create_opts) { | 272 | - |
191 | - error_setg(errp, "Protocol driver '%s' does not support image creation", | 273 | - /* The rest of the write-side critical section is run with |
192 | - proto_drv->format_name); | 274 | - * the mutex taken, similar to qemu_co_rwlock_wrlock. Do |
193 | - return; | 275 | - * not account for the lock twice in self->locks_held. |
194 | - } | 276 | - */ |
195 | - | 277 | - self->locks_held--; |
196 | /* Create parameter list */ | 278 | } |
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 | |||
207 | -- | 279 | -- |
208 | 2.24.1 | 280 | 2.30.2 |
209 | 281 | ||
210 | diff view generated by jsdifflib |
1 | The generic fallback implementation effectively does the same. | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> | 3 | Test that rwlock upgrade is fair, and that readers go back to sleep if |
4 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 4 | a writer is in line. |
5 | Message-Id: <20200122164532.178040-5-mreitz@redhat.com> | 5 | |
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 6 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
7 | Message-id: 20210325112941.365238-6-pbonzini@redhat.com | ||
8 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
7 | --- | 9 | --- |
8 | block/iscsi.c | 56 --------------------------------------------------- | 10 | tests/unit/test-coroutine.c | 62 +++++++++++++++++++++++++++++++++++++ |
9 | 1 file changed, 56 deletions(-) | 11 | 1 file changed, 62 insertions(+) |
10 | 12 | ||
11 | diff --git a/block/iscsi.c b/block/iscsi.c | 13 | diff --git a/tests/unit/test-coroutine.c b/tests/unit/test-coroutine.c |
12 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/block/iscsi.c | 15 | --- a/tests/unit/test-coroutine.c |
14 | +++ b/block/iscsi.c | 16 | +++ b/tests/unit/test-coroutine.c |
15 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset, | 17 | @@ -XXX,XX +XXX,XX @@ static void test_co_mutex_lockable(void) |
16 | return 0; | 18 | g_assert(QEMU_MAKE_LOCKABLE(null_pointer) == NULL); |
17 | } | 19 | } |
18 | 20 | ||
19 | -static int coroutine_fn iscsi_co_create_opts(const char *filename, QemuOpts *opts, | 21 | +static CoRwlock rwlock; |
20 | - Error **errp) | 22 | + |
21 | -{ | 23 | +/* Test that readers are properly sent back to the queue when upgrading, |
22 | - int ret = 0; | 24 | + * even if they are the sole readers. The test scenario is as follows: |
23 | - int64_t total_size = 0; | 25 | + * |
24 | - BlockDriverState *bs; | 26 | + * |
25 | - IscsiLun *iscsilun = NULL; | 27 | + * | c1 | c2 | |
26 | - QDict *bs_options; | 28 | + * |--------------+------------+ |
27 | - Error *local_err = NULL; | 29 | + * | rdlock | | |
28 | - | 30 | + * | yield | | |
29 | - bs = bdrv_new(); | 31 | + * | | wrlock | |
30 | - | 32 | + * | | <queued> | |
31 | - /* Read out options */ | 33 | + * | upgrade | | |
32 | - total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), | 34 | + * | <queued> | <dequeued> | |
33 | - BDRV_SECTOR_SIZE); | 35 | + * | | unlock | |
34 | - bs->opaque = g_new0(struct IscsiLun, 1); | 36 | + * | <dequeued> | | |
35 | - iscsilun = bs->opaque; | 37 | + * | unlock | | |
36 | - | 38 | + */ |
37 | - bs_options = qdict_new(); | 39 | + |
38 | - iscsi_parse_filename(filename, bs_options, &local_err); | 40 | +static void coroutine_fn rwlock_yield_upgrade(void *opaque) |
39 | - if (local_err) { | 41 | +{ |
40 | - error_propagate(errp, local_err); | 42 | + qemu_co_rwlock_rdlock(&rwlock); |
41 | - ret = -EINVAL; | 43 | + qemu_coroutine_yield(); |
42 | - } else { | 44 | + |
43 | - ret = iscsi_open(bs, bs_options, 0, NULL); | 45 | + qemu_co_rwlock_upgrade(&rwlock); |
44 | - } | 46 | + qemu_co_rwlock_unlock(&rwlock); |
45 | - qobject_unref(bs_options); | 47 | + |
46 | - | 48 | + *(bool *)opaque = true; |
47 | - if (ret != 0) { | 49 | +} |
48 | - goto out; | 50 | + |
49 | - } | 51 | +static void coroutine_fn rwlock_wrlock_yield(void *opaque) |
50 | - iscsi_detach_aio_context(bs); | 52 | +{ |
51 | - if (iscsilun->type != TYPE_DISK) { | 53 | + qemu_co_rwlock_wrlock(&rwlock); |
52 | - ret = -ENODEV; | 54 | + qemu_coroutine_yield(); |
53 | - goto out; | 55 | + |
54 | - } | 56 | + qemu_co_rwlock_unlock(&rwlock); |
55 | - if (bs->total_sectors < total_size) { | 57 | + *(bool *)opaque = true; |
56 | - ret = -ENOSPC; | 58 | +} |
57 | - goto out; | 59 | + |
58 | - } | 60 | +static void test_co_rwlock_upgrade(void) |
59 | - | 61 | +{ |
60 | - ret = 0; | 62 | + bool c1_done = false; |
61 | -out: | 63 | + bool c2_done = false; |
62 | - if (iscsilun->iscsi != NULL) { | 64 | + Coroutine *c1, *c2; |
63 | - iscsi_destroy_context(iscsilun->iscsi); | 65 | + |
64 | - } | 66 | + qemu_co_rwlock_init(&rwlock); |
65 | - g_free(bs->opaque); | 67 | + c1 = qemu_coroutine_create(rwlock_yield_upgrade, &c1_done); |
66 | - bs->opaque = NULL; | 68 | + c2 = qemu_coroutine_create(rwlock_wrlock_yield, &c2_done); |
67 | - bdrv_unref(bs); | 69 | + |
68 | - return ret; | 70 | + qemu_coroutine_enter(c1); |
69 | -} | 71 | + qemu_coroutine_enter(c2); |
70 | - | 72 | + |
71 | static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) | 73 | + /* c1 now should go to sleep. */ |
72 | { | 74 | + qemu_coroutine_enter(c1); |
73 | IscsiLun *iscsilun = bs->opaque; | 75 | + g_assert(!c1_done); |
74 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iscsi = { | 76 | + |
75 | .bdrv_parse_filename = iscsi_parse_filename, | 77 | + qemu_coroutine_enter(c2); |
76 | .bdrv_file_open = iscsi_open, | 78 | + g_assert(c1_done); |
77 | .bdrv_close = iscsi_close, | 79 | + g_assert(c2_done); |
78 | - .bdrv_co_create_opts = iscsi_co_create_opts, | 80 | +} |
79 | - .create_opts = &iscsi_create_opts, | 81 | + |
80 | .bdrv_reopen_prepare = iscsi_reopen_prepare, | 82 | /* |
81 | .bdrv_reopen_commit = iscsi_reopen_commit, | 83 | * Check that creation, enter, and return work |
82 | .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache, | 84 | */ |
83 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iser = { | 85 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) |
84 | .bdrv_parse_filename = iscsi_parse_filename, | 86 | g_test_add_func("/basic/order", test_order); |
85 | .bdrv_file_open = iscsi_open, | 87 | g_test_add_func("/locking/co-mutex", test_co_mutex); |
86 | .bdrv_close = iscsi_close, | 88 | g_test_add_func("/locking/co-mutex/lockable", test_co_mutex_lockable); |
87 | - .bdrv_co_create_opts = iscsi_co_create_opts, | 89 | + g_test_add_func("/locking/co-rwlock/upgrade", test_co_rwlock_upgrade); |
88 | - .create_opts = &iscsi_create_opts, | 90 | if (g_test_perf()) { |
89 | .bdrv_reopen_prepare = iscsi_reopen_prepare, | 91 | g_test_add_func("/perf/lifecycle", perf_lifecycle); |
90 | .bdrv_reopen_commit = iscsi_reopen_commit, | 92 | g_test_add_func("/perf/nesting", perf_nesting); |
91 | .bdrv_co_invalidate_cache = iscsi_co_invalidate_cache, | ||
92 | -- | 93 | -- |
93 | 2.24.1 | 94 | 2.30.2 |
94 | 95 | ||
95 | diff view generated by jsdifflib |
1 | From: Peter Krempa <pkrempa@redhat.com> | 1 | From: David Edmondson <david.edmondson@oracle.com> |
---|---|---|---|
2 | 2 | ||
3 | When a management application manages node names there's no reason to | 3 | Test that downgrading an rwlock does not result in a failure to |
4 | recurse into backing images in the output of query-named-block-nodes. | 4 | schedule coroutines queued on the rwlock. |
5 | 5 | ||
6 | Add a parameter to the command which will return just the top level | 6 | The diagram associated with test_co_rwlock_downgrade() describes the |
7 | structs. | 7 | intended behaviour, but what was observed previously corresponds to: |
8 | 8 | ||
9 | Signed-off-by: Peter Krempa <pkrempa@redhat.com> | 9 | | c1 | c2 | c3 | c4 | |
10 | Message-Id: <4470f8c779abc404dcf65e375db195cd91a80651.1579509782.git.pkrempa@redhat.com> | 10 | |--------+------------+------------+----------| |
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | 11 | | rdlock | | | | |
12 | [mreitz: Fixed coding style] | 12 | | yield | | | | |
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 13 | | | wrlock | | | |
14 | | | <queued> | | | | ||
15 | | | | rdlock | | | ||
16 | | | | <queued> | | | ||
17 | | | | | wrlock | | ||
18 | | | | | <queued> | | ||
19 | | unlock | | | | | ||
20 | | yield | | | | | ||
21 | | | <dequeued> | | | | ||
22 | | | downgrade | | | | ||
23 | | | ... | | | | ||
24 | | | unlock | | | | ||
25 | | | | <dequeued> | | | ||
26 | | | | <queued> | | | ||
27 | |||
28 | This results in a failure... | ||
29 | |||
30 | ERROR:../tests/test-coroutine.c:369:test_co_rwlock_downgrade: assertion failed: (c3_done) | ||
31 | Bail out! ERROR:../tests/test-coroutine.c:369:test_co_rwlock_downgrade: assertion failed: (c3_done) | ||
32 | |||
33 | ...as a result of the c3 coroutine failing to run to completion. | ||
34 | |||
35 | Signed-off-by: David Edmondson <david.edmondson@oracle.com> | ||
36 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
37 | Message-id: 20210325112941.365238-7-pbonzini@redhat.com | ||
38 | Message-Id: <20210309144015.557477-5-david.edmondson@oracle.com> | ||
39 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
40 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | --- | 41 | --- |
15 | block.c | 5 +++-- | 42 | tests/unit/test-coroutine.c | 99 +++++++++++++++++++++++++++++++++++++ |
16 | block/qapi.c | 11 +++++++++-- | 43 | 1 file changed, 99 insertions(+) |
17 | blockdev.c | 8 ++++++-- | ||
18 | include/block/block.h | 2 +- | ||
19 | include/block/qapi.h | 4 +++- | ||
20 | monitor/hmp-cmds.c | 2 +- | ||
21 | qapi/block-core.json | 7 ++++++- | ||
22 | 7 files changed, 29 insertions(+), 10 deletions(-) | ||
23 | 44 | ||
24 | diff --git a/block.c b/block.c | 45 | diff --git a/tests/unit/test-coroutine.c b/tests/unit/test-coroutine.c |
25 | index XXXXXXX..XXXXXXX 100644 | 46 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/block.c | 47 | --- a/tests/unit/test-coroutine.c |
27 | +++ b/block.c | 48 | +++ b/tests/unit/test-coroutine.c |
28 | @@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_node(const char *node_name) | 49 | @@ -XXX,XX +XXX,XX @@ static void test_co_rwlock_upgrade(void) |
50 | g_assert(c2_done); | ||
29 | } | 51 | } |
30 | 52 | ||
31 | /* Put this QMP function here so it can access the static graph_bdrv_states. */ | 53 | +static void coroutine_fn rwlock_rdlock_yield(void *opaque) |
32 | -BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp) | 54 | +{ |
33 | +BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, | 55 | + qemu_co_rwlock_rdlock(&rwlock); |
34 | + Error **errp) | 56 | + qemu_coroutine_yield(); |
35 | { | ||
36 | BlockDeviceInfoList *list, *entry; | ||
37 | BlockDriverState *bs; | ||
38 | |||
39 | list = NULL; | ||
40 | QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) { | ||
41 | - BlockDeviceInfo *info = bdrv_block_device_info(NULL, bs, errp); | ||
42 | + BlockDeviceInfo *info = bdrv_block_device_info(NULL, bs, flat, errp); | ||
43 | if (!info) { | ||
44 | qapi_free_BlockDeviceInfoList(list); | ||
45 | return NULL; | ||
46 | diff --git a/block/qapi.c b/block/qapi.c | ||
47 | index XXXXXXX..XXXXXXX 100644 | ||
48 | --- a/block/qapi.c | ||
49 | +++ b/block/qapi.c | ||
50 | @@ -XXX,XX +XXX,XX @@ | ||
51 | #include "qemu/cutils.h" | ||
52 | |||
53 | BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, | ||
54 | - BlockDriverState *bs, Error **errp) | ||
55 | + BlockDriverState *bs, | ||
56 | + bool flat, | ||
57 | + Error **errp) | ||
58 | { | ||
59 | ImageInfo **p_image_info; | ||
60 | BlockDriverState *bs0; | ||
61 | @@ -XXX,XX +XXX,XX @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, | ||
62 | return NULL; | ||
63 | } | ||
64 | |||
65 | + /* stop gathering data for flat output */ | ||
66 | + if (flat) { | ||
67 | + break; | ||
68 | + } | ||
69 | + | 57 | + |
70 | if (bs0->drv && bs0->backing) { | 58 | + qemu_co_rwlock_unlock(&rwlock); |
71 | info->backing_file_depth++; | 59 | + qemu_coroutine_yield(); |
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 | + | 60 | + |
98 | + return bdrv_named_nodes_list(return_flat, errp); | 61 | + *(bool *)opaque = true; |
99 | } | 62 | +} |
100 | 63 | + | |
101 | XDbgBlockGraph *qmp_x_debug_query_block_graph(Error **errp) | 64 | +static void coroutine_fn rwlock_wrlock_downgrade(void *opaque) |
102 | diff --git a/include/block/block.h b/include/block/block.h | 65 | +{ |
103 | index XXXXXXX..XXXXXXX 100644 | 66 | + qemu_co_rwlock_wrlock(&rwlock); |
104 | --- a/include/block/block.h | 67 | + |
105 | +++ b/include/block/block.h | 68 | + qemu_co_rwlock_downgrade(&rwlock); |
106 | @@ -XXX,XX +XXX,XX @@ void bdrv_lock_medium(BlockDriverState *bs, bool locked); | 69 | + qemu_co_rwlock_unlock(&rwlock); |
107 | void bdrv_eject(BlockDriverState *bs, bool eject_flag); | 70 | + *(bool *)opaque = true; |
108 | const char *bdrv_get_format_name(BlockDriverState *bs); | 71 | +} |
109 | BlockDriverState *bdrv_find_node(const char *node_name); | 72 | + |
110 | -BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp); | 73 | +static void coroutine_fn rwlock_rdlock(void *opaque) |
111 | +BlockDeviceInfoList *bdrv_named_nodes_list(bool flat, Error **errp); | 74 | +{ |
112 | XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp); | 75 | + qemu_co_rwlock_rdlock(&rwlock); |
113 | BlockDriverState *bdrv_lookup_bs(const char *device, | 76 | + |
114 | const char *node_name, | 77 | + qemu_co_rwlock_unlock(&rwlock); |
115 | diff --git a/include/block/qapi.h b/include/block/qapi.h | 78 | + *(bool *)opaque = true; |
116 | index XXXXXXX..XXXXXXX 100644 | 79 | +} |
117 | --- a/include/block/qapi.h | 80 | + |
118 | +++ b/include/block/qapi.h | 81 | +static void coroutine_fn rwlock_wrlock(void *opaque) |
119 | @@ -XXX,XX +XXX,XX @@ | 82 | +{ |
120 | #include "block/snapshot.h" | 83 | + qemu_co_rwlock_wrlock(&rwlock); |
121 | 84 | + | |
122 | BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, | 85 | + qemu_co_rwlock_unlock(&rwlock); |
123 | - BlockDriverState *bs, Error **errp); | 86 | + *(bool *)opaque = true; |
124 | + BlockDriverState *bs, | 87 | +} |
125 | + bool flat, | 88 | + |
126 | + Error **errp); | 89 | +/* |
127 | int bdrv_query_snapshot_info_list(BlockDriverState *bs, | 90 | + * Check that downgrading a reader-writer lock does not cause a hang. |
128 | SnapshotInfoList **p_list, | 91 | + * |
129 | Error **errp); | 92 | + * Four coroutines are used to produce a situation where there are |
130 | diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c | 93 | + * both reader and writer hopefuls waiting to acquire an rwlock that |
131 | index XXXXXXX..XXXXXXX 100644 | 94 | + * is held by a reader. |
132 | --- a/monitor/hmp-cmds.c | 95 | + * |
133 | +++ b/monitor/hmp-cmds.c | 96 | + * The correct sequence of operations we aim to provoke can be |
134 | @@ -XXX,XX +XXX,XX @@ void hmp_info_block(Monitor *mon, const QDict *qdict) | 97 | + * represented as: |
135 | } | 98 | + * |
136 | 99 | + * | c1 | c2 | c3 | c4 | | |
137 | /* Print node information */ | 100 | + * |--------+------------+------------+------------| |
138 | - blockdev_list = qmp_query_named_block_nodes(NULL); | 101 | + * | rdlock | | | | |
139 | + blockdev_list = qmp_query_named_block_nodes(false, false, NULL); | 102 | + * | yield | | | | |
140 | for (blockdev = blockdev_list; blockdev; blockdev = blockdev->next) { | 103 | + * | | wrlock | | | |
141 | assert(blockdev->value->has_node_name); | 104 | + * | | <queued> | | | |
142 | if (device && strcmp(device, blockdev->value->node_name)) { | 105 | + * | | | rdlock | | |
143 | diff --git a/qapi/block-core.json b/qapi/block-core.json | 106 | + * | | | <queued> | | |
144 | index XXXXXXX..XXXXXXX 100644 | 107 | + * | | | | wrlock | |
145 | --- a/qapi/block-core.json | 108 | + * | | | | <queued> | |
146 | +++ b/qapi/block-core.json | 109 | + * | unlock | | | | |
147 | @@ -XXX,XX +XXX,XX @@ | 110 | + * | yield | | | | |
148 | # | 111 | + * | | <dequeued> | | | |
149 | # Get the named block driver list | 112 | + * | | downgrade | | | |
150 | # | 113 | + * | | | <dequeued> | | |
151 | +# @flat: Omit the nested data about backing image ("backing-image" key) if true. | 114 | + * | | | unlock | | |
152 | +# Default is false (Since 5.0) | 115 | + * | | ... | | | |
153 | +# | 116 | + * | | unlock | | | |
154 | # Returns: the list of BlockDeviceInfo | 117 | + * | | | | <dequeued> | |
155 | # | 118 | + * | | | | unlock | |
156 | # Since: 2.0 | 119 | + */ |
157 | @@ -XXX,XX +XXX,XX @@ | 120 | +static void test_co_rwlock_downgrade(void) |
158 | # } } ] } | 121 | +{ |
159 | # | 122 | + bool c1_done = false; |
160 | ## | 123 | + bool c2_done = false; |
161 | -{ 'command': 'query-named-block-nodes', 'returns': [ 'BlockDeviceInfo' ] } | 124 | + bool c3_done = false; |
162 | +{ 'command': 'query-named-block-nodes', | 125 | + bool c4_done = false; |
163 | + 'returns': [ 'BlockDeviceInfo' ], | 126 | + Coroutine *c1, *c2, *c3, *c4; |
164 | + 'data': { '*flat': 'bool' } } | 127 | + |
165 | 128 | + qemu_co_rwlock_init(&rwlock); | |
166 | ## | 129 | + |
167 | # @XDbgBlockGraphNodeType: | 130 | + c1 = qemu_coroutine_create(rwlock_rdlock_yield, &c1_done); |
131 | + c2 = qemu_coroutine_create(rwlock_wrlock_downgrade, &c2_done); | ||
132 | + c3 = qemu_coroutine_create(rwlock_rdlock, &c3_done); | ||
133 | + c4 = qemu_coroutine_create(rwlock_wrlock, &c4_done); | ||
134 | + | ||
135 | + qemu_coroutine_enter(c1); | ||
136 | + qemu_coroutine_enter(c2); | ||
137 | + qemu_coroutine_enter(c3); | ||
138 | + qemu_coroutine_enter(c4); | ||
139 | + | ||
140 | + qemu_coroutine_enter(c1); | ||
141 | + | ||
142 | + g_assert(c2_done); | ||
143 | + g_assert(c3_done); | ||
144 | + g_assert(c4_done); | ||
145 | + | ||
146 | + qemu_coroutine_enter(c1); | ||
147 | + | ||
148 | + g_assert(c1_done); | ||
149 | +} | ||
150 | + | ||
151 | /* | ||
152 | * Check that creation, enter, and return work | ||
153 | */ | ||
154 | @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) | ||
155 | g_test_add_func("/locking/co-mutex", test_co_mutex); | ||
156 | g_test_add_func("/locking/co-mutex/lockable", test_co_mutex_lockable); | ||
157 | g_test_add_func("/locking/co-rwlock/upgrade", test_co_rwlock_upgrade); | ||
158 | + g_test_add_func("/locking/co-rwlock/downgrade", test_co_rwlock_downgrade); | ||
159 | if (g_test_perf()) { | ||
160 | g_test_add_func("/perf/lifecycle", perf_lifecycle); | ||
161 | g_test_add_func("/perf/nesting", perf_nesting); | ||
168 | -- | 162 | -- |
169 | 2.24.1 | 163 | 2.30.2 |
170 | 164 | ||
171 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Daniel P. Berrangé <berrange@redhat.com> | ||
2 | 1 | ||
3 | When initializing the LUKS header the size with default encryption | ||
4 | parameters will currently be 2068480 bytes. This is rounded up to | ||
5 | a multiple of the cluster size, 2081792, with 64k sectors. If the | ||
6 | end of the header is not the same as the end of the cluster we fill | ||
7 | the extra space with zeros. This was forgetting that not even the | ||
8 | space allocated for the header will be fully initialized, as we | ||
9 | only write key material for the first key slot. The space left | ||
10 | for the other 7 slots is never written to. | ||
11 | |||
12 | An optimization to the ref count checking code: | ||
13 | |||
14 | commit a5fff8d4b4d928311a5005efa12d0991fe3b66f9 (refs/bisect/bad) | ||
15 | Author: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
16 | Date: Wed Feb 27 16:14:30 2019 +0300 | ||
17 | |||
18 | qcow2-refcount: avoid eating RAM | ||
19 | |||
20 | made the assumption that every cluster which was allocated would | ||
21 | have at least some data written to it. This was violated by way | ||
22 | the LUKS header is only partially written, with much space simply | ||
23 | reserved for future use. | ||
24 | |||
25 | Depending on the cluster size this problem was masked by the | ||
26 | logic which wrote zeros between the end of the LUKS header and | ||
27 | the end of the cluster. | ||
28 | |||
29 | $ qemu-img create --object secret,id=cluster_encrypt0,data=123456 \ | ||
30 | -f qcow2 -o cluster_size=2k,encrypt.iter-time=1,\ | ||
31 | encrypt.format=luks,encrypt.key-secret=cluster_encrypt0 \ | ||
32 | cluster_size_check.qcow2 100M | ||
33 | Formatting 'cluster_size_check.qcow2', fmt=qcow2 size=104857600 | ||
34 | encrypt.format=luks encrypt.key-secret=cluster_encrypt0 | ||
35 | encrypt.iter-time=1 cluster_size=2048 lazy_refcounts=off refcount_bits=16 | ||
36 | |||
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> | ||
69 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
70 | --- | ||
71 | block/qcow2.c | 11 +++-- | ||
72 | tests/qemu-iotests/284 | 97 ++++++++++++++++++++++++++++++++++++++ | ||
73 | tests/qemu-iotests/284.out | 62 ++++++++++++++++++++++++ | ||
74 | tests/qemu-iotests/group | 1 + | ||
75 | 4 files changed, 167 insertions(+), 4 deletions(-) | ||
76 | create mode 100755 tests/qemu-iotests/284 | ||
77 | create mode 100644 tests/qemu-iotests/284.out | ||
78 | |||
79 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
80 | index XXXXXXX..XXXXXXX 100644 | ||
81 | --- a/block/qcow2.c | ||
82 | +++ b/block/qcow2.c | ||
83 | @@ -XXX,XX +XXX,XX @@ static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, | ||
84 | s->crypto_header.length = headerlen; | ||
85 | s->crypto_header.offset = ret; | ||
86 | |||
87 | - /* Zero fill remaining space in cluster so it has predictable | ||
88 | - * content in case of future spec changes */ | ||
89 | + /* | ||
90 | + * Zero fill all space in cluster so it has predictable | ||
91 | + * content, as we may not initialize some regions of the | ||
92 | + * header (eg only 1 out of 8 key slots will be initialized) | ||
93 | + */ | ||
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 | + | ||
130 | +# creator | ||
131 | +owner=berrange@redhat.com | ||
132 | + | ||
133 | +seq=`basename $0` | ||
134 | +echo "QA output created by $seq" | ||
135 | + | ||
136 | +status=1 # failure is the default! | ||
137 | + | ||
138 | +_cleanup() | ||
139 | +{ | ||
140 | + _cleanup_test_img | ||
141 | +} | ||
142 | +trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
143 | + | ||
144 | +# get standard environment, filters and checks | ||
145 | +. ./common.rc | ||
146 | +. ./common.filter | ||
147 | + | ||
148 | +_supported_fmt qcow2 | ||
149 | +_supported_proto generic | ||
150 | +_supported_os Linux | ||
151 | + | ||
152 | + | ||
153 | +size=1M | ||
154 | + | ||
155 | +SECRET="secret,id=sec0,data=astrochicken" | ||
156 | + | ||
157 | +IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0" | ||
158 | +QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT | ||
159 | + | ||
160 | +_run_test() | ||
161 | +{ | ||
162 | + IMGOPTSSYNTAX=true | ||
163 | + OLD_TEST_IMG="$TEST_IMG" | ||
164 | + TEST_IMG="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0" | ||
165 | + QEMU_IMG_EXTRA_ARGS="--image-opts --object $SECRET" | ||
166 | + | ||
167 | + echo | ||
168 | + echo "== cluster size $csize" | ||
169 | + echo "== checking image refcounts ==" | ||
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 | -- | ||
285 | 2.24.1 | ||
286 | |||
287 | 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 |
Deleted patch | |||
---|---|---|---|
1 | First, driver=qcow2 will not work so well with non-qcow2 formats (and | ||
2 | this test claims to support qcow, qed, and vmdk). | ||
3 | 1 | ||
4 | Second, vmdk will always report the backing file format to be vmdk. | ||
5 | Filter that out so the output looks like for all other formats. | ||
6 | |||
7 | Third, the flat vmdk subformats do not support backing files, so they | ||
8 | will not work with this test. | ||
9 | |||
10 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
11 | Message-Id: <20191219144243.1763246-1-mreitz@redhat.com> | ||
12 | Tested-by: Thomas Huth <thuth@redhat.com> | ||
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
14 | --- | ||
15 | tests/qemu-iotests/279 | 7 +++++-- | ||
16 | 1 file changed, 5 insertions(+), 2 deletions(-) | ||
17 | |||
18 | diff --git a/tests/qemu-iotests/279 b/tests/qemu-iotests/279 | ||
19 | index XXXXXXX..XXXXXXX 100755 | ||
20 | --- a/tests/qemu-iotests/279 | ||
21 | +++ b/tests/qemu-iotests/279 | ||
22 | @@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
23 | _supported_fmt qcow qcow2 vmdk qed | ||
24 | _supported_proto file | ||
25 | _supported_os Linux | ||
26 | +_unsupported_imgopts "subformat=monolithicFlat" \ | ||
27 | + "subformat=twoGbMaxExtentFlat" \ | ||
28 | |||
29 | TEST_IMG="$TEST_IMG.base" _make_test_img 64M | ||
30 | TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base" | ||
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 | 2.24.1 | ||
48 | |||
49 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | When nbd_close() is called from a coroutine, the connection_co never | ||
2 | gets to run, and thus nbd_teardown_connection() hangs. | ||
3 | 1 | ||
4 | This is because aio_co_enter() only puts the connection_co into the main | ||
5 | coroutine's wake-up queue, so this main coroutine needs to yield and | ||
6 | wait for connection_co to terminate. | ||
7 | |||
8 | Suggested-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
10 | Message-Id: <20200122164532.178040-2-mreitz@redhat.com> | ||
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
12 | Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> | ||
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
14 | --- | ||
15 | block/nbd.c | 14 +++++++++++++- | ||
16 | 1 file changed, 13 insertions(+), 1 deletion(-) | ||
17 | |||
18 | diff --git a/block/nbd.c b/block/nbd.c | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/block/nbd.c | ||
21 | +++ b/block/nbd.c | ||
22 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVNBDState { | ||
23 | CoMutex send_mutex; | ||
24 | CoQueue free_sema; | ||
25 | Coroutine *connection_co; | ||
26 | + Coroutine *teardown_co; | ||
27 | QemuCoSleepState *connection_co_sleep_ns_state; | ||
28 | bool drained; | ||
29 | bool wait_drained_end; | ||
30 | @@ -XXX,XX +XXX,XX @@ static void nbd_teardown_connection(BlockDriverState *bs) | ||
31 | qemu_co_sleep_wake(s->connection_co_sleep_ns_state); | ||
32 | } | ||
33 | } | ||
34 | - BDRV_POLL_WHILE(bs, s->connection_co); | ||
35 | + if (qemu_in_coroutine()) { | ||
36 | + s->teardown_co = qemu_coroutine_self(); | ||
37 | + /* connection_co resumes us when it terminates */ | ||
38 | + qemu_coroutine_yield(); | ||
39 | + s->teardown_co = NULL; | ||
40 | + } else { | ||
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 | |||
57 | -- | ||
58 | 2.24.1 | ||
59 | |||
60 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | The generic fallback implementation effectively does the same. | ||
2 | 1 | ||
3 | Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> | ||
4 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
5 | Message-Id: <20200122164532.178040-4-mreitz@redhat.com> | ||
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
7 | --- | ||
8 | block/file-posix.c | 67 ---------------------------------------------- | ||
9 | 1 file changed, 67 deletions(-) | ||
10 | |||
11 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
12 | index XXXXXXX..XXXXXXX 100644 | ||
13 | --- a/block/file-posix.c | ||
14 | +++ b/block/file-posix.c | ||
15 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int hdev_co_pwrite_zeroes(BlockDriverState *bs, | ||
16 | return raw_do_pwrite_zeroes(bs, offset, bytes, flags, true); | ||
17 | } | ||
18 | |||
19 | -static int coroutine_fn hdev_co_create_opts(const char *filename, QemuOpts *opts, | ||
20 | - Error **errp) | ||
21 | -{ | ||
22 | - int fd; | ||
23 | - int ret = 0; | ||
24 | - struct stat stat_buf; | ||
25 | - int64_t total_size = 0; | ||
26 | - bool has_prefix; | ||
27 | - | ||
28 | - /* This function is used by both protocol block drivers and therefore either | ||
29 | - * of these prefixes may be given. | ||
30 | - * The return value has to be stored somewhere, otherwise this is an error | ||
31 | - * due to -Werror=unused-value. */ | ||
32 | - has_prefix = | ||
33 | - strstart(filename, "host_device:", &filename) || | ||
34 | - strstart(filename, "host_cdrom:" , &filename); | ||
35 | - | ||
36 | - (void)has_prefix; | ||
37 | - | ||
38 | - ret = raw_normalize_devicepath(&filename, errp); | ||
39 | - if (ret < 0) { | ||
40 | - return ret; | ||
41 | - } | ||
42 | - | ||
43 | - /* Read out options */ | ||
44 | - total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), | ||
45 | - BDRV_SECTOR_SIZE); | ||
46 | - | ||
47 | - fd = qemu_open(filename, O_WRONLY | O_BINARY); | ||
48 | - if (fd < 0) { | ||
49 | - ret = -errno; | ||
50 | - error_setg_errno(errp, -ret, "Could not open device"); | ||
51 | - return ret; | ||
52 | - } | ||
53 | - | ||
54 | - if (fstat(fd, &stat_buf) < 0) { | ||
55 | - ret = -errno; | ||
56 | - error_setg_errno(errp, -ret, "Could not stat device"); | ||
57 | - } else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode)) { | ||
58 | - error_setg(errp, | ||
59 | - "The given file is neither a block nor a character device"); | ||
60 | - ret = -ENODEV; | ||
61 | - } else if (lseek(fd, 0, SEEK_END) < total_size) { | ||
62 | - error_setg(errp, "Device is too small"); | ||
63 | - ret = -ENOSPC; | ||
64 | - } | ||
65 | - | ||
66 | - if (!ret && total_size) { | ||
67 | - uint8_t buf[BDRV_SECTOR_SIZE] = { 0 }; | ||
68 | - int64_t zero_size = MIN(BDRV_SECTOR_SIZE, total_size); | ||
69 | - if (lseek(fd, 0, SEEK_SET) == -1) { | ||
70 | - ret = -errno; | ||
71 | - } else { | ||
72 | - ret = qemu_write_full(fd, buf, zero_size); | ||
73 | - ret = ret == zero_size ? 0 : -errno; | ||
74 | - } | ||
75 | - } | ||
76 | - qemu_close(fd); | ||
77 | - return ret; | ||
78 | -} | ||
79 | - | ||
80 | static BlockDriver bdrv_host_device = { | ||
81 | .format_name = "host_device", | ||
82 | .protocol_name = "host_device", | ||
83 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_device = { | ||
84 | .bdrv_reopen_prepare = raw_reopen_prepare, | ||
85 | .bdrv_reopen_commit = raw_reopen_commit, | ||
86 | .bdrv_reopen_abort = raw_reopen_abort, | ||
87 | - .bdrv_co_create_opts = hdev_co_create_opts, | ||
88 | - .create_opts = &raw_create_opts, | ||
89 | .mutable_opts = mutable_opts, | ||
90 | .bdrv_co_invalidate_cache = raw_co_invalidate_cache, | ||
91 | .bdrv_co_pwrite_zeroes = hdev_co_pwrite_zeroes, | ||
92 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_cdrom = { | ||
93 | .bdrv_reopen_prepare = raw_reopen_prepare, | ||
94 | .bdrv_reopen_commit = raw_reopen_commit, | ||
95 | .bdrv_reopen_abort = raw_reopen_abort, | ||
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 | -- | ||
111 | 2.24.1 | ||
112 | |||
113 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
2 | Message-Id: <20200122164532.178040-6-mreitz@redhat.com> | ||
3 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
4 | Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com> | ||
5 | [mreitz: Added a note that NBD does not support resizing, which is why | ||
6 | the second case is expected to fail] | ||
7 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
8 | --- | ||
9 | tests/qemu-iotests/259 | 62 ++++++++++++++++++++++++++++++++++++++ | ||
10 | tests/qemu-iotests/259.out | 14 +++++++++ | ||
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 | 1 | ||
16 | diff --git a/tests/qemu-iotests/259 b/tests/qemu-iotests/259 | ||
17 | new file mode 100755 | ||
18 | index XXXXXXX..XXXXXXX | ||
19 | --- /dev/null | ||
20 | +++ b/tests/qemu-iotests/259 | ||
21 | @@ -XXX,XX +XXX,XX @@ | ||
22 | +#!/usr/bin/env bash | ||
23 | +# | ||
24 | +# Test generic image creation fallback (by using NBD) | ||
25 | +# | ||
26 | +# Copyright (C) 2019 Red Hat, Inc. | ||
27 | +# | ||
28 | +# This program is free software; you can redistribute it and/or modify | ||
29 | +# it under the terms of the GNU General Public License as published by | ||
30 | +# the Free Software Foundation; either version 2 of the License, or | ||
31 | +# (at your option) any later version. | ||
32 | +# | ||
33 | +# This program is distributed in the hope that it will be useful, | ||
34 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
35 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
36 | +# GNU General Public License for more details. | ||
37 | +# | ||
38 | +# You should have received a copy of the GNU General Public License | ||
39 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
40 | +# | ||
41 | + | ||
42 | +# creator | ||
43 | +owner=mreitz@redhat.com | ||
44 | + | ||
45 | +seq=$(basename $0) | ||
46 | +echo "QA output created by $seq" | ||
47 | + | ||
48 | +status=1 # failure is the default! | ||
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 | + | ||
64 | + | ||
65 | +_make_test_img 64M | ||
66 | + | ||
67 | +echo | ||
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 | -- | ||
117 | 2.24.1 | ||
118 | |||
119 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | s.target_has_backing does not reflect whether the target BDS has a | ||
2 | backing file; it only tells whether we should use a backing file during | ||
3 | conversion (specified by -B). | ||
4 | 1 | ||
5 | As such, if you use convert -n, the target does not necessarily actually | ||
6 | have a backing file, and then dereferencing out_bs->backing fails here. | ||
7 | |||
8 | When converting to an existing file, we should set | ||
9 | target_backing_sectors to a negative value, because first, as the | ||
10 | comment explains, this value is only used for optimization, so it is | ||
11 | always fine to do that. | ||
12 | |||
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 | --- | ||
26 | qemu-img.c | 2 +- | ||
27 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
28 | |||
29 | diff --git a/qemu-img.c b/qemu-img.c | ||
30 | index XXXXXXX..XXXXXXX 100644 | ||
31 | --- a/qemu-img.c | ||
32 | +++ b/qemu-img.c | ||
33 | @@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv) | ||
34 | } | ||
35 | } | ||
36 | |||
37 | - if (s.target_has_backing) { | ||
38 | + if (s.target_has_backing && s.target_is_new) { | ||
39 | /* Errors are treated as "backing length unknown" (which means | ||
40 | * s.target_backing_sectors has to be negative, which it will | ||
41 | * be automatically). The backing file length is used only | ||
42 | -- | ||
43 | 2.24.1 | ||
44 | |||
45 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | This must not crash. | ||
2 | 1 | ||
3 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
4 | Message-Id: <20200121155915.98232-3-mreitz@redhat.com> | ||
5 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
6 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
7 | --- | ||
8 | tests/qemu-iotests/122 | 14 ++++++++++++++ | ||
9 | tests/qemu-iotests/122.out | 5 +++++ | ||
10 | 2 files changed, 19 insertions(+) | ||
11 | |||
12 | diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 | ||
13 | index XXXXXXX..XXXXXXX 100755 | ||
14 | --- a/tests/qemu-iotests/122 | ||
15 | +++ b/tests/qemu-iotests/122 | ||
16 | @@ -XXX,XX +XXX,XX @@ $QEMU_IMG convert -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG".orig | ||
17 | |||
18 | $QEMU_IMG compare "$TEST_IMG" "$TEST_IMG".orig | ||
19 | |||
20 | +echo | ||
21 | +echo '=== -n -B to an image without a backing file ===' | ||
22 | +echo | ||
23 | + | ||
24 | +# Base for the output | ||
25 | +TEST_IMG="$TEST_IMG".base _make_test_img 64M | ||
26 | + | ||
27 | +# Output that does have $TEST_IMG.base set as its (implicit) backing file | ||
28 | +TEST_IMG="$TEST_IMG".orig _make_test_img 64M | ||
29 | + | ||
30 | +# Convert with -n, which should not confuse -B with "target BDS has a | ||
31 | +# backing file" | ||
32 | +$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -n "$TEST_IMG" "$TEST_IMG".orig | ||
33 | + | ||
34 | # success, all done | ||
35 | echo '*** done' | ||
36 | rm -f $seq.full | ||
37 | diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out | ||
38 | index XXXXXXX..XXXXXXX 100644 | ||
39 | --- a/tests/qemu-iotests/122.out | ||
40 | +++ b/tests/qemu-iotests/122.out | ||
41 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864 | ||
42 | wrote 65536/65536 bytes at offset 0 | ||
43 | 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) | ||
44 | Images are identical. | ||
45 | + | ||
46 | +=== -n -B to an image without a backing file === | ||
47 | + | ||
48 | +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 | ||
49 | +Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864 | ||
50 | *** done | ||
51 | -- | ||
52 | 2.24.1 | ||
53 | |||
54 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | When printing the snapshot list (e.g. with qemu-img snapshot -l), the VM | ||
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 | 1 | ||
8 | Considering previously the maximum width was four characters and the | ||
9 | field width was chosen to be three characters wider, let us adjust the | ||
10 | field width to be eleven now. | ||
11 | |||
12 | Fixes: de38b5005e946aa3714963ea4c501e279e7d3666 | ||
13 | Buglink: https://bugs.launchpad.net/qemu/+bug/1859989 | ||
14 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
15 | Message-Id: <20200117105859.241818-2-mreitz@redhat.com> | ||
16 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
17 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
18 | --- | ||
19 | block/qapi.c | 4 ++-- | ||
20 | 1 file changed, 2 insertions(+), 2 deletions(-) | ||
21 | |||
22 | diff --git a/block/qapi.c b/block/qapi.c | ||
23 | index XXXXXXX..XXXXXXX 100644 | ||
24 | --- a/block/qapi.c | ||
25 | +++ b/block/qapi.c | ||
26 | @@ -XXX,XX +XXX,XX @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn) | ||
27 | char *sizing = NULL; | ||
28 | |||
29 | if (!sn) { | ||
30 | - qemu_printf("%-10s%-20s%7s%20s%15s", | ||
31 | + qemu_printf("%-10s%-20s%11s%20s%15s", | ||
32 | "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK"); | ||
33 | } else { | ||
34 | ti = sn->date_sec; | ||
35 | @@ -XXX,XX +XXX,XX @@ void bdrv_snapshot_dump(QEMUSnapshotInfo *sn) | ||
36 | (int)(secs % 60), | ||
37 | (int)((sn->vm_clock_nsec / 1000000) % 1000)); | ||
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 | -- | ||
45 | 2.24.1 | ||
46 | |||
47 | diff view generated by jsdifflib |