1 | The following changes since commit cfe6c547690b06fbce54a6d0f7b05dd7f18e36ea: | 1 | The following changes since commit 79b677d658d3d35e1e776826ac4abb28cdce69b8: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/xanclic/tags/pull-block-2019-01-31' into staging (2019-01-31 19:26:09 +0000) | 3 | Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging (2023-02-21 11:28:31 +0000) |
4 | 4 | ||
5 | are available in the Git repository at: | 5 | are available in the Git repository at: |
6 | 6 | ||
7 | git://repo.or.cz/qemu/kevin.git tags/for-upstream | 7 | https://repo.or.cz/qemu/kevin.git tags/for-upstream |
8 | 8 | ||
9 | for you to fetch changes up to 7471a649fc3a391dd497297013fb2525ca9821ba: | 9 | for you to fetch changes up to 0f385a2420d2c3f8ae7ed65fbe2712027664059e: |
10 | 10 | ||
11 | scsi-disk: Add device_id property (2019-02-01 13:48:11 +0100) | 11 | block/rbd: Add support for layered encryption (2023-02-23 19:49:35 +0100) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | Block layer patches: | 14 | Block layer patches |
15 | 15 | ||
16 | - vmdk: Support for blockdev-create | 16 | - Lock the graph, part 2 (BlockDriver callbacks) |
17 | - block: Apply auto-read-only for ro-whitelist drivers | 17 | - virtio-scsi: fix SCSIDevice hot unplug with IOThread |
18 | - virtio-scsi: Fixes related to attaching/detaching iothreads | 18 | - rbd: Add support for layered encryption |
19 | - scsi-disk: Fixed erroneously detected multipath setup with multiple | ||
20 | disks created with node-names. Added device_id property. | ||
21 | - block: Fix hangs in synchronous APIs with iothreads | ||
22 | - block: Fix invalidate_cache error path for parent activation | ||
23 | - block-backend, mirror, qcow2, vpc, vdi, qemu-iotests: | ||
24 | Minor fixes and code improvements | ||
25 | 19 | ||
26 | ---------------------------------------------------------------- | 20 | ---------------------------------------------------------------- |
27 | Alberto Garcia (7): | 21 | Emanuele Giuseppe Esposito (5): |
28 | mirror: Release the dirty bitmap if mirror_start_job() fails | 22 | block/qed: add missing graph rdlock in qed_need_check_timer_entry |
29 | mirror: Block the source BlockDriverState in mirror_start_job() | 23 | block: Mark bdrv_co_flush() and callers GRAPH_RDLOCK |
30 | qcow2: Assert that refcount block offsets fit in the refcount table | 24 | block: Mark bdrv_co_pdiscard() and callers GRAPH_RDLOCK |
31 | virtio-scsi: Move BlockBackend back to the main AioContext on unplug | 25 | block: Mark bdrv_co_copy_range() GRAPH_RDLOCK |
32 | scsi-disk: Acquire the AioContext in scsi_*_realize() | 26 | block: Mark bdrv_co_is_inserted() and callers GRAPH_RDLOCK |
33 | virtio-scsi: Forbid devices with different iothreads sharing a blockdev | ||
34 | qtest.py: Wait for the result of qtest commands | ||
35 | 27 | ||
36 | Fam Zheng (3): | 28 | Kevin Wolf (18): |
37 | vmdk: Refactor vmdk_create_extent | 29 | block: Make bdrv_can_set_read_only() static |
38 | vmdk: Implement .bdrv_co_create callback | 30 | mirror: Fix access of uninitialised fields during start |
39 | iotests: Filter cid numbers in VMDK extent info | 31 | block: Mark bdrv_co_truncate() and callers GRAPH_RDLOCK |
32 | block: Mark bdrv_co_block_status() and callers GRAPH_RDLOCK | ||
33 | block: Mark bdrv_co_ioctl() and callers GRAPH_RDLOCK | ||
34 | block: Mark bdrv_co_pwrite_zeroes() and callers GRAPH_RDLOCK | ||
35 | block: Mark read/write in block/io.c GRAPH_RDLOCK | ||
36 | block: Mark public read/write functions GRAPH_RDLOCK | ||
37 | block: Mark bdrv_co_pwrite_sync() and callers GRAPH_RDLOCK | ||
38 | block: Mark bdrv_co_do_pwrite_zeroes() GRAPH_RDLOCK | ||
39 | block: Mark preadv_snapshot/snapshot_block_status GRAPH_RDLOCK | ||
40 | block: Mark bdrv_co_create() and callers GRAPH_RDLOCK | ||
41 | block: Mark bdrv_co_io_(un)plug() and callers GRAPH_RDLOCK | ||
42 | block: Mark bdrv_co_eject/lock_medium() and callers GRAPH_RDLOCK | ||
43 | block: Mark bdrv_(un)register_buf() GRAPH_RDLOCK | ||
44 | block: Mark bdrv_co_delete_file() and callers GRAPH_RDLOCK | ||
45 | block: Mark bdrv_*_dirty_bitmap() and callers GRAPH_RDLOCK | ||
46 | block: Mark bdrv_co_refresh_total_sectors() and callers GRAPH_RDLOCK | ||
40 | 47 | ||
41 | John Snow (1): | 48 | Or Ozeri (3): |
42 | iotests/236: fix transaction kwarg order | 49 | block/rbd: Remove redundant stack variable passphrase_len |
50 | block/rbd: Add luks-any encryption opening option | ||
51 | block/rbd: Add support for layered encryption | ||
43 | 52 | ||
44 | Kevin Wolf (7): | 53 | Stefan Hajnoczi (3): |
45 | block: Fix hangs in synchronous APIs with iothreads | 54 | scsi: protect req->aiocb with AioContext lock |
46 | iotests: Add VMDK tests for blockdev-create | 55 | dma-helpers: prevent dma_blk_cb() vs dma_aio_cancel() race |
47 | vmdk: Reject excess extents in blockdev-create | 56 | virtio-scsi: reset SCSI devices from main loop thread |
48 | block: Apply auto-read-only for ro-whitelist drivers | ||
49 | block: Fix invalidate_cache error path for parent activation | ||
50 | scsi-disk: Don't use empty string as device id | ||
51 | scsi-disk: Add device_id property | ||
52 | 57 | ||
53 | Markus Armbruster (2): | 58 | qapi/block-core.json | 27 +++++- |
54 | block: Replace qdict_put() by qdict_put_obj() where appropriate | 59 | block/coroutines.h | 2 +- |
55 | block: Eliminate the S_1KiB, S_2KiB, ... macros | 60 | block/qcow2.h | 27 ++++-- |
56 | 61 | block/qed.h | 45 +++++---- | |
57 | Max Reitz (2): | 62 | include/block/block-copy.h | 6 +- |
58 | iotests: Make 234 stable | 63 | include/block/block-global-state.h | 14 +-- |
59 | iotests: Filter second BLOCK_JOB_ERROR from 229 | 64 | include/block/block-io.h | 110 ++++++++++++---------- |
60 | 65 | include/block/block_int-common.h | 173 ++++++++++++++++++---------------- | |
61 | Peter Maydell (3): | 66 | include/block/block_int-io.h | 53 ++++++----- |
62 | block/vpc: Don't take address of fields in packed structs | 67 | include/block/dirty-bitmap.h | 12 +-- |
63 | block/vdi: Don't take address of fields in packed structs | 68 | include/hw/virtio/virtio-scsi.h | 11 ++- |
64 | uuid: Make qemu_uuid_bswap() take and return a QemuUUID | 69 | include/sysemu/block-backend-io.h | 7 +- |
65 | 70 | block.c | 12 ++- | |
66 | Thomas Huth (1): | 71 | block/backup.c | 3 + |
67 | block: Remove blk_attach_dev_legacy() / legacy_dev code | 72 | block/blkdebug.c | 19 ++-- |
68 | 73 | block/blklogwrites.c | 35 ++++--- | |
69 | yuchenlin (1): | 74 | block/blkreplay.c | 24 +++-- |
70 | qemu-iotests: add test case for dmg | 75 | block/blkverify.c | 5 +- |
71 | 76 | block/block-backend.c | 39 +++++--- | |
72 | qapi/block-core.json | 71 +++ | 77 | block/block-copy.c | 32 ++++--- |
73 | qapi/qapi-schema.json | 16 +- | 78 | block/bochs.c | 2 +- |
74 | block/qcow2.h | 10 +- | 79 | block/commit.c | 5 +- |
75 | include/qemu/units.h | 73 --- | 80 | block/copy-before-write.c | 33 ++++--- |
76 | include/qemu/uuid.h | 2 +- | 81 | block/copy-on-read.c | 44 +++++---- |
77 | include/sysemu/block-backend.h | 5 +- | 82 | block/create.c | 9 +- |
78 | block.c | 27 +- | 83 | block/crypto.c | 16 ++-- |
79 | block/blklogwrites.c | 5 +- | 84 | block/dirty-bitmap.c | 2 + |
80 | block/block-backend.c | 59 +-- | 85 | block/file-posix.c | 27 +++--- |
81 | block/io.c | 8 +- | 86 | block/file-win32.c | 7 +- |
82 | block/mirror.c | 11 + | 87 | block/filter-compress.c | 36 ++++--- |
83 | block/nbd-client.c | 1 + | 88 | block/io.c | 108 +++++++++++++-------- |
84 | block/nvme.c | 1 + | 89 | block/iscsi.c | 28 +++--- |
85 | block/qcow2-refcount.c | 3 + | 90 | block/mirror.c | 59 ++++++++---- |
86 | block/qcow2.c | 1 + | 91 | block/parallels.c | 33 +++---- |
87 | block/qed.c | 1 + | 92 | block/preallocate.c | 38 ++++---- |
88 | block/vdi.c | 57 ++- | 93 | block/qcow.c | 46 +++++---- |
89 | block/vmdk.c | 532 +++++++++++++++------ | 94 | block/qcow2-cluster.c | 17 ++-- |
90 | block/vpc.c | 4 +- | 95 | block/qcow2.c | 136 +++++++++++++++------------ |
91 | hw/acpi/vmgenid.c | 6 +- | 96 | block/qed-check.c | 3 +- |
92 | hw/scsi/scsi-disk.c | 59 ++- | 97 | block/qed-table.c | 10 +- |
93 | hw/scsi/virtio-scsi.c | 13 + | 98 | block/qed.c | 101 ++++++++++---------- |
94 | tests/test-block-iothread.c | 372 ++++++++++++++ | 99 | block/quorum.c | 62 +++++++----- |
95 | tests/vmgenid-test.c | 2 +- | 100 | block/raw-format.c | 76 ++++++++------- |
96 | util/uuid.c | 10 +- | 101 | block/rbd.c | 188 ++++++++++++++++++++++++++++++++++--- |
97 | scripts/qtest.py | 6 + | 102 | block/replication.c | 18 ++-- |
98 | tests/Makefile.include | 2 + | 103 | block/snapshot-access.c | 8 +- |
99 | tests/qemu-iotests/141.out | 4 +- | 104 | block/stream.c | 40 ++++---- |
100 | tests/qemu-iotests/229 | 6 +- | 105 | block/throttle.c | 36 ++++--- |
101 | tests/qemu-iotests/229.out | 1 - | 106 | block/vdi.c | 11 +-- |
102 | tests/qemu-iotests/234 | 56 ++- | 107 | block/vhdx.c | 18 ++-- |
103 | tests/qemu-iotests/234.out | 10 +- | 108 | block/vmdk.c | 132 ++++++++++++-------------- |
104 | tests/qemu-iotests/236.out | 56 +-- | 109 | block/vpc.c | 11 +-- |
105 | tests/qemu-iotests/237 | 237 +++++++++ | 110 | hw/scsi/scsi-disk.c | 23 +++-- |
106 | tests/qemu-iotests/237.out | 348 ++++++++++++++ | 111 | hw/scsi/scsi-generic.c | 11 ++- |
107 | tests/qemu-iotests/239 | 53 ++ | 112 | hw/scsi/virtio-scsi.c | 169 ++++++++++++++++++++++++++------- |
108 | tests/qemu-iotests/239.out | 4 + | 113 | qemu-img.c | 8 +- |
109 | tests/qemu-iotests/240 | 129 +++++ | 114 | softmmu/dma-helpers.c | 12 ++- |
110 | tests/qemu-iotests/240.out | 54 +++ | 115 | tests/unit/test-bdrv-drain.c | 20 ++-- |
111 | tests/qemu-iotests/check | 7 + | 116 | tests/unit/test-block-iothread.c | 3 +- |
112 | tests/qemu-iotests/common.filter | 1 + | 117 | 59 files changed, 1355 insertions(+), 907 deletions(-) |
113 | tests/qemu-iotests/group | 3 + | ||
114 | tests/qemu-iotests/iotests.py | 22 +- | ||
115 | .../qemu-iotests/sample_images/simple-dmg.dmg.bz2 | Bin 0 -> 3479 bytes | ||
116 | 44 files changed, 1931 insertions(+), 417 deletions(-) | ||
117 | create mode 100644 tests/test-block-iothread.c | ||
118 | create mode 100755 tests/qemu-iotests/237 | ||
119 | create mode 100644 tests/qemu-iotests/237.out | ||
120 | create mode 100755 tests/qemu-iotests/239 | ||
121 | create mode 100644 tests/qemu-iotests/239.out | ||
122 | create mode 100755 tests/qemu-iotests/240 | ||
123 | create mode 100644 tests/qemu-iotests/240.out | ||
124 | create mode 100644 tests/qemu-iotests/sample_images/simple-dmg.dmg.bz2 | ||
125 | diff view generated by jsdifflib |
1 | From: Fam Zheng <famz@redhat.com> | 1 | It is never called outside of block.c. |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Fam Zheng <famz@redhat.com> | 3 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | Message-Id: <20230203152202.49054-2-kwolf@redhat.com> | ||
5 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
6 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> | ||
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
5 | --- | 8 | --- |
6 | tests/qemu-iotests/common.filter | 1 + | 9 | include/block/block-io.h | 2 -- |
7 | tests/qemu-iotests/iotests.py | 1 + | 10 | block.c | 4 ++-- |
8 | 2 files changed, 2 insertions(+) | 11 | 2 files changed, 2 insertions(+), 4 deletions(-) |
9 | 12 | ||
10 | diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter | 13 | diff --git a/include/block/block-io.h b/include/block/block-io.h |
11 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
12 | --- a/tests/qemu-iotests/common.filter | 15 | --- a/include/block/block-io.h |
13 | +++ b/tests/qemu-iotests/common.filter | 16 | +++ b/include/block/block-io.h |
14 | @@ -XXX,XX +XXX,XX @@ _filter_img_info() | 17 | @@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, |
15 | -e "/table_size: [0-9]\\+/d" \ | 18 | int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, |
16 | -e "/compat: '[^']*'/d" \ | 19 | int64_t bytes); |
17 | -e "/compat6: \\(on\\|off\\)/d" \ | 20 | |
18 | + -e "s/cid: [0-9]\+/cid: XXXXXXXXXX/" \ | 21 | -int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, |
19 | -e "/static: \\(on\\|off\\)/d" \ | 22 | - bool ignore_allow_rdw, Error **errp); |
20 | -e "/zeroed_grain: \\(on\\|off\\)/d" \ | 23 | int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, |
21 | -e "/subformat: '[^']*'/d" \ | 24 | Error **errp); |
22 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | 25 | bool bdrv_is_read_only(BlockDriverState *bs); |
26 | diff --git a/block.c b/block.c | ||
23 | index XXXXXXX..XXXXXXX 100644 | 27 | index XXXXXXX..XXXXXXX 100644 |
24 | --- a/tests/qemu-iotests/iotests.py | 28 | --- a/block.c |
25 | +++ b/tests/qemu-iotests/iotests.py | 29 | +++ b/block.c |
26 | @@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename): | 30 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_read_only(BlockDriverState *bs) |
27 | .replace(imgfmt, 'IMGFMT') | 31 | return !(bs->open_flags & BDRV_O_RDWR); |
28 | line = re.sub('iters: [0-9]+', 'iters: XXX', line) | 32 | } |
29 | line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line) | 33 | |
30 | + line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line) | 34 | -int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, |
31 | lines.append(line) | 35 | - bool ignore_allow_rdw, Error **errp) |
32 | return '\n'.join(lines) | 36 | +static int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, |
37 | + bool ignore_allow_rdw, Error **errp) | ||
38 | { | ||
39 | IO_CODE(); | ||
33 | 40 | ||
34 | -- | 41 | -- |
35 | 2.20.1 | 42 | 2.39.2 |
36 | |||
37 | diff view generated by jsdifflib |
1 | From: Alberto Garcia <berto@igalia.com> | 1 | bdrv_mirror_top_pwritev() accesses the job object when active mirroring |
---|---|---|---|
2 | is enabled. It disables this code during early initialisation while | ||
3 | s->job isn't set yet. | ||
2 | 4 | ||
3 | The mirror_start_job() function used for the commit-active job blocks | 5 | However, s->job is still set way too early when the job object isn't |
4 | the source, target and all intermediate nodes for the duration of the | 6 | fully initialised. For example, &s->ops_in_flight isn't initialised yet |
5 | job. | 7 | and the in_flight bitmap doesn't exist yet. This causes crashes when a |
8 | write request comes in too early. | ||
6 | 9 | ||
7 | target <- intermediate <- source | 10 | Move the assignment of s->job to when the mirror job is actually fully |
11 | initialised to make sure that the mirror_top driver doesn't access it | ||
12 | too early. | ||
8 | 13 | ||
9 | Since 4ef85a9c2339 this function creates a dummy mirror_top_bs that | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | goes on top of the source node, and it is this dummy node that gets | 15 | Message-Id: <20230203152202.49054-3-kwolf@redhat.com> |
11 | blocked instead. The source node is never blocked or added to the | 16 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
12 | job's list of nodes. | 17 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> |
13 | |||
14 | target <- intermediate <- source <- mirror_top | ||
15 | |||
16 | At the moment I don't think it is possible to exploit this problem | ||
17 | because any additional job on 'source' would either be forbidden for | ||
18 | other reasons or it would need to involve an additional node that is | ||
19 | blocked, causing an error. | ||
20 | |||
21 | This can be seen in the error messages, however, because they never | ||
22 | refer to the source node being blocked: | ||
23 | |||
24 | $ qemu-img create -f qcow2 hd0.qcow2 1M | ||
25 | $ qemu-img create -f qcow2 -b hd0.qcow2 hd1.qcow2 | ||
26 | $ qemu-io -c 'write 0 1M' hd0.qcow2 | ||
27 | $ $QEMU -drive if=none,file=hd1.qcow2,node-name=hd1 | ||
28 | { "execute": "qmp_capabilities" } | ||
29 | { "execute": "block-commit", "arguments": {"device": "hd1", "speed": 256}} | ||
30 | { "execute": "block-stream", "arguments": {"device": "hd1"}} | ||
31 | { "error": {"class": "GenericError", | ||
32 | "desc": "Node 'hd0' is busy: block device is in use by block job: commit"}} | ||
33 | |||
34 | After this patch the error message refers to 'hd1', as it should. | ||
35 | |||
36 | The expected output of iotest 141 also needs to be updated for the | ||
37 | same reason. | ||
38 | |||
39 | Signed-off-by: Alberto Garcia <berto@igalia.com> | ||
40 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
41 | --- | 19 | --- |
42 | block/mirror.c | 8 ++++++++ | 20 | block/mirror.c | 8 +++++++- |
43 | tests/qemu-iotests/141.out | 4 ++-- | 21 | 1 file changed, 7 insertions(+), 1 deletion(-) |
44 | 2 files changed, 10 insertions(+), 2 deletions(-) | ||
45 | 22 | ||
46 | diff --git a/block/mirror.c b/block/mirror.c | 23 | diff --git a/block/mirror.c b/block/mirror.c |
47 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
48 | --- a/block/mirror.c | 25 | --- a/block/mirror.c |
49 | +++ b/block/mirror.c | 26 | +++ b/block/mirror.c |
50 | @@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs, | 27 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp) |
28 | { | ||
29 | MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); | ||
30 | BlockDriverState *bs = s->mirror_top_bs->backing->bs; | ||
31 | + MirrorBDSOpaque *mirror_top_opaque = s->mirror_top_bs->opaque; | ||
32 | BlockDriverState *target_bs = blk_bs(s->target); | ||
33 | bool need_drain = true; | ||
34 | BlockDeviceIoStatus iostatus; | ||
35 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp) | ||
36 | } | ||
37 | } | ||
38 | |||
39 | + /* | ||
40 | + * Only now the job is fully initialised and mirror_top_bs should start | ||
41 | + * accessing it. | ||
42 | + */ | ||
43 | + mirror_top_opaque->job = s; | ||
44 | + | ||
45 | assert(!s->dbi); | ||
46 | s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap); | ||
47 | for (;;) { | ||
48 | @@ -XXX,XX +XXX,XX @@ static BlockJob *mirror_start_job( | ||
49 | if (!s) { | ||
51 | goto fail; | 50 | goto fail; |
52 | } | 51 | } |
53 | 52 | - bs_opaque->job = s; | |
54 | + ret = block_job_add_bdrv(&s->common, "source", bs, 0, | 53 | |
55 | + BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE | | 54 | /* The block job now has a reference to this node */ |
56 | + BLK_PERM_CONSISTENT_READ, | 55 | bdrv_unref(mirror_top_bs); |
57 | + errp); | ||
58 | + if (ret < 0) { | ||
59 | + goto fail; | ||
60 | + } | ||
61 | + | ||
62 | /* Required permissions are already taken with blk_new() */ | ||
63 | block_job_add_bdrv(&s->common, "target", target, 0, BLK_PERM_ALL, | ||
64 | &error_abort); | ||
65 | diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out | ||
66 | index XXXXXXX..XXXXXXX 100644 | ||
67 | --- a/tests/qemu-iotests/141.out | ||
68 | +++ b/tests/qemu-iotests/141.out | ||
69 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. | ||
70 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}} | ||
71 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}} | ||
72 | {"return": {}} | ||
73 | -{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}} | ||
74 | +{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: mirror"}} | ||
75 | {"return": {}} | ||
76 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}} | ||
77 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}} | ||
78 | @@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. | ||
79 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}} | ||
80 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} | ||
81 | {"return": {}} | ||
82 | -{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}} | ||
83 | +{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}} | ||
84 | {"return": {}} | ||
85 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}} | ||
86 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}} | ||
87 | -- | 56 | -- |
88 | 2.20.1 | 57 | 2.39.2 |
89 | |||
90 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | This adds GRAPH_RDLOCK annotations to declare that callers of | ||
2 | bdrv_co_truncate() need to hold a reader lock for the graph. | ||
1 | 3 | ||
4 | For some places, we know that they will hold the lock, but we don't have | ||
5 | the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock() | ||
6 | with a FIXME comment. These places will be removed once everything is | ||
7 | properly annotated. | ||
8 | |||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | Message-Id: <20230203152202.49054-4-kwolf@redhat.com> | ||
11 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | include/block/block-io.h | 6 +++--- | ||
15 | include/block/block_int-common.h | 7 ++++--- | ||
16 | block/block-backend.c | 1 + | ||
17 | block/crypto.c | 2 +- | ||
18 | block/io.c | 1 + | ||
19 | block/parallels.c | 14 ++++++++------ | ||
20 | block/preallocate.c | 2 +- | ||
21 | block/qcow.c | 17 ++++++++++++----- | ||
22 | block/qcow2.c | 14 ++++++++------ | ||
23 | block/raw-format.c | 6 +++--- | ||
24 | block/vmdk.c | 2 ++ | ||
25 | 11 files changed, 44 insertions(+), 28 deletions(-) | ||
26 | |||
27 | diff --git a/include/block/block-io.h b/include/block/block-io.h | ||
28 | index XXXXXXX..XXXXXXX 100644 | ||
29 | --- a/include/block/block-io.h | ||
30 | +++ b/include/block/block-io.h | ||
31 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset, | ||
32 | int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, | ||
33 | int64_t bytes, BdrvRequestFlags flags); | ||
34 | |||
35 | -int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
36 | - PreallocMode prealloc, BdrvRequestFlags flags, | ||
37 | - Error **errp); | ||
38 | +int coroutine_fn GRAPH_RDLOCK | ||
39 | +bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
40 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); | ||
41 | |||
42 | int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs); | ||
43 | int64_t co_wrapper_mixed bdrv_nb_sectors(BlockDriverState *bs); | ||
44 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
45 | index XXXXXXX..XXXXXXX 100644 | ||
46 | --- a/include/block/block_int-common.h | ||
47 | +++ b/include/block/block_int-common.h | ||
48 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
49 | * If @exact is true and this function fails but would succeed | ||
50 | * with @exact = false, it should return -ENOTSUP. | ||
51 | */ | ||
52 | - int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset, | ||
53 | - bool exact, PreallocMode prealloc, | ||
54 | - BdrvRequestFlags flags, Error **errp); | ||
55 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_truncate)( | ||
56 | + BlockDriverState *bs, int64_t offset, bool exact, | ||
57 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); | ||
58 | + | ||
59 | int64_t coroutine_fn (*bdrv_co_getlength)(BlockDriverState *bs); | ||
60 | int64_t coroutine_fn (*bdrv_co_get_allocated_file_size)( | ||
61 | BlockDriverState *bs); | ||
62 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
63 | index XXXXXXX..XXXXXXX 100644 | ||
64 | --- a/block/block-backend.c | ||
65 | +++ b/block/block-backend.c | ||
66 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_truncate(BlockBackend *blk, int64_t offset, bool exact, | ||
67 | Error **errp) | ||
68 | { | ||
69 | IO_OR_GS_CODE(); | ||
70 | + GRAPH_RDLOCK_GUARD(); | ||
71 | if (!blk_is_available(blk)) { | ||
72 | error_setg(errp, "No medium inserted"); | ||
73 | return -ENOMEDIUM; | ||
74 | diff --git a/block/crypto.c b/block/crypto.c | ||
75 | index XXXXXXX..XXXXXXX 100644 | ||
76 | --- a/block/crypto.c | ||
77 | +++ b/block/crypto.c | ||
78 | @@ -XXX,XX +XXX,XX @@ block_crypto_co_create_generic(BlockDriverState *bs, int64_t size, | ||
79 | return ret; | ||
80 | } | ||
81 | |||
82 | -static int coroutine_fn | ||
83 | +static int coroutine_fn GRAPH_RDLOCK | ||
84 | block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, | ||
85 | PreallocMode prealloc, BdrvRequestFlags flags, | ||
86 | Error **errp) | ||
87 | diff --git a/block/io.c b/block/io.c | ||
88 | index XXXXXXX..XXXXXXX 100644 | ||
89 | --- a/block/io.c | ||
90 | +++ b/block/io.c | ||
91 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
92 | int64_t old_size, new_bytes; | ||
93 | int ret; | ||
94 | IO_CODE(); | ||
95 | + assert_bdrv_graph_readable(); | ||
96 | |||
97 | /* if bs->drv == NULL, bs is closed, so there's nothing to do here */ | ||
98 | if (!drv) { | ||
99 | diff --git a/block/parallels.c b/block/parallels.c | ||
100 | index XXXXXXX..XXXXXXX 100644 | ||
101 | --- a/block/parallels.c | ||
102 | +++ b/block/parallels.c | ||
103 | @@ -XXX,XX +XXX,XX @@ static int64_t block_status(BDRVParallelsState *s, int64_t sector_num, | ||
104 | return start_off; | ||
105 | } | ||
106 | |||
107 | -static coroutine_fn int64_t allocate_clusters(BlockDriverState *bs, | ||
108 | - int64_t sector_num, | ||
109 | - int nb_sectors, int *pnum) | ||
110 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
111 | +allocate_clusters(BlockDriverState *bs, int64_t sector_num, | ||
112 | + int nb_sectors, int *pnum) | ||
113 | { | ||
114 | int ret = 0; | ||
115 | BDRVParallelsState *s = bs->opaque; | ||
116 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int parallels_co_writev(BlockDriverState *bs, | ||
117 | QEMUIOVector hd_qiov; | ||
118 | int ret = 0; | ||
119 | |||
120 | + assume_graph_lock(); /* FIXME */ | ||
121 | + | ||
122 | qemu_iovec_init(&hd_qiov, qiov->niov); | ||
123 | |||
124 | while (nb_sectors > 0) { | ||
125 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs, | ||
126 | } | ||
127 | |||
128 | |||
129 | -static int coroutine_fn parallels_co_check(BlockDriverState *bs, | ||
130 | - BdrvCheckResult *res, | ||
131 | - BdrvCheckMode fix) | ||
132 | +static int coroutine_fn GRAPH_RDLOCK | ||
133 | +parallels_co_check(BlockDriverState *bs, BdrvCheckResult *res, | ||
134 | + BdrvCheckMode fix) | ||
135 | { | ||
136 | BDRVParallelsState *s = bs->opaque; | ||
137 | int64_t size, prev_off, high_off; | ||
138 | diff --git a/block/preallocate.c b/block/preallocate.c | ||
139 | index XXXXXXX..XXXXXXX 100644 | ||
140 | --- a/block/preallocate.c | ||
141 | +++ b/block/preallocate.c | ||
142 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int preallocate_co_pwritev_part(BlockDriverState *bs, | ||
143 | flags); | ||
144 | } | ||
145 | |||
146 | -static int coroutine_fn | ||
147 | +static int coroutine_fn GRAPH_RDLOCK | ||
148 | preallocate_co_truncate(BlockDriverState *bs, int64_t offset, | ||
149 | bool exact, PreallocMode prealloc, | ||
150 | BdrvRequestFlags flags, Error **errp) | ||
151 | diff --git a/block/qcow.c b/block/qcow.c | ||
152 | index XXXXXXX..XXXXXXX 100644 | ||
153 | --- a/block/qcow.c | ||
154 | +++ b/block/qcow.c | ||
155 | @@ -XXX,XX +XXX,XX @@ static int qcow_reopen_prepare(BDRVReopenState *state, | ||
156 | * return 0 if not allocated, 1 if *result is assigned, and negative | ||
157 | * errno on failure. | ||
158 | */ | ||
159 | -static int coroutine_fn get_cluster_offset(BlockDriverState *bs, | ||
160 | - uint64_t offset, int allocate, | ||
161 | - int compressed_size, | ||
162 | - int n_start, int n_end, | ||
163 | - uint64_t *result) | ||
164 | +static int coroutine_fn GRAPH_RDLOCK | ||
165 | +get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate, | ||
166 | + int compressed_size, int n_start, int n_end, | ||
167 | + uint64_t *result) | ||
168 | { | ||
169 | BDRVQcowState *s = bs->opaque; | ||
170 | int min_index, i, j, l1_index, l2_index, ret; | ||
171 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_block_status(BlockDriverState *bs, | ||
172 | int64_t n; | ||
173 | uint64_t cluster_offset; | ||
174 | |||
175 | + assume_graph_lock(); /* FIXME */ | ||
176 | + | ||
177 | qemu_co_mutex_lock(&s->lock); | ||
178 | ret = get_cluster_offset(bs, offset, 0, 0, 0, 0, &cluster_offset); | ||
179 | qemu_co_mutex_unlock(&s->lock); | ||
180 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset, | ||
181 | uint8_t *buf; | ||
182 | void *orig_buf; | ||
183 | |||
184 | + assume_graph_lock(); /* FIXME */ | ||
185 | + | ||
186 | if (qiov->niov > 1) { | ||
187 | buf = orig_buf = qemu_try_blockalign(bs, qiov->size); | ||
188 | if (buf == NULL) { | ||
189 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, int64_t offset, | ||
190 | uint8_t *buf; | ||
191 | void *orig_buf; | ||
192 | |||
193 | + assume_graph_lock(); /* FIXME */ | ||
194 | + | ||
195 | s->cluster_cache_offset = -1; /* disable compressed cache */ | ||
196 | |||
197 | /* We must always copy the iov when encrypting, so we | ||
198 | @@ -XXX,XX +XXX,XX @@ qcow_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
199 | uint8_t *buf, *out_buf; | ||
200 | uint64_t cluster_offset; | ||
201 | |||
202 | + assume_graph_lock(); /* FIXME */ | ||
203 | + | ||
204 | buf = qemu_blockalign(bs, s->cluster_size); | ||
205 | if (bytes != s->cluster_size) { | ||
206 | if (bytes > s->cluster_size || | ||
207 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
208 | index XXXXXXX..XXXXXXX 100644 | ||
209 | --- a/block/qcow2.c | ||
210 | +++ b/block/qcow2.c | ||
211 | @@ -XXX,XX +XXX,XX @@ static int qcow2_set_up_encryption(BlockDriverState *bs, | ||
212 | * | ||
213 | * Returns: 0 on success, -errno on failure. | ||
214 | */ | ||
215 | -static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset, | ||
216 | - uint64_t new_length, PreallocMode mode, | ||
217 | - Error **errp) | ||
218 | +static int coroutine_fn GRAPH_RDLOCK | ||
219 | +preallocate_co(BlockDriverState *bs, uint64_t offset, uint64_t new_length, | ||
220 | + PreallocMode mode, Error **errp) | ||
221 | { | ||
222 | BDRVQcow2State *s = bs->opaque; | ||
223 | uint64_t bytes; | ||
224 | @@ -XXX,XX +XXX,XX @@ fail: | ||
225 | return ret; | ||
226 | } | ||
227 | |||
228 | -static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, | ||
229 | - bool exact, PreallocMode prealloc, | ||
230 | - BdrvRequestFlags flags, Error **errp) | ||
231 | +static int coroutine_fn GRAPH_RDLOCK | ||
232 | +qcow2_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, | ||
233 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp) | ||
234 | { | ||
235 | BDRVQcow2State *s = bs->opaque; | ||
236 | uint64_t old_length; | ||
237 | @@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs, | ||
238 | AioTaskPool *aio = NULL; | ||
239 | int ret = 0; | ||
240 | |||
241 | + assume_graph_lock(); /* FIXME */ | ||
242 | + | ||
243 | if (has_data_file(bs)) { | ||
244 | return -ENOTSUP; | ||
245 | } | ||
246 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
247 | index XXXXXXX..XXXXXXX 100644 | ||
248 | --- a/block/raw-format.c | ||
249 | +++ b/block/raw-format.c | ||
250 | @@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) | ||
251 | } | ||
252 | } | ||
253 | |||
254 | -static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset, | ||
255 | - bool exact, PreallocMode prealloc, | ||
256 | - BdrvRequestFlags flags, Error **errp) | ||
257 | +static int coroutine_fn GRAPH_RDLOCK | ||
258 | +raw_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, | ||
259 | + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp) | ||
260 | { | ||
261 | BDRVRawState *s = bs->opaque; | ||
262 | |||
263 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
264 | index XXXXXXX..XXXXXXX 100644 | ||
265 | --- a/block/vmdk.c | ||
266 | +++ b/block/vmdk.c | ||
267 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn | ||
268 | vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
269 | QEMUIOVector *qiov) | ||
270 | { | ||
271 | + assume_graph_lock(); /* FIXME */ | ||
272 | + | ||
273 | if (bytes == 0) { | ||
274 | /* The caller will write bytes 0 to signal EOF. | ||
275 | * When receive it, we align EOF to a sector boundary. */ | ||
276 | -- | ||
277 | 2.39.2 | diff view generated by jsdifflib |
1 | From: Alberto Garcia <berto@igalia.com> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_co_block_status() need to hold a reader lock for the graph. | ||
2 | 3 | ||
3 | At the moment I don't see how to make this function fail after the | 4 | For some places, we know that they will hold the lock, but we don't have |
4 | dirty bitmap has been created, but if that was possible then we would | 5 | the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock() |
5 | hit the assert(QLIST_EMPTY(&bs->dirty_bitmaps)) in bdrv_close(). | 6 | with a FIXME comment. These places will be removed once everything is |
7 | properly annotated. | ||
6 | 8 | ||
7 | Signed-off-by: Alberto Garcia <berto@igalia.com> | 9 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | Message-Id: <20230203152202.49054-5-kwolf@redhat.com> | ||
12 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | --- | 14 | --- |
10 | block/mirror.c | 3 +++ | 15 | block/coroutines.h | 2 +- |
11 | 1 file changed, 3 insertions(+) | 16 | include/block/block-copy.h | 6 +++--- |
17 | include/block/block-io.h | 22 +++++++++++----------- | ||
18 | include/block/block_int-common.h | 3 ++- | ||
19 | block/backup.c | 3 +++ | ||
20 | block/block-backend.c | 2 ++ | ||
21 | block/block-copy.c | 19 +++++++++++-------- | ||
22 | block/io.c | 13 ++++++++----- | ||
23 | block/mirror.c | 14 +++++++++----- | ||
24 | block/qcow.c | 11 ++++------- | ||
25 | block/quorum.c | 9 ++++----- | ||
26 | block/stream.c | 32 ++++++++++++++++++-------------- | ||
27 | qemu-img.c | 4 +++- | ||
28 | tests/unit/test-block-iothread.c | 3 ++- | ||
29 | 14 files changed, 81 insertions(+), 62 deletions(-) | ||
12 | 30 | ||
31 | diff --git a/block/coroutines.h b/block/coroutines.h | ||
32 | index XXXXXXX..XXXXXXX 100644 | ||
33 | --- a/block/coroutines.h | ||
34 | +++ b/block/coroutines.h | ||
35 | @@ -XXX,XX +XXX,XX @@ bdrv_co_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix); | ||
36 | int coroutine_fn GRAPH_RDLOCK | ||
37 | bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp); | ||
38 | |||
39 | -int coroutine_fn | ||
40 | +int coroutine_fn GRAPH_RDLOCK | ||
41 | bdrv_co_common_block_status_above(BlockDriverState *bs, | ||
42 | BlockDriverState *base, | ||
43 | bool include_base, | ||
44 | diff --git a/include/block/block-copy.h b/include/block/block-copy.h | ||
45 | index XXXXXXX..XXXXXXX 100644 | ||
46 | --- a/include/block/block-copy.h | ||
47 | +++ b/include/block/block-copy.h | ||
48 | @@ -XXX,XX +XXX,XX @@ void block_copy_set_progress_meter(BlockCopyState *s, ProgressMeter *pm); | ||
49 | void block_copy_state_free(BlockCopyState *s); | ||
50 | |||
51 | void block_copy_reset(BlockCopyState *s, int64_t offset, int64_t bytes); | ||
52 | -int64_t coroutine_fn block_copy_reset_unallocated(BlockCopyState *s, | ||
53 | - int64_t offset, | ||
54 | - int64_t *count); | ||
55 | + | ||
56 | +int64_t coroutine_fn GRAPH_RDLOCK | ||
57 | +block_copy_reset_unallocated(BlockCopyState *s, int64_t offset, int64_t *count); | ||
58 | |||
59 | int coroutine_fn block_copy(BlockCopyState *s, int64_t offset, int64_t bytes, | ||
60 | bool ignore_ratelimit, uint64_t timeout_ns, | ||
61 | diff --git a/include/block/block-io.h b/include/block/block-io.h | ||
62 | index XXXXXXX..XXXXXXX 100644 | ||
63 | --- a/include/block/block-io.h | ||
64 | +++ b/include/block/block-io.h | ||
65 | @@ -XXX,XX +XXX,XX @@ int bdrv_block_status(BlockDriverState *bs, int64_t offset, | ||
66 | int64_t bytes, int64_t *pnum, int64_t *map, | ||
67 | BlockDriverState **file); | ||
68 | |||
69 | -int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs, | ||
70 | - BlockDriverState *base, | ||
71 | - int64_t offset, int64_t bytes, | ||
72 | - int64_t *pnum, int64_t *map, | ||
73 | - BlockDriverState **file); | ||
74 | +int coroutine_fn GRAPH_RDLOCK | ||
75 | +bdrv_co_block_status_above(BlockDriverState *bs, BlockDriverState *base, | ||
76 | + int64_t offset, int64_t bytes, int64_t *pnum, | ||
77 | + int64_t *map, BlockDriverState **file); | ||
78 | int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, | ||
79 | int64_t offset, int64_t bytes, int64_t *pnum, | ||
80 | int64_t *map, BlockDriverState **file); | ||
81 | |||
82 | -int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, | ||
83 | - int64_t bytes, int64_t *pnum); | ||
84 | +int coroutine_fn GRAPH_RDLOCK | ||
85 | +bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
86 | + int64_t *pnum); | ||
87 | int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
88 | int64_t *pnum); | ||
89 | |||
90 | -int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top, | ||
91 | - BlockDriverState *base, | ||
92 | - bool include_base, int64_t offset, | ||
93 | - int64_t bytes, int64_t *pnum); | ||
94 | +int coroutine_fn GRAPH_RDLOCK | ||
95 | +bdrv_co_is_allocated_above(BlockDriverState *top, BlockDriverState *base, | ||
96 | + bool include_base, int64_t offset, int64_t bytes, | ||
97 | + int64_t *pnum); | ||
98 | int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, | ||
99 | bool include_base, int64_t offset, int64_t bytes, | ||
100 | int64_t *pnum); | ||
101 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
102 | index XXXXXXX..XXXXXXX 100644 | ||
103 | --- a/include/block/block_int-common.h | ||
104 | +++ b/include/block/block_int-common.h | ||
105 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
106 | * *pnum value for the block-status cache on protocol nodes, prior | ||
107 | * to clamping *pnum for return to its caller. | ||
108 | */ | ||
109 | - int coroutine_fn (*bdrv_co_block_status)(BlockDriverState *bs, | ||
110 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_block_status)( | ||
111 | + BlockDriverState *bs, | ||
112 | bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum, | ||
113 | int64_t *map, BlockDriverState **file); | ||
114 | |||
115 | diff --git a/block/backup.c b/block/backup.c | ||
116 | index XXXXXXX..XXXXXXX 100644 | ||
117 | --- a/block/backup.c | ||
118 | +++ b/block/backup.c | ||
119 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *job, Error **errp) | ||
120 | return -ECANCELED; | ||
121 | } | ||
122 | |||
123 | + /* rdlock protects the subsequent call to bdrv_is_allocated() */ | ||
124 | + bdrv_graph_co_rdlock(); | ||
125 | ret = block_copy_reset_unallocated(s->bcs, offset, &count); | ||
126 | + bdrv_graph_co_rdunlock(); | ||
127 | if (ret < 0) { | ||
128 | return ret; | ||
129 | } | ||
130 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
131 | index XXXXXXX..XXXXXXX 100644 | ||
132 | --- a/block/block-backend.c | ||
133 | +++ b/block/block-backend.c | ||
134 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_block_status_above(BlockBackend *blk, | ||
135 | BlockDriverState **file) | ||
136 | { | ||
137 | IO_CODE(); | ||
138 | + GRAPH_RDLOCK_GUARD(); | ||
139 | return bdrv_co_block_status_above(blk_bs(blk), base, offset, bytes, pnum, | ||
140 | map, file); | ||
141 | } | ||
142 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_is_allocated_above(BlockBackend *blk, | ||
143 | int64_t bytes, int64_t *pnum) | ||
144 | { | ||
145 | IO_CODE(); | ||
146 | + GRAPH_RDLOCK_GUARD(); | ||
147 | return bdrv_co_is_allocated_above(blk_bs(blk), base, include_base, offset, | ||
148 | bytes, pnum); | ||
149 | } | ||
150 | diff --git a/block/block-copy.c b/block/block-copy.c | ||
151 | index XXXXXXX..XXXXXXX 100644 | ||
152 | --- a/block/block-copy.c | ||
153 | +++ b/block/block-copy.c | ||
154 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int block_copy_task_entry(AioTask *task) | ||
155 | return ret; | ||
156 | } | ||
157 | |||
158 | -static coroutine_fn int block_copy_block_status(BlockCopyState *s, | ||
159 | - int64_t offset, | ||
160 | - int64_t bytes, int64_t *pnum) | ||
161 | +static coroutine_fn GRAPH_RDLOCK | ||
162 | +int block_copy_block_status(BlockCopyState *s, int64_t offset, int64_t bytes, | ||
163 | + int64_t *pnum) | ||
164 | { | ||
165 | int64_t num; | ||
166 | BlockDriverState *base; | ||
167 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int block_copy_block_status(BlockCopyState *s, | ||
168 | * Check if the cluster starting at offset is allocated or not. | ||
169 | * return via pnum the number of contiguous clusters sharing this allocation. | ||
170 | */ | ||
171 | -static int coroutine_fn block_copy_is_cluster_allocated(BlockCopyState *s, | ||
172 | - int64_t offset, | ||
173 | - int64_t *pnum) | ||
174 | +static int coroutine_fn GRAPH_RDLOCK | ||
175 | +block_copy_is_cluster_allocated(BlockCopyState *s, int64_t offset, | ||
176 | + int64_t *pnum) | ||
177 | { | ||
178 | BlockDriverState *bs = s->source->bs; | ||
179 | int64_t count, total_count = 0; | ||
180 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_is_cluster_allocated(BlockCopyState *s, | ||
181 | assert(QEMU_IS_ALIGNED(offset, s->cluster_size)); | ||
182 | |||
183 | while (true) { | ||
184 | + /* protected in backup_run() */ | ||
185 | ret = bdrv_co_is_allocated(bs, offset, bytes, &count); | ||
186 | if (ret < 0) { | ||
187 | return ret; | ||
188 | @@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn block_copy_reset_unallocated(BlockCopyState *s, | ||
189 | * Returns 1 if dirty clusters found and successfully copied, 0 if no dirty | ||
190 | * clusters found and -errno on failure. | ||
191 | */ | ||
192 | -static int coroutine_fn | ||
193 | +static int coroutine_fn GRAPH_RDLOCK | ||
194 | block_copy_dirty_clusters(BlockCopyCallState *call_state) | ||
195 | { | ||
196 | BlockCopyState *s = call_state->s; | ||
197 | @@ -XXX,XX +XXX,XX @@ void block_copy_kick(BlockCopyCallState *call_state) | ||
198 | * it means that some I/O operation failed in context of _this_ block_copy call, | ||
199 | * not some parallel operation. | ||
200 | */ | ||
201 | -static int coroutine_fn block_copy_common(BlockCopyCallState *call_state) | ||
202 | +static int coroutine_fn GRAPH_RDLOCK | ||
203 | +block_copy_common(BlockCopyCallState *call_state) | ||
204 | { | ||
205 | int ret; | ||
206 | BlockCopyState *s = call_state->s; | ||
207 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_copy_common(BlockCopyCallState *call_state) | ||
208 | |||
209 | static void coroutine_fn block_copy_async_co_entry(void *opaque) | ||
210 | { | ||
211 | + GRAPH_RDLOCK_GUARD(); | ||
212 | block_copy_common(opaque); | ||
213 | } | ||
214 | |||
215 | diff --git a/block/io.c b/block/io.c | ||
216 | index XXXXXXX..XXXXXXX 100644 | ||
217 | --- a/block/io.c | ||
218 | +++ b/block/io.c | ||
219 | @@ -XXX,XX +XXX,XX @@ int bdrv_flush_all(void) | ||
220 | * BDRV_BLOCK_OFFSET_VALID bit is set, 'map' and 'file' (if non-NULL) are | ||
221 | * set to the host mapping and BDS corresponding to the guest offset. | ||
222 | */ | ||
223 | -static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs, | ||
224 | - bool want_zero, | ||
225 | - int64_t offset, int64_t bytes, | ||
226 | - int64_t *pnum, int64_t *map, | ||
227 | - BlockDriverState **file) | ||
228 | +static int coroutine_fn GRAPH_RDLOCK | ||
229 | +bdrv_co_block_status(BlockDriverState *bs, bool want_zero, | ||
230 | + int64_t offset, int64_t bytes, | ||
231 | + int64_t *pnum, int64_t *map, BlockDriverState **file) | ||
232 | { | ||
233 | int64_t total_size; | ||
234 | int64_t n; /* bytes */ | ||
235 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs, | ||
236 | bool has_filtered_child; | ||
237 | |||
238 | assert(pnum); | ||
239 | + assert_bdrv_graph_readable(); | ||
240 | *pnum = 0; | ||
241 | total_size = bdrv_getlength(bs); | ||
242 | if (total_size < 0) { | ||
243 | @@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs, | ||
244 | IO_CODE(); | ||
245 | |||
246 | assert(!include_base || base); /* Can't include NULL base */ | ||
247 | + assert_bdrv_graph_readable(); | ||
248 | |||
249 | if (!depth) { | ||
250 | depth = &dummy; | ||
251 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, | ||
252 | int64_t pnum = bytes; | ||
253 | IO_CODE(); | ||
254 | |||
255 | + assume_graph_lock(); /* FIXME */ | ||
256 | + | ||
257 | if (!bytes) { | ||
258 | return 1; | ||
259 | } | ||
13 | diff --git a/block/mirror.c b/block/mirror.c | 260 | diff --git a/block/mirror.c b/block/mirror.c |
14 | index XXXXXXX..XXXXXXX 100644 | 261 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/block/mirror.c | 262 | --- a/block/mirror.c |
16 | +++ b/block/mirror.c | 263 | +++ b/block/mirror.c |
17 | @@ -XXX,XX +XXX,XX @@ fail: | 264 | @@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s) |
18 | g_free(s->replaces); | 265 | MirrorMethod mirror_method = MIRROR_METHOD_COPY; |
19 | blk_unref(s->target); | 266 | |
20 | bs_opaque->job = NULL; | 267 | assert(!(offset % s->granularity)); |
21 | + if (s->dirty_bitmap) { | 268 | - ret = bdrv_block_status_above(source, NULL, offset, |
22 | + bdrv_release_dirty_bitmap(bs, s->dirty_bitmap); | 269 | - nb_chunks * s->granularity, |
270 | - &io_bytes, NULL, NULL); | ||
271 | + WITH_GRAPH_RDLOCK_GUARD() { | ||
272 | + ret = bdrv_block_status_above(source, NULL, offset, | ||
273 | + nb_chunks * s->granularity, | ||
274 | + &io_bytes, NULL, NULL); | ||
23 | + } | 275 | + } |
24 | job_early_fail(&s->common.job); | 276 | if (ret < 0) { |
25 | } | 277 | io_bytes = MIN(nb_chunks * s->granularity, max_io_bytes); |
26 | 278 | } else if (ret & BDRV_BLOCK_DATA) { | |
279 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s) | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | - ret = bdrv_is_allocated_above(bs, s->base_overlay, true, offset, bytes, | ||
284 | - &count); | ||
285 | + WITH_GRAPH_RDLOCK_GUARD() { | ||
286 | + ret = bdrv_is_allocated_above(bs, s->base_overlay, true, offset, | ||
287 | + bytes, &count); | ||
288 | + } | ||
289 | if (ret < 0) { | ||
290 | return ret; | ||
291 | } | ||
292 | diff --git a/block/qcow.c b/block/qcow.c | ||
293 | index XXXXXXX..XXXXXXX 100644 | ||
294 | --- a/block/qcow.c | ||
295 | +++ b/block/qcow.c | ||
296 | @@ -XXX,XX +XXX,XX @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate, | ||
297 | return 1; | ||
298 | } | ||
299 | |||
300 | -static int coroutine_fn qcow_co_block_status(BlockDriverState *bs, | ||
301 | - bool want_zero, | ||
302 | - int64_t offset, int64_t bytes, | ||
303 | - int64_t *pnum, int64_t *map, | ||
304 | - BlockDriverState **file) | ||
305 | +static int coroutine_fn GRAPH_RDLOCK | ||
306 | +qcow_co_block_status(BlockDriverState *bs, bool want_zero, | ||
307 | + int64_t offset, int64_t bytes, int64_t *pnum, | ||
308 | + int64_t *map, BlockDriverState **file) | ||
309 | { | ||
310 | BDRVQcowState *s = bs->opaque; | ||
311 | int index_in_cluster, ret; | ||
312 | int64_t n; | ||
313 | uint64_t cluster_offset; | ||
314 | |||
315 | - assume_graph_lock(); /* FIXME */ | ||
316 | - | ||
317 | qemu_co_mutex_lock(&s->lock); | ||
318 | ret = get_cluster_offset(bs, offset, 0, 0, 0, 0, &cluster_offset); | ||
319 | qemu_co_mutex_unlock(&s->lock); | ||
320 | diff --git a/block/quorum.c b/block/quorum.c | ||
321 | index XXXXXXX..XXXXXXX 100644 | ||
322 | --- a/block/quorum.c | ||
323 | +++ b/block/quorum.c | ||
324 | @@ -XXX,XX +XXX,XX @@ static void quorum_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
325 | * return BDRV_BLOCK_ZERO if *all* children agree that a certain | ||
326 | * region contains zeroes, and BDRV_BLOCK_DATA otherwise. | ||
327 | */ | ||
328 | -static int coroutine_fn quorum_co_block_status(BlockDriverState *bs, | ||
329 | - bool want_zero, | ||
330 | - int64_t offset, int64_t count, | ||
331 | - int64_t *pnum, int64_t *map, | ||
332 | - BlockDriverState **file) | ||
333 | +static int coroutine_fn GRAPH_RDLOCK | ||
334 | +quorum_co_block_status(BlockDriverState *bs, bool want_zero, | ||
335 | + int64_t offset, int64_t count, | ||
336 | + int64_t *pnum, int64_t *map, BlockDriverState **file) | ||
337 | { | ||
338 | BDRVQuorumState *s = bs->opaque; | ||
339 | int i, ret; | ||
340 | diff --git a/block/stream.c b/block/stream.c | ||
341 | index XXXXXXX..XXXXXXX 100644 | ||
342 | --- a/block/stream.c | ||
343 | +++ b/block/stream.c | ||
344 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_run(Job *job, Error **errp) | ||
345 | |||
346 | copy = false; | ||
347 | |||
348 | - ret = bdrv_is_allocated(unfiltered_bs, offset, STREAM_CHUNK, &n); | ||
349 | - if (ret == 1) { | ||
350 | - /* Allocated in the top, no need to copy. */ | ||
351 | - } else if (ret >= 0) { | ||
352 | - /* Copy if allocated in the intermediate images. Limit to the | ||
353 | - * known-unallocated area [offset, offset+n*BDRV_SECTOR_SIZE). */ | ||
354 | - ret = bdrv_is_allocated_above(bdrv_cow_bs(unfiltered_bs), | ||
355 | - s->base_overlay, true, | ||
356 | - offset, n, &n); | ||
357 | - /* Finish early if end of backing file has been reached */ | ||
358 | - if (ret == 0 && n == 0) { | ||
359 | - n = len - offset; | ||
360 | + WITH_GRAPH_RDLOCK_GUARD() { | ||
361 | + ret = bdrv_is_allocated(unfiltered_bs, offset, STREAM_CHUNK, &n); | ||
362 | + if (ret == 1) { | ||
363 | + /* Allocated in the top, no need to copy. */ | ||
364 | + } else if (ret >= 0) { | ||
365 | + /* | ||
366 | + * Copy if allocated in the intermediate images. Limit to the | ||
367 | + * known-unallocated area [offset, offset+n*BDRV_SECTOR_SIZE). | ||
368 | + */ | ||
369 | + ret = bdrv_is_allocated_above(bdrv_cow_bs(unfiltered_bs), | ||
370 | + s->base_overlay, true, | ||
371 | + offset, n, &n); | ||
372 | + /* Finish early if end of backing file has been reached */ | ||
373 | + if (ret == 0 && n == 0) { | ||
374 | + n = len - offset; | ||
375 | + } | ||
376 | + | ||
377 | + copy = (ret > 0); | ||
378 | } | ||
379 | - | ||
380 | - copy = (ret > 0); | ||
381 | } | ||
382 | trace_stream_one_iteration(s, offset, n, ret); | ||
383 | if (copy) { | ||
384 | diff --git a/qemu-img.c b/qemu-img.c | ||
385 | index XXXXXXX..XXXXXXX 100644 | ||
386 | --- a/qemu-img.c | ||
387 | +++ b/qemu-img.c | ||
388 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn convert_co_do_copy(void *opaque) | ||
389 | qemu_co_mutex_unlock(&s->lock); | ||
390 | break; | ||
391 | } | ||
392 | - n = convert_iteration_sectors(s, s->sector_num); | ||
393 | + WITH_GRAPH_RDLOCK_GUARD() { | ||
394 | + n = convert_iteration_sectors(s, s->sector_num); | ||
395 | + } | ||
396 | if (n < 0) { | ||
397 | qemu_co_mutex_unlock(&s->lock); | ||
398 | s->ret = n; | ||
399 | diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c | ||
400 | index XXXXXXX..XXXXXXX 100644 | ||
401 | --- a/tests/unit/test-block-iothread.c | ||
402 | +++ b/tests/unit/test-block-iothread.c | ||
403 | @@ -XXX,XX +XXX,XX @@ static void test_sync_op_blk_truncate(BlockBackend *blk) | ||
404 | g_assert_cmpint(ret, ==, -EINVAL); | ||
405 | } | ||
406 | |||
407 | -static void test_sync_op_block_status(BdrvChild *c) | ||
408 | +/* Disable TSA to make bdrv_test.bdrv_co_block_status writable */ | ||
409 | +static void TSA_NO_TSA test_sync_op_block_status(BdrvChild *c) | ||
410 | { | ||
411 | int ret; | ||
412 | int64_t n; | ||
27 | -- | 413 | -- |
28 | 2.20.1 | 414 | 2.39.2 |
29 | |||
30 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | This adds GRAPH_RDLOCK annotations to declare that callers of | ||
2 | bdrv_co_ioctl() need to hold a reader lock for the graph. | ||
1 | 3 | ||
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
5 | Message-Id: <20230203152202.49054-6-kwolf@redhat.com> | ||
6 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | include/block/block-io.h | 3 ++- | ||
10 | include/block/block_int-common.h | 9 +++++---- | ||
11 | block/block-backend.c | 1 + | ||
12 | block/io.c | 1 + | ||
13 | block/raw-format.c | 4 ++-- | ||
14 | 5 files changed, 11 insertions(+), 7 deletions(-) | ||
15 | |||
16 | diff --git a/include/block/block-io.h b/include/block/block-io.h | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/include/block/block-io.h | ||
19 | +++ b/include/block/block-io.h | ||
20 | @@ -XXX,XX +XXX,XX @@ void bdrv_aio_cancel(BlockAIOCB *acb); | ||
21 | void bdrv_aio_cancel_async(BlockAIOCB *acb); | ||
22 | |||
23 | /* sg packet commands */ | ||
24 | -int coroutine_fn bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); | ||
25 | +int coroutine_fn GRAPH_RDLOCK | ||
26 | +bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); | ||
27 | |||
28 | /* Ensure contents are flushed to disk. */ | ||
29 | int coroutine_fn bdrv_co_flush(BlockDriverState *bs); | ||
30 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/include/block/block_int-common.h | ||
33 | +++ b/include/block/block_int-common.h | ||
34 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
35 | void coroutine_fn (*bdrv_co_lock_medium)(BlockDriverState *bs, bool locked); | ||
36 | |||
37 | /* to control generic scsi devices */ | ||
38 | - BlockAIOCB *(*bdrv_aio_ioctl)(BlockDriverState *bs, | ||
39 | - unsigned long int req, void *buf, | ||
40 | + BlockAIOCB *coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_aio_ioctl)( | ||
41 | + BlockDriverState *bs, unsigned long int req, void *buf, | ||
42 | BlockCompletionFunc *cb, void *opaque); | ||
43 | - int coroutine_fn (*bdrv_co_ioctl)(BlockDriverState *bs, | ||
44 | - unsigned long int req, void *buf); | ||
45 | + | ||
46 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_ioctl)( | ||
47 | + BlockDriverState *bs, unsigned long int req, void *buf); | ||
48 | |||
49 | /* | ||
50 | * Returns 0 for completed check, -errno for internal errors. | ||
51 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
52 | index XXXXXXX..XXXXXXX 100644 | ||
53 | --- a/block/block-backend.c | ||
54 | +++ b/block/block-backend.c | ||
55 | @@ -XXX,XX +XXX,XX @@ blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf) | ||
56 | IO_CODE(); | ||
57 | |||
58 | blk_wait_while_drained(blk); | ||
59 | + GRAPH_RDLOCK_GUARD(); | ||
60 | |||
61 | if (!blk_is_available(blk)) { | ||
62 | return -ENOMEDIUM; | ||
63 | diff --git a/block/io.c b/block/io.c | ||
64 | index XXXXXXX..XXXXXXX 100644 | ||
65 | --- a/block/io.c | ||
66 | +++ b/block/io.c | ||
67 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf) | ||
68 | }; | ||
69 | BlockAIOCB *acb; | ||
70 | IO_CODE(); | ||
71 | + assert_bdrv_graph_readable(); | ||
72 | |||
73 | bdrv_inc_in_flight(bs); | ||
74 | if (!drv || (!drv->bdrv_aio_ioctl && !drv->bdrv_co_ioctl)) { | ||
75 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
76 | index XXXXXXX..XXXXXXX 100644 | ||
77 | --- a/block/raw-format.c | ||
78 | +++ b/block/raw-format.c | ||
79 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_lock_medium(BlockDriverState *bs, bool locked) | ||
80 | bdrv_co_lock_medium(bs->file->bs, locked); | ||
81 | } | ||
82 | |||
83 | -static int coroutine_fn raw_co_ioctl(BlockDriverState *bs, | ||
84 | - unsigned long int req, void *buf) | ||
85 | +static int coroutine_fn GRAPH_RDLOCK | ||
86 | +raw_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) | ||
87 | { | ||
88 | BDRVRawState *s = bs->opaque; | ||
89 | if (s->offset || s->has_size) { | ||
90 | -- | ||
91 | 2.39.2 | diff view generated by jsdifflib |
1 | From: Peter Maydell <peter.maydell@linaro.org> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Taking the address of a field in a packed struct is a bad idea, because | 3 | This function is called in two different places: |
4 | it might not be actually aligned enough for that pointer type (and | 4 | - timer callback, which does not take the graph rdlock. |
5 | thus cause a crash on dereference on some host architectures). Newer | 5 | - bdrv_qed_drain_begin(), which is .bdrv_drain_begin() |
6 | versions of clang warn about this. Avoid the bug by generating the | 6 | callback documented as function that does not take the lock. |
7 | UUID into a local variable which is definitely safely aligned and | ||
8 | then copying it into place. | ||
9 | 7 | ||
10 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | 8 | Since it calls recursive functions that traverse the |
9 | graph, we need to protect them with the graph rdlock. | ||
10 | |||
11 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Message-Id: <20230203152202.49054-7-kwolf@redhat.com> | ||
14 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 16 | --- |
13 | block/vpc.c | 4 +++- | 17 | block/qed.c | 4 +++- |
14 | 1 file changed, 3 insertions(+), 1 deletion(-) | 18 | 1 file changed, 3 insertions(+), 1 deletion(-) |
15 | 19 | ||
16 | diff --git a/block/vpc.c b/block/vpc.c | 20 | diff --git a/block/qed.c b/block/qed.c |
17 | index XXXXXXX..XXXXXXX 100644 | 21 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block/vpc.c | 22 | --- a/block/qed.c |
19 | +++ b/block/vpc.c | 23 | +++ b/block/qed.c |
20 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts, | 24 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn qed_unplug_allocating_write_reqs(BDRVQEDState *s) |
21 | int64_t total_size; | 25 | qemu_co_mutex_unlock(&s->table_lock); |
22 | int disk_type; | 26 | } |
23 | int ret = -EIO; | 27 | |
24 | + QemuUUID uuid; | 28 | -static void coroutine_fn qed_need_check_timer(BDRVQEDState *s) |
25 | 29 | +static void coroutine_fn GRAPH_RDLOCK qed_need_check_timer(BDRVQEDState *s) | |
26 | assert(opts->driver == BLOCKDEV_DRIVER_VPC); | 30 | { |
27 | vpc_opts = &opts->u.vpc; | 31 | int ret; |
28 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts, | 32 | |
29 | 33 | trace_qed_need_check_timer_cb(s); | |
30 | footer->type = cpu_to_be32(disk_type); | 34 | + assert_bdrv_graph_readable(); |
31 | 35 | ||
32 | - qemu_uuid_generate(&footer->uuid); | 36 | if (!qed_plug_allocating_write_reqs(s)) { |
33 | + qemu_uuid_generate(&uuid); | 37 | return; |
34 | + footer->uuid = uuid; | 38 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn qed_need_check_timer(BDRVQEDState *s) |
35 | 39 | static void coroutine_fn qed_need_check_timer_entry(void *opaque) | |
36 | footer->checksum = cpu_to_be32(vpc_checksum(buf, HEADER_SIZE)); | 40 | { |
37 | 41 | BDRVQEDState *s = opaque; | |
42 | + GRAPH_RDLOCK_GUARD(); | ||
43 | |||
44 | qed_need_check_timer(opaque); | ||
45 | bdrv_dec_in_flight(s->bs); | ||
38 | -- | 46 | -- |
39 | 2.20.1 | 47 | 2.39.2 |
40 | |||
41 | diff view generated by jsdifflib |
1 | From: Fam Zheng <famz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | The extracted vmdk_init_extent takes a BlockBackend object and | 3 | This adds GRAPH_RDLOCK annotations to declare that callers of |
4 | initializes the format metadata. It is the common part between "qemu-img | 4 | bdrv_co_flush() need to hold a reader lock for the graph. |
5 | create" and "blockdev-create". | ||
6 | 5 | ||
7 | Add a "BlockBackend *pbb" parameter to vmdk_create_extent, to return the | 6 | For some places, we know that they will hold the lock, but we don't have |
8 | opened BB to the caller in the next patch. | 7 | the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock() |
8 | with a FIXME comment. These places will be removed once everything is | ||
9 | properly annotated. | ||
9 | 10 | ||
10 | Signed-off-by: Fam Zheng <famz@redhat.com> | 11 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
11 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | Message-Id: <20230203152202.49054-8-kwolf@redhat.com> | ||
14 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 16 | --- |
14 | block/vmdk.c | 69 ++++++++++++++++++++++++++++++++-------------------- | 17 | block/qcow2.h | 5 +++- |
15 | 1 file changed, 43 insertions(+), 26 deletions(-) | 18 | block/qed.h | 29 +++++++++++++-------- |
19 | include/block/block-io.h | 2 +- | ||
20 | include/block/block_int-common.h | 12 +++++---- | ||
21 | block/blkdebug.c | 2 +- | ||
22 | block/blklogwrites.c | 21 ++++++++++----- | ||
23 | block/blkreplay.c | 2 +- | ||
24 | block/blkverify.c | 2 +- | ||
25 | block/block-backend.c | 3 ++- | ||
26 | block/copy-before-write.c | 2 +- | ||
27 | block/file-posix.c | 4 +-- | ||
28 | block/io.c | 7 +++++ | ||
29 | block/mirror.c | 2 +- | ||
30 | block/preallocate.c | 2 +- | ||
31 | block/qed-check.c | 3 ++- | ||
32 | block/qed-table.c | 6 ++--- | ||
33 | block/qed.c | 44 +++++++++++++++++++------------- | ||
34 | block/quorum.c | 2 +- | ||
35 | block/throttle.c | 2 +- | ||
36 | block/vmdk.c | 6 +++-- | ||
37 | 20 files changed, 98 insertions(+), 60 deletions(-) | ||
16 | 38 | ||
39 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
40 | index XXXXXXX..XXXXXXX 100644 | ||
41 | --- a/block/qcow2.h | ||
42 | +++ b/block/qcow2.h | ||
43 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs); | ||
44 | /* qcow2-cluster.c functions */ | ||
45 | int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, | ||
46 | bool exact_size); | ||
47 | -int coroutine_fn qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size); | ||
48 | + | ||
49 | +int coroutine_fn GRAPH_RDLOCK | ||
50 | +qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size); | ||
51 | + | ||
52 | int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index); | ||
53 | int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, | ||
54 | uint8_t *buf, int nb_sectors, bool enc, Error **errp); | ||
55 | diff --git a/block/qed.h b/block/qed.h | ||
56 | index XXXXXXX..XXXXXXX 100644 | ||
57 | --- a/block/qed.h | ||
58 | +++ b/block/qed.h | ||
59 | @@ -XXX,XX +XXX,XX @@ void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table); | ||
60 | * Table I/O functions | ||
61 | */ | ||
62 | int coroutine_fn qed_read_l1_table_sync(BDRVQEDState *s); | ||
63 | -int coroutine_fn qed_write_l1_table(BDRVQEDState *s, unsigned int index, | ||
64 | - unsigned int n); | ||
65 | -int coroutine_fn qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index, | ||
66 | - unsigned int n); | ||
67 | + | ||
68 | +int coroutine_fn GRAPH_RDLOCK | ||
69 | +qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n); | ||
70 | + | ||
71 | +int coroutine_fn GRAPH_RDLOCK | ||
72 | +qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index, unsigned int n); | ||
73 | + | ||
74 | int coroutine_fn qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, | ||
75 | uint64_t offset); | ||
76 | int coroutine_fn qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, | ||
77 | uint64_t offset); | ||
78 | -int coroutine_fn qed_write_l2_table(BDRVQEDState *s, QEDRequest *request, | ||
79 | - unsigned int index, unsigned int n, | ||
80 | - bool flush); | ||
81 | -int coroutine_fn qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request, | ||
82 | - unsigned int index, unsigned int n, | ||
83 | - bool flush); | ||
84 | + | ||
85 | +int coroutine_fn GRAPH_RDLOCK | ||
86 | +qed_write_l2_table(BDRVQEDState *s, QEDRequest *request, unsigned int index, | ||
87 | + unsigned int n, bool flush); | ||
88 | + | ||
89 | +int coroutine_fn GRAPH_RDLOCK | ||
90 | +qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request, | ||
91 | + unsigned int index, unsigned int n, bool flush); | ||
92 | |||
93 | /** | ||
94 | * Cluster functions | ||
95 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn qed_find_cluster(BDRVQEDState *s, QEDRequest *request, | ||
96 | /** | ||
97 | * Consistency check | ||
98 | */ | ||
99 | -int coroutine_fn qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix); | ||
100 | +int coroutine_fn GRAPH_RDLOCK | ||
101 | +qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix); | ||
102 | + | ||
103 | |||
104 | QEDTable *qed_alloc_table(BDRVQEDState *s); | ||
105 | |||
106 | diff --git a/include/block/block-io.h b/include/block/block-io.h | ||
107 | index XXXXXXX..XXXXXXX 100644 | ||
108 | --- a/include/block/block-io.h | ||
109 | +++ b/include/block/block-io.h | ||
110 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn GRAPH_RDLOCK | ||
111 | bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); | ||
112 | |||
113 | /* Ensure contents are flushed to disk. */ | ||
114 | -int coroutine_fn bdrv_co_flush(BlockDriverState *bs); | ||
115 | +int coroutine_fn GRAPH_RDLOCK bdrv_co_flush(BlockDriverState *bs); | ||
116 | |||
117 | int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, | ||
118 | int64_t bytes); | ||
119 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
120 | index XXXXXXX..XXXXXXX 100644 | ||
121 | --- a/include/block/block_int-common.h | ||
122 | +++ b/include/block/block_int-common.h | ||
123 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
124 | BlockAIOCB *(*bdrv_aio_pwritev)(BlockDriverState *bs, | ||
125 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
126 | BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); | ||
127 | - BlockAIOCB *(*bdrv_aio_flush)(BlockDriverState *bs, | ||
128 | - BlockCompletionFunc *cb, void *opaque); | ||
129 | + BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_flush)( | ||
130 | + BlockDriverState *bs, BlockCompletionFunc *cb, void *opaque); | ||
131 | BlockAIOCB *(*bdrv_aio_pdiscard)(BlockDriverState *bs, | ||
132 | int64_t offset, int bytes, | ||
133 | BlockCompletionFunc *cb, void *opaque); | ||
134 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
135 | * layers, if needed. This function is needed for deterministic | ||
136 | * synchronization of the flush finishing callback. | ||
137 | */ | ||
138 | - int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs); | ||
139 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_flush)(BlockDriverState *bs); | ||
140 | |||
141 | /* Delete a created file. */ | ||
142 | int coroutine_fn (*bdrv_co_delete_file)(BlockDriverState *bs, | ||
143 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
144 | * Flushes all data that was already written to the OS all the way down to | ||
145 | * the disk (for example file-posix.c calls fsync()). | ||
146 | */ | ||
147 | - int coroutine_fn (*bdrv_co_flush_to_disk)(BlockDriverState *bs); | ||
148 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_flush_to_disk)( | ||
149 | + BlockDriverState *bs); | ||
150 | |||
151 | /* | ||
152 | * Flushes all internal caches to the OS. The data may still sit in a | ||
153 | * writeback cache of the host OS, but it will survive a crash of the qemu | ||
154 | * process. | ||
155 | */ | ||
156 | - int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs); | ||
157 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_flush_to_os)( | ||
158 | + BlockDriverState *bs); | ||
159 | |||
160 | /* | ||
161 | * Truncate @bs to @offset bytes using the given @prealloc mode | ||
162 | diff --git a/block/blkdebug.c b/block/blkdebug.c | ||
163 | index XXXXXXX..XXXXXXX 100644 | ||
164 | --- a/block/blkdebug.c | ||
165 | +++ b/block/blkdebug.c | ||
166 | @@ -XXX,XX +XXX,XX @@ blkdebug_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
167 | return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); | ||
168 | } | ||
169 | |||
170 | -static int coroutine_fn blkdebug_co_flush(BlockDriverState *bs) | ||
171 | +static int GRAPH_RDLOCK coroutine_fn blkdebug_co_flush(BlockDriverState *bs) | ||
172 | { | ||
173 | int err = rule_check(bs, 0, 0, BLKDEBUG_IO_TYPE_FLUSH); | ||
174 | |||
175 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | ||
176 | index XXXXXXX..XXXXXXX 100644 | ||
177 | --- a/block/blklogwrites.c | ||
178 | +++ b/block/blklogwrites.c | ||
179 | @@ -XXX,XX +XXX,XX @@ typedef struct BlkLogWritesFileReq { | ||
180 | uint64_t bytes; | ||
181 | int file_flags; | ||
182 | QEMUIOVector *qiov; | ||
183 | - int (*func)(struct BlkLogWritesFileReq *r); | ||
184 | + int GRAPH_RDLOCK_PTR (*func)(struct BlkLogWritesFileReq *r); | ||
185 | int file_ret; | ||
186 | } BlkLogWritesFileReq; | ||
187 | |||
188 | @@ -XXX,XX +XXX,XX @@ typedef struct { | ||
189 | int log_ret; | ||
190 | } BlkLogWritesLogReq; | ||
191 | |||
192 | -static void coroutine_fn blk_log_writes_co_do_log(BlkLogWritesLogReq *lr) | ||
193 | +static void coroutine_fn GRAPH_RDLOCK | ||
194 | +blk_log_writes_co_do_log(BlkLogWritesLogReq *lr) | ||
195 | { | ||
196 | BDRVBlkLogWritesState *s = lr->bs->opaque; | ||
197 | uint64_t cur_log_offset = s->cur_log_sector << s->sectorbits; | ||
198 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn blk_log_writes_co_do_log(BlkLogWritesLogReq *lr) | ||
199 | } | ||
200 | } | ||
201 | |||
202 | -static void coroutine_fn blk_log_writes_co_do_file(BlkLogWritesFileReq *fr) | ||
203 | +static void coroutine_fn GRAPH_RDLOCK | ||
204 | +blk_log_writes_co_do_file(BlkLogWritesFileReq *fr) | ||
205 | { | ||
206 | fr->file_ret = fr->func(fr); | ||
207 | } | ||
208 | |||
209 | -static int coroutine_fn | ||
210 | +static int coroutine_fn GRAPH_RDLOCK | ||
211 | blk_log_writes_co_log(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | ||
212 | QEMUIOVector *qiov, int flags, | ||
213 | - int (*file_func)(BlkLogWritesFileReq *r), | ||
214 | + int /*GRAPH_RDLOCK*/ (*file_func)(BlkLogWritesFileReq *r), | ||
215 | uint64_t entry_flags, bool is_zero_write) | ||
216 | { | ||
217 | QEMUIOVector log_qiov; | ||
218 | @@ -XXX,XX +XXX,XX @@ blk_log_writes_co_do_file_pwrite_zeroes(BlkLogWritesFileReq *fr) | ||
219 | fr->file_flags); | ||
220 | } | ||
221 | |||
222 | -static int coroutine_fn blk_log_writes_co_do_file_flush(BlkLogWritesFileReq *fr) | ||
223 | +static int coroutine_fn GRAPH_RDLOCK | ||
224 | +blk_log_writes_co_do_file_flush(BlkLogWritesFileReq *fr) | ||
225 | { | ||
226 | return bdrv_co_flush(fr->bs->file->bs); | ||
227 | } | ||
228 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn | ||
229 | blk_log_writes_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
230 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
231 | { | ||
232 | + assume_graph_lock(); /* FIXME */ | ||
233 | return blk_log_writes_co_log(bs, offset, bytes, qiov, flags, | ||
234 | blk_log_writes_co_do_file_pwritev, 0, false); | ||
235 | } | ||
236 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn | ||
237 | blk_log_writes_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, | ||
238 | int64_t bytes, BdrvRequestFlags flags) | ||
239 | { | ||
240 | + assume_graph_lock(); /* FIXME */ | ||
241 | return blk_log_writes_co_log(bs, offset, bytes, NULL, flags, | ||
242 | blk_log_writes_co_do_file_pwrite_zeroes, 0, | ||
243 | true); | ||
244 | } | ||
245 | |||
246 | -static int coroutine_fn blk_log_writes_co_flush_to_disk(BlockDriverState *bs) | ||
247 | +static int coroutine_fn GRAPH_RDLOCK | ||
248 | +blk_log_writes_co_flush_to_disk(BlockDriverState *bs) | ||
249 | { | ||
250 | return blk_log_writes_co_log(bs, 0, 0, NULL, 0, | ||
251 | blk_log_writes_co_do_file_flush, | ||
252 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blk_log_writes_co_flush_to_disk(BlockDriverState *bs) | ||
253 | static int coroutine_fn | ||
254 | blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
255 | { | ||
256 | + assume_graph_lock(); /* FIXME */ | ||
257 | return blk_log_writes_co_log(bs, offset, bytes, NULL, 0, | ||
258 | blk_log_writes_co_do_file_pdiscard, | ||
259 | LOG_DISCARD_FLAG, false); | ||
260 | diff --git a/block/blkreplay.c b/block/blkreplay.c | ||
261 | index XXXXXXX..XXXXXXX 100644 | ||
262 | --- a/block/blkreplay.c | ||
263 | +++ b/block/blkreplay.c | ||
264 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs, | ||
265 | return ret; | ||
266 | } | ||
267 | |||
268 | -static int coroutine_fn blkreplay_co_flush(BlockDriverState *bs) | ||
269 | +static int coroutine_fn GRAPH_RDLOCK blkreplay_co_flush(BlockDriverState *bs) | ||
270 | { | ||
271 | uint64_t reqid = blkreplay_next_id(); | ||
272 | int ret = bdrv_co_flush(bs->file->bs); | ||
273 | diff --git a/block/blkverify.c b/block/blkverify.c | ||
274 | index XXXXXXX..XXXXXXX 100644 | ||
275 | --- a/block/blkverify.c | ||
276 | +++ b/block/blkverify.c | ||
277 | @@ -XXX,XX +XXX,XX @@ blkverify_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
278 | return blkverify_co_prwv(bs, &r, offset, bytes, qiov, qiov, flags, true); | ||
279 | } | ||
280 | |||
281 | -static int coroutine_fn blkverify_co_flush(BlockDriverState *bs) | ||
282 | +static int coroutine_fn GRAPH_RDLOCK blkverify_co_flush(BlockDriverState *bs) | ||
283 | { | ||
284 | BDRVBlkverifyState *s = bs->opaque; | ||
285 | |||
286 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
287 | index XXXXXXX..XXXXXXX 100644 | ||
288 | --- a/block/block-backend.c | ||
289 | +++ b/block/block-backend.c | ||
290 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, | ||
291 | /* To be called between exactly one pair of blk_inc/dec_in_flight() */ | ||
292 | static int coroutine_fn blk_co_do_flush(BlockBackend *blk) | ||
293 | { | ||
294 | - blk_wait_while_drained(blk); | ||
295 | IO_CODE(); | ||
296 | + blk_wait_while_drained(blk); | ||
297 | + GRAPH_RDLOCK_GUARD(); | ||
298 | |||
299 | if (!blk_is_available(blk)) { | ||
300 | return -ENOMEDIUM; | ||
301 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
302 | index XXXXXXX..XXXXXXX 100644 | ||
303 | --- a/block/copy-before-write.c | ||
304 | +++ b/block/copy-before-write.c | ||
305 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int cbw_co_pwritev(BlockDriverState *bs, | ||
306 | return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); | ||
307 | } | ||
308 | |||
309 | -static int coroutine_fn cbw_co_flush(BlockDriverState *bs) | ||
310 | +static int coroutine_fn GRAPH_RDLOCK cbw_co_flush(BlockDriverState *bs) | ||
311 | { | ||
312 | if (!bs->file) { | ||
313 | return 0; | ||
314 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
315 | index XXXXXXX..XXXXXXX 100644 | ||
316 | --- a/block/file-posix.c | ||
317 | +++ b/block/file-posix.c | ||
318 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn check_cache_dropped(BlockDriverState *bs, Error **errp) | ||
319 | } | ||
320 | #endif /* __linux__ */ | ||
321 | |||
322 | -static void coroutine_fn raw_co_invalidate_cache(BlockDriverState *bs, | ||
323 | - Error **errp) | ||
324 | +static void coroutine_fn GRAPH_RDLOCK | ||
325 | +raw_co_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
326 | { | ||
327 | BDRVRawState *s = bs->opaque; | ||
328 | int ret; | ||
329 | diff --git a/block/io.c b/block/io.c | ||
330 | index XXXXXXX..XXXXXXX 100644 | ||
331 | --- a/block/io.c | ||
332 | +++ b/block/io.c | ||
333 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset, | ||
334 | int ret; | ||
335 | IO_CODE(); | ||
336 | |||
337 | + assume_graph_lock(); /* FIXME */ | ||
338 | + | ||
339 | ret = bdrv_co_pwrite(child, offset, bytes, buf, flags); | ||
340 | if (ret < 0) { | ||
341 | return ret; | ||
342 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs, | ||
343 | QEMUIOVector local_qiov; | ||
344 | int ret; | ||
345 | |||
346 | + assume_graph_lock(); /* FIXME */ | ||
347 | + | ||
348 | bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort); | ||
349 | |||
350 | if (!drv) { | ||
351 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, | ||
352 | int head = 0; | ||
353 | int tail = 0; | ||
354 | |||
355 | + assume_graph_lock(); /* FIXME */ | ||
356 | + | ||
357 | int64_t max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, | ||
358 | INT64_MAX); | ||
359 | int alignment = MAX(bs->bl.pwrite_zeroes_alignment, | ||
360 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs) | ||
361 | int ret = 0; | ||
362 | IO_CODE(); | ||
363 | |||
364 | + assert_bdrv_graph_readable(); | ||
365 | bdrv_inc_in_flight(bs); | ||
366 | |||
367 | if (!bdrv_co_is_inserted(bs) || bdrv_is_read_only(bs) || | ||
368 | diff --git a/block/mirror.c b/block/mirror.c | ||
369 | index XXXXXXX..XXXXXXX 100644 | ||
370 | --- a/block/mirror.c | ||
371 | +++ b/block/mirror.c | ||
372 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs, | ||
373 | return ret; | ||
374 | } | ||
375 | |||
376 | -static int coroutine_fn bdrv_mirror_top_flush(BlockDriverState *bs) | ||
377 | +static int coroutine_fn GRAPH_RDLOCK bdrv_mirror_top_flush(BlockDriverState *bs) | ||
378 | { | ||
379 | if (bs->backing == NULL) { | ||
380 | /* we can be here after failed bdrv_append in mirror_start_job */ | ||
381 | diff --git a/block/preallocate.c b/block/preallocate.c | ||
382 | index XXXXXXX..XXXXXXX 100644 | ||
383 | --- a/block/preallocate.c | ||
384 | +++ b/block/preallocate.c | ||
385 | @@ -XXX,XX +XXX,XX @@ preallocate_co_truncate(BlockDriverState *bs, int64_t offset, | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | -static int coroutine_fn preallocate_co_flush(BlockDriverState *bs) | ||
390 | +static int coroutine_fn GRAPH_RDLOCK preallocate_co_flush(BlockDriverState *bs) | ||
391 | { | ||
392 | return bdrv_co_flush(bs->file->bs); | ||
393 | } | ||
394 | diff --git a/block/qed-check.c b/block/qed-check.c | ||
395 | index XXXXXXX..XXXXXXX 100644 | ||
396 | --- a/block/qed-check.c | ||
397 | +++ b/block/qed-check.c | ||
398 | @@ -XXX,XX +XXX,XX @@ static unsigned int qed_check_l2_table(QEDCheck *check, QEDTable *table) | ||
399 | /** | ||
400 | * Descend tables and check each cluster is referenced once only | ||
401 | */ | ||
402 | -static int coroutine_fn qed_check_l1_table(QEDCheck *check, QEDTable *table) | ||
403 | +static int coroutine_fn GRAPH_RDLOCK | ||
404 | +qed_check_l1_table(QEDCheck *check, QEDTable *table) | ||
405 | { | ||
406 | BDRVQEDState *s = check->s; | ||
407 | unsigned int i, num_invalid_l1 = 0; | ||
408 | diff --git a/block/qed-table.c b/block/qed-table.c | ||
409 | index XXXXXXX..XXXXXXX 100644 | ||
410 | --- a/block/qed-table.c | ||
411 | +++ b/block/qed-table.c | ||
412 | @@ -XXX,XX +XXX,XX @@ out: | ||
413 | * | ||
414 | * Called with table_lock held. | ||
415 | */ | ||
416 | -static int coroutine_fn qed_write_table(BDRVQEDState *s, uint64_t offset, | ||
417 | - QEDTable *table, unsigned int index, | ||
418 | - unsigned int n, bool flush) | ||
419 | +static int coroutine_fn GRAPH_RDLOCK | ||
420 | +qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table, | ||
421 | + unsigned int index, unsigned int n, bool flush) | ||
422 | { | ||
423 | unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1; | ||
424 | unsigned int start, end, i; | ||
425 | diff --git a/block/qed.c b/block/qed.c | ||
426 | index XXXXXXX..XXXXXXX 100644 | ||
427 | --- a/block/qed.c | ||
428 | +++ b/block/qed.c | ||
429 | @@ -XXX,XX +XXX,XX @@ static void bdrv_qed_init_state(BlockDriverState *bs) | ||
430 | } | ||
431 | |||
432 | /* Called with table_lock held. */ | ||
433 | -static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options, | ||
434 | - int flags, Error **errp) | ||
435 | +static int coroutine_fn GRAPH_RDLOCK | ||
436 | +bdrv_qed_do_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) | ||
437 | { | ||
438 | BDRVQEDState *s = bs->opaque; | ||
439 | QEDHeader le_header; | ||
440 | @@ -XXX,XX +XXX,XX @@ typedef struct QEDOpenCo { | ||
441 | int ret; | ||
442 | } QEDOpenCo; | ||
443 | |||
444 | -static void coroutine_fn bdrv_qed_open_entry(void *opaque) | ||
445 | +static void coroutine_fn GRAPH_RDLOCK bdrv_qed_open_entry(void *opaque) | ||
446 | { | ||
447 | QEDOpenCo *qoc = opaque; | ||
448 | BDRVQEDState *s = qoc->bs->opaque; | ||
449 | @@ -XXX,XX +XXX,XX @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, | ||
450 | }; | ||
451 | int ret; | ||
452 | |||
453 | + assume_graph_lock(); /* FIXME */ | ||
454 | + | ||
455 | ret = bdrv_open_file_child(NULL, options, "file", bs, errp); | ||
456 | if (ret < 0) { | ||
457 | return ret; | ||
458 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn qed_aio_complete(QEDAIOCB *acb) | ||
459 | * | ||
460 | * Called with table_lock held. | ||
461 | */ | ||
462 | -static int coroutine_fn qed_aio_write_l1_update(QEDAIOCB *acb) | ||
463 | +static int coroutine_fn GRAPH_RDLOCK qed_aio_write_l1_update(QEDAIOCB *acb) | ||
464 | { | ||
465 | BDRVQEDState *s = acb_to_s(acb); | ||
466 | CachedL2Table *l2_table = acb->request.l2_table; | ||
467 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_write_l1_update(QEDAIOCB *acb) | ||
468 | * | ||
469 | * Called with table_lock held. | ||
470 | */ | ||
471 | -static int coroutine_fn qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset) | ||
472 | +static int coroutine_fn GRAPH_RDLOCK | ||
473 | +qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset) | ||
474 | { | ||
475 | BDRVQEDState *s = acb_to_s(acb); | ||
476 | bool need_alloc = acb->find_cluster_ret == QED_CLUSTER_L1; | ||
477 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_write_main(QEDAIOCB *acb) | ||
478 | * | ||
479 | * Called with table_lock held. | ||
480 | */ | ||
481 | -static int coroutine_fn qed_aio_write_cow(QEDAIOCB *acb) | ||
482 | +static int coroutine_fn GRAPH_RDLOCK qed_aio_write_cow(QEDAIOCB *acb) | ||
483 | { | ||
484 | BDRVQEDState *s = acb_to_s(acb); | ||
485 | uint64_t start, len, offset; | ||
486 | @@ -XXX,XX +XXX,XX @@ static bool qed_should_set_need_check(BDRVQEDState *s) | ||
487 | * | ||
488 | * Called with table_lock held. | ||
489 | */ | ||
490 | -static int coroutine_fn qed_aio_write_alloc(QEDAIOCB *acb, size_t len) | ||
491 | +static int coroutine_fn GRAPH_RDLOCK | ||
492 | +qed_aio_write_alloc(QEDAIOCB *acb, size_t len) | ||
493 | { | ||
494 | BDRVQEDState *s = acb_to_s(acb); | ||
495 | int ret; | ||
496 | @@ -XXX,XX +XXX,XX @@ out: | ||
497 | * | ||
498 | * Called with table_lock held. | ||
499 | */ | ||
500 | -static int coroutine_fn qed_aio_write_data(void *opaque, int ret, | ||
501 | - uint64_t offset, size_t len) | ||
502 | +static int coroutine_fn GRAPH_RDLOCK | ||
503 | +qed_aio_write_data(void *opaque, int ret, uint64_t offset, size_t len) | ||
504 | { | ||
505 | QEDAIOCB *acb = opaque; | ||
506 | |||
507 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_read_data(void *opaque, int ret, | ||
508 | /** | ||
509 | * Begin next I/O or complete the request | ||
510 | */ | ||
511 | -static int coroutine_fn qed_aio_next_io(QEDAIOCB *acb) | ||
512 | +static int coroutine_fn GRAPH_RDLOCK qed_aio_next_io(QEDAIOCB *acb) | ||
513 | { | ||
514 | BDRVQEDState *s = acb_to_s(acb); | ||
515 | uint64_t offset; | ||
516 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_aio_next_io(QEDAIOCB *acb) | ||
517 | return ret; | ||
518 | } | ||
519 | |||
520 | -static int coroutine_fn qed_co_request(BlockDriverState *bs, int64_t sector_num, | ||
521 | - QEMUIOVector *qiov, int nb_sectors, | ||
522 | - int flags) | ||
523 | +static int coroutine_fn GRAPH_RDLOCK | ||
524 | +qed_co_request(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, | ||
525 | + int nb_sectors, int flags) | ||
526 | { | ||
527 | QEDAIOCB acb = { | ||
528 | .bs = bs, | ||
529 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_readv(BlockDriverState *bs, | ||
530 | int64_t sector_num, int nb_sectors, | ||
531 | QEMUIOVector *qiov) | ||
532 | { | ||
533 | + assume_graph_lock(); /* FIXME */ | ||
534 | return qed_co_request(bs, sector_num, qiov, nb_sectors, 0); | ||
535 | } | ||
536 | |||
537 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_writev(BlockDriverState *bs, | ||
538 | int64_t sector_num, int nb_sectors, | ||
539 | QEMUIOVector *qiov, int flags) | ||
540 | { | ||
541 | + assume_graph_lock(); /* FIXME */ | ||
542 | return qed_co_request(bs, sector_num, qiov, nb_sectors, QED_AIOCB_WRITE); | ||
543 | } | ||
544 | |||
545 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs, | ||
546 | { | ||
547 | BDRVQEDState *s = bs->opaque; | ||
548 | |||
549 | + assume_graph_lock(); /* FIXME */ | ||
550 | + | ||
551 | /* | ||
552 | * Zero writes start without an I/O buffer. If a buffer becomes necessary | ||
553 | * then it will be allocated during request processing. | ||
554 | @@ -XXX,XX +XXX,XX @@ static int bdrv_qed_change_backing_file(BlockDriverState *bs, | ||
555 | return ret; | ||
556 | } | ||
557 | |||
558 | -static void coroutine_fn bdrv_qed_co_invalidate_cache(BlockDriverState *bs, | ||
559 | - Error **errp) | ||
560 | +static void coroutine_fn GRAPH_RDLOCK | ||
561 | +bdrv_qed_co_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
562 | { | ||
563 | BDRVQEDState *s = bs->opaque; | ||
564 | int ret; | ||
565 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_qed_co_invalidate_cache(BlockDriverState *bs, | ||
566 | } | ||
567 | } | ||
568 | |||
569 | -static int coroutine_fn bdrv_qed_co_check(BlockDriverState *bs, | ||
570 | - BdrvCheckResult *result, | ||
571 | - BdrvCheckMode fix) | ||
572 | +static int coroutine_fn GRAPH_RDLOCK | ||
573 | +bdrv_qed_co_check(BlockDriverState *bs, BdrvCheckResult *result, | ||
574 | + BdrvCheckMode fix) | ||
575 | { | ||
576 | BDRVQEDState *s = bs->opaque; | ||
577 | int ret; | ||
578 | diff --git a/block/quorum.c b/block/quorum.c | ||
579 | index XXXXXXX..XXXXXXX 100644 | ||
580 | --- a/block/quorum.c | ||
581 | +++ b/block/quorum.c | ||
582 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn quorum_co_getlength(BlockDriverState *bs) | ||
583 | return result; | ||
584 | } | ||
585 | |||
586 | -static coroutine_fn int quorum_co_flush(BlockDriverState *bs) | ||
587 | +static coroutine_fn GRAPH_RDLOCK int quorum_co_flush(BlockDriverState *bs) | ||
588 | { | ||
589 | BDRVQuorumState *s = bs->opaque; | ||
590 | QuorumVoteVersion *winner = NULL; | ||
591 | diff --git a/block/throttle.c b/block/throttle.c | ||
592 | index XXXXXXX..XXXXXXX 100644 | ||
593 | --- a/block/throttle.c | ||
594 | +++ b/block/throttle.c | ||
595 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn throttle_co_pwritev_compressed(BlockDriverState *bs, | ||
596 | BDRV_REQ_WRITE_COMPRESSED); | ||
597 | } | ||
598 | |||
599 | -static int coroutine_fn throttle_co_flush(BlockDriverState *bs) | ||
600 | +static int coroutine_fn GRAPH_RDLOCK throttle_co_flush(BlockDriverState *bs) | ||
601 | { | ||
602 | return bdrv_co_flush(bs->file->bs); | ||
603 | } | ||
17 | diff --git a/block/vmdk.c b/block/vmdk.c | 604 | diff --git a/block/vmdk.c b/block/vmdk.c |
18 | index XXXXXXX..XXXXXXX 100644 | 605 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/block/vmdk.c | 606 | --- a/block/vmdk.c |
20 | +++ b/block/vmdk.c | 607 | +++ b/block/vmdk.c |
21 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_pwrite_zeroes(BlockDriverState *bs, | 608 | @@ -XXX,XX +XXX,XX @@ exit: |
22 | return ret; | 609 | return ret; |
23 | } | 610 | } |
24 | 611 | ||
25 | -static int vmdk_create_extent(const char *filename, int64_t filesize, | 612 | -static int coroutine_fn vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, |
26 | - bool flat, bool compress, bool zeroed_grain, | 613 | - uint32_t offset) |
27 | - QemuOpts *opts, Error **errp) | 614 | +static int coroutine_fn GRAPH_RDLOCK |
28 | +static int vmdk_init_extent(BlockBackend *blk, | 615 | +vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, uint32_t offset) |
29 | + int64_t filesize, bool flat, | 616 | { |
30 | + bool compress, bool zeroed_grain, | 617 | offset = cpu_to_le32(offset); |
31 | + Error **errp) | 618 | /* update L2 table */ |
32 | { | 619 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_pwritev(BlockDriverState *bs, uint64_t offset, |
33 | int ret, i; | 620 | uint64_t bytes_done = 0; |
34 | - BlockBackend *blk = NULL; | 621 | VmdkMetaData m_data; |
35 | VMDK4Header header; | 622 | |
36 | - Error *local_err = NULL; | 623 | + assume_graph_lock(); /* FIXME */ |
37 | uint32_t tmp, magic, grains, gd_sectors, gt_size, gt_count; | 624 | + |
38 | uint32_t *gd_buf = NULL; | 625 | if (DIV_ROUND_UP(offset, BDRV_SECTOR_SIZE) > bs->total_sectors) { |
39 | int gd_buf_size; | 626 | error_report("Wrong offset: offset=0x%" PRIx64 |
40 | 627 | " total_sectors=0x%" PRIx64, | |
41 | - ret = bdrv_create_file(filename, opts, &local_err); | ||
42 | - if (ret < 0) { | ||
43 | - error_propagate(errp, local_err); | ||
44 | - goto exit; | ||
45 | - } | ||
46 | - | ||
47 | - blk = blk_new_open(filename, NULL, NULL, | ||
48 | - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, | ||
49 | - &local_err); | ||
50 | - if (blk == NULL) { | ||
51 | - error_propagate(errp, local_err); | ||
52 | - ret = -EIO; | ||
53 | - goto exit; | ||
54 | - } | ||
55 | - | ||
56 | - blk_set_allow_write_beyond_eof(blk, true); | ||
57 | - | ||
58 | if (flat) { | ||
59 | ret = blk_truncate(blk, filesize, PREALLOC_MODE_OFF, errp); | ||
60 | goto exit; | ||
61 | @@ -XXX,XX +XXX,XX @@ static int vmdk_create_extent(const char *filename, int64_t filesize, | ||
62 | gd_buf, gd_buf_size, 0); | ||
63 | if (ret < 0) { | ||
64 | error_setg(errp, QERR_IO_ERROR); | ||
65 | - goto exit; | ||
66 | } | ||
67 | |||
68 | ret = 0; | ||
69 | +exit: | ||
70 | + g_free(gd_buf); | ||
71 | + return ret; | ||
72 | +} | ||
73 | + | ||
74 | +static int vmdk_create_extent(const char *filename, int64_t filesize, | ||
75 | + bool flat, bool compress, bool zeroed_grain, | ||
76 | + BlockBackend **pbb, | ||
77 | + QemuOpts *opts, Error **errp) | ||
78 | +{ | ||
79 | + int ret; | ||
80 | + BlockBackend *blk = NULL; | ||
81 | + Error *local_err = NULL; | ||
82 | + | ||
83 | + ret = bdrv_create_file(filename, opts, &local_err); | ||
84 | + if (ret < 0) { | ||
85 | + error_propagate(errp, local_err); | ||
86 | + goto exit; | ||
87 | + } | ||
88 | + | ||
89 | + blk = blk_new_open(filename, NULL, NULL, | ||
90 | + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, | ||
91 | + &local_err); | ||
92 | + if (blk == NULL) { | ||
93 | + error_propagate(errp, local_err); | ||
94 | + ret = -EIO; | ||
95 | + goto exit; | ||
96 | + } | ||
97 | + | ||
98 | + blk_set_allow_write_beyond_eof(blk, true); | ||
99 | + | ||
100 | + ret = vmdk_init_extent(blk, filesize, flat, compress, zeroed_grain, errp); | ||
101 | exit: | ||
102 | if (blk) { | ||
103 | - blk_unref(blk); | ||
104 | + if (pbb) { | ||
105 | + *pbb = blk; | ||
106 | + } else { | ||
107 | + blk_unref(blk); | ||
108 | + blk = NULL; | ||
109 | + } | ||
110 | } | ||
111 | - g_free(gd_buf); | ||
112 | return ret; | ||
113 | } | ||
114 | |||
115 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_create_opts(const char *filename, QemuOpts *opts | ||
116 | snprintf(ext_filename, PATH_MAX, "%s%s", path, desc_filename); | ||
117 | |||
118 | if (vmdk_create_extent(ext_filename, size, | ||
119 | - flat, compress, zeroed_grain, opts, errp)) { | ||
120 | + flat, compress, zeroed_grain, NULL, opts, errp)) { | ||
121 | ret = -EINVAL; | ||
122 | goto exit; | ||
123 | } | ||
124 | -- | 628 | -- |
125 | 2.20.1 | 629 | 2.39.2 |
126 | |||
127 | diff view generated by jsdifflib |
1 | From: Thomas Huth <thuth@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | The last user of blk_attach_dev_legacy() was the code in xen_disk which | 3 | This adds GRAPH_RDLOCK annotations to declare that callers of |
4 | has recently been reworked. Now there is no user for this legacy function | 4 | bdrv_co_pdiscard() need to hold a reader lock for the graph. |
5 | anymore. Thus we can finally remove all code related to the "legacy_dev" | ||
6 | flag, too, and turn the related "void *" in block-backend.c into proper | ||
7 | "DeviceState *" to fix some of the remaining TODOs there. | ||
8 | 5 | ||
9 | Signed-off-by: Thomas Huth <thuth@redhat.com> | 6 | For some places, we know that they will hold the lock, but we don't have |
10 | Reviewed-by: Stefano Garzarella <sgarzare@redhat.com> | 7 | the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock() |
8 | with a FIXME comment. These places will be removed once everything is | ||
9 | properly annotated. | ||
10 | |||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | Message-Id: <20230203152202.49054-9-kwolf@redhat.com> | ||
13 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | --- | 15 | --- |
13 | include/sysemu/block-backend.h | 5 ++-- | 16 | include/block/block-io.h | 5 +++-- |
14 | block/block-backend.c | 54 ++++++---------------------------- | 17 | include/block/block_int-common.h | 15 +++++++++------ |
15 | 2 files changed, 11 insertions(+), 48 deletions(-) | 18 | include/block/block_int-io.h | 2 +- |
19 | block/blkdebug.c | 4 ++-- | ||
20 | block/blklogwrites.c | 5 ++--- | ||
21 | block/blkreplay.c | 4 ++-- | ||
22 | block/block-backend.c | 1 + | ||
23 | block/copy-before-write.c | 8 ++++---- | ||
24 | block/copy-on-read.c | 4 ++-- | ||
25 | block/filter-compress.c | 4 ++-- | ||
26 | block/io.c | 2 ++ | ||
27 | block/mirror.c | 14 +++++++++----- | ||
28 | block/preallocate.c | 4 ++-- | ||
29 | block/raw-format.c | 4 ++-- | ||
30 | block/snapshot-access.c | 4 ++-- | ||
31 | block/throttle.c | 4 ++-- | ||
32 | 16 files changed, 47 insertions(+), 37 deletions(-) | ||
16 | 33 | ||
17 | diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h | 34 | diff --git a/include/block/block-io.h b/include/block/block-io.h |
18 | index XXXXXXX..XXXXXXX 100644 | 35 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/include/sysemu/block-backend.h | 36 | --- a/include/block/block-io.h |
20 | +++ b/include/sysemu/block-backend.h | 37 | +++ b/include/block/block-io.h |
21 | @@ -XXX,XX +XXX,XX @@ void blk_iostatus_disable(BlockBackend *blk); | 38 | @@ -XXX,XX +XXX,XX @@ bdrv_co_ioctl(BlockDriverState *bs, int req, void *buf); |
22 | void blk_iostatus_reset(BlockBackend *blk); | 39 | /* Ensure contents are flushed to disk. */ |
23 | void blk_iostatus_set_err(BlockBackend *blk, int error); | 40 | int coroutine_fn GRAPH_RDLOCK bdrv_co_flush(BlockDriverState *bs); |
24 | int blk_attach_dev(BlockBackend *blk, DeviceState *dev); | 41 | |
25 | -void blk_attach_dev_legacy(BlockBackend *blk, void *dev); | 42 | -int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, |
26 | -void blk_detach_dev(BlockBackend *blk, void *dev); | 43 | - int64_t bytes); |
27 | -void *blk_get_attached_dev(BlockBackend *blk); | 44 | +int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard(BdrvChild *child, int64_t offset, |
28 | +void blk_detach_dev(BlockBackend *blk, DeviceState *dev); | 45 | + int64_t bytes); |
29 | +DeviceState *blk_get_attached_dev(BlockBackend *blk); | 46 | + |
30 | char *blk_get_attached_dev_id(BlockBackend *blk); | 47 | bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs); |
31 | BlockBackend *blk_by_dev(void *dev); | 48 | int bdrv_block_status(BlockDriverState *bs, int64_t offset, |
32 | BlockBackend *blk_by_qdev_id(const char *id, Error **errp); | 49 | int64_t bytes, int64_t *pnum, int64_t *map, |
50 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
51 | index XXXXXXX..XXXXXXX 100644 | ||
52 | --- a/include/block/block_int-common.h | ||
53 | +++ b/include/block/block_int-common.h | ||
54 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
55 | BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); | ||
56 | BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_flush)( | ||
57 | BlockDriverState *bs, BlockCompletionFunc *cb, void *opaque); | ||
58 | - BlockAIOCB *(*bdrv_aio_pdiscard)(BlockDriverState *bs, | ||
59 | - int64_t offset, int bytes, | ||
60 | + | ||
61 | + BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_pdiscard)( | ||
62 | + BlockDriverState *bs, int64_t offset, int bytes, | ||
63 | BlockCompletionFunc *cb, void *opaque); | ||
64 | |||
65 | int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs, | ||
66 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
67 | */ | ||
68 | int coroutine_fn (*bdrv_co_pwrite_zeroes)(BlockDriverState *bs, | ||
69 | int64_t offset, int64_t bytes, BdrvRequestFlags flags); | ||
70 | - int coroutine_fn (*bdrv_co_pdiscard)(BlockDriverState *bs, | ||
71 | - int64_t offset, int64_t bytes); | ||
72 | + | ||
73 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pdiscard)( | ||
74 | + BlockDriverState *bs, int64_t offset, int64_t bytes); | ||
75 | |||
76 | /* | ||
77 | * Map [offset, offset + nbytes) range onto a child of @bs to copy from, | ||
78 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
79 | int coroutine_fn (*bdrv_co_snapshot_block_status)(BlockDriverState *bs, | ||
80 | bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum, | ||
81 | int64_t *map, BlockDriverState **file); | ||
82 | - int coroutine_fn (*bdrv_co_pdiscard_snapshot)(BlockDriverState *bs, | ||
83 | - int64_t offset, int64_t bytes); | ||
84 | + | ||
85 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pdiscard_snapshot)( | ||
86 | + BlockDriverState *bs, int64_t offset, int64_t bytes); | ||
87 | |||
88 | /* | ||
89 | * Invalidate any cached meta-data. | ||
90 | diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h | ||
91 | index XXXXXXX..XXXXXXX 100644 | ||
92 | --- a/include/block/block_int-io.h | ||
93 | +++ b/include/block/block_int-io.h | ||
94 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_preadv_snapshot(BdrvChild *child, | ||
95 | int coroutine_fn bdrv_co_snapshot_block_status(BlockDriverState *bs, | ||
96 | bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum, | ||
97 | int64_t *map, BlockDriverState **file); | ||
98 | -int coroutine_fn bdrv_co_pdiscard_snapshot(BlockDriverState *bs, | ||
99 | +int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard_snapshot(BlockDriverState *bs, | ||
100 | int64_t offset, int64_t bytes); | ||
101 | |||
102 | |||
103 | diff --git a/block/blkdebug.c b/block/blkdebug.c | ||
104 | index XXXXXXX..XXXXXXX 100644 | ||
105 | --- a/block/blkdebug.c | ||
106 | +++ b/block/blkdebug.c | ||
107 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs, | ||
108 | return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); | ||
109 | } | ||
110 | |||
111 | -static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs, | ||
112 | - int64_t offset, int64_t bytes) | ||
113 | +static int coroutine_fn GRAPH_RDLOCK | ||
114 | +blkdebug_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
115 | { | ||
116 | uint32_t align = bs->bl.pdiscard_alignment; | ||
117 | int err; | ||
118 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | ||
119 | index XXXXXXX..XXXXXXX 100644 | ||
120 | --- a/block/blklogwrites.c | ||
121 | +++ b/block/blklogwrites.c | ||
122 | @@ -XXX,XX +XXX,XX @@ blk_log_writes_co_do_file_flush(BlkLogWritesFileReq *fr) | ||
123 | return bdrv_co_flush(fr->bs->file->bs); | ||
124 | } | ||
125 | |||
126 | -static int coroutine_fn | ||
127 | +static int coroutine_fn GRAPH_RDLOCK | ||
128 | blk_log_writes_co_do_file_pdiscard(BlkLogWritesFileReq *fr) | ||
129 | { | ||
130 | return bdrv_co_pdiscard(fr->bs->file, fr->offset, fr->bytes); | ||
131 | @@ -XXX,XX +XXX,XX @@ blk_log_writes_co_flush_to_disk(BlockDriverState *bs) | ||
132 | LOG_FLUSH_FLAG, false); | ||
133 | } | ||
134 | |||
135 | -static int coroutine_fn | ||
136 | +static int coroutine_fn GRAPH_RDLOCK | ||
137 | blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
138 | { | ||
139 | - assume_graph_lock(); /* FIXME */ | ||
140 | return blk_log_writes_co_log(bs, offset, bytes, NULL, 0, | ||
141 | blk_log_writes_co_do_file_pdiscard, | ||
142 | LOG_DISCARD_FLAG, false); | ||
143 | diff --git a/block/blkreplay.c b/block/blkreplay.c | ||
144 | index XXXXXXX..XXXXXXX 100644 | ||
145 | --- a/block/blkreplay.c | ||
146 | +++ b/block/blkreplay.c | ||
147 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs, | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | -static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs, | ||
152 | - int64_t offset, int64_t bytes) | ||
153 | +static int coroutine_fn GRAPH_RDLOCK | ||
154 | +blkreplay_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
155 | { | ||
156 | uint64_t reqid = blkreplay_next_id(); | ||
157 | int ret = bdrv_co_pdiscard(bs->file, offset, bytes); | ||
33 | diff --git a/block/block-backend.c b/block/block-backend.c | 158 | diff --git a/block/block-backend.c b/block/block-backend.c |
34 | index XXXXXXX..XXXXXXX 100644 | 159 | index XXXXXXX..XXXXXXX 100644 |
35 | --- a/block/block-backend.c | 160 | --- a/block/block-backend.c |
36 | +++ b/block/block-backend.c | 161 | +++ b/block/block-backend.c |
37 | @@ -XXX,XX +XXX,XX @@ struct BlockBackend { | 162 | @@ -XXX,XX +XXX,XX @@ blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes) |
38 | QTAILQ_ENTRY(BlockBackend) monitor_link; /* for monitor_block_backends */ | 163 | IO_CODE(); |
39 | BlockBackendPublic public; | 164 | |
40 | 165 | blk_wait_while_drained(blk); | |
41 | - void *dev; /* attached device model, if any */ | 166 | + GRAPH_RDLOCK_GUARD(); |
42 | - bool legacy_dev; /* true if dev is not a DeviceState */ | 167 | |
43 | - /* TODO change to DeviceState when all users are qdevified */ | 168 | ret = blk_check_byte_request(blk, offset, bytes); |
44 | + DeviceState *dev; /* attached device model, if any */ | 169 | if (ret < 0) { |
45 | const BlockDevOps *dev_ops; | 170 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c |
46 | void *dev_opaque; | 171 | index XXXXXXX..XXXXXXX 100644 |
47 | 172 | --- a/block/copy-before-write.c | |
48 | @@ -XXX,XX +XXX,XX @@ void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm) | 173 | +++ b/block/copy-before-write.c |
49 | *shared_perm = blk->shared_perm; | 174 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int cbw_do_copy_before_write(BlockDriverState *bs, |
50 | } | ||
51 | |||
52 | -static int blk_do_attach_dev(BlockBackend *blk, void *dev) | ||
53 | +/* | ||
54 | + * Attach device model @dev to @blk. | ||
55 | + * Return 0 on success, -EBUSY when a device model is attached already. | ||
56 | + */ | ||
57 | +int blk_attach_dev(BlockBackend *blk, DeviceState *dev) | ||
58 | { | ||
59 | if (blk->dev) { | ||
60 | return -EBUSY; | ||
61 | @@ -XXX,XX +XXX,XX @@ static int blk_do_attach_dev(BlockBackend *blk, void *dev) | ||
62 | |||
63 | blk_ref(blk); | ||
64 | blk->dev = dev; | ||
65 | - blk->legacy_dev = false; | ||
66 | blk_iostatus_reset(blk); | ||
67 | |||
68 | return 0; | 175 | return 0; |
69 | } | 176 | } |
70 | 177 | ||
71 | -/* | 178 | -static int coroutine_fn cbw_co_pdiscard(BlockDriverState *bs, |
72 | - * Attach device model @dev to @blk. | 179 | - int64_t offset, int64_t bytes) |
73 | - * Return 0 on success, -EBUSY when a device model is attached already. | 180 | +static int coroutine_fn GRAPH_RDLOCK |
74 | - */ | 181 | +cbw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) |
75 | -int blk_attach_dev(BlockBackend *blk, DeviceState *dev) | 182 | { |
76 | -{ | 183 | int ret = cbw_do_copy_before_write(bs, offset, bytes, 0); |
77 | - return blk_do_attach_dev(blk, dev); | 184 | if (ret < 0) { |
78 | -} | 185 | @@ -XXX,XX +XXX,XX @@ cbw_co_snapshot_block_status(BlockDriverState *bs, |
79 | - | 186 | return ret; |
80 | -/* | 187 | } |
81 | - * Attach device model @dev to @blk. | 188 | |
82 | - * @blk must not have a device model attached already. | 189 | -static int coroutine_fn cbw_co_pdiscard_snapshot(BlockDriverState *bs, |
83 | - * TODO qdevified devices don't use this, remove when devices are qdevified | 190 | - int64_t offset, int64_t bytes) |
84 | - */ | 191 | +static int coroutine_fn GRAPH_RDLOCK |
85 | -void blk_attach_dev_legacy(BlockBackend *blk, void *dev) | 192 | +cbw_co_pdiscard_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes) |
86 | -{ | 193 | { |
87 | - if (blk_do_attach_dev(blk, dev) < 0) { | 194 | BDRVCopyBeforeWriteState *s = bs->opaque; |
88 | - abort(); | 195 | |
89 | - } | 196 | diff --git a/block/copy-on-read.c b/block/copy-on-read.c |
90 | - blk->legacy_dev = true; | 197 | index XXXXXXX..XXXXXXX 100644 |
91 | -} | 198 | --- a/block/copy-on-read.c |
92 | - | 199 | +++ b/block/copy-on-read.c |
93 | /* | 200 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs, |
94 | * Detach device model @dev from @blk. | 201 | } |
95 | * @dev must be currently attached to @blk. | 202 | |
96 | */ | 203 | |
97 | -void blk_detach_dev(BlockBackend *blk, void *dev) | 204 | -static int coroutine_fn cor_co_pdiscard(BlockDriverState *bs, |
98 | -/* TODO change to DeviceState *dev when all users are qdevified */ | 205 | - int64_t offset, int64_t bytes) |
99 | +void blk_detach_dev(BlockBackend *blk, DeviceState *dev) | 206 | +static int coroutine_fn GRAPH_RDLOCK |
100 | { | 207 | +cor_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) |
101 | assert(blk->dev == dev); | 208 | { |
102 | blk->dev = NULL; | 209 | return bdrv_co_pdiscard(bs->file, offset, bytes); |
103 | @@ -XXX,XX +XXX,XX @@ void blk_detach_dev(BlockBackend *blk, void *dev) | 210 | } |
104 | /* | 211 | diff --git a/block/filter-compress.c b/block/filter-compress.c |
105 | * Return the device model attached to @blk if any, else null. | 212 | index XXXXXXX..XXXXXXX 100644 |
106 | */ | 213 | --- a/block/filter-compress.c |
107 | -void *blk_get_attached_dev(BlockBackend *blk) | 214 | +++ b/block/filter-compress.c |
108 | -/* TODO change to return DeviceState * when all users are qdevified */ | 215 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn compress_co_pwrite_zeroes(BlockDriverState *bs, |
109 | +DeviceState *blk_get_attached_dev(BlockBackend *blk) | 216 | } |
110 | { | 217 | |
111 | return blk->dev; | 218 | |
112 | } | 219 | -static int coroutine_fn compress_co_pdiscard(BlockDriverState *bs, |
113 | @@ -XXX,XX +XXX,XX @@ void *blk_get_attached_dev(BlockBackend *blk) | 220 | - int64_t offset, int64_t bytes) |
114 | * device attached to the BlockBackend. */ | 221 | +static int coroutine_fn GRAPH_RDLOCK |
115 | char *blk_get_attached_dev_id(BlockBackend *blk) | 222 | +compress_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) |
116 | { | 223 | { |
117 | - DeviceState *dev; | 224 | return bdrv_co_pdiscard(bs->file, offset, bytes); |
118 | - | 225 | } |
119 | - assert(!blk->legacy_dev); | 226 | diff --git a/block/io.c b/block/io.c |
120 | - dev = blk->dev; | 227 | index XXXXXXX..XXXXXXX 100644 |
121 | + DeviceState *dev = blk->dev; | 228 | --- a/block/io.c |
122 | 229 | +++ b/block/io.c | |
123 | if (!dev) { | 230 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, |
124 | return g_strdup(""); | 231 | int head, tail, align; |
125 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_dev(void *dev) | 232 | BlockDriverState *bs = child->bs; |
126 | void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, | 233 | IO_CODE(); |
127 | void *opaque) | 234 | + assert_bdrv_graph_readable(); |
128 | { | 235 | |
129 | - /* All drivers that use blk_set_dev_ops() are qdevified and we want to keep | 236 | if (!bs || !bs->drv || !bdrv_co_is_inserted(bs)) { |
130 | - * it that way, so we can assume blk->dev, if present, is a DeviceState if | 237 | return -ENOMEDIUM; |
131 | - * blk->dev_ops is set. Non-device users may use dev_ops without device. */ | 238 | @@ -XXX,XX +XXX,XX @@ bdrv_co_pdiscard_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes) |
132 | - assert(!blk->legacy_dev); | 239 | BlockDriver *drv = bs->drv; |
133 | - | 240 | int ret; |
134 | blk->dev_ops = ops; | 241 | IO_CODE(); |
135 | blk->dev_opaque = opaque; | 242 | + assert_bdrv_graph_readable(); |
136 | 243 | ||
137 | @@ -XXX,XX +XXX,XX @@ void blk_dev_change_media_cb(BlockBackend *blk, bool load, Error **errp) | 244 | if (!drv) { |
138 | bool tray_was_open, tray_is_open; | 245 | return -ENOMEDIUM; |
139 | Error *local_err = NULL; | 246 | diff --git a/block/mirror.c b/block/mirror.c |
140 | 247 | index XXXXXXX..XXXXXXX 100644 | |
141 | - assert(!blk->legacy_dev); | 248 | --- a/block/mirror.c |
142 | - | 249 | +++ b/block/mirror.c |
143 | tray_was_open = blk_dev_is_tray_open(blk); | 250 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_preadv(BlockDriverState *bs, |
144 | blk->dev_ops->change_media_cb(blk->dev_opaque, load, &local_err); | 251 | return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); |
145 | if (local_err) { | 252 | } |
146 | @@ -XXX,XX +XXX,XX @@ void blk_eject(BlockBackend *blk, bool eject_flag) | 253 | |
147 | BlockDriverState *bs = blk_bs(blk); | 254 | -static int coroutine_fn bdrv_mirror_top_do_write(BlockDriverState *bs, |
148 | char *id; | 255 | - MirrorMethod method, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, |
149 | 256 | - int flags) | |
150 | - /* blk_eject is only called by qdevified devices */ | 257 | +static int coroutine_fn GRAPH_RDLOCK |
151 | - assert(!blk->legacy_dev); | 258 | +bdrv_mirror_top_do_write(BlockDriverState *bs, MirrorMethod method, |
152 | - | 259 | + uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, |
153 | if (bs) { | 260 | + int flags) |
154 | bdrv_eject(bs, eject_flag); | 261 | { |
155 | } | 262 | MirrorOp *op = NULL; |
263 | MirrorBDSOpaque *s = bs->opaque; | ||
264 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs, | ||
265 | int ret = 0; | ||
266 | bool copy_to_target = false; | ||
267 | |||
268 | + assume_graph_lock(); /* FIXME */ | ||
269 | + | ||
270 | if (s->job) { | ||
271 | copy_to_target = s->job->ret >= 0 && | ||
272 | !job_is_cancelled(&s->job->common.job) && | ||
273 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn GRAPH_RDLOCK bdrv_mirror_top_flush(BlockDriverState *bs) | ||
274 | static int coroutine_fn bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs, | ||
275 | int64_t offset, int64_t bytes, BdrvRequestFlags flags) | ||
276 | { | ||
277 | + assume_graph_lock(); /* FIXME */ | ||
278 | return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_ZERO, offset, bytes, NULL, | ||
279 | flags); | ||
280 | } | ||
281 | |||
282 | -static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs, | ||
283 | - int64_t offset, int64_t bytes) | ||
284 | +static int coroutine_fn GRAPH_RDLOCK | ||
285 | +bdrv_mirror_top_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
286 | { | ||
287 | return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_DISCARD, offset, bytes, | ||
288 | NULL, 0); | ||
289 | diff --git a/block/preallocate.c b/block/preallocate.c | ||
290 | index XXXXXXX..XXXXXXX 100644 | ||
291 | --- a/block/preallocate.c | ||
292 | +++ b/block/preallocate.c | ||
293 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int preallocate_co_preadv_part( | ||
294 | flags); | ||
295 | } | ||
296 | |||
297 | -static int coroutine_fn preallocate_co_pdiscard(BlockDriverState *bs, | ||
298 | - int64_t offset, int64_t bytes) | ||
299 | +static int coroutine_fn GRAPH_RDLOCK | ||
300 | +preallocate_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
301 | { | ||
302 | return bdrv_co_pdiscard(bs->file, offset, bytes); | ||
303 | } | ||
304 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
305 | index XXXXXXX..XXXXXXX 100644 | ||
306 | --- a/block/raw-format.c | ||
307 | +++ b/block/raw-format.c | ||
308 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs, | ||
309 | return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); | ||
310 | } | ||
311 | |||
312 | -static int coroutine_fn raw_co_pdiscard(BlockDriverState *bs, | ||
313 | - int64_t offset, int64_t bytes) | ||
314 | +static int coroutine_fn GRAPH_RDLOCK | ||
315 | +raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
316 | { | ||
317 | int ret; | ||
318 | |||
319 | diff --git a/block/snapshot-access.c b/block/snapshot-access.c | ||
320 | index XXXXXXX..XXXXXXX 100644 | ||
321 | --- a/block/snapshot-access.c | ||
322 | +++ b/block/snapshot-access.c | ||
323 | @@ -XXX,XX +XXX,XX @@ snapshot_access_co_block_status(BlockDriverState *bs, | ||
324 | bytes, pnum, map, file); | ||
325 | } | ||
326 | |||
327 | -static int coroutine_fn snapshot_access_co_pdiscard(BlockDriverState *bs, | ||
328 | - int64_t offset, int64_t bytes) | ||
329 | +static int coroutine_fn GRAPH_RDLOCK | ||
330 | +snapshot_access_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
331 | { | ||
332 | return bdrv_co_pdiscard_snapshot(bs->file->bs, offset, bytes); | ||
333 | } | ||
334 | diff --git a/block/throttle.c b/block/throttle.c | ||
335 | index XXXXXXX..XXXXXXX 100644 | ||
336 | --- a/block/throttle.c | ||
337 | +++ b/block/throttle.c | ||
338 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn throttle_co_pwrite_zeroes(BlockDriverState *bs, | ||
339 | return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); | ||
340 | } | ||
341 | |||
342 | -static int coroutine_fn throttle_co_pdiscard(BlockDriverState *bs, | ||
343 | - int64_t offset, int64_t bytes) | ||
344 | +static int coroutine_fn GRAPH_RDLOCK | ||
345 | +throttle_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
346 | { | ||
347 | ThrottleGroupMember *tgm = bs->opaque; | ||
348 | throttle_group_co_io_limits_intercept(tgm, bytes, true); | ||
156 | -- | 349 | -- |
157 | 2.20.1 | 350 | 2.39.2 |
158 | |||
159 | diff view generated by jsdifflib |
1 | From: Markus Armbruster <armbru@redhat.com> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_co_pwrite_zeroes() need to hold a reader lock for the graph. | ||
2 | 3 | ||
3 | Patch created mechanically by rerunning: | 4 | For some places, we know that they will hold the lock, but we don't have |
5 | the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock() | ||
6 | with a FIXME comment. These places will be removed once everything is | ||
7 | properly annotated. | ||
4 | 8 | ||
5 | $ spatch --sp-file scripts/coccinelle/qobject.cocci \ | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
6 | --macro-file scripts/cocci-macro-file.h \ | 10 | Message-Id: <20230203152202.49054-10-kwolf@redhat.com> |
7 | --dir block --in-place | 11 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
8 | |||
9 | Signed-off-by: Markus Armbruster <armbru@redhat.com> | ||
10 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
13 | --- | 13 | --- |
14 | block/blklogwrites.c | 5 ++--- | 14 | block/qcow2.h | 6 ++++-- |
15 | 1 file changed, 2 insertions(+), 3 deletions(-) | 15 | include/block/block-io.h | 9 +++++---- |
16 | include/block/block_int-common.h | 5 +++-- | ||
17 | block/blkdebug.c | 6 +++--- | ||
18 | block/blklogwrites.c | 5 ++--- | ||
19 | block/blkreplay.c | 5 +++-- | ||
20 | block/block-copy.c | 13 +++++++------ | ||
21 | block/copy-before-write.c | 5 +++-- | ||
22 | block/copy-on-read.c | 6 +++--- | ||
23 | block/filter-compress.c | 6 +++--- | ||
24 | block/io.c | 12 +++++++++--- | ||
25 | block/mirror.c | 6 +++--- | ||
26 | block/preallocate.c | 11 +++++++---- | ||
27 | block/qcow2.c | 30 ++++++++++++++++++------------ | ||
28 | block/qed.c | 9 +++------ | ||
29 | block/quorum.c | 15 ++++++++++----- | ||
30 | block/raw-format.c | 6 +++--- | ||
31 | block/throttle.c | 6 +++--- | ||
32 | 18 files changed, 92 insertions(+), 69 deletions(-) | ||
16 | 33 | ||
34 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/block/qcow2.h | ||
37 | +++ b/block/qcow2.h | ||
38 | @@ -XXX,XX +XXX,XX @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); | ||
39 | int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, | ||
40 | uint64_t bytes, enum qcow2_discard_type type, | ||
41 | bool full_discard); | ||
42 | -int coroutine_fn qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, | ||
43 | - uint64_t bytes, int flags); | ||
44 | + | ||
45 | +int coroutine_fn GRAPH_RDLOCK | ||
46 | +qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | ||
47 | + int flags); | ||
48 | |||
49 | int qcow2_expand_zero_clusters(BlockDriverState *bs, | ||
50 | BlockDriverAmendStatusCB *status_cb, | ||
51 | diff --git a/include/block/block-io.h b/include/block/block-io.h | ||
52 | index XXXXXXX..XXXXXXX 100644 | ||
53 | --- a/include/block/block-io.h | ||
54 | +++ b/include/block/block-io.h | ||
55 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset, | ||
56 | * function is not suitable for zeroing the entire image in a single request | ||
57 | * because it may allocate memory for the entire region. | ||
58 | */ | ||
59 | -int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, | ||
60 | - int64_t bytes, BdrvRequestFlags flags); | ||
61 | +int coroutine_fn GRAPH_RDLOCK | ||
62 | +bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, int64_t bytes, | ||
63 | + BdrvRequestFlags flags); | ||
64 | |||
65 | int coroutine_fn GRAPH_RDLOCK | ||
66 | bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
67 | @@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base, | ||
68 | bool include_base, int64_t offset, int64_t bytes, | ||
69 | int64_t *pnum); | ||
70 | |||
71 | -int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, | ||
72 | - int64_t bytes); | ||
73 | +int coroutine_fn GRAPH_RDLOCK | ||
74 | +bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, int64_t bytes); | ||
75 | |||
76 | int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, | ||
77 | Error **errp); | ||
78 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
79 | index XXXXXXX..XXXXXXX 100644 | ||
80 | --- a/include/block/block_int-common.h | ||
81 | +++ b/include/block/block_int-common.h | ||
82 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
83 | * function pointer may be NULL or return -ENOSUP and .bdrv_co_writev() | ||
84 | * will be called instead. | ||
85 | */ | ||
86 | - int coroutine_fn (*bdrv_co_pwrite_zeroes)(BlockDriverState *bs, | ||
87 | - int64_t offset, int64_t bytes, BdrvRequestFlags flags); | ||
88 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pwrite_zeroes)( | ||
89 | + BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
90 | + BdrvRequestFlags flags); | ||
91 | |||
92 | int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pdiscard)( | ||
93 | BlockDriverState *bs, int64_t offset, int64_t bytes); | ||
94 | diff --git a/block/blkdebug.c b/block/blkdebug.c | ||
95 | index XXXXXXX..XXXXXXX 100644 | ||
96 | --- a/block/blkdebug.c | ||
97 | +++ b/block/blkdebug.c | ||
98 | @@ -XXX,XX +XXX,XX @@ static int GRAPH_RDLOCK coroutine_fn blkdebug_co_flush(BlockDriverState *bs) | ||
99 | return bdrv_co_flush(bs->file->bs); | ||
100 | } | ||
101 | |||
102 | -static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs, | ||
103 | - int64_t offset, int64_t bytes, | ||
104 | - BdrvRequestFlags flags) | ||
105 | +static int coroutine_fn GRAPH_RDLOCK | ||
106 | +blkdebug_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
107 | + BdrvRequestFlags flags) | ||
108 | { | ||
109 | uint32_t align = MAX(bs->bl.request_alignment, | ||
110 | bs->bl.pwrite_zeroes_alignment); | ||
17 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | 111 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c |
18 | index XXXXXXX..XXXXXXX 100644 | 112 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/block/blklogwrites.c | 113 | --- a/block/blklogwrites.c |
20 | +++ b/block/blklogwrites.c | 114 | +++ b/block/blklogwrites.c |
21 | @@ -XXX,XX +XXX,XX @@ static void blk_log_writes_refresh_filename(BlockDriverState *bs, | 115 | @@ -XXX,XX +XXX,XX @@ blk_log_writes_co_do_file_pwritev(BlkLogWritesFileReq *fr) |
22 | qdict_put_str(opts, "driver", "blklogwrites"); | 116 | fr->qiov, fr->file_flags); |
23 | 117 | } | |
24 | qobject_ref(bs->file->bs->full_open_options); | 118 | |
25 | - qdict_put_obj(opts, "file", QOBJECT(bs->file->bs->full_open_options)); | 119 | -static int coroutine_fn |
26 | + qdict_put(opts, "file", bs->file->bs->full_open_options); | 120 | +static int coroutine_fn GRAPH_RDLOCK |
27 | qobject_ref(s->log_file->bs->full_open_options); | 121 | blk_log_writes_co_do_file_pwrite_zeroes(BlkLogWritesFileReq *fr) |
28 | - qdict_put_obj(opts, "log", | 122 | { |
29 | - QOBJECT(s->log_file->bs->full_open_options)); | 123 | return bdrv_co_pwrite_zeroes(fr->bs->file, fr->offset, fr->bytes, |
30 | + qdict_put(opts, "log", s->log_file->bs->full_open_options); | 124 | @@ -XXX,XX +XXX,XX @@ blk_log_writes_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, |
31 | qdict_put_int(opts, "log-sector-size", s->sectorsize); | 125 | blk_log_writes_co_do_file_pwritev, 0, false); |
32 | 126 | } | |
33 | bs->full_open_options = opts; | 127 | |
128 | -static int coroutine_fn | ||
129 | +static int coroutine_fn GRAPH_RDLOCK | ||
130 | blk_log_writes_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, | ||
131 | int64_t bytes, BdrvRequestFlags flags) | ||
132 | { | ||
133 | - assume_graph_lock(); /* FIXME */ | ||
134 | return blk_log_writes_co_log(bs, offset, bytes, NULL, flags, | ||
135 | blk_log_writes_co_do_file_pwrite_zeroes, 0, | ||
136 | true); | ||
137 | diff --git a/block/blkreplay.c b/block/blkreplay.c | ||
138 | index XXXXXXX..XXXXXXX 100644 | ||
139 | --- a/block/blkreplay.c | ||
140 | +++ b/block/blkreplay.c | ||
141 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs, | ||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | -static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs, | ||
146 | - int64_t offset, int64_t bytes, BdrvRequestFlags flags) | ||
147 | +static int coroutine_fn GRAPH_RDLOCK | ||
148 | +blkreplay_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
149 | + BdrvRequestFlags flags) | ||
150 | { | ||
151 | uint64_t reqid = blkreplay_next_id(); | ||
152 | int ret = bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); | ||
153 | diff --git a/block/block-copy.c b/block/block-copy.c | ||
154 | index XXXXXXX..XXXXXXX 100644 | ||
155 | --- a/block/block-copy.c | ||
156 | +++ b/block/block-copy.c | ||
157 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int block_copy_task_run(AioTaskPool *pool, | ||
158 | * value of @method should be used for subsequent tasks. | ||
159 | * Returns 0 on success. | ||
160 | */ | ||
161 | -static int coroutine_fn block_copy_do_copy(BlockCopyState *s, | ||
162 | - int64_t offset, int64_t bytes, | ||
163 | - BlockCopyMethod *method, | ||
164 | - bool *error_is_read) | ||
165 | +static int coroutine_fn GRAPH_RDLOCK | ||
166 | +block_copy_do_copy(BlockCopyState *s, int64_t offset, int64_t bytes, | ||
167 | + BlockCopyMethod *method, bool *error_is_read) | ||
168 | { | ||
169 | int ret; | ||
170 | int64_t nbytes = MIN(offset + bytes, s->len) - offset; | ||
171 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int block_copy_task_entry(AioTask *task) | ||
172 | BlockCopyMethod method = t->method; | ||
173 | int ret; | ||
174 | |||
175 | - ret = block_copy_do_copy(s, t->req.offset, t->req.bytes, &method, | ||
176 | - &error_is_read); | ||
177 | + WITH_GRAPH_RDLOCK_GUARD() { | ||
178 | + ret = block_copy_do_copy(s, t->req.offset, t->req.bytes, &method, | ||
179 | + &error_is_read); | ||
180 | + } | ||
181 | |||
182 | WITH_QEMU_LOCK_GUARD(&s->lock) { | ||
183 | if (s->method == t->method) { | ||
184 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
185 | index XXXXXXX..XXXXXXX 100644 | ||
186 | --- a/block/copy-before-write.c | ||
187 | +++ b/block/copy-before-write.c | ||
188 | @@ -XXX,XX +XXX,XX @@ cbw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
189 | return bdrv_co_pdiscard(bs->file, offset, bytes); | ||
190 | } | ||
191 | |||
192 | -static int coroutine_fn cbw_co_pwrite_zeroes(BlockDriverState *bs, | ||
193 | - int64_t offset, int64_t bytes, BdrvRequestFlags flags) | ||
194 | +static int coroutine_fn GRAPH_RDLOCK | ||
195 | +cbw_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
196 | + BdrvRequestFlags flags) | ||
197 | { | ||
198 | int ret = cbw_do_copy_before_write(bs, offset, bytes, flags); | ||
199 | if (ret < 0) { | ||
200 | diff --git a/block/copy-on-read.c b/block/copy-on-read.c | ||
201 | index XXXXXXX..XXXXXXX 100644 | ||
202 | --- a/block/copy-on-read.c | ||
203 | +++ b/block/copy-on-read.c | ||
204 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn cor_co_pwritev_part(BlockDriverState *bs, | ||
205 | } | ||
206 | |||
207 | |||
208 | -static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs, | ||
209 | - int64_t offset, int64_t bytes, | ||
210 | - BdrvRequestFlags flags) | ||
211 | +static int coroutine_fn GRAPH_RDLOCK | ||
212 | +cor_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
213 | + BdrvRequestFlags flags) | ||
214 | { | ||
215 | return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); | ||
216 | } | ||
217 | diff --git a/block/filter-compress.c b/block/filter-compress.c | ||
218 | index XXXXXXX..XXXXXXX 100644 | ||
219 | --- a/block/filter-compress.c | ||
220 | +++ b/block/filter-compress.c | ||
221 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn compress_co_pwritev_part(BlockDriverState *bs, | ||
222 | } | ||
223 | |||
224 | |||
225 | -static int coroutine_fn compress_co_pwrite_zeroes(BlockDriverState *bs, | ||
226 | - int64_t offset, int64_t bytes, | ||
227 | - BdrvRequestFlags flags) | ||
228 | +static int coroutine_fn GRAPH_RDLOCK | ||
229 | +compress_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
230 | + BdrvRequestFlags flags) | ||
231 | { | ||
232 | return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); | ||
233 | } | ||
234 | diff --git a/block/io.c b/block/io.c | ||
235 | index XXXXXXX..XXXXXXX 100644 | ||
236 | --- a/block/io.c | ||
237 | +++ b/block/io.c | ||
238 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, | ||
239 | int64_t progress = 0; | ||
240 | bool skip_write; | ||
241 | |||
242 | + assume_graph_lock(); /* FIXME */ | ||
243 | + | ||
244 | bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort); | ||
245 | |||
246 | if (!drv) { | ||
247 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, | ||
248 | bs->bl.request_alignment); | ||
249 | int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFFER); | ||
250 | |||
251 | + assert_bdrv_graph_readable(); | ||
252 | bdrv_check_request(offset, bytes, &error_abort); | ||
253 | |||
254 | if (!drv) { | ||
255 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, | ||
256 | int64_t bytes_remaining = bytes; | ||
257 | int max_transfer; | ||
258 | |||
259 | + assume_graph_lock(); /* FIXME */ | ||
260 | + | ||
261 | bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort); | ||
262 | |||
263 | if (!drv) { | ||
264 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwrite_zeroes(BdrvChild *child, int64_t offset, | ||
265 | { | ||
266 | IO_CODE(); | ||
267 | trace_bdrv_co_pwrite_zeroes(child->bs, offset, bytes, flags); | ||
268 | + assert_bdrv_graph_readable(); | ||
269 | |||
270 | if (!(child->bs->open_flags & BDRV_O_UNMAP)) { | ||
271 | flags &= ~BDRV_REQ_MAY_UNMAP; | ||
272 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, | ||
273 | int64_t pnum = bytes; | ||
274 | IO_CODE(); | ||
275 | |||
276 | - assume_graph_lock(); /* FIXME */ | ||
277 | - | ||
278 | if (!bytes) { | ||
279 | return 1; | ||
280 | } | ||
281 | @@ -XXX,XX +XXX,XX @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host, size_t size) | ||
282 | } | ||
283 | } | ||
284 | |||
285 | -static int coroutine_fn bdrv_co_copy_range_internal( | ||
286 | +static int coroutine_fn GRAPH_RDLOCK bdrv_co_copy_range_internal( | ||
287 | BdrvChild *src, int64_t src_offset, BdrvChild *dst, | ||
288 | int64_t dst_offset, int64_t bytes, | ||
289 | BdrvRequestFlags read_flags, BdrvRequestFlags write_flags, | ||
290 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset, | ||
291 | BdrvRequestFlags write_flags) | ||
292 | { | ||
293 | IO_CODE(); | ||
294 | + assume_graph_lock(); /* FIXME */ | ||
295 | trace_bdrv_co_copy_range_from(src, src_offset, dst, dst_offset, bytes, | ||
296 | read_flags, write_flags); | ||
297 | return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset, | ||
298 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset, | ||
299 | BdrvRequestFlags write_flags) | ||
300 | { | ||
301 | IO_CODE(); | ||
302 | + assume_graph_lock(); /* FIXME */ | ||
303 | trace_bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, | ||
304 | read_flags, write_flags); | ||
305 | return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset, | ||
306 | diff --git a/block/mirror.c b/block/mirror.c | ||
307 | index XXXXXXX..XXXXXXX 100644 | ||
308 | --- a/block/mirror.c | ||
309 | +++ b/block/mirror.c | ||
310 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn GRAPH_RDLOCK bdrv_mirror_top_flush(BlockDriverState *bs) | ||
311 | return bdrv_co_flush(bs->backing->bs); | ||
312 | } | ||
313 | |||
314 | -static int coroutine_fn bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs, | ||
315 | - int64_t offset, int64_t bytes, BdrvRequestFlags flags) | ||
316 | +static int coroutine_fn GRAPH_RDLOCK | ||
317 | +bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs, int64_t offset, | ||
318 | + int64_t bytes, BdrvRequestFlags flags) | ||
319 | { | ||
320 | - assume_graph_lock(); /* FIXME */ | ||
321 | return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_ZERO, offset, bytes, NULL, | ||
322 | flags); | ||
323 | } | ||
324 | diff --git a/block/preallocate.c b/block/preallocate.c | ||
325 | index XXXXXXX..XXXXXXX 100644 | ||
326 | --- a/block/preallocate.c | ||
327 | +++ b/block/preallocate.c | ||
328 | @@ -XXX,XX +XXX,XX @@ static bool has_prealloc_perms(BlockDriverState *bs) | ||
329 | * want_merge_zero is used to merge write-zero request with preallocation in | ||
330 | * one bdrv_co_pwrite_zeroes() call. | ||
331 | */ | ||
332 | -static bool coroutine_fn handle_write(BlockDriverState *bs, int64_t offset, | ||
333 | - int64_t bytes, bool want_merge_zero) | ||
334 | +static bool coroutine_fn GRAPH_RDLOCK | ||
335 | +handle_write(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
336 | + bool want_merge_zero) | ||
337 | { | ||
338 | BDRVPreallocateState *s = bs->opaque; | ||
339 | int64_t end = offset + bytes; | ||
340 | @@ -XXX,XX +XXX,XX @@ static bool coroutine_fn handle_write(BlockDriverState *bs, int64_t offset, | ||
341 | return want_merge_zero; | ||
342 | } | ||
343 | |||
344 | -static int coroutine_fn preallocate_co_pwrite_zeroes(BlockDriverState *bs, | ||
345 | - int64_t offset, int64_t bytes, BdrvRequestFlags flags) | ||
346 | +static int coroutine_fn GRAPH_RDLOCK | ||
347 | +preallocate_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, | ||
348 | + int64_t bytes, BdrvRequestFlags flags) | ||
349 | { | ||
350 | bool want_merge_zero = | ||
351 | !(flags & ~(BDRV_REQ_ZERO_WRITE | BDRV_REQ_NO_FALLBACK)); | ||
352 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int preallocate_co_pwritev_part(BlockDriverState *bs, | ||
353 | size_t qiov_offset, | ||
354 | BdrvRequestFlags flags) | ||
355 | { | ||
356 | + assume_graph_lock(); /* FIXME */ | ||
357 | handle_write(bs, offset, bytes, false); | ||
358 | |||
359 | return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset, | ||
360 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
361 | index XXXXXXX..XXXXXXX 100644 | ||
362 | --- a/block/qcow2.c | ||
363 | +++ b/block/qcow2.c | ||
364 | @@ -XXX,XX +XXX,XX @@ static bool merge_cow(uint64_t offset, unsigned bytes, | ||
365 | * Return 1 if the COW regions read as zeroes, 0 if not, < 0 on error. | ||
366 | * Note that returning 0 does not guarantee non-zero data. | ||
367 | */ | ||
368 | -static int coroutine_fn is_zero_cow(BlockDriverState *bs, QCowL2Meta *m) | ||
369 | +static int coroutine_fn GRAPH_RDLOCK | ||
370 | +is_zero_cow(BlockDriverState *bs, QCowL2Meta *m) | ||
371 | { | ||
372 | /* | ||
373 | * This check is designed for optimization shortcut so it must be | ||
374 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn is_zero_cow(BlockDriverState *bs, QCowL2Meta *m) | ||
375 | m->cow_end.nb_bytes); | ||
376 | } | ||
377 | |||
378 | -static int coroutine_fn handle_alloc_space(BlockDriverState *bs, | ||
379 | - QCowL2Meta *l2meta) | ||
380 | +static int coroutine_fn GRAPH_RDLOCK | ||
381 | +handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta) | ||
382 | { | ||
383 | BDRVQcow2State *s = bs->opaque; | ||
384 | QCowL2Meta *m; | ||
385 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn handle_alloc_space(BlockDriverState *bs, | ||
386 | * l2meta - if not NULL, qcow2_co_pwritev_task() will consume it. Caller must | ||
387 | * not use it somehow after qcow2_co_pwritev_task() call | ||
388 | */ | ||
389 | -static coroutine_fn int qcow2_co_pwritev_task(BlockDriverState *bs, | ||
390 | - uint64_t host_offset, | ||
391 | - uint64_t offset, uint64_t bytes, | ||
392 | - QEMUIOVector *qiov, | ||
393 | - uint64_t qiov_offset, | ||
394 | - QCowL2Meta *l2meta) | ||
395 | +static coroutine_fn GRAPH_RDLOCK | ||
396 | +int qcow2_co_pwritev_task(BlockDriverState *bs, uint64_t host_offset, | ||
397 | + uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, | ||
398 | + uint64_t qiov_offset, QCowL2Meta *l2meta) | ||
399 | { | ||
400 | int ret; | ||
401 | BDRVQcow2State *s = bs->opaque; | ||
402 | @@ -XXX,XX +XXX,XX @@ out_locked: | ||
403 | return ret; | ||
404 | } | ||
405 | |||
406 | -static coroutine_fn int qcow2_co_pwritev_task_entry(AioTask *task) | ||
407 | +/* | ||
408 | + * This function can count as GRAPH_RDLOCK because qcow2_co_pwritev_part() holds | ||
409 | + * the graph lock and keeps it until this coroutine has terminated. | ||
410 | + */ | ||
411 | +static coroutine_fn GRAPH_RDLOCK int qcow2_co_pwritev_task_entry(AioTask *task) | ||
412 | { | ||
413 | Qcow2AioTask *t = container_of(task, Qcow2AioTask, task); | ||
414 | |||
415 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_part( | ||
416 | QCowL2Meta *l2meta = NULL; | ||
417 | AioTaskPool *aio = NULL; | ||
418 | |||
419 | + assume_graph_lock(); /* FIXME */ | ||
420 | + | ||
421 | trace_qcow2_writev_start_req(qemu_coroutine_self(), offset, bytes); | ||
422 | |||
423 | while (bytes != 0 && aio_task_pool_status(aio) == 0) { | ||
424 | @@ -XXX,XX +XXX,XX @@ static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
425 | return res >= 0 && (res & BDRV_BLOCK_ZERO) && bytes == 0; | ||
426 | } | ||
427 | |||
428 | -static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs, | ||
429 | - int64_t offset, int64_t bytes, BdrvRequestFlags flags) | ||
430 | +static int coroutine_fn GRAPH_RDLOCK | ||
431 | +qcow2_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
432 | + BdrvRequestFlags flags) | ||
433 | { | ||
434 | int ret; | ||
435 | BDRVQcow2State *s = bs->opaque; | ||
436 | diff --git a/block/qed.c b/block/qed.c | ||
437 | index XXXXXXX..XXXXXXX 100644 | ||
438 | --- a/block/qed.c | ||
439 | +++ b/block/qed.c | ||
440 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_writev(BlockDriverState *bs, | ||
441 | return qed_co_request(bs, sector_num, qiov, nb_sectors, QED_AIOCB_WRITE); | ||
442 | } | ||
443 | |||
444 | -static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs, | ||
445 | - int64_t offset, | ||
446 | - int64_t bytes, | ||
447 | - BdrvRequestFlags flags) | ||
448 | +static int coroutine_fn GRAPH_RDLOCK | ||
449 | +bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
450 | + BdrvRequestFlags flags) | ||
451 | { | ||
452 | BDRVQEDState *s = bs->opaque; | ||
453 | |||
454 | - assume_graph_lock(); /* FIXME */ | ||
455 | - | ||
456 | /* | ||
457 | * Zero writes start without an I/O buffer. If a buffer becomes necessary | ||
458 | * then it will be allocated during request processing. | ||
459 | diff --git a/block/quorum.c b/block/quorum.c | ||
460 | index XXXXXXX..XXXXXXX 100644 | ||
461 | --- a/block/quorum.c | ||
462 | +++ b/block/quorum.c | ||
463 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn quorum_co_preadv(BlockDriverState *bs, | ||
464 | return ret; | ||
465 | } | ||
466 | |||
467 | -static void coroutine_fn write_quorum_entry(void *opaque) | ||
468 | +/* | ||
469 | + * This function can count as GRAPH_RDLOCK because quorum_co_pwritev() holds the | ||
470 | + * graph lock and keeps it until this coroutine has terminated. | ||
471 | + */ | ||
472 | +static void coroutine_fn GRAPH_RDLOCK write_quorum_entry(void *opaque) | ||
473 | { | ||
474 | QuorumCo *co = opaque; | ||
475 | QuorumAIOCB *acb = co->acb; | ||
476 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn quorum_co_pwritev(BlockDriverState *bs, int64_t offset, | ||
477 | QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags); | ||
478 | int i, ret; | ||
479 | |||
480 | + assume_graph_lock(); /* FIXME */ | ||
481 | + | ||
482 | for (i = 0; i < s->num_children; i++) { | ||
483 | Coroutine *co; | ||
484 | QuorumCo data = { | ||
485 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn quorum_co_pwritev(BlockDriverState *bs, int64_t offset, | ||
486 | return ret; | ||
487 | } | ||
488 | |||
489 | -static int coroutine_fn quorum_co_pwrite_zeroes(BlockDriverState *bs, | ||
490 | - int64_t offset, int64_t bytes, | ||
491 | - BdrvRequestFlags flags) | ||
492 | - | ||
493 | +static int coroutine_fn GRAPH_RDLOCK | ||
494 | +quorum_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
495 | + BdrvRequestFlags flags) | ||
496 | { | ||
497 | return quorum_co_pwritev(bs, offset, bytes, NULL, | ||
498 | flags | BDRV_REQ_ZERO_WRITE); | ||
499 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
500 | index XXXXXXX..XXXXXXX 100644 | ||
501 | --- a/block/raw-format.c | ||
502 | +++ b/block/raw-format.c | ||
503 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs, | ||
504 | return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID; | ||
505 | } | ||
506 | |||
507 | -static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs, | ||
508 | - int64_t offset, int64_t bytes, | ||
509 | - BdrvRequestFlags flags) | ||
510 | +static int coroutine_fn GRAPH_RDLOCK | ||
511 | +raw_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
512 | + BdrvRequestFlags flags) | ||
513 | { | ||
514 | int ret; | ||
515 | |||
516 | diff --git a/block/throttle.c b/block/throttle.c | ||
517 | index XXXXXXX..XXXXXXX 100644 | ||
518 | --- a/block/throttle.c | ||
519 | +++ b/block/throttle.c | ||
520 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs, | ||
521 | return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); | ||
522 | } | ||
523 | |||
524 | -static int coroutine_fn throttle_co_pwrite_zeroes(BlockDriverState *bs, | ||
525 | - int64_t offset, int64_t bytes, | ||
526 | - BdrvRequestFlags flags) | ||
527 | +static int coroutine_fn GRAPH_RDLOCK | ||
528 | +throttle_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
529 | + BdrvRequestFlags flags) | ||
530 | { | ||
531 | ThrottleGroupMember *tgm = bs->opaque; | ||
532 | throttle_group_co_io_limits_intercept(tgm, bytes, true); | ||
34 | -- | 533 | -- |
35 | 2.20.1 | 534 | 2.39.2 |
36 | |||
37 | diff view generated by jsdifflib |
1 | The new device_id property specifies which value to use for the vendor | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | specific designator in the Device Identification VPD page. | 2 | bdrv_driver_*() need to hold a reader lock for the graph. It doesn't add |
3 | the annotation to public functions yet. | ||
3 | 4 | ||
4 | In particular, this is necessary for libvirt to maintain guest ABI | 5 | For some places, we know that they will hold the lock, but we don't have |
5 | compatibility when no serial number is given and a VM is switched from | 6 | the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock() |
6 | -drive (where the BlockBackend name is used) to -blockdev (where the | 7 | with a FIXME comment. These places will be removed once everything is |
7 | vendor specific designator is left out by default). | 8 | properly annotated. |
8 | 9 | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | Reviewed-by: Eric Blake <eblake@redhat.com> | 11 | Message-Id: <20230203152202.49054-11-kwolf@redhat.com> |
12 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
11 | --- | 14 | --- |
12 | hw/scsi/scsi-disk.c | 24 ++++++++++++++++-------- | 15 | block/qcow2.h | 5 ++- |
13 | 1 file changed, 16 insertions(+), 8 deletions(-) | 16 | include/block/block_int-common.h | 40 ++++++++++--------- |
17 | block/io.c | 66 +++++++++++++++----------------- | ||
18 | block/parallels.c | 8 ++-- | ||
19 | block/qcow.c | 20 ++++------ | ||
20 | block/qcow2-cluster.c | 10 ++--- | ||
21 | block/qcow2.c | 37 ++++++++++-------- | ||
22 | block/qed.c | 14 +++---- | ||
23 | block/quorum.c | 8 ++-- | ||
24 | block/vmdk.c | 4 +- | ||
25 | 10 files changed, 101 insertions(+), 111 deletions(-) | ||
14 | 26 | ||
15 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c | 27 | diff --git a/block/qcow2.h b/block/qcow2.h |
16 | index XXXXXXX..XXXXXXX 100644 | 28 | index XXXXXXX..XXXXXXX 100644 |
17 | --- a/hw/scsi/scsi-disk.c | 29 | --- a/block/qcow2.h |
18 | +++ b/hw/scsi/scsi-disk.c | 30 | +++ b/block/qcow2.h |
19 | @@ -XXX,XX +XXX,XX @@ typedef struct SCSIDiskState | 31 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, |
20 | char *serial; | 32 | void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry, |
21 | char *vendor; | 33 | uint64_t *coffset, int *csize); |
22 | char *product; | 34 | |
23 | + char *device_id; | 35 | -int coroutine_fn qcow2_alloc_cluster_link_l2(BlockDriverState *bs, |
24 | bool tray_open; | 36 | - QCowL2Meta *m); |
25 | bool tray_locked; | 37 | +int coroutine_fn GRAPH_RDLOCK |
38 | +qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); | ||
39 | + | ||
40 | void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); | ||
41 | int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, | ||
42 | uint64_t bytes, enum qcow2_discard_type type, | ||
43 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
44 | index XXXXXXX..XXXXXXX 100644 | ||
45 | --- a/include/block/block_int-common.h | ||
46 | +++ b/include/block/block_int-common.h | ||
47 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
48 | Error **errp); | ||
49 | |||
50 | /* aio */ | ||
51 | - BlockAIOCB *(*bdrv_aio_preadv)(BlockDriverState *bs, | ||
52 | + BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_preadv)(BlockDriverState *bs, | ||
53 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
54 | BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); | ||
55 | - BlockAIOCB *(*bdrv_aio_pwritev)(BlockDriverState *bs, | ||
56 | + | ||
57 | + BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_pwritev)(BlockDriverState *bs, | ||
58 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
59 | BdrvRequestFlags flags, BlockCompletionFunc *cb, void *opaque); | ||
60 | + | ||
61 | BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_flush)( | ||
62 | BlockDriverState *bs, BlockCompletionFunc *cb, void *opaque); | ||
63 | |||
64 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
65 | BlockDriverState *bs, int64_t offset, int bytes, | ||
66 | BlockCompletionFunc *cb, void *opaque); | ||
67 | |||
68 | - int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs, | ||
69 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_readv)(BlockDriverState *bs, | ||
70 | int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); | ||
71 | |||
72 | /** | ||
73 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
74 | * | ||
75 | * The buffer in @qiov may point directly to guest memory. | ||
76 | */ | ||
77 | - int coroutine_fn (*bdrv_co_preadv)(BlockDriverState *bs, | ||
78 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_preadv)(BlockDriverState *bs, | ||
79 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
80 | BdrvRequestFlags flags); | ||
81 | |||
82 | - int coroutine_fn (*bdrv_co_preadv_part)(BlockDriverState *bs, | ||
83 | - int64_t offset, int64_t bytes, | ||
84 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_preadv_part)( | ||
85 | + BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
86 | QEMUIOVector *qiov, size_t qiov_offset, | ||
87 | BdrvRequestFlags flags); | ||
88 | |||
89 | - int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs, | ||
90 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_writev)(BlockDriverState *bs, | ||
91 | int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, | ||
92 | int flags); | ||
93 | /** | ||
94 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
95 | * | ||
96 | * The buffer in @qiov may point directly to guest memory. | ||
97 | */ | ||
98 | - int coroutine_fn (*bdrv_co_pwritev)(BlockDriverState *bs, | ||
99 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
100 | - BdrvRequestFlags flags); | ||
101 | - int coroutine_fn (*bdrv_co_pwritev_part)(BlockDriverState *bs, | ||
102 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset, | ||
103 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pwritev)( | ||
104 | + BlockDriverState *bs, int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
105 | BdrvRequestFlags flags); | ||
106 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pwritev_part)( | ||
107 | + BlockDriverState *bs, int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
108 | + size_t qiov_offset, BdrvRequestFlags flags); | ||
109 | |||
26 | /* | 110 | /* |
27 | @@ -XXX,XX +XXX,XX @@ static int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) | 111 | * Efficiently zero a region of the disk image. Typically an image format |
28 | 112 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | |
29 | case 0x83: /* Device identification page, mandatory */ | 113 | BlockMeasureInfo *(*bdrv_measure)(QemuOpts *opts, BlockDriverState *in_bs, |
30 | { | 114 | Error **errp); |
31 | - const char *str = s->serial ?: blk_name(s->qdev.conf.blk); | 115 | |
32 | - int max_len = s->serial ? 20 : 255 - 8; | 116 | - int coroutine_fn (*bdrv_co_pwritev_compressed)(BlockDriverState *bs, |
33 | - int id_len = strlen(str); | 117 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov); |
34 | + int id_len = s->device_id ? MIN(strlen(s->device_id), 255 - 8) : 0; | 118 | - int coroutine_fn (*bdrv_co_pwritev_compressed_part)(BlockDriverState *bs, |
35 | 119 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, | |
36 | - if (id_len > max_len) { | 120 | - size_t qiov_offset); |
37 | - id_len = max_len; | 121 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pwritev_compressed)( |
38 | - } | 122 | + BlockDriverState *bs, int64_t offset, int64_t bytes, |
39 | DPRINTF("Inquiry EVPD[Device identification] " | 123 | + QEMUIOVector *qiov); |
40 | "buffer size %zd\n", req->cmd.xfer); | 124 | + |
41 | 125 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pwritev_compressed_part)( | |
42 | @@ -XXX,XX +XXX,XX @@ static int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) | 126 | + BlockDriverState *bs, int64_t offset, int64_t bytes, |
43 | outbuf[buflen++] = 0; /* not officially assigned */ | 127 | + QEMUIOVector *qiov, size_t qiov_offset); |
44 | outbuf[buflen++] = 0; /* reserved */ | 128 | |
45 | outbuf[buflen++] = id_len; /* length of data following */ | 129 | int coroutine_fn (*bdrv_co_get_info)(BlockDriverState *bs, |
46 | - memcpy(outbuf + buflen, str, id_len); | 130 | BlockDriverInfo *bdi); |
47 | + memcpy(outbuf + buflen, s->device_id, id_len); | 131 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
48 | buflen += id_len; | 132 | BlockDriverState *bs, const char *name, Error **errp); |
49 | } | 133 | }; |
50 | 134 | ||
51 | @@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp) | 135 | -static inline bool block_driver_can_compress(BlockDriver *drv) |
52 | if (!s->vendor) { | 136 | +static inline bool TSA_NO_TSA block_driver_can_compress(BlockDriver *drv) |
53 | s->vendor = g_strdup("QEMU"); | 137 | { |
138 | return drv->bdrv_co_pwritev_compressed || | ||
139 | drv->bdrv_co_pwritev_compressed_part; | ||
140 | diff --git a/block/io.c b/block/io.c | ||
141 | index XXXXXXX..XXXXXXX 100644 | ||
142 | --- a/block/io.c | ||
143 | +++ b/block/io.c | ||
144 | @@ -XXX,XX +XXX,XX @@ void bdrv_refresh_limits(BlockDriverState *bs, Transaction *tran, Error **errp) | ||
145 | bool have_limits; | ||
146 | |||
147 | GLOBAL_STATE_CODE(); | ||
148 | + assume_graph_lock(); /* FIXME */ | ||
149 | |||
150 | if (tran) { | ||
151 | BdrvRefreshLimitsState *s = g_new(BdrvRefreshLimitsState, 1); | ||
152 | @@ -XXX,XX +XXX,XX @@ static void bdrv_co_io_em_complete(void *opaque, int ret) | ||
153 | aio_co_wake(co->coroutine); | ||
154 | } | ||
155 | |||
156 | -static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs, | ||
157 | - int64_t offset, int64_t bytes, | ||
158 | - QEMUIOVector *qiov, | ||
159 | - size_t qiov_offset, int flags) | ||
160 | +static int coroutine_fn GRAPH_RDLOCK | ||
161 | +bdrv_driver_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
162 | + QEMUIOVector *qiov, size_t qiov_offset, int flags) | ||
163 | { | ||
164 | BlockDriver *drv = bs->drv; | ||
165 | int64_t sector_num; | ||
166 | @@ -XXX,XX +XXX,XX @@ out: | ||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | -static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs, | ||
171 | - int64_t offset, int64_t bytes, | ||
172 | - QEMUIOVector *qiov, | ||
173 | - size_t qiov_offset, | ||
174 | - BdrvRequestFlags flags) | ||
175 | +static int coroutine_fn GRAPH_RDLOCK | ||
176 | +bdrv_driver_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
177 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
178 | + BdrvRequestFlags flags) | ||
179 | { | ||
180 | BlockDriver *drv = bs->drv; | ||
181 | bool emulate_fua = false; | ||
182 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs, | ||
183 | QEMUIOVector local_qiov; | ||
184 | int ret; | ||
185 | |||
186 | - assume_graph_lock(); /* FIXME */ | ||
187 | - | ||
188 | bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort); | ||
189 | |||
190 | if (!drv) { | ||
191 | @@ -XXX,XX +XXX,XX @@ emulate_flags: | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | -static int coroutine_fn | ||
196 | +static int coroutine_fn GRAPH_RDLOCK | ||
197 | bdrv_driver_pwritev_compressed(BlockDriverState *bs, int64_t offset, | ||
198 | int64_t bytes, QEMUIOVector *qiov, | ||
199 | size_t qiov_offset) | ||
200 | @@ -XXX,XX +XXX,XX @@ bdrv_driver_pwritev_compressed(BlockDriverState *bs, int64_t offset, | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | -static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, | ||
205 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
206 | - size_t qiov_offset, int flags) | ||
207 | +static int coroutine_fn GRAPH_RDLOCK | ||
208 | +bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes, | ||
209 | + QEMUIOVector *qiov, size_t qiov_offset, int flags) | ||
210 | { | ||
211 | BlockDriverState *bs = child->bs; | ||
212 | |||
213 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child, | ||
214 | int64_t progress = 0; | ||
215 | bool skip_write; | ||
216 | |||
217 | - assume_graph_lock(); /* FIXME */ | ||
218 | - | ||
219 | bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort); | ||
220 | |||
221 | if (!drv) { | ||
222 | @@ -XXX,XX +XXX,XX @@ err: | ||
223 | * handles copy on read, zeroing after EOF, and fragmentation of large | ||
224 | * reads; any other features must be implemented by the caller. | ||
225 | */ | ||
226 | -static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child, | ||
227 | - BdrvTrackedRequest *req, int64_t offset, int64_t bytes, | ||
228 | - int64_t align, QEMUIOVector *qiov, size_t qiov_offset, int flags) | ||
229 | +static int coroutine_fn GRAPH_RDLOCK | ||
230 | +bdrv_aligned_preadv(BdrvChild *child, BdrvTrackedRequest *req, | ||
231 | + int64_t offset, int64_t bytes, int64_t align, | ||
232 | + QEMUIOVector *qiov, size_t qiov_offset, int flags) | ||
233 | { | ||
234 | BlockDriverState *bs = child->bs; | ||
235 | int64_t total_bytes, max_bytes; | ||
236 | @@ -XXX,XX +XXX,XX @@ static bool bdrv_init_padding(BlockDriverState *bs, | ||
237 | return true; | ||
238 | } | ||
239 | |||
240 | -static coroutine_fn int bdrv_padding_rmw_read(BdrvChild *child, | ||
241 | - BdrvTrackedRequest *req, | ||
242 | - BdrvRequestPadding *pad, | ||
243 | - bool zero_middle) | ||
244 | +static int coroutine_fn GRAPH_RDLOCK | ||
245 | +bdrv_padding_rmw_read(BdrvChild *child, BdrvTrackedRequest *req, | ||
246 | + BdrvRequestPadding *pad, bool zero_middle) | ||
247 | { | ||
248 | QEMUIOVector local_qiov; | ||
249 | BlockDriverState *bs = child->bs; | ||
250 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, | ||
251 | int ret; | ||
252 | IO_CODE(); | ||
253 | |||
254 | + assume_graph_lock(); /* FIXME */ | ||
255 | + | ||
256 | trace_bdrv_co_preadv_part(bs, offset, bytes, flags); | ||
257 | |||
258 | if (!bdrv_co_is_inserted(bs)) { | ||
259 | @@ -XXX,XX +XXX,XX @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, int64_t bytes, | ||
260 | * Forwards an already correctly aligned write request to the BlockDriver, | ||
261 | * after possibly fragmenting it. | ||
262 | */ | ||
263 | -static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, | ||
264 | - BdrvTrackedRequest *req, int64_t offset, int64_t bytes, | ||
265 | - int64_t align, QEMUIOVector *qiov, size_t qiov_offset, | ||
266 | - BdrvRequestFlags flags) | ||
267 | +static int coroutine_fn GRAPH_RDLOCK | ||
268 | +bdrv_aligned_pwritev(BdrvChild *child, BdrvTrackedRequest *req, | ||
269 | + int64_t offset, int64_t bytes, int64_t align, | ||
270 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
271 | + BdrvRequestFlags flags) | ||
272 | { | ||
273 | BlockDriverState *bs = child->bs; | ||
274 | BlockDriver *drv = bs->drv; | ||
275 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, | ||
276 | int64_t bytes_remaining = bytes; | ||
277 | int max_transfer; | ||
278 | |||
279 | - assume_graph_lock(); /* FIXME */ | ||
280 | - | ||
281 | bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort); | ||
282 | |||
283 | if (!drv) { | ||
284 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, | ||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | -static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child, | ||
289 | - int64_t offset, | ||
290 | - int64_t bytes, | ||
291 | - BdrvRequestFlags flags, | ||
292 | - BdrvTrackedRequest *req) | ||
293 | +static int coroutine_fn GRAPH_RDLOCK | ||
294 | +bdrv_co_do_zero_pwritev(BdrvChild *child, int64_t offset, int64_t bytes, | ||
295 | + BdrvRequestFlags flags, BdrvTrackedRequest *req) | ||
296 | { | ||
297 | BlockDriverState *bs = child->bs; | ||
298 | QEMUIOVector local_qiov; | ||
299 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, | ||
300 | bool padded = false; | ||
301 | IO_CODE(); | ||
302 | |||
303 | + assume_graph_lock(); /* FIXME */ | ||
304 | + | ||
305 | trace_bdrv_co_pwritev_part(child->bs, offset, bytes, flags); | ||
306 | |||
307 | if (!bdrv_co_is_inserted(bs)) { | ||
308 | diff --git a/block/parallels.c b/block/parallels.c | ||
309 | index XXXXXXX..XXXXXXX 100644 | ||
310 | --- a/block/parallels.c | ||
311 | +++ b/block/parallels.c | ||
312 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_block_status(BlockDriverState *bs, | ||
313 | return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID; | ||
314 | } | ||
315 | |||
316 | -static coroutine_fn int parallels_co_writev(BlockDriverState *bs, | ||
317 | - int64_t sector_num, int nb_sectors, | ||
318 | - QEMUIOVector *qiov, int flags) | ||
319 | +static int coroutine_fn GRAPH_RDLOCK | ||
320 | +parallels_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors, | ||
321 | + QEMUIOVector *qiov, int flags) | ||
322 | { | ||
323 | BDRVParallelsState *s = bs->opaque; | ||
324 | uint64_t bytes_done = 0; | ||
325 | QEMUIOVector hd_qiov; | ||
326 | int ret = 0; | ||
327 | |||
328 | - assume_graph_lock(); /* FIXME */ | ||
329 | - | ||
330 | qemu_iovec_init(&hd_qiov, qiov->niov); | ||
331 | |||
332 | while (nb_sectors > 0) { | ||
333 | diff --git a/block/qcow.c b/block/qcow.c | ||
334 | index XXXXXXX..XXXXXXX 100644 | ||
335 | --- a/block/qcow.c | ||
336 | +++ b/block/qcow.c | ||
337 | @@ -XXX,XX +XXX,XX @@ static void qcow_refresh_limits(BlockDriverState *bs, Error **errp) | ||
338 | bs->bl.request_alignment = BDRV_SECTOR_SIZE; | ||
339 | } | ||
340 | |||
341 | -static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset, | ||
342 | - int64_t bytes, QEMUIOVector *qiov, | ||
343 | - BdrvRequestFlags flags) | ||
344 | +static int coroutine_fn GRAPH_RDLOCK | ||
345 | +qcow_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
346 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
347 | { | ||
348 | BDRVQcowState *s = bs->opaque; | ||
349 | int offset_in_cluster; | ||
350 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset, | ||
351 | uint8_t *buf; | ||
352 | void *orig_buf; | ||
353 | |||
354 | - assume_graph_lock(); /* FIXME */ | ||
355 | - | ||
356 | if (qiov->niov > 1) { | ||
357 | buf = orig_buf = qemu_try_blockalign(bs, qiov->size); | ||
358 | if (buf == NULL) { | ||
359 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset, | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | -static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, int64_t offset, | ||
364 | - int64_t bytes, QEMUIOVector *qiov, | ||
365 | - BdrvRequestFlags flags) | ||
366 | +static int coroutine_fn GRAPH_RDLOCK | ||
367 | +qcow_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
368 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
369 | { | ||
370 | BDRVQcowState *s = bs->opaque; | ||
371 | int offset_in_cluster; | ||
372 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, int64_t offset, | ||
373 | uint8_t *buf; | ||
374 | void *orig_buf; | ||
375 | |||
376 | - assume_graph_lock(); /* FIXME */ | ||
377 | - | ||
378 | s->cluster_cache_offset = -1; /* disable compressed cache */ | ||
379 | |||
380 | /* We must always copy the iov when encrypting, so we | ||
381 | @@ -XXX,XX +XXX,XX @@ static int qcow_make_empty(BlockDriverState *bs) | ||
382 | |||
383 | /* XXX: put compressed sectors first, then all the cluster aligned | ||
384 | tables to avoid losing bytes in alignment */ | ||
385 | -static coroutine_fn int | ||
386 | +static int coroutine_fn GRAPH_RDLOCK | ||
387 | qcow_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
388 | QEMUIOVector *qiov) | ||
389 | { | ||
390 | @@ -XXX,XX +XXX,XX @@ qcow_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
391 | uint8_t *buf, *out_buf; | ||
392 | uint64_t cluster_offset; | ||
393 | |||
394 | - assume_graph_lock(); /* FIXME */ | ||
395 | - | ||
396 | buf = qemu_blockalign(bs, s->cluster_size); | ||
397 | if (bytes != s->cluster_size) { | ||
398 | if (bytes > s->cluster_size || | ||
399 | diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c | ||
400 | index XXXXXXX..XXXXXXX 100644 | ||
401 | --- a/block/qcow2-cluster.c | ||
402 | +++ b/block/qcow2-cluster.c | ||
403 | @@ -XXX,XX +XXX,XX @@ static int count_contiguous_subclusters(BlockDriverState *bs, int nb_clusters, | ||
404 | return count; | ||
405 | } | ||
406 | |||
407 | -static int coroutine_fn do_perform_cow_read(BlockDriverState *bs, | ||
408 | - uint64_t src_cluster_offset, | ||
409 | - unsigned offset_in_cluster, | ||
410 | - QEMUIOVector *qiov) | ||
411 | +static int coroutine_fn GRAPH_RDLOCK | ||
412 | +do_perform_cow_read(BlockDriverState *bs, uint64_t src_cluster_offset, | ||
413 | + unsigned offset_in_cluster, QEMUIOVector *qiov) | ||
414 | { | ||
415 | int ret; | ||
416 | |||
417 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, | ||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | -static int coroutine_fn perform_cow(BlockDriverState *bs, QCowL2Meta *m) | ||
422 | +static int coroutine_fn GRAPH_RDLOCK | ||
423 | +perform_cow(BlockDriverState *bs, QCowL2Meta *m) | ||
424 | { | ||
425 | BDRVQcow2State *s = bs->opaque; | ||
426 | Qcow2COWRegion *start = &m->cow_start; | ||
427 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
428 | index XXXXXXX..XXXXXXX 100644 | ||
429 | --- a/block/qcow2.c | ||
430 | +++ b/block/qcow2.c | ||
431 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs, | ||
432 | return status; | ||
433 | } | ||
434 | |||
435 | -static coroutine_fn int qcow2_handle_l2meta(BlockDriverState *bs, | ||
436 | - QCowL2Meta **pl2meta, | ||
437 | - bool link_l2) | ||
438 | +static int coroutine_fn GRAPH_RDLOCK | ||
439 | +qcow2_handle_l2meta(BlockDriverState *bs, QCowL2Meta **pl2meta, bool link_l2) | ||
440 | { | ||
441 | int ret = 0; | ||
442 | QCowL2Meta *l2meta = *pl2meta; | ||
443 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn GRAPH_RDLOCK int qcow2_co_pwritev_task_entry(AioTask *task) | ||
444 | t->l2meta); | ||
445 | } | ||
446 | |||
447 | -static coroutine_fn int qcow2_co_pwritev_part( | ||
448 | - BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
449 | - QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags) | ||
450 | +static int coroutine_fn GRAPH_RDLOCK | ||
451 | +qcow2_co_pwritev_part(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
452 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
453 | + BdrvRequestFlags flags) | ||
454 | { | ||
455 | BDRVQcow2State *s = bs->opaque; | ||
456 | int offset_in_cluster; | ||
457 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_part( | ||
458 | QCowL2Meta *l2meta = NULL; | ||
459 | AioTaskPool *aio = NULL; | ||
460 | |||
461 | - assume_graph_lock(); /* FIXME */ | ||
462 | - | ||
463 | trace_qcow2_writev_start_req(qemu_coroutine_self(), offset, bytes); | ||
464 | |||
465 | while (bytes != 0 && aio_task_pool_status(aio) == 0) { | ||
466 | @@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_to(BlockDriverState *bs, | ||
467 | uint64_t host_offset; | ||
468 | QCowL2Meta *l2meta = NULL; | ||
469 | |||
470 | + assume_graph_lock(); /* FIXME */ | ||
471 | assert(!bs->encrypted); | ||
472 | |||
473 | qemu_co_mutex_lock(&s->lock); | ||
474 | @@ -XXX,XX +XXX,XX @@ fail: | ||
475 | return ret; | ||
476 | } | ||
477 | |||
478 | -static coroutine_fn int | ||
479 | +static int coroutine_fn GRAPH_RDLOCK | ||
480 | qcow2_co_pwritev_compressed_task(BlockDriverState *bs, | ||
481 | uint64_t offset, uint64_t bytes, | ||
482 | QEMUIOVector *qiov, size_t qiov_offset) | ||
483 | @@ -XXX,XX +XXX,XX @@ fail: | ||
484 | return ret; | ||
485 | } | ||
486 | |||
487 | -static coroutine_fn int qcow2_co_pwritev_compressed_task_entry(AioTask *task) | ||
488 | +/* | ||
489 | + * This function can count as GRAPH_RDLOCK because | ||
490 | + * qcow2_co_pwritev_compressed_part() holds the graph lock and keeps it until | ||
491 | + * this coroutine has terminated. | ||
492 | + */ | ||
493 | +static int coroutine_fn GRAPH_RDLOCK | ||
494 | +qcow2_co_pwritev_compressed_task_entry(AioTask *task) | ||
495 | { | ||
496 | Qcow2AioTask *t = container_of(task, Qcow2AioTask, task); | ||
497 | |||
498 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_compressed_task_entry(AioTask *task) | ||
499 | * XXX: put compressed sectors first, then all the cluster aligned | ||
500 | * tables to avoid losing bytes in alignment | ||
501 | */ | ||
502 | -static coroutine_fn int | ||
503 | +static int coroutine_fn GRAPH_RDLOCK | ||
504 | qcow2_co_pwritev_compressed_part(BlockDriverState *bs, | ||
505 | int64_t offset, int64_t bytes, | ||
506 | QEMUIOVector *qiov, size_t qiov_offset) | ||
507 | @@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs, | ||
508 | AioTaskPool *aio = NULL; | ||
509 | int ret = 0; | ||
510 | |||
511 | - assume_graph_lock(); /* FIXME */ | ||
512 | - | ||
513 | if (has_data_file(bs)) { | ||
514 | return -ENOTSUP; | ||
54 | } | 515 | } |
55 | + if (!s->device_id) { | 516 | @@ -XXX,XX +XXX,XX @@ static int64_t qcow2_check_vmstate_request(BlockDriverState *bs, |
56 | + if (s->serial) { | 517 | return pos; |
57 | + s->device_id = g_strdup_printf("%.20s", s->serial); | 518 | } |
58 | + } else { | 519 | |
59 | + const char *str = blk_name(s->qdev.conf.blk); | 520 | -static coroutine_fn int qcow2_co_save_vmstate(BlockDriverState *bs, |
60 | + if (str && *str) { | 521 | - QEMUIOVector *qiov, int64_t pos) |
61 | + s->device_id = g_strdup(str); | 522 | +static int coroutine_fn GRAPH_RDLOCK |
62 | + } | 523 | +qcow2_co_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) |
63 | + } | 524 | { |
64 | + } | 525 | int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos); |
65 | 526 | if (offset < 0) { | |
66 | if (blk_is_sg(s->qdev.conf.blk)) { | 527 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_save_vmstate(BlockDriverState *bs, |
67 | error_setg(errp, "unwanted /dev/sg*"); | 528 | return bs->drv->bdrv_co_pwritev_part(bs, offset, qiov->size, qiov, 0, 0); |
68 | @@ -XXX,XX +XXX,XX @@ static const TypeInfo scsi_disk_base_info = { | 529 | } |
69 | DEFINE_PROP_STRING("ver", SCSIDiskState, version), \ | 530 | |
70 | DEFINE_PROP_STRING("serial", SCSIDiskState, serial), \ | 531 | -static coroutine_fn int qcow2_co_load_vmstate(BlockDriverState *bs, |
71 | DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor), \ | 532 | - QEMUIOVector *qiov, int64_t pos) |
72 | - DEFINE_PROP_STRING("product", SCSIDiskState, product) | 533 | +static int coroutine_fn GRAPH_RDLOCK |
73 | + DEFINE_PROP_STRING("product", SCSIDiskState, product), \ | 534 | +qcow2_co_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos) |
74 | + DEFINE_PROP_STRING("device_id", SCSIDiskState, device_id) | 535 | { |
75 | + | 536 | int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos); |
76 | 537 | if (offset < 0) { | |
77 | static Property scsi_hd_properties[] = { | 538 | diff --git a/block/qed.c b/block/qed.c |
78 | DEFINE_SCSI_DISK_PROPERTIES(), | 539 | index XXXXXXX..XXXXXXX 100644 |
540 | --- a/block/qed.c | ||
541 | +++ b/block/qed.c | ||
542 | @@ -XXX,XX +XXX,XX @@ qed_co_request(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov, | ||
543 | return qed_aio_next_io(&acb); | ||
544 | } | ||
545 | |||
546 | -static int coroutine_fn bdrv_qed_co_readv(BlockDriverState *bs, | ||
547 | - int64_t sector_num, int nb_sectors, | ||
548 | - QEMUIOVector *qiov) | ||
549 | +static int coroutine_fn GRAPH_RDLOCK | ||
550 | +bdrv_qed_co_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors, | ||
551 | + QEMUIOVector *qiov) | ||
552 | { | ||
553 | - assume_graph_lock(); /* FIXME */ | ||
554 | return qed_co_request(bs, sector_num, qiov, nb_sectors, 0); | ||
555 | } | ||
556 | |||
557 | -static int coroutine_fn bdrv_qed_co_writev(BlockDriverState *bs, | ||
558 | - int64_t sector_num, int nb_sectors, | ||
559 | - QEMUIOVector *qiov, int flags) | ||
560 | +static int coroutine_fn GRAPH_RDLOCK | ||
561 | +bdrv_qed_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors, | ||
562 | + QEMUIOVector *qiov, int flags) | ||
563 | { | ||
564 | - assume_graph_lock(); /* FIXME */ | ||
565 | return qed_co_request(bs, sector_num, qiov, nb_sectors, QED_AIOCB_WRITE); | ||
566 | } | ||
567 | |||
568 | diff --git a/block/quorum.c b/block/quorum.c | ||
569 | index XXXXXXX..XXXXXXX 100644 | ||
570 | --- a/block/quorum.c | ||
571 | +++ b/block/quorum.c | ||
572 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn GRAPH_RDLOCK write_quorum_entry(void *opaque) | ||
573 | } | ||
574 | } | ||
575 | |||
576 | -static int coroutine_fn quorum_co_pwritev(BlockDriverState *bs, int64_t offset, | ||
577 | - int64_t bytes, QEMUIOVector *qiov, | ||
578 | - BdrvRequestFlags flags) | ||
579 | +static int coroutine_fn GRAPH_RDLOCK | ||
580 | +quorum_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
581 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
582 | { | ||
583 | BDRVQuorumState *s = bs->opaque; | ||
584 | QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags); | ||
585 | int i, ret; | ||
586 | |||
587 | - assume_graph_lock(); /* FIXME */ | ||
588 | - | ||
589 | for (i = 0; i < s->num_children; i++) { | ||
590 | Coroutine *co; | ||
591 | QuorumCo data = { | ||
592 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
593 | index XXXXXXX..XXXXXXX 100644 | ||
594 | --- a/block/vmdk.c | ||
595 | +++ b/block/vmdk.c | ||
596 | @@ -XXX,XX +XXX,XX @@ vmdk_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
597 | return ret; | ||
598 | } | ||
599 | |||
600 | -static int coroutine_fn | ||
601 | +static int coroutine_fn GRAPH_RDLOCK | ||
602 | vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
603 | QEMUIOVector *qiov) | ||
604 | { | ||
605 | - assume_graph_lock(); /* FIXME */ | ||
606 | - | ||
607 | if (bytes == 0) { | ||
608 | /* The caller will write bytes 0 to signal EOF. | ||
609 | * When receive it, we align EOF to a sector boundary. */ | ||
79 | -- | 610 | -- |
80 | 2.20.1 | 611 | 2.39.2 |
81 | |||
82 | diff view generated by jsdifflib |
1 | From: Markus Armbruster <armbru@redhat.com> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_co_pread*/pwrite*() need to hold a reader lock for the graph. | ||
2 | 3 | ||
3 | We define 54 macros for the powers of two >= 1024. We use six, in six | 4 | For some places, we know that they will hold the lock, but we don't have |
4 | macro definitions. Four of them could just as well use the common MiB | 5 | the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock() |
5 | macro, so do that. The remaining two can't, because they get passed | 6 | with a FIXME comment. These places will be removed once everything is |
6 | to stringify. Replace the macro by the literal number there. | 7 | properly annotated. |
7 | Slightly harder to read in one instance (1048576 vs. S_1MiB), so add a | ||
8 | comment there. The other instance is a wash: 65536 vs S_64KiB. 65536 | ||
9 | has been good enough for more than seven years there. | ||
10 | 8 | ||
11 | This effectively reverts commit 540b8492618 and 1240ac558d3. | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
12 | 10 | Message-Id: <20230203152202.49054-12-kwolf@redhat.com> | |
13 | Signed-off-by: Markus Armbruster <armbru@redhat.com> | 11 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
14 | Reviewed-by: Alberto Garcia <berto@igalia.com> | ||
15 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
16 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | --- | 13 | --- |
19 | block/qcow2.h | 10 +++--- | 14 | block/qcow2.h | 9 ++--- |
20 | include/qemu/units.h | 73 -------------------------------------------- | 15 | block/qed.h | 18 +++++----- |
21 | block/vdi.c | 3 +- | 16 | include/block/block_int-io.h | 14 ++++---- |
22 | 3 files changed, 7 insertions(+), 79 deletions(-) | 17 | block/blkdebug.c | 4 +-- |
18 | block/blklogwrites.c | 7 ++-- | ||
19 | block/blkreplay.c | 10 +++--- | ||
20 | block/block-backend.c | 2 ++ | ||
21 | block/bochs.c | 2 +- | ||
22 | block/commit.c | 5 +-- | ||
23 | block/copy-before-write.c | 16 ++++----- | ||
24 | block/copy-on-read.c | 26 ++++++--------- | ||
25 | block/crypto.c | 4 +-- | ||
26 | block/filter-compress.c | 19 +++++------ | ||
27 | block/io.c | 7 ++-- | ||
28 | block/mirror.c | 18 +++++----- | ||
29 | block/parallels.c | 8 +++-- | ||
30 | block/preallocate.c | 18 +++++----- | ||
31 | block/qcow.c | 8 ++--- | ||
32 | block/qcow2-cluster.c | 7 ++-- | ||
33 | block/qcow2.c | 53 +++++++++++++++-------------- | ||
34 | block/qed-table.c | 4 +-- | ||
35 | block/qed.c | 31 +++++++++-------- | ||
36 | block/quorum.c | 29 ++++++++++------ | ||
37 | block/raw-format.c | 12 +++---- | ||
38 | block/replication.c | 15 ++++----- | ||
39 | block/throttle.c | 21 +++++------- | ||
40 | block/vdi.c | 4 +-- | ||
41 | block/vhdx.c | 11 +++--- | ||
42 | block/vmdk.c | 65 +++++++++++++++--------------------- | ||
43 | block/vpc.c | 4 +-- | ||
44 | tests/unit/test-bdrv-drain.c | 20 ++++++----- | ||
45 | 31 files changed, 233 insertions(+), 238 deletions(-) | ||
23 | 46 | ||
24 | diff --git a/block/qcow2.h b/block/qcow2.h | 47 | diff --git a/block/qcow2.h b/block/qcow2.h |
25 | index XXXXXXX..XXXXXXX 100644 | 48 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/block/qcow2.h | 49 | --- a/block/qcow2.h |
27 | +++ b/block/qcow2.h | 50 | +++ b/block/qcow2.h |
51 | @@ -XXX,XX +XXX,XX @@ int qcow2_validate_table(BlockDriverState *bs, uint64_t offset, | ||
52 | Error **errp); | ||
53 | |||
54 | /* qcow2-refcount.c functions */ | ||
55 | -int coroutine_fn qcow2_refcount_init(BlockDriverState *bs); | ||
56 | +int coroutine_fn GRAPH_RDLOCK qcow2_refcount_init(BlockDriverState *bs); | ||
57 | void qcow2_refcount_close(BlockDriverState *bs); | ||
58 | |||
59 | int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index, | ||
60 | @@ -XXX,XX +XXX,XX @@ void qcow2_free_snapshots(BlockDriverState *bs); | ||
61 | int qcow2_read_snapshots(BlockDriverState *bs, Error **errp); | ||
62 | int qcow2_write_snapshots(BlockDriverState *bs); | ||
63 | |||
64 | -int coroutine_fn qcow2_check_read_snapshot_table(BlockDriverState *bs, | ||
65 | - BdrvCheckResult *result, | ||
66 | - BdrvCheckMode fix); | ||
67 | +int coroutine_fn GRAPH_RDLOCK | ||
68 | +qcow2_check_read_snapshot_table(BlockDriverState *bs, BdrvCheckResult *result, | ||
69 | + BdrvCheckMode fix); | ||
70 | + | ||
71 | int coroutine_fn qcow2_check_fix_snapshot_table(BlockDriverState *bs, | ||
72 | BdrvCheckResult *result, | ||
73 | BdrvCheckMode fix); | ||
74 | diff --git a/block/qed.h b/block/qed.h | ||
75 | index XXXXXXX..XXXXXXX 100644 | ||
76 | --- a/block/qed.h | ||
77 | +++ b/block/qed.h | ||
78 | @@ -XXX,XX +XXX,XX @@ void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table); | ||
79 | /** | ||
80 | * Table I/O functions | ||
81 | */ | ||
82 | -int coroutine_fn qed_read_l1_table_sync(BDRVQEDState *s); | ||
83 | +int coroutine_fn GRAPH_RDLOCK qed_read_l1_table_sync(BDRVQEDState *s); | ||
84 | |||
85 | int coroutine_fn GRAPH_RDLOCK | ||
86 | qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n); | ||
87 | @@ -XXX,XX +XXX,XX @@ qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n); | ||
88 | int coroutine_fn GRAPH_RDLOCK | ||
89 | qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index, unsigned int n); | ||
90 | |||
91 | -int coroutine_fn qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, | ||
92 | - uint64_t offset); | ||
93 | -int coroutine_fn qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, | ||
94 | - uint64_t offset); | ||
95 | +int coroutine_fn GRAPH_RDLOCK | ||
96 | +qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset); | ||
97 | + | ||
98 | +int coroutine_fn GRAPH_RDLOCK | ||
99 | +qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset); | ||
100 | |||
101 | int coroutine_fn GRAPH_RDLOCK | ||
102 | qed_write_l2_table(BDRVQEDState *s, QEDRequest *request, unsigned int index, | ||
103 | @@ -XXX,XX +XXX,XX @@ qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request, | ||
104 | /** | ||
105 | * Cluster functions | ||
106 | */ | ||
107 | -int coroutine_fn qed_find_cluster(BDRVQEDState *s, QEDRequest *request, | ||
108 | - uint64_t pos, size_t *len, | ||
109 | - uint64_t *img_offset); | ||
110 | +int coroutine_fn GRAPH_RDLOCK | ||
111 | +qed_find_cluster(BDRVQEDState *s, QEDRequest *request, uint64_t pos, | ||
112 | + size_t *len, uint64_t *img_offset); | ||
113 | |||
114 | /** | ||
115 | * Consistency check | ||
116 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn qed_find_cluster(BDRVQEDState *s, QEDRequest *request, | ||
117 | int coroutine_fn GRAPH_RDLOCK | ||
118 | qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix); | ||
119 | |||
120 | - | ||
121 | QEDTable *qed_alloc_table(BDRVQEDState *s); | ||
122 | |||
123 | /** | ||
124 | diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h | ||
125 | index XXXXXXX..XXXXXXX 100644 | ||
126 | --- a/include/block/block_int-io.h | ||
127 | +++ b/include/block/block_int-io.h | ||
128 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard_snapshot(BlockDriverState *bs, | ||
129 | int64_t offset, int64_t bytes); | ||
130 | |||
131 | |||
132 | -int coroutine_fn bdrv_co_preadv(BdrvChild *child, | ||
133 | +int coroutine_fn GRAPH_RDLOCK bdrv_co_preadv(BdrvChild *child, | ||
134 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
135 | BdrvRequestFlags flags); | ||
136 | -int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, | ||
137 | +int coroutine_fn GRAPH_RDLOCK bdrv_co_preadv_part(BdrvChild *child, | ||
138 | int64_t offset, int64_t bytes, | ||
139 | QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags); | ||
140 | -int coroutine_fn bdrv_co_pwritev(BdrvChild *child, | ||
141 | +int coroutine_fn GRAPH_RDLOCK bdrv_co_pwritev(BdrvChild *child, | ||
142 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, | ||
143 | BdrvRequestFlags flags); | ||
144 | -int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, | ||
145 | +int coroutine_fn GRAPH_RDLOCK bdrv_co_pwritev_part(BdrvChild *child, | ||
146 | int64_t offset, int64_t bytes, | ||
147 | QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags); | ||
148 | |||
149 | -static inline int coroutine_fn bdrv_co_pread(BdrvChild *child, | ||
150 | +static inline int coroutine_fn GRAPH_RDLOCK bdrv_co_pread(BdrvChild *child, | ||
151 | int64_t offset, int64_t bytes, void *buf, BdrvRequestFlags flags) | ||
152 | { | ||
153 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
154 | IO_CODE(); | ||
155 | + assert_bdrv_graph_readable(); | ||
156 | |||
157 | return bdrv_co_preadv(child, offset, bytes, &qiov, flags); | ||
158 | } | ||
159 | |||
160 | -static inline int coroutine_fn bdrv_co_pwrite(BdrvChild *child, | ||
161 | +static inline int coroutine_fn GRAPH_RDLOCK bdrv_co_pwrite(BdrvChild *child, | ||
162 | int64_t offset, int64_t bytes, const void *buf, BdrvRequestFlags flags) | ||
163 | { | ||
164 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); | ||
165 | IO_CODE(); | ||
166 | + assert_bdrv_graph_readable(); | ||
167 | |||
168 | return bdrv_co_pwritev(child, offset, bytes, &qiov, flags); | ||
169 | } | ||
170 | diff --git a/block/blkdebug.c b/block/blkdebug.c | ||
171 | index XXXXXXX..XXXXXXX 100644 | ||
172 | --- a/block/blkdebug.c | ||
173 | +++ b/block/blkdebug.c | ||
174 | @@ -XXX,XX +XXX,XX @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | ||
175 | return -error; | ||
176 | } | ||
177 | |||
178 | -static int coroutine_fn | ||
179 | +static int coroutine_fn GRAPH_RDLOCK | ||
180 | blkdebug_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
181 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
182 | { | ||
183 | @@ -XXX,XX +XXX,XX @@ blkdebug_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
184 | return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); | ||
185 | } | ||
186 | |||
187 | -static int coroutine_fn | ||
188 | +static int coroutine_fn GRAPH_RDLOCK | ||
189 | blkdebug_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
190 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
191 | { | ||
192 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | ||
193 | index XXXXXXX..XXXXXXX 100644 | ||
194 | --- a/block/blklogwrites.c | ||
195 | +++ b/block/blklogwrites.c | ||
196 | @@ -XXX,XX +XXX,XX @@ static void blk_log_writes_refresh_limits(BlockDriverState *bs, Error **errp) | ||
197 | bs->bl.request_alignment = s->sectorsize; | ||
198 | } | ||
199 | |||
200 | -static int coroutine_fn | ||
201 | +static int coroutine_fn GRAPH_RDLOCK | ||
202 | blk_log_writes_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
203 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
204 | { | ||
205 | @@ -XXX,XX +XXX,XX @@ blk_log_writes_co_log(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | ||
206 | return fr.file_ret; | ||
207 | } | ||
208 | |||
209 | -static int coroutine_fn | ||
210 | +static int coroutine_fn GRAPH_RDLOCK | ||
211 | blk_log_writes_co_do_file_pwritev(BlkLogWritesFileReq *fr) | ||
212 | { | ||
213 | return bdrv_co_pwritev(fr->bs->file, fr->offset, fr->bytes, | ||
214 | @@ -XXX,XX +XXX,XX @@ blk_log_writes_co_do_file_pdiscard(BlkLogWritesFileReq *fr) | ||
215 | return bdrv_co_pdiscard(fr->bs->file, fr->offset, fr->bytes); | ||
216 | } | ||
217 | |||
218 | -static int coroutine_fn | ||
219 | +static int coroutine_fn GRAPH_RDLOCK | ||
220 | blk_log_writes_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
221 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
222 | { | ||
223 | - assume_graph_lock(); /* FIXME */ | ||
224 | return blk_log_writes_co_log(bs, offset, bytes, qiov, flags, | ||
225 | blk_log_writes_co_do_file_pwritev, 0, false); | ||
226 | } | ||
227 | diff --git a/block/blkreplay.c b/block/blkreplay.c | ||
228 | index XXXXXXX..XXXXXXX 100644 | ||
229 | --- a/block/blkreplay.c | ||
230 | +++ b/block/blkreplay.c | ||
231 | @@ -XXX,XX +XXX,XX @@ static void block_request_create(uint64_t reqid, BlockDriverState *bs, | ||
232 | replay_block_event(req->bh, reqid); | ||
233 | } | ||
234 | |||
235 | -static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs, | ||
236 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
237 | +static int coroutine_fn GRAPH_RDLOCK | ||
238 | +blkreplay_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
239 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
240 | { | ||
241 | uint64_t reqid = blkreplay_next_id(); | ||
242 | int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); | ||
243 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs, | ||
244 | return ret; | ||
245 | } | ||
246 | |||
247 | -static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs, | ||
248 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
249 | +static int coroutine_fn GRAPH_RDLOCK | ||
250 | +blkreplay_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
251 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
252 | { | ||
253 | uint64_t reqid = blkreplay_next_id(); | ||
254 | int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); | ||
255 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
256 | index XXXXXXX..XXXXXXX 100644 | ||
257 | --- a/block/block-backend.c | ||
258 | +++ b/block/block-backend.c | ||
259 | @@ -XXX,XX +XXX,XX @@ blk_co_do_preadv_part(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
260 | IO_CODE(); | ||
261 | |||
262 | blk_wait_while_drained(blk); | ||
263 | + GRAPH_RDLOCK_GUARD(); | ||
264 | |||
265 | /* Call blk_bs() only after waiting, the graph may have changed */ | ||
266 | bs = blk_bs(blk); | ||
267 | @@ -XXX,XX +XXX,XX @@ blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes, | ||
268 | IO_CODE(); | ||
269 | |||
270 | blk_wait_while_drained(blk); | ||
271 | + GRAPH_RDLOCK_GUARD(); | ||
272 | |||
273 | /* Call blk_bs() only after waiting, the graph may have changed */ | ||
274 | bs = blk_bs(blk); | ||
275 | diff --git a/block/bochs.c b/block/bochs.c | ||
276 | index XXXXXXX..XXXXXXX 100644 | ||
277 | --- a/block/bochs.c | ||
278 | +++ b/block/bochs.c | ||
279 | @@ -XXX,XX +XXX,XX @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num) | ||
280 | return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset)); | ||
281 | } | ||
282 | |||
283 | -static int coroutine_fn | ||
284 | +static int coroutine_fn GRAPH_RDLOCK | ||
285 | bochs_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
286 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
287 | { | ||
288 | diff --git a/block/commit.c b/block/commit.c | ||
289 | index XXXXXXX..XXXXXXX 100644 | ||
290 | --- a/block/commit.c | ||
291 | +++ b/block/commit.c | ||
292 | @@ -XXX,XX +XXX,XX @@ static const BlockJobDriver commit_job_driver = { | ||
293 | }, | ||
294 | }; | ||
295 | |||
296 | -static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs, | ||
297 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
298 | +static int coroutine_fn GRAPH_RDLOCK | ||
299 | +bdrv_commit_top_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
300 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
301 | { | ||
302 | return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); | ||
303 | } | ||
304 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
305 | index XXXXXXX..XXXXXXX 100644 | ||
306 | --- a/block/copy-before-write.c | ||
307 | +++ b/block/copy-before-write.c | ||
308 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVCopyBeforeWriteState { | ||
309 | int snapshot_error; | ||
310 | } BDRVCopyBeforeWriteState; | ||
311 | |||
312 | -static coroutine_fn int cbw_co_preadv( | ||
313 | - BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
314 | - QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
315 | +static int coroutine_fn GRAPH_RDLOCK | ||
316 | +cbw_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
317 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
318 | { | ||
319 | return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); | ||
320 | } | ||
321 | @@ -XXX,XX +XXX,XX @@ cbw_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
322 | return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); | ||
323 | } | ||
324 | |||
325 | -static coroutine_fn int cbw_co_pwritev(BlockDriverState *bs, | ||
326 | - int64_t offset, | ||
327 | - int64_t bytes, | ||
328 | - QEMUIOVector *qiov, | ||
329 | - BdrvRequestFlags flags) | ||
330 | +static coroutine_fn GRAPH_RDLOCK | ||
331 | +int cbw_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
332 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
333 | { | ||
334 | int ret = cbw_do_copy_before_write(bs, offset, bytes, flags); | ||
335 | if (ret < 0) { | ||
336 | @@ -XXX,XX +XXX,XX @@ cbw_co_preadv_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
337 | BdrvChild *file; | ||
338 | int ret; | ||
339 | |||
340 | + assume_graph_lock(); /* FIXME */ | ||
341 | + | ||
342 | /* TODO: upgrade to async loop using AioTask */ | ||
343 | while (bytes) { | ||
344 | int64_t cur_bytes; | ||
345 | diff --git a/block/copy-on-read.c b/block/copy-on-read.c | ||
346 | index XXXXXXX..XXXXXXX 100644 | ||
347 | --- a/block/copy-on-read.c | ||
348 | +++ b/block/copy-on-read.c | ||
349 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn cor_co_getlength(BlockDriverState *bs) | ||
350 | } | ||
351 | |||
352 | |||
353 | -static int coroutine_fn cor_co_preadv_part(BlockDriverState *bs, | ||
354 | - int64_t offset, int64_t bytes, | ||
355 | - QEMUIOVector *qiov, | ||
356 | - size_t qiov_offset, | ||
357 | - BdrvRequestFlags flags) | ||
358 | +static int coroutine_fn GRAPH_RDLOCK | ||
359 | +cor_co_preadv_part(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
360 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
361 | + BdrvRequestFlags flags) | ||
362 | { | ||
363 | int64_t n; | ||
364 | int local_flags; | ||
365 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn cor_co_preadv_part(BlockDriverState *bs, | ||
366 | } | ||
367 | |||
368 | |||
369 | -static int coroutine_fn cor_co_pwritev_part(BlockDriverState *bs, | ||
370 | - int64_t offset, | ||
371 | - int64_t bytes, | ||
372 | - QEMUIOVector *qiov, | ||
373 | - size_t qiov_offset, | ||
374 | - BdrvRequestFlags flags) | ||
375 | +static int coroutine_fn GRAPH_RDLOCK | ||
376 | +cor_co_pwritev_part(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
377 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
378 | + BdrvRequestFlags flags) | ||
379 | { | ||
380 | return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset, | ||
381 | flags); | ||
382 | @@ -XXX,XX +XXX,XX @@ cor_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
383 | } | ||
384 | |||
385 | |||
386 | -static int coroutine_fn cor_co_pwritev_compressed(BlockDriverState *bs, | ||
387 | - int64_t offset, | ||
388 | - int64_t bytes, | ||
389 | - QEMUIOVector *qiov) | ||
390 | +static int coroutine_fn GRAPH_RDLOCK | ||
391 | +cor_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
392 | + QEMUIOVector *qiov) | ||
393 | { | ||
394 | return bdrv_co_pwritev(bs->file, offset, bytes, qiov, | ||
395 | BDRV_REQ_WRITE_COMPRESSED); | ||
396 | diff --git a/block/crypto.c b/block/crypto.c | ||
397 | index XXXXXXX..XXXXXXX 100644 | ||
398 | --- a/block/crypto.c | ||
399 | +++ b/block/crypto.c | ||
400 | @@ -XXX,XX +XXX,XX @@ static int block_crypto_reopen_prepare(BDRVReopenState *state, | ||
401 | */ | ||
402 | #define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024) | ||
403 | |||
404 | -static coroutine_fn int | ||
405 | +static int coroutine_fn GRAPH_RDLOCK | ||
406 | block_crypto_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
407 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
408 | { | ||
409 | @@ -XXX,XX +XXX,XX @@ block_crypto_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
410 | } | ||
411 | |||
412 | |||
413 | -static coroutine_fn int | ||
414 | +static int coroutine_fn GRAPH_RDLOCK | ||
415 | block_crypto_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
416 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
417 | { | ||
418 | diff --git a/block/filter-compress.c b/block/filter-compress.c | ||
419 | index XXXXXXX..XXXXXXX 100644 | ||
420 | --- a/block/filter-compress.c | ||
421 | +++ b/block/filter-compress.c | ||
422 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn compress_co_getlength(BlockDriverState *bs) | ||
423 | } | ||
424 | |||
425 | |||
426 | -static int coroutine_fn compress_co_preadv_part(BlockDriverState *bs, | ||
427 | - int64_t offset, int64_t bytes, | ||
428 | - QEMUIOVector *qiov, | ||
429 | - size_t qiov_offset, | ||
430 | - BdrvRequestFlags flags) | ||
431 | +static int coroutine_fn GRAPH_RDLOCK | ||
432 | +compress_co_preadv_part(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
433 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
434 | + BdrvRequestFlags flags) | ||
435 | { | ||
436 | return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset, | ||
437 | flags); | ||
438 | } | ||
439 | |||
440 | |||
441 | -static int coroutine_fn compress_co_pwritev_part(BlockDriverState *bs, | ||
442 | - int64_t offset, | ||
443 | - int64_t bytes, | ||
444 | - QEMUIOVector *qiov, | ||
445 | - size_t qiov_offset, | ||
446 | - BdrvRequestFlags flags) | ||
447 | +static int coroutine_fn GRAPH_RDLOCK | ||
448 | +compress_co_pwritev_part(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
449 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
450 | + BdrvRequestFlags flags) | ||
451 | { | ||
452 | return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset, | ||
453 | flags | BDRV_REQ_WRITE_COMPRESSED); | ||
454 | diff --git a/block/io.c b/block/io.c | ||
455 | index XXXXXXX..XXXXXXX 100644 | ||
456 | --- a/block/io.c | ||
457 | +++ b/block/io.c | ||
458 | @@ -XXX,XX +XXX,XX @@ bdrv_driver_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
459 | unsigned int nb_sectors; | ||
460 | QEMUIOVector local_qiov; | ||
461 | int ret; | ||
462 | + assert_bdrv_graph_readable(); | ||
463 | |||
464 | bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort); | ||
465 | assert(!(flags & ~bs->supported_read_flags)); | ||
466 | @@ -XXX,XX +XXX,XX @@ bdrv_driver_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
467 | unsigned int nb_sectors; | ||
468 | QEMUIOVector local_qiov; | ||
469 | int ret; | ||
470 | + assert_bdrv_graph_readable(); | ||
471 | |||
472 | bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort); | ||
473 | |||
474 | @@ -XXX,XX +XXX,XX @@ bdrv_driver_pwritev_compressed(BlockDriverState *bs, int64_t offset, | ||
475 | BlockDriver *drv = bs->drv; | ||
476 | QEMUIOVector local_qiov; | ||
477 | int ret; | ||
478 | + assert_bdrv_graph_readable(); | ||
479 | |||
480 | bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, &error_abort); | ||
481 | |||
482 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_preadv_part(BdrvChild *child, | ||
483 | int ret; | ||
484 | IO_CODE(); | ||
485 | |||
486 | - assume_graph_lock(); /* FIXME */ | ||
487 | - | ||
488 | trace_bdrv_co_preadv_part(bs, offset, bytes, flags); | ||
489 | |||
490 | if (!bdrv_co_is_inserted(bs)) { | ||
491 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child, | ||
492 | bool padded = false; | ||
493 | IO_CODE(); | ||
494 | |||
495 | - assume_graph_lock(); /* FIXME */ | ||
496 | - | ||
497 | trace_bdrv_co_pwritev_part(child->bs, offset, bytes, flags); | ||
498 | |||
499 | if (!bdrv_co_is_inserted(bs)) { | ||
500 | diff --git a/block/mirror.c b/block/mirror.c | ||
501 | index XXXXXXX..XXXXXXX 100644 | ||
502 | --- a/block/mirror.c | ||
503 | +++ b/block/mirror.c | ||
504 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_co_read(void *opaque) | ||
505 | op->is_in_flight = true; | ||
506 | trace_mirror_one_iteration(s, op->offset, op->bytes); | ||
507 | |||
508 | - ret = bdrv_co_preadv(s->mirror_top_bs->backing, op->offset, op->bytes, | ||
509 | - &op->qiov, 0); | ||
510 | + WITH_GRAPH_RDLOCK_GUARD() { | ||
511 | + ret = bdrv_co_preadv(s->mirror_top_bs->backing, op->offset, op->bytes, | ||
512 | + &op->qiov, 0); | ||
513 | + } | ||
514 | mirror_read_complete(op, ret); | ||
515 | } | ||
516 | |||
517 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn active_write_settle(MirrorOp *op) | ||
518 | g_free(op); | ||
519 | } | ||
520 | |||
521 | -static int coroutine_fn bdrv_mirror_top_preadv(BlockDriverState *bs, | ||
522 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
523 | +static int coroutine_fn GRAPH_RDLOCK | ||
524 | +bdrv_mirror_top_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
525 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
526 | { | ||
527 | return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); | ||
528 | } | ||
529 | @@ -XXX,XX +XXX,XX @@ out: | ||
530 | return ret; | ||
531 | } | ||
532 | |||
533 | -static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs, | ||
534 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
535 | +static int coroutine_fn GRAPH_RDLOCK | ||
536 | +bdrv_mirror_top_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
537 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
538 | { | ||
539 | MirrorBDSOpaque *s = bs->opaque; | ||
540 | QEMUIOVector bounce_qiov; | ||
541 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs, | ||
542 | int ret = 0; | ||
543 | bool copy_to_target = false; | ||
544 | |||
545 | - assume_graph_lock(); /* FIXME */ | ||
546 | - | ||
547 | if (s->job) { | ||
548 | copy_to_target = s->job->ret >= 0 && | ||
549 | !job_is_cancelled(&s->job->common.job) && | ||
550 | diff --git a/block/parallels.c b/block/parallels.c | ||
551 | index XXXXXXX..XXXXXXX 100644 | ||
552 | --- a/block/parallels.c | ||
553 | +++ b/block/parallels.c | ||
554 | @@ -XXX,XX +XXX,XX @@ allocate_clusters(BlockDriverState *bs, int64_t sector_num, | ||
555 | } | ||
556 | |||
557 | |||
558 | -static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs) | ||
559 | +static int coroutine_fn GRAPH_RDLOCK | ||
560 | +parallels_co_flush_to_os(BlockDriverState *bs) | ||
561 | { | ||
562 | BDRVParallelsState *s = bs->opaque; | ||
563 | unsigned long size = DIV_ROUND_UP(s->header_size, s->bat_dirty_block); | ||
564 | @@ -XXX,XX +XXX,XX @@ parallels_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors, | ||
565 | return ret; | ||
566 | } | ||
567 | |||
568 | -static coroutine_fn int parallels_co_readv(BlockDriverState *bs, | ||
569 | - int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) | ||
570 | +static int coroutine_fn GRAPH_RDLOCK | ||
571 | +parallels_co_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors, | ||
572 | + QEMUIOVector *qiov) | ||
573 | { | ||
574 | BDRVParallelsState *s = bs->opaque; | ||
575 | uint64_t bytes_done = 0; | ||
576 | diff --git a/block/preallocate.c b/block/preallocate.c | ||
577 | index XXXXXXX..XXXXXXX 100644 | ||
578 | --- a/block/preallocate.c | ||
579 | +++ b/block/preallocate.c | ||
580 | @@ -XXX,XX +XXX,XX @@ static void preallocate_reopen_abort(BDRVReopenState *state) | ||
581 | state->opaque = NULL; | ||
582 | } | ||
583 | |||
584 | -static coroutine_fn int preallocate_co_preadv_part( | ||
585 | - BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
586 | - QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags) | ||
587 | +static int coroutine_fn GRAPH_RDLOCK | ||
588 | +preallocate_co_preadv_part(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
589 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
590 | + BdrvRequestFlags flags) | ||
591 | { | ||
592 | return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset, | ||
593 | flags); | ||
594 | @@ -XXX,XX +XXX,XX @@ preallocate_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, | ||
595 | return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); | ||
596 | } | ||
597 | |||
598 | -static coroutine_fn int preallocate_co_pwritev_part(BlockDriverState *bs, | ||
599 | - int64_t offset, | ||
600 | - int64_t bytes, | ||
601 | - QEMUIOVector *qiov, | ||
602 | - size_t qiov_offset, | ||
603 | - BdrvRequestFlags flags) | ||
604 | +static int coroutine_fn GRAPH_RDLOCK | ||
605 | +preallocate_co_pwritev_part(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
606 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
607 | + BdrvRequestFlags flags) | ||
608 | { | ||
609 | - assume_graph_lock(); /* FIXME */ | ||
610 | handle_write(bs, offset, bytes, false); | ||
611 | |||
612 | return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset, | ||
613 | diff --git a/block/qcow.c b/block/qcow.c | ||
614 | index XXXXXXX..XXXXXXX 100644 | ||
615 | --- a/block/qcow.c | ||
616 | +++ b/block/qcow.c | ||
617 | @@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcowState { | ||
618 | |||
619 | static QemuOptsList qcow_create_opts; | ||
620 | |||
621 | -static int coroutine_fn decompress_cluster(BlockDriverState *bs, | ||
622 | - uint64_t cluster_offset); | ||
623 | +static int coroutine_fn GRAPH_RDLOCK | ||
624 | +decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); | ||
625 | |||
626 | static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) | ||
627 | { | ||
628 | @@ -XXX,XX +XXX,XX @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size, | ||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | -static int coroutine_fn decompress_cluster(BlockDriverState *bs, | ||
633 | - uint64_t cluster_offset) | ||
634 | +static int coroutine_fn GRAPH_RDLOCK | ||
635 | +decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset) | ||
636 | { | ||
637 | BDRVQcowState *s = bs->opaque; | ||
638 | int ret, csize; | ||
639 | diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c | ||
640 | index XXXXXXX..XXXXXXX 100644 | ||
641 | --- a/block/qcow2-cluster.c | ||
642 | +++ b/block/qcow2-cluster.c | ||
643 | @@ -XXX,XX +XXX,XX @@ do_perform_cow_read(BlockDriverState *bs, uint64_t src_cluster_offset, | ||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | -static int coroutine_fn do_perform_cow_write(BlockDriverState *bs, | ||
648 | - uint64_t cluster_offset, | ||
649 | - unsigned offset_in_cluster, | ||
650 | - QEMUIOVector *qiov) | ||
651 | +static int coroutine_fn GRAPH_RDLOCK | ||
652 | +do_perform_cow_write(BlockDriverState *bs, uint64_t cluster_offset, | ||
653 | + unsigned offset_in_cluster, QEMUIOVector *qiov) | ||
654 | { | ||
655 | BDRVQcow2State *s = bs->opaque; | ||
656 | int ret; | ||
657 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
658 | index XXXXXXX..XXXXXXX 100644 | ||
659 | --- a/block/qcow2.c | ||
660 | +++ b/block/qcow2.c | ||
661 | @@ -XXX,XX +XXX,XX @@ static void qcow2_add_check_result(BdrvCheckResult *out, | ||
662 | } | ||
663 | } | ||
664 | |||
665 | -static int coroutine_fn qcow2_co_check_locked(BlockDriverState *bs, | ||
666 | - BdrvCheckResult *result, | ||
667 | - BdrvCheckMode fix) | ||
668 | +static int coroutine_fn GRAPH_RDLOCK | ||
669 | +qcow2_co_check_locked(BlockDriverState *bs, BdrvCheckResult *result, | ||
670 | + BdrvCheckMode fix) | ||
671 | { | ||
672 | BdrvCheckResult snapshot_res = {}; | ||
673 | BdrvCheckResult refcount_res = {}; | ||
674 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_check_locked(BlockDriverState *bs, | ||
675 | return ret; | ||
676 | } | ||
677 | |||
678 | -static int coroutine_fn qcow2_co_check(BlockDriverState *bs, | ||
679 | - BdrvCheckResult *result, | ||
680 | - BdrvCheckMode fix) | ||
681 | +static int coroutine_fn GRAPH_RDLOCK | ||
682 | +qcow2_co_check(BlockDriverState *bs, BdrvCheckResult *result, | ||
683 | + BdrvCheckMode fix) | ||
684 | { | ||
685 | BDRVQcow2State *s = bs->opaque; | ||
686 | int ret; | ||
687 | @@ -XXX,XX +XXX,XX @@ static int validate_compression_type(BDRVQcow2State *s, Error **errp) | ||
688 | } | ||
689 | |||
690 | /* Called with s->lock held. */ | ||
691 | -static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, | ||
692 | - int flags, bool open_data_file, | ||
693 | - Error **errp) | ||
694 | +static int coroutine_fn GRAPH_RDLOCK | ||
695 | +qcow2_do_open(BlockDriverState *bs, QDict *options, int flags, | ||
696 | + bool open_data_file, Error **errp) | ||
697 | { | ||
698 | ERRP_GUARD(); | ||
699 | BDRVQcow2State *s = bs->opaque; | ||
700 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn qcow2_open_entry(void *opaque) | ||
701 | QCow2OpenCo *qoc = opaque; | ||
702 | BDRVQcow2State *s = qoc->bs->opaque; | ||
703 | |||
704 | + assume_graph_lock(); /* FIXME */ | ||
705 | + | ||
706 | qemu_co_mutex_lock(&s->lock); | ||
707 | qoc->ret = qcow2_do_open(qoc->bs, qoc->options, qoc->flags, true, | ||
708 | qoc->errp); | ||
709 | @@ -XXX,XX +XXX,XX @@ out: | ||
710 | return ret; | ||
711 | } | ||
712 | |||
713 | -static coroutine_fn int | ||
714 | +static int coroutine_fn GRAPH_RDLOCK | ||
715 | qcow2_co_preadv_encrypted(BlockDriverState *bs, | ||
716 | uint64_t host_offset, | ||
717 | uint64_t offset, | ||
718 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_add_task(BlockDriverState *bs, | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | -static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs, | ||
723 | - QCow2SubclusterType subc_type, | ||
724 | - uint64_t host_offset, | ||
725 | - uint64_t offset, uint64_t bytes, | ||
726 | - QEMUIOVector *qiov, | ||
727 | - size_t qiov_offset) | ||
728 | +static int coroutine_fn GRAPH_RDLOCK | ||
729 | +qcow2_co_preadv_task(BlockDriverState *bs, QCow2SubclusterType subc_type, | ||
730 | + uint64_t host_offset, uint64_t offset, uint64_t bytes, | ||
731 | + QEMUIOVector *qiov, size_t qiov_offset) | ||
732 | { | ||
733 | BDRVQcow2State *s = bs->opaque; | ||
734 | |||
735 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs, | ||
736 | g_assert_not_reached(); | ||
737 | } | ||
738 | |||
739 | -static coroutine_fn int qcow2_co_preadv_task_entry(AioTask *task) | ||
740 | +/* | ||
741 | + * This function can count as GRAPH_RDLOCK because qcow2_co_preadv_part() holds | ||
742 | + * the graph lock and keeps it until this coroutine has terminated. | ||
743 | + */ | ||
744 | +static int coroutine_fn GRAPH_RDLOCK qcow2_co_preadv_task_entry(AioTask *task) | ||
745 | { | ||
746 | Qcow2AioTask *t = container_of(task, Qcow2AioTask, task); | ||
747 | |||
748 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_task_entry(AioTask *task) | ||
749 | t->qiov, t->qiov_offset); | ||
750 | } | ||
751 | |||
752 | -static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs, | ||
753 | - int64_t offset, int64_t bytes, | ||
754 | - QEMUIOVector *qiov, | ||
755 | - size_t qiov_offset, | ||
756 | - BdrvRequestFlags flags) | ||
757 | +static int coroutine_fn GRAPH_RDLOCK | ||
758 | +qcow2_co_preadv_part(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
759 | + QEMUIOVector *qiov, size_t qiov_offset, | ||
760 | + BdrvRequestFlags flags) | ||
761 | { | ||
762 | BDRVQcow2State *s = bs->opaque; | ||
763 | int ret = 0; | ||
764 | @@ -XXX,XX +XXX,XX @@ static void qcow2_close(BlockDriverState *bs) | ||
765 | qcow2_do_close(bs, true); | ||
766 | } | ||
767 | |||
768 | -static void coroutine_fn qcow2_co_invalidate_cache(BlockDriverState *bs, | ||
769 | - Error **errp) | ||
770 | +static void coroutine_fn GRAPH_RDLOCK | ||
771 | +qcow2_co_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
772 | { | ||
773 | ERRP_GUARD(); | ||
774 | BDRVQcow2State *s = bs->opaque; | ||
775 | @@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs, | ||
776 | return ret; | ||
777 | } | ||
778 | |||
779 | -static int coroutine_fn | ||
780 | +static int coroutine_fn GRAPH_RDLOCK | ||
781 | qcow2_co_preadv_compressed(BlockDriverState *bs, | ||
782 | uint64_t l2_entry, | ||
783 | uint64_t offset, | ||
784 | diff --git a/block/qed-table.c b/block/qed-table.c | ||
785 | index XXXXXXX..XXXXXXX 100644 | ||
786 | --- a/block/qed-table.c | ||
787 | +++ b/block/qed-table.c | ||
28 | @@ -XXX,XX +XXX,XX @@ | 788 | @@ -XXX,XX +XXX,XX @@ |
29 | 789 | #include "qemu/memalign.h" | |
30 | /* 8 MB refcount table is enough for 2 PB images at 64k cluster size | 790 | |
31 | * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */ | 791 | /* Called with table_lock held. */ |
32 | -#define QCOW_MAX_REFTABLE_SIZE S_8MiB | 792 | -static int coroutine_fn qed_read_table(BDRVQEDState *s, uint64_t offset, |
33 | +#define QCOW_MAX_REFTABLE_SIZE (8 * MiB) | 793 | - QEDTable *table) |
34 | 794 | +static int coroutine_fn GRAPH_RDLOCK | |
35 | /* 32 MB L1 table is enough for 2 PB images at 64k cluster size | 795 | +qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table) |
36 | * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */ | 796 | { |
37 | -#define QCOW_MAX_L1_SIZE S_32MiB | 797 | unsigned int bytes = s->header.cluster_size * s->header.table_size; |
38 | +#define QCOW_MAX_L1_SIZE (32 * MiB) | 798 | |
39 | 799 | diff --git a/block/qed.c b/block/qed.c | |
40 | /* Allow for an average of 1k per snapshot table entry, should be plenty of | 800 | index XXXXXXX..XXXXXXX 100644 |
41 | * space for snapshot names and IDs */ | 801 | --- a/block/qed.c |
42 | @@ -XXX,XX +XXX,XX @@ | 802 | +++ b/block/qed.c |
43 | #define MIN_REFCOUNT_CACHE_SIZE 4 /* clusters */ | 803 | @@ -XXX,XX +XXX,XX @@ int qed_write_header_sync(BDRVQEDState *s) |
44 | 804 | * | |
45 | #ifdef CONFIG_LINUX | 805 | * No new allocating reqs can start while this function runs. |
46 | -#define DEFAULT_L2_CACHE_MAX_SIZE S_32MiB | 806 | */ |
47 | +#define DEFAULT_L2_CACHE_MAX_SIZE (32 * MiB) | 807 | -static int coroutine_fn qed_write_header(BDRVQEDState *s) |
48 | #define DEFAULT_CACHE_CLEAN_INTERVAL 600 /* seconds */ | 808 | +static int coroutine_fn GRAPH_RDLOCK qed_write_header(BDRVQEDState *s) |
49 | #else | 809 | { |
50 | -#define DEFAULT_L2_CACHE_MAX_SIZE S_8MiB | 810 | /* We must write full sectors for O_DIRECT but cannot necessarily generate |
51 | +#define DEFAULT_L2_CACHE_MAX_SIZE (8 * MiB) | 811 | * the data following the header if an unrecognized compat feature is |
52 | /* Cache clean interval is currently available only on Linux, so must be 0 */ | 812 | @@ -XXX,XX +XXX,XX @@ fail: |
53 | #define DEFAULT_CACHE_CLEAN_INTERVAL 0 | 813 | return ret; |
54 | #endif | 814 | } |
55 | 815 | ||
56 | -#define DEFAULT_CLUSTER_SIZE S_64KiB | 816 | -static int coroutine_fn bdrv_qed_co_block_status(BlockDriverState *bs, |
57 | +#define DEFAULT_CLUSTER_SIZE 65536 | 817 | - bool want_zero, |
58 | 818 | - int64_t pos, int64_t bytes, | |
59 | #define QCOW2_OPT_LAZY_REFCOUNTS "lazy-refcounts" | 819 | - int64_t *pnum, int64_t *map, |
60 | #define QCOW2_OPT_DISCARD_REQUEST "pass-discard-request" | 820 | - BlockDriverState **file) |
61 | diff --git a/include/qemu/units.h b/include/qemu/units.h | 821 | +static int coroutine_fn GRAPH_RDLOCK |
62 | index XXXXXXX..XXXXXXX 100644 | 822 | +bdrv_qed_co_block_status(BlockDriverState *bs, bool want_zero, int64_t pos, |
63 | --- a/include/qemu/units.h | 823 | + int64_t bytes, int64_t *pnum, int64_t *map, |
64 | +++ b/include/qemu/units.h | 824 | + BlockDriverState **file) |
65 | @@ -XXX,XX +XXX,XX @@ | 825 | { |
66 | #define PiB (INT64_C(1) << 50) | 826 | BDRVQEDState *s = bs->opaque; |
67 | #define EiB (INT64_C(1) << 60) | 827 | size_t len = MIN(bytes, SIZE_MAX); |
68 | 828 | @@ -XXX,XX +XXX,XX @@ static BDRVQEDState *acb_to_s(QEDAIOCB *acb) | |
69 | -/* | 829 | * This function reads qiov->size bytes starting at pos from the backing file. |
70 | - * The following lookup table is intended to be used when a literal string of | 830 | * If there is no backing file then zeroes are read. |
71 | - * the number of bytes is required (for example if it needs to be stringified). | 831 | */ |
72 | - * It can also be used for generic shortcuts of power-of-two sizes. | 832 | -static int coroutine_fn qed_read_backing_file(BDRVQEDState *s, uint64_t pos, |
73 | - * This table is generated using the AWK script below: | 833 | - QEMUIOVector *qiov) |
74 | - * | 834 | +static int coroutine_fn GRAPH_RDLOCK |
75 | - * BEGIN { | 835 | +qed_read_backing_file(BDRVQEDState *s, uint64_t pos, QEMUIOVector *qiov) |
76 | - * suffix="KMGTPE"; | 836 | { |
77 | - * for(i=10; i<64; i++) { | 837 | if (s->bs->backing) { |
78 | - * val=2**i; | 838 | BLKDBG_EVENT(s->bs->file, BLKDBG_READ_BACKING_AIO); |
79 | - * s=substr(suffix, int(i/10), 1); | 839 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn qed_read_backing_file(BDRVQEDState *s, uint64_t pos, |
80 | - * n=2**(i%10); | 840 | * @len: Number of bytes |
81 | - * pad=21-int(log(n)/log(10)); | 841 | * @offset: Byte offset in image file |
82 | - * printf("#define S_%d%siB %*d\n", n, s, pad, val); | 842 | */ |
83 | - * } | 843 | -static int coroutine_fn qed_copy_from_backing_file(BDRVQEDState *s, |
84 | - * } | 844 | - uint64_t pos, uint64_t len, |
85 | - */ | 845 | - uint64_t offset) |
86 | - | 846 | +static int coroutine_fn GRAPH_RDLOCK |
87 | -#define S_1KiB 1024 | 847 | +qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos, uint64_t len, |
88 | -#define S_2KiB 2048 | 848 | + uint64_t offset) |
89 | -#define S_4KiB 4096 | 849 | { |
90 | -#define S_8KiB 8192 | 850 | QEMUIOVector qiov; |
91 | -#define S_16KiB 16384 | 851 | int ret; |
92 | -#define S_32KiB 32768 | 852 | @@ -XXX,XX +XXX,XX @@ qed_aio_write_l2_update(QEDAIOCB *acb, uint64_t offset) |
93 | -#define S_64KiB 65536 | 853 | * |
94 | -#define S_128KiB 131072 | 854 | * Called with table_lock *not* held. |
95 | -#define S_256KiB 262144 | 855 | */ |
96 | -#define S_512KiB 524288 | 856 | -static int coroutine_fn qed_aio_write_main(QEDAIOCB *acb) |
97 | -#define S_1MiB 1048576 | 857 | +static int coroutine_fn GRAPH_RDLOCK qed_aio_write_main(QEDAIOCB *acb) |
98 | -#define S_2MiB 2097152 | 858 | { |
99 | -#define S_4MiB 4194304 | 859 | BDRVQEDState *s = acb_to_s(acb); |
100 | -#define S_8MiB 8388608 | 860 | uint64_t offset = acb->cur_cluster + |
101 | -#define S_16MiB 16777216 | 861 | @@ -XXX,XX +XXX,XX @@ qed_aio_write_alloc(QEDAIOCB *acb, size_t len) |
102 | -#define S_32MiB 33554432 | 862 | * |
103 | -#define S_64MiB 67108864 | 863 | * Called with table_lock held. |
104 | -#define S_128MiB 134217728 | 864 | */ |
105 | -#define S_256MiB 268435456 | 865 | -static int coroutine_fn qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, |
106 | -#define S_512MiB 536870912 | 866 | - size_t len) |
107 | -#define S_1GiB 1073741824 | 867 | +static int coroutine_fn GRAPH_RDLOCK |
108 | -#define S_2GiB 2147483648 | 868 | +qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len) |
109 | -#define S_4GiB 4294967296 | 869 | { |
110 | -#define S_8GiB 8589934592 | 870 | BDRVQEDState *s = acb_to_s(acb); |
111 | -#define S_16GiB 17179869184 | 871 | int r; |
112 | -#define S_32GiB 34359738368 | 872 | @@ -XXX,XX +XXX,XX @@ qed_aio_write_data(void *opaque, int ret, uint64_t offset, size_t len) |
113 | -#define S_64GiB 68719476736 | 873 | * |
114 | -#define S_128GiB 137438953472 | 874 | * Called with table_lock held. |
115 | -#define S_256GiB 274877906944 | 875 | */ |
116 | -#define S_512GiB 549755813888 | 876 | -static int coroutine_fn qed_aio_read_data(void *opaque, int ret, |
117 | -#define S_1TiB 1099511627776 | 877 | - uint64_t offset, size_t len) |
118 | -#define S_2TiB 2199023255552 | 878 | +static int coroutine_fn GRAPH_RDLOCK |
119 | -#define S_4TiB 4398046511104 | 879 | +qed_aio_read_data(void *opaque, int ret, uint64_t offset, size_t len) |
120 | -#define S_8TiB 8796093022208 | 880 | { |
121 | -#define S_16TiB 17592186044416 | 881 | QEDAIOCB *acb = opaque; |
122 | -#define S_32TiB 35184372088832 | 882 | BDRVQEDState *s = acb_to_s(acb); |
123 | -#define S_64TiB 70368744177664 | 883 | diff --git a/block/quorum.c b/block/quorum.c |
124 | -#define S_128TiB 140737488355328 | 884 | index XXXXXXX..XXXXXXX 100644 |
125 | -#define S_256TiB 281474976710656 | 885 | --- a/block/quorum.c |
126 | -#define S_512TiB 562949953421312 | 886 | +++ b/block/quorum.c |
127 | -#define S_1PiB 1125899906842624 | 887 | @@ -XXX,XX +XXX,XX @@ static void quorum_report_bad_versions(BDRVQuorumState *s, |
128 | -#define S_2PiB 2251799813685248 | 888 | } |
129 | -#define S_4PiB 4503599627370496 | 889 | } |
130 | -#define S_8PiB 9007199254740992 | 890 | |
131 | -#define S_16PiB 18014398509481984 | 891 | -static void coroutine_fn quorum_rewrite_entry(void *opaque) |
132 | -#define S_32PiB 36028797018963968 | 892 | +/* |
133 | -#define S_64PiB 72057594037927936 | 893 | + * This function can count as GRAPH_RDLOCK because read_quorum_children() holds |
134 | -#define S_128PiB 144115188075855872 | 894 | + * the graph lock and keeps it until this coroutine has terminated. |
135 | -#define S_256PiB 288230376151711744 | 895 | + */ |
136 | -#define S_512PiB 576460752303423488 | 896 | +static void coroutine_fn GRAPH_RDLOCK quorum_rewrite_entry(void *opaque) |
137 | -#define S_1EiB 1152921504606846976 | 897 | { |
138 | -#define S_2EiB 2305843009213693952 | 898 | QuorumCo *co = opaque; |
139 | -#define S_4EiB 4611686018427387904 | 899 | QuorumAIOCB *acb = co->acb; |
140 | -#define S_8EiB 9223372036854775808 | 900 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn quorum_rewrite_entry(void *opaque) |
141 | - | 901 | } |
142 | #endif | 902 | } |
903 | |||
904 | -static bool quorum_rewrite_bad_versions(QuorumAIOCB *acb, | ||
905 | - QuorumVoteValue *value) | ||
906 | +static bool coroutine_fn GRAPH_RDLOCK | ||
907 | +quorum_rewrite_bad_versions(QuorumAIOCB *acb, QuorumVoteValue *value) | ||
908 | { | ||
909 | QuorumVoteVersion *version; | ||
910 | QuorumVoteItem *item; | ||
911 | @@ -XXX,XX +XXX,XX @@ static int quorum_vote_error(QuorumAIOCB *acb) | ||
912 | return ret; | ||
913 | } | ||
914 | |||
915 | -static void quorum_vote(QuorumAIOCB *acb) | ||
916 | +static void coroutine_fn GRAPH_RDLOCK quorum_vote(QuorumAIOCB *acb) | ||
917 | { | ||
918 | bool quorum = true; | ||
919 | int i, j, ret; | ||
920 | @@ -XXX,XX +XXX,XX @@ free_exit: | ||
921 | quorum_free_vote_list(&acb->votes); | ||
922 | } | ||
923 | |||
924 | -static void coroutine_fn read_quorum_children_entry(void *opaque) | ||
925 | +/* | ||
926 | + * This function can count as GRAPH_RDLOCK because read_quorum_children() holds | ||
927 | + * the graph lock and keeps it until this coroutine has terminated. | ||
928 | + */ | ||
929 | +static void coroutine_fn GRAPH_RDLOCK read_quorum_children_entry(void *opaque) | ||
930 | { | ||
931 | QuorumCo *co = opaque; | ||
932 | QuorumAIOCB *acb = co->acb; | ||
933 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn read_quorum_children_entry(void *opaque) | ||
934 | } | ||
935 | } | ||
936 | |||
937 | -static int coroutine_fn read_quorum_children(QuorumAIOCB *acb) | ||
938 | +static int coroutine_fn GRAPH_RDLOCK read_quorum_children(QuorumAIOCB *acb) | ||
939 | { | ||
940 | BDRVQuorumState *s = acb->bs->opaque; | ||
941 | int i; | ||
942 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn read_quorum_children(QuorumAIOCB *acb) | ||
943 | return acb->vote_ret; | ||
944 | } | ||
945 | |||
946 | -static int coroutine_fn read_fifo_child(QuorumAIOCB *acb) | ||
947 | +static int coroutine_fn GRAPH_RDLOCK read_fifo_child(QuorumAIOCB *acb) | ||
948 | { | ||
949 | BDRVQuorumState *s = acb->bs->opaque; | ||
950 | int n, ret; | ||
951 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn read_fifo_child(QuorumAIOCB *acb) | ||
952 | return ret; | ||
953 | } | ||
954 | |||
955 | -static int coroutine_fn quorum_co_preadv(BlockDriverState *bs, | ||
956 | - int64_t offset, int64_t bytes, | ||
957 | - QEMUIOVector *qiov, | ||
958 | - BdrvRequestFlags flags) | ||
959 | +static int coroutine_fn GRAPH_RDLOCK | ||
960 | +quorum_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
961 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
962 | { | ||
963 | BDRVQuorumState *s = bs->opaque; | ||
964 | QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags); | ||
965 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
966 | index XXXXXXX..XXXXXXX 100644 | ||
967 | --- a/block/raw-format.c | ||
968 | +++ b/block/raw-format.c | ||
969 | @@ -XXX,XX +XXX,XX @@ static inline int raw_adjust_offset(BlockDriverState *bs, int64_t *offset, | ||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | -static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset, | ||
974 | - int64_t bytes, QEMUIOVector *qiov, | ||
975 | - BdrvRequestFlags flags) | ||
976 | +static int coroutine_fn GRAPH_RDLOCK | ||
977 | +raw_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
978 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
979 | { | ||
980 | int ret; | ||
981 | |||
982 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset, | ||
983 | return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); | ||
984 | } | ||
985 | |||
986 | -static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset, | ||
987 | - int64_t bytes, QEMUIOVector *qiov, | ||
988 | - BdrvRequestFlags flags) | ||
989 | +static int coroutine_fn GRAPH_RDLOCK | ||
990 | +raw_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
991 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
992 | { | ||
993 | void *buf = NULL; | ||
994 | BlockDriver *drv; | ||
995 | diff --git a/block/replication.c b/block/replication.c | ||
996 | index XXXXXXX..XXXXXXX 100644 | ||
997 | --- a/block/replication.c | ||
998 | +++ b/block/replication.c | ||
999 | @@ -XXX,XX +XXX,XX @@ static int replication_return_value(BDRVReplicationState *s, int ret) | ||
1000 | return ret; | ||
1001 | } | ||
1002 | |||
1003 | -static coroutine_fn int replication_co_readv(BlockDriverState *bs, | ||
1004 | - int64_t sector_num, | ||
1005 | - int remaining_sectors, | ||
1006 | - QEMUIOVector *qiov) | ||
1007 | +static int coroutine_fn GRAPH_RDLOCK | ||
1008 | +replication_co_readv(BlockDriverState *bs, int64_t sector_num, | ||
1009 | + int remaining_sectors, QEMUIOVector *qiov) | ||
1010 | { | ||
1011 | BDRVReplicationState *s = bs->opaque; | ||
1012 | int ret; | ||
1013 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int replication_co_readv(BlockDriverState *bs, | ||
1014 | return replication_return_value(s, ret); | ||
1015 | } | ||
1016 | |||
1017 | -static coroutine_fn int replication_co_writev(BlockDriverState *bs, | ||
1018 | - int64_t sector_num, | ||
1019 | - int remaining_sectors, | ||
1020 | - QEMUIOVector *qiov, | ||
1021 | - int flags) | ||
1022 | +static int coroutine_fn GRAPH_RDLOCK | ||
1023 | +replication_co_writev(BlockDriverState *bs, int64_t sector_num, | ||
1024 | + int remaining_sectors, QEMUIOVector *qiov, int flags) | ||
1025 | { | ||
1026 | BDRVReplicationState *s = bs->opaque; | ||
1027 | QEMUIOVector hd_qiov; | ||
1028 | diff --git a/block/throttle.c b/block/throttle.c | ||
1029 | index XXXXXXX..XXXXXXX 100644 | ||
1030 | --- a/block/throttle.c | ||
1031 | +++ b/block/throttle.c | ||
1032 | @@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn throttle_co_getlength(BlockDriverState *bs) | ||
1033 | return bdrv_co_getlength(bs->file->bs); | ||
1034 | } | ||
1035 | |||
1036 | -static int coroutine_fn throttle_co_preadv(BlockDriverState *bs, | ||
1037 | - int64_t offset, int64_t bytes, | ||
1038 | - QEMUIOVector *qiov, | ||
1039 | - BdrvRequestFlags flags) | ||
1040 | +static int coroutine_fn GRAPH_RDLOCK | ||
1041 | +throttle_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1042 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
1043 | { | ||
1044 | |||
1045 | ThrottleGroupMember *tgm = bs->opaque; | ||
1046 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn throttle_co_preadv(BlockDriverState *bs, | ||
1047 | return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); | ||
1048 | } | ||
1049 | |||
1050 | -static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs, | ||
1051 | - int64_t offset, int64_t bytes, | ||
1052 | - QEMUIOVector *qiov, | ||
1053 | - BdrvRequestFlags flags) | ||
1054 | +static int coroutine_fn GRAPH_RDLOCK | ||
1055 | +throttle_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1056 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
1057 | { | ||
1058 | ThrottleGroupMember *tgm = bs->opaque; | ||
1059 | throttle_group_co_io_limits_intercept(tgm, bytes, true); | ||
1060 | @@ -XXX,XX +XXX,XX @@ throttle_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
1061 | return bdrv_co_pdiscard(bs->file, offset, bytes); | ||
1062 | } | ||
1063 | |||
1064 | -static int coroutine_fn throttle_co_pwritev_compressed(BlockDriverState *bs, | ||
1065 | - int64_t offset, | ||
1066 | - int64_t bytes, | ||
1067 | - QEMUIOVector *qiov) | ||
1068 | +static int coroutine_fn GRAPH_RDLOCK | ||
1069 | +throttle_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, | ||
1070 | + int64_t bytes, QEMUIOVector *qiov) | ||
1071 | { | ||
1072 | return throttle_co_pwritev(bs, offset, bytes, qiov, | ||
1073 | BDRV_REQ_WRITE_COMPRESSED); | ||
143 | diff --git a/block/vdi.c b/block/vdi.c | 1074 | diff --git a/block/vdi.c b/block/vdi.c |
144 | index XXXXXXX..XXXXXXX 100644 | 1075 | index XXXXXXX..XXXXXXX 100644 |
145 | --- a/block/vdi.c | 1076 | --- a/block/vdi.c |
146 | +++ b/block/vdi.c | 1077 | +++ b/block/vdi.c |
147 | @@ -XXX,XX +XXX,XX @@ | 1078 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_block_status(BlockDriverState *bs, |
148 | #define BLOCK_OPT_STATIC "static" | 1079 | (s->header.image_type == VDI_TYPE_STATIC ? BDRV_BLOCK_RECURSE : 0); |
149 | 1080 | } | |
150 | #define SECTOR_SIZE 512 | 1081 | |
151 | -#define DEFAULT_CLUSTER_SIZE S_1MiB | 1082 | -static int coroutine_fn |
152 | +#define DEFAULT_CLUSTER_SIZE 1048576 | 1083 | +static int coroutine_fn GRAPH_RDLOCK |
153 | +/* Note: can't use 1 * MiB, because it's passed to stringify() */ | 1084 | vdi_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, |
154 | 1085 | QEMUIOVector *qiov, BdrvRequestFlags flags) | |
155 | #if defined(CONFIG_VDI_DEBUG) | 1086 | { |
156 | #define VDI_DEBUG 1 | 1087 | @@ -XXX,XX +XXX,XX @@ vdi_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, |
1088 | return ret; | ||
1089 | } | ||
1090 | |||
1091 | -static int coroutine_fn | ||
1092 | +static int coroutine_fn GRAPH_RDLOCK | ||
1093 | vdi_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1094 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
1095 | { | ||
1096 | diff --git a/block/vhdx.c b/block/vhdx.c | ||
1097 | index XXXXXXX..XXXXXXX 100644 | ||
1098 | --- a/block/vhdx.c | ||
1099 | +++ b/block/vhdx.c | ||
1100 | @@ -XXX,XX +XXX,XX @@ vhdx_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) | ||
1101 | } | ||
1102 | |||
1103 | |||
1104 | -static coroutine_fn int vhdx_co_readv(BlockDriverState *bs, int64_t sector_num, | ||
1105 | - int nb_sectors, QEMUIOVector *qiov) | ||
1106 | +static int coroutine_fn GRAPH_RDLOCK | ||
1107 | +vhdx_co_readv(BlockDriverState *bs, int64_t sector_num, int nb_sectors, | ||
1108 | + QEMUIOVector *qiov) | ||
1109 | { | ||
1110 | BDRVVHDXState *s = bs->opaque; | ||
1111 | int ret = 0; | ||
1112 | @@ -XXX,XX +XXX,XX @@ int vhdx_user_visible_write(BlockDriverState *bs, BDRVVHDXState *s) | ||
1113 | return ret; | ||
1114 | } | ||
1115 | |||
1116 | -static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, | ||
1117 | - int nb_sectors, QEMUIOVector *qiov, | ||
1118 | - int flags) | ||
1119 | +static int coroutine_fn GRAPH_RDLOCK | ||
1120 | +vhdx_co_writev(BlockDriverState *bs, int64_t sector_num, int nb_sectors, | ||
1121 | + QEMUIOVector *qiov, int flags) | ||
1122 | { | ||
1123 | int ret = -ENOTSUP; | ||
1124 | BDRVVHDXState *s = bs->opaque; | ||
1125 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
1126 | index XXXXXXX..XXXXXXX 100644 | ||
1127 | --- a/block/vmdk.c | ||
1128 | +++ b/block/vmdk.c | ||
1129 | @@ -XXX,XX +XXX,XX @@ static void vmdk_refresh_limits(BlockDriverState *bs, Error **errp) | ||
1130 | * [@skip_start_sector, @skip_end_sector) is not copied or written, and leave | ||
1131 | * it for call to write user data in the request. | ||
1132 | */ | ||
1133 | -static int coroutine_fn get_whole_cluster(BlockDriverState *bs, | ||
1134 | - VmdkExtent *extent, | ||
1135 | - uint64_t cluster_offset, | ||
1136 | - uint64_t offset, | ||
1137 | - uint64_t skip_start_bytes, | ||
1138 | - uint64_t skip_end_bytes, | ||
1139 | - bool zeroed) | ||
1140 | +static int coroutine_fn GRAPH_RDLOCK | ||
1141 | +get_whole_cluster(BlockDriverState *bs, VmdkExtent *extent, | ||
1142 | + uint64_t cluster_offset, uint64_t offset, | ||
1143 | + uint64_t skip_start_bytes, uint64_t skip_end_bytes, | ||
1144 | + bool zeroed) | ||
1145 | { | ||
1146 | int ret = VMDK_OK; | ||
1147 | int64_t cluster_bytes; | ||
1148 | @@ -XXX,XX +XXX,XX @@ vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, uint32_t offset) | ||
1149 | * VMDK_UNALLOC if cluster is not mapped and @allocate is false. | ||
1150 | * VMDK_ERROR if failed. | ||
1151 | */ | ||
1152 | -static int coroutine_fn get_cluster_offset(BlockDriverState *bs, | ||
1153 | - VmdkExtent *extent, | ||
1154 | - VmdkMetaData *m_data, | ||
1155 | - uint64_t offset, | ||
1156 | - bool allocate, | ||
1157 | - uint64_t *cluster_offset, | ||
1158 | - uint64_t skip_start_bytes, | ||
1159 | - uint64_t skip_end_bytes) | ||
1160 | +static int coroutine_fn GRAPH_RDLOCK | ||
1161 | +get_cluster_offset(BlockDriverState *bs, VmdkExtent *extent, | ||
1162 | + VmdkMetaData *m_data, uint64_t offset, bool allocate, | ||
1163 | + uint64_t *cluster_offset, uint64_t skip_start_bytes, | ||
1164 | + uint64_t skip_end_bytes) | ||
1165 | { | ||
1166 | unsigned int l1_index, l2_offset, l2_index; | ||
1167 | int min_index, i, j; | ||
1168 | @@ -XXX,XX +XXX,XX @@ static inline uint64_t vmdk_find_offset_in_cluster(VmdkExtent *extent, | ||
1169 | return extent_relative_offset % cluster_size; | ||
1170 | } | ||
1171 | |||
1172 | -static int coroutine_fn vmdk_co_block_status(BlockDriverState *bs, | ||
1173 | - bool want_zero, | ||
1174 | - int64_t offset, int64_t bytes, | ||
1175 | - int64_t *pnum, int64_t *map, | ||
1176 | - BlockDriverState **file) | ||
1177 | +static int coroutine_fn GRAPH_RDLOCK | ||
1178 | +vmdk_co_block_status(BlockDriverState *bs, bool want_zero, | ||
1179 | + int64_t offset, int64_t bytes, int64_t *pnum, | ||
1180 | + int64_t *map, BlockDriverState **file) | ||
1181 | { | ||
1182 | BDRVVmdkState *s = bs->opaque; | ||
1183 | int64_t index_in_cluster, n, ret; | ||
1184 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_block_status(BlockDriverState *bs, | ||
1185 | return ret; | ||
1186 | } | ||
1187 | |||
1188 | -static int coroutine_fn | ||
1189 | +static int coroutine_fn GRAPH_RDLOCK | ||
1190 | vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, | ||
1191 | int64_t offset_in_cluster, QEMUIOVector *qiov, | ||
1192 | uint64_t qiov_offset, uint64_t n_bytes, | ||
1193 | @@ -XXX,XX +XXX,XX @@ vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, | ||
1194 | return ret; | ||
1195 | } | ||
1196 | |||
1197 | -static int coroutine_fn | ||
1198 | +static int coroutine_fn GRAPH_RDLOCK | ||
1199 | vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, | ||
1200 | - int64_t offset_in_cluster, QEMUIOVector *qiov, | ||
1201 | - int bytes) | ||
1202 | + int64_t offset_in_cluster, QEMUIOVector *qiov, int bytes) | ||
1203 | { | ||
1204 | int ret; | ||
1205 | int cluster_bytes, buf_bytes; | ||
1206 | @@ -XXX,XX +XXX,XX @@ vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, | ||
1207 | return ret; | ||
1208 | } | ||
1209 | |||
1210 | -static int coroutine_fn | ||
1211 | +static int coroutine_fn GRAPH_RDLOCK | ||
1212 | vmdk_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1213 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
1214 | { | ||
1215 | @@ -XXX,XX +XXX,XX @@ fail: | ||
1216 | * | ||
1217 | * Returns: error code with 0 for success. | ||
1218 | */ | ||
1219 | -static int coroutine_fn vmdk_pwritev(BlockDriverState *bs, uint64_t offset, | ||
1220 | - uint64_t bytes, QEMUIOVector *qiov, | ||
1221 | - bool zeroed, bool zero_dry_run) | ||
1222 | +static int coroutine_fn GRAPH_RDLOCK | ||
1223 | +vmdk_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, | ||
1224 | + QEMUIOVector *qiov, bool zeroed, bool zero_dry_run) | ||
1225 | { | ||
1226 | BDRVVmdkState *s = bs->opaque; | ||
1227 | VmdkExtent *extent = NULL; | ||
1228 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_pwritev(BlockDriverState *bs, uint64_t offset, | ||
1229 | uint64_t bytes_done = 0; | ||
1230 | VmdkMetaData m_data; | ||
1231 | |||
1232 | - assume_graph_lock(); /* FIXME */ | ||
1233 | - | ||
1234 | if (DIV_ROUND_UP(offset, BDRV_SECTOR_SIZE) > bs->total_sectors) { | ||
1235 | error_report("Wrong offset: offset=0x%" PRIx64 | ||
1236 | " total_sectors=0x%" PRIx64, | ||
1237 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_pwritev(BlockDriverState *bs, uint64_t offset, | ||
1238 | return 0; | ||
1239 | } | ||
1240 | |||
1241 | -static int coroutine_fn | ||
1242 | +static int coroutine_fn GRAPH_RDLOCK | ||
1243 | vmdk_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1244 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
1245 | { | ||
1246 | @@ -XXX,XX +XXX,XX @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1247 | return vmdk_co_pwritev(bs, offset, bytes, qiov, 0); | ||
1248 | } | ||
1249 | |||
1250 | -static int coroutine_fn vmdk_co_pwrite_zeroes(BlockDriverState *bs, | ||
1251 | - int64_t offset, | ||
1252 | - int64_t bytes, | ||
1253 | - BdrvRequestFlags flags) | ||
1254 | +static int coroutine_fn GRAPH_RDLOCK | ||
1255 | +vmdk_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1256 | + BdrvRequestFlags flags) | ||
1257 | { | ||
1258 | int ret; | ||
1259 | BDRVVmdkState *s = bs->opaque; | ||
1260 | @@ -XXX,XX +XXX,XX @@ static VmdkExtentInfo *vmdk_get_extent_info(VmdkExtent *extent) | ||
1261 | return info; | ||
1262 | } | ||
1263 | |||
1264 | -static int coroutine_fn vmdk_co_check(BlockDriverState *bs, | ||
1265 | - BdrvCheckResult *result, | ||
1266 | - BdrvCheckMode fix) | ||
1267 | +static int coroutine_fn GRAPH_RDLOCK | ||
1268 | +vmdk_co_check(BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckMode fix) | ||
1269 | { | ||
1270 | BDRVVmdkState *s = bs->opaque; | ||
1271 | VmdkExtent *extent = NULL; | ||
1272 | diff --git a/block/vpc.c b/block/vpc.c | ||
1273 | index XXXXXXX..XXXXXXX 100644 | ||
1274 | --- a/block/vpc.c | ||
1275 | +++ b/block/vpc.c | ||
1276 | @@ -XXX,XX +XXX,XX @@ vpc_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) | ||
1277 | return 0; | ||
1278 | } | ||
1279 | |||
1280 | -static int coroutine_fn | ||
1281 | +static int coroutine_fn GRAPH_RDLOCK | ||
1282 | vpc_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1283 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
1284 | { | ||
1285 | @@ -XXX,XX +XXX,XX @@ fail: | ||
1286 | return ret; | ||
1287 | } | ||
1288 | |||
1289 | -static int coroutine_fn | ||
1290 | +static int coroutine_fn GRAPH_RDLOCK | ||
1291 | vpc_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1292 | QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
1293 | { | ||
1294 | diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c | ||
1295 | index XXXXXXX..XXXXXXX 100644 | ||
1296 | --- a/tests/unit/test-bdrv-drain.c | ||
1297 | +++ b/tests/unit/test-bdrv-drain.c | ||
1298 | @@ -XXX,XX +XXX,XX @@ static void bdrv_test_top_close(BlockDriverState *bs) | ||
1299 | } | ||
1300 | } | ||
1301 | |||
1302 | -static int coroutine_fn bdrv_test_top_co_preadv(BlockDriverState *bs, | ||
1303 | - int64_t offset, int64_t bytes, | ||
1304 | - QEMUIOVector *qiov, | ||
1305 | - BdrvRequestFlags flags) | ||
1306 | +static int coroutine_fn GRAPH_RDLOCK | ||
1307 | +bdrv_test_top_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1308 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
1309 | { | ||
1310 | BDRVTestTopState *tts = bs->opaque; | ||
1311 | return bdrv_co_preadv(tts->wait_child, offset, bytes, qiov, flags); | ||
1312 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque) | ||
1313 | void *buffer = g_malloc(65536); | ||
1314 | QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buffer, 65536); | ||
1315 | |||
1316 | + GRAPH_RDLOCK_GUARD(); | ||
1317 | + | ||
1318 | /* Pretend some internal write operation from parent to child. | ||
1319 | * Important: We have to read from the child, not from the parent! | ||
1320 | * Draining works by first propagating it all up the tree to the | ||
1321 | @@ -XXX,XX +XXX,XX @@ static void bdrv_replace_test_close(BlockDriverState *bs) | ||
1322 | * Otherwise: | ||
1323 | * Set .has_read to true and return success. | ||
1324 | */ | ||
1325 | -static int coroutine_fn bdrv_replace_test_co_preadv(BlockDriverState *bs, | ||
1326 | - int64_t offset, | ||
1327 | - int64_t bytes, | ||
1328 | - QEMUIOVector *qiov, | ||
1329 | - BdrvRequestFlags flags) | ||
1330 | +static int coroutine_fn GRAPH_RDLOCK | ||
1331 | +bdrv_replace_test_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
1332 | + QEMUIOVector *qiov, BdrvRequestFlags flags) | ||
1333 | { | ||
1334 | BDRVReplaceTestState *s = bs->opaque; | ||
1335 | |||
1336 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_replace_test_read_entry(void *opaque) | ||
1337 | int ret; | ||
1338 | |||
1339 | /* Queue a read request post-drain */ | ||
1340 | + bdrv_graph_co_rdlock(); | ||
1341 | ret = bdrv_replace_test_co_preadv(bs, 0, 1, &qiov, 0); | ||
1342 | + bdrv_graph_co_rdunlock(); | ||
1343 | + | ||
1344 | g_assert(ret >= 0); | ||
1345 | bdrv_dec_in_flight(bs); | ||
1346 | } | ||
157 | -- | 1347 | -- |
158 | 2.20.1 | 1348 | 2.39.2 |
159 | |||
160 | diff view generated by jsdifflib |
1 | From: Alberto Garcia <berto@igalia.com> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_co_pwrite_sync() need to hold a reader lock for the graph. | ||
2 | 3 | ||
3 | The cmd() method of the QEMUQtestProtocol class sends a qtest command | 4 | For some places, we know that they will hold the lock, but we don't have |
4 | to QEMU but doesn't wait for the return message ("OK", "FAIL", "ERR"). | 5 | the GRAPH_RDLOCK annotations yet. In this case, add assume_graph_lock() |
5 | Because of this, it can return control to the caller before the | 6 | with a FIXME comment. These places will be removed once everything is |
6 | command has actually finished. | 7 | properly annotated. |
7 | 8 | ||
8 | In cases like clock_step or clock_set this means that cmd() can return | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | before all the timers triggered by the clock change have been fired. | 10 | Message-Id: <20230203152202.49054-13-kwolf@redhat.com> |
10 | This can be fixed by making cmd() wait for the output of the qtest | 11 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
11 | command. | ||
12 | |||
13 | This fixes iotests 093 and 136, which are flaky since commit | ||
14 | 8258292e18c39480b64eba9f3551 when the machine is under heavy workload. | ||
15 | |||
16 | Signed-off-by: Alberto Garcia <berto@igalia.com> | ||
17 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
19 | --- | 13 | --- |
20 | scripts/qtest.py | 6 ++++++ | 14 | block/qcow2.h | 2 +- |
21 | 1 file changed, 6 insertions(+) | 15 | include/block/block-io.h | 7 ++++--- |
16 | block/io.c | 3 +-- | ||
17 | 3 files changed, 6 insertions(+), 6 deletions(-) | ||
22 | 18 | ||
23 | diff --git a/scripts/qtest.py b/scripts/qtest.py | 19 | diff --git a/block/qcow2.h b/block/qcow2.h |
24 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/scripts/qtest.py | 21 | --- a/block/qcow2.h |
26 | +++ b/scripts/qtest.py | 22 | +++ b/block/qcow2.h |
27 | @@ -XXX,XX +XXX,XX @@ class QEMUQtestProtocol(object): | 23 | @@ -XXX,XX +XXX,XX @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res, |
28 | """ | 24 | int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, |
29 | self._address = address | 25 | BlockDriverAmendStatusCB *status_cb, |
30 | self._sock = self._get_sock() | 26 | void *cb_opaque, Error **errp); |
31 | + self._sockfile = None | 27 | -int coroutine_fn qcow2_shrink_reftable(BlockDriverState *bs); |
32 | if server: | 28 | +int coroutine_fn GRAPH_RDLOCK qcow2_shrink_reftable(BlockDriverState *bs); |
33 | self._sock.bind(self._address) | 29 | int64_t qcow2_get_last_cluster(BlockDriverState *bs, int64_t size); |
34 | self._sock.listen(1) | 30 | int coroutine_fn qcow2_detect_metadata_preallocation(BlockDriverState *bs); |
35 | @@ -XXX,XX +XXX,XX @@ class QEMUQtestProtocol(object): | 31 | |
36 | @raise socket.error on socket connection errors | 32 | diff --git a/include/block/block-io.h b/include/block/block-io.h |
37 | """ | 33 | index XXXXXXX..XXXXXXX 100644 |
38 | self._sock.connect(self._address) | 34 | --- a/include/block/block-io.h |
39 | + self._sockfile = self._sock.makefile() | 35 | +++ b/include/block/block-io.h |
40 | 36 | @@ -XXX,XX +XXX,XX @@ int co_wrapper_mixed_bdrv_rdlock | |
41 | def accept(self): | 37 | bdrv_pwrite_sync(BdrvChild *child, int64_t offset, int64_t bytes, |
42 | """ | 38 | const void *buf, BdrvRequestFlags flags); |
43 | @@ -XXX,XX +XXX,XX @@ class QEMUQtestProtocol(object): | 39 | |
44 | @raise socket.error on socket connection errors | 40 | -int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset, |
45 | """ | 41 | - int64_t bytes, const void *buf, |
46 | self._sock, _ = self._sock.accept() | 42 | - BdrvRequestFlags flags); |
47 | + self._sockfile = self._sock.makefile() | 43 | +int coroutine_fn GRAPH_RDLOCK |
48 | 44 | +bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset, int64_t bytes, | |
49 | def cmd(self, qtest_cmd): | 45 | + const void *buf, BdrvRequestFlags flags); |
50 | """ | 46 | + |
51 | @@ -XXX,XX +XXX,XX @@ class QEMUQtestProtocol(object): | 47 | /* |
52 | @param qtest_cmd: qtest command text to be sent | 48 | * Efficiently zero a region of the disk image. Note that this is a regular |
53 | """ | 49 | * I/O request like read or write and should have a reasonable size. This |
54 | self._sock.sendall((qtest_cmd + "\n").encode('utf-8')) | 50 | diff --git a/block/io.c b/block/io.c |
55 | + resp = self._sockfile.readline() | 51 | index XXXXXXX..XXXXXXX 100644 |
56 | + return resp | 52 | --- a/block/io.c |
57 | 53 | +++ b/block/io.c | |
58 | def close(self): | 54 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwrite_sync(BdrvChild *child, int64_t offset, |
59 | self._sock.close() | 55 | { |
60 | + self._sockfile.close() | 56 | int ret; |
61 | 57 | IO_CODE(); | |
62 | def settimeout(self, timeout): | 58 | - |
63 | self._sock.settimeout(timeout) | 59 | - assume_graph_lock(); /* FIXME */ |
60 | + assert_bdrv_graph_readable(); | ||
61 | |||
62 | ret = bdrv_co_pwrite(child, offset, bytes, buf, flags); | ||
63 | if (ret < 0) { | ||
64 | -- | 64 | -- |
65 | 2.20.1 | 65 | 2.39.2 |
66 | |||
67 | diff view generated by jsdifflib |
1 | From: John Snow <jsnow@redhat.com> | 1 | All callers are already GRAPH_RDLOCK, so just add the annotation and |
---|---|---|---|
2 | remove assume_graph_lock(). | ||
2 | 3 | ||
3 | It's not enough to order the kwargs for consistent QMP log output, | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | we must also sort any sub-dictionaries in lists that appear as values. | 5 | Message-Id: <20230203152202.49054-14-kwolf@redhat.com> |
5 | 6 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | |
6 | Reported-by: Kevin Wolf <kwolf@redhat.com> | ||
7 | Signed-off-by: John Snow <jsnow@redhat.com> | ||
8 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
9 | Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> | ||
10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
11 | --- | 8 | --- |
12 | tests/qemu-iotests/236.out | 56 +++++++++++++++++------------------ | 9 | block/io.c | 7 +++---- |
13 | tests/qemu-iotests/iotests.py | 21 ++++++------- | 10 | 1 file changed, 3 insertions(+), 4 deletions(-) |
14 | 2 files changed, 39 insertions(+), 38 deletions(-) | ||
15 | 11 | ||
16 | diff --git a/tests/qemu-iotests/236.out b/tests/qemu-iotests/236.out | 12 | diff --git a/block/io.c b/block/io.c |
17 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/tests/qemu-iotests/236.out | 14 | --- a/block/io.c |
19 | +++ b/tests/qemu-iotests/236.out | 15 | +++ b/block/io.c |
20 | @@ -XXX,XX +XXX,XX @@ write -P0xcd 0x3ff0000 64k | 16 | @@ -XXX,XX +XXX,XX @@ fail: |
21 | "actions": [ | 17 | return ret; |
22 | { | 18 | } |
23 | "data": { | 19 | |
24 | - "node": "drive0", | 20 | -static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, |
25 | - "name": "bitmapB" | 21 | - int64_t offset, int64_t bytes, BdrvRequestFlags flags) |
26 | + "name": "bitmapB", | 22 | +static int coroutine_fn GRAPH_RDLOCK |
27 | + "node": "drive0" | 23 | +bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, |
28 | }, | 24 | + BdrvRequestFlags flags) |
29 | "type": "block-dirty-bitmap-disable" | 25 | { |
30 | }, | 26 | BlockDriver *drv = bs->drv; |
31 | { | 27 | QEMUIOVector qiov; |
32 | "data": { | 28 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, |
33 | - "node": "drive0", | 29 | int head = 0; |
34 | + "granularity": 65536, | 30 | int tail = 0; |
35 | "name": "bitmapC", | 31 | |
36 | - "granularity": 65536 | 32 | - assume_graph_lock(); /* FIXME */ |
37 | + "node": "drive0" | 33 | - |
38 | }, | 34 | int64_t max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, |
39 | "type": "block-dirty-bitmap-add" | 35 | INT64_MAX); |
40 | }, | 36 | int alignment = MAX(bs->bl.pwrite_zeroes_alignment, |
41 | { | ||
42 | "data": { | ||
43 | - "node": "drive0", | ||
44 | - "name": "bitmapA" | ||
45 | + "name": "bitmapA", | ||
46 | + "node": "drive0" | ||
47 | }, | ||
48 | "type": "block-dirty-bitmap-clear" | ||
49 | }, | ||
50 | @@ -XXX,XX +XXX,XX @@ write -P0xcd 0x3ff0000 64k | ||
51 | "actions": [ | ||
52 | { | ||
53 | "data": { | ||
54 | - "node": "drive0", | ||
55 | - "name": "bitmapB" | ||
56 | + "name": "bitmapB", | ||
57 | + "node": "drive0" | ||
58 | }, | ||
59 | "type": "block-dirty-bitmap-disable" | ||
60 | }, | ||
61 | { | ||
62 | "data": { | ||
63 | - "node": "drive0", | ||
64 | + "granularity": 65536, | ||
65 | "name": "bitmapC", | ||
66 | - "granularity": 65536 | ||
67 | + "node": "drive0" | ||
68 | }, | ||
69 | "type": "block-dirty-bitmap-add" | ||
70 | }, | ||
71 | { | ||
72 | "data": { | ||
73 | - "node": "drive0", | ||
74 | - "name": "bitmapC" | ||
75 | + "name": "bitmapC", | ||
76 | + "node": "drive0" | ||
77 | }, | ||
78 | "type": "block-dirty-bitmap-disable" | ||
79 | }, | ||
80 | { | ||
81 | "data": { | ||
82 | - "node": "drive0", | ||
83 | - "name": "bitmapC" | ||
84 | + "name": "bitmapC", | ||
85 | + "node": "drive0" | ||
86 | }, | ||
87 | "type": "block-dirty-bitmap-enable" | ||
88 | } | ||
89 | @@ -XXX,XX +XXX,XX @@ write -P0xea 0x3fe0000 64k | ||
90 | "actions": [ | ||
91 | { | ||
92 | "data": { | ||
93 | - "node": "drive0", | ||
94 | - "name": "bitmapA" | ||
95 | + "name": "bitmapA", | ||
96 | + "node": "drive0" | ||
97 | }, | ||
98 | "type": "block-dirty-bitmap-disable" | ||
99 | }, | ||
100 | { | ||
101 | "data": { | ||
102 | - "node": "drive0", | ||
103 | - "name": "bitmapC" | ||
104 | + "name": "bitmapC", | ||
105 | + "node": "drive0" | ||
106 | }, | ||
107 | "type": "block-dirty-bitmap-disable" | ||
108 | } | ||
109 | @@ -XXX,XX +XXX,XX @@ write -P0xea 0x3fe0000 64k | ||
110 | "actions": [ | ||
111 | { | ||
112 | "data": { | ||
113 | - "node": "drive0", | ||
114 | "disabled": true, | ||
115 | + "granularity": 65536, | ||
116 | "name": "bitmapD", | ||
117 | - "granularity": 65536 | ||
118 | + "node": "drive0" | ||
119 | }, | ||
120 | "type": "block-dirty-bitmap-add" | ||
121 | }, | ||
122 | { | ||
123 | "data": { | ||
124 | - "node": "drive0", | ||
125 | - "target": "bitmapD", | ||
126 | "bitmaps": [ | ||
127 | "bitmapB", | ||
128 | "bitmapC" | ||
129 | - ] | ||
130 | + ], | ||
131 | + "node": "drive0", | ||
132 | + "target": "bitmapD" | ||
133 | }, | ||
134 | "type": "block-dirty-bitmap-merge" | ||
135 | }, | ||
136 | @@ -XXX,XX +XXX,XX @@ write -P0xea 0x3fe0000 64k | ||
137 | "actions": [ | ||
138 | { | ||
139 | "data": { | ||
140 | - "node": "drive0", | ||
141 | "disabled": true, | ||
142 | + "granularity": 65536, | ||
143 | "name": "bitmapD", | ||
144 | - "granularity": 65536 | ||
145 | + "node": "drive0" | ||
146 | }, | ||
147 | "type": "block-dirty-bitmap-add" | ||
148 | }, | ||
149 | { | ||
150 | "data": { | ||
151 | - "node": "drive0", | ||
152 | - "target": "bitmapD", | ||
153 | "bitmaps": [ | ||
154 | "bitmapB", | ||
155 | "bitmapC" | ||
156 | - ] | ||
157 | + ], | ||
158 | + "node": "drive0", | ||
159 | + "target": "bitmapD" | ||
160 | }, | ||
161 | "type": "block-dirty-bitmap-merge" | ||
162 | } | ||
163 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
164 | index XXXXXXX..XXXXXXX 100644 | ||
165 | --- a/tests/qemu-iotests/iotests.py | ||
166 | +++ b/tests/qemu-iotests/iotests.py | ||
167 | @@ -XXX,XX +XXX,XX @@ def qemu_img(*args): | ||
168 | sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args)))) | ||
169 | return exitcode | ||
170 | |||
171 | -def ordered_kwargs(kwargs): | ||
172 | - # kwargs prior to 3.6 are not ordered, so: | ||
173 | - od = OrderedDict() | ||
174 | - for k, v in sorted(kwargs.items()): | ||
175 | - if isinstance(v, dict): | ||
176 | - od[k] = ordered_kwargs(v) | ||
177 | - else: | ||
178 | - od[k] = v | ||
179 | - return od | ||
180 | +def ordered_qmp(qmsg): | ||
181 | + # Dictionaries are not ordered prior to 3.6, therefore: | ||
182 | + if isinstance(qmsg, list): | ||
183 | + return [ordered_qmp(atom) for atom in qmsg] | ||
184 | + if isinstance(qmsg, dict): | ||
185 | + od = OrderedDict() | ||
186 | + for k, v in sorted(qmsg.items()): | ||
187 | + od[k] = ordered_qmp(v) | ||
188 | + return od | ||
189 | + return qmsg | ||
190 | |||
191 | def qemu_img_create(*args): | ||
192 | args = list(args) | ||
193 | @@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine): | ||
194 | def qmp_log(self, cmd, filters=[], indent=None, **kwargs): | ||
195 | full_cmd = OrderedDict(( | ||
196 | ("execute", cmd), | ||
197 | - ("arguments", ordered_kwargs(kwargs)) | ||
198 | + ("arguments", ordered_qmp(kwargs)) | ||
199 | )) | ||
200 | log(full_cmd, filters, indent=indent) | ||
201 | result = self.qmp(cmd, **kwargs) | ||
202 | -- | 37 | -- |
203 | 2.20.1 | 38 | 2.39.2 |
204 | |||
205 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Without this filter, this test sometimes fails. | 3 | This adds GRAPH_RDLOCK annotations to declare that callers of |
4 | bdrv_co_copy_range() need to hold a reader lock for the graph. | ||
4 | 5 | ||
5 | Signed-off-by: Max Reitz <mreitz@redhat.com> | 6 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
6 | Reviewed-by: John Snow <jsnow@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | Message-Id: <20230203152202.49054-15-kwolf@redhat.com> | ||
9 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 10 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | --- | 11 | --- |
9 | tests/qemu-iotests/229 | 6 +++++- | 12 | include/block/block-io.h | 9 +++++---- |
10 | tests/qemu-iotests/229.out | 1 - | 13 | include/block/block_int-common.h | 24 ++++++++---------------- |
11 | 2 files changed, 5 insertions(+), 2 deletions(-) | 14 | include/block/block_int-io.h | 20 ++++++++++---------- |
15 | block/block-backend.c | 2 ++ | ||
16 | block/file-posix.c | 16 +++++++--------- | ||
17 | block/io.c | 7 +++++-- | ||
18 | block/iscsi.c | 28 ++++++++++++---------------- | ||
19 | block/qcow2.c | 5 ++--- | ||
20 | block/raw-format.c | 28 ++++++++++++---------------- | ||
21 | qemu-img.c | 4 +++- | ||
22 | 10 files changed, 66 insertions(+), 77 deletions(-) | ||
12 | 23 | ||
13 | diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229 | 24 | diff --git a/include/block/block-io.h b/include/block/block-io.h |
14 | index XXXXXXX..XXXXXXX 100755 | 25 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/tests/qemu-iotests/229 | 26 | --- a/include/block/block-io.h |
16 | +++ b/tests/qemu-iotests/229 | 27 | +++ b/include/block/block-io.h |
17 | @@ -XXX,XX +XXX,XX @@ echo | 28 | @@ -XXX,XX +XXX,XX @@ bool co_wrapper bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, |
18 | echo '=== Force cancel job paused in error state ===' | 29 | * |
19 | echo | 30 | * Returns: 0 if succeeded; negative error code if failed. |
20 | 31 | **/ | |
21 | +# Filter out BLOCK_JOB_ERROR events because they may or may not occur. | 32 | -int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset, |
22 | +# Cancelling the job means resuming it for a bit before it is actually | 33 | - BdrvChild *dst, int64_t dst_offset, |
23 | +# aborted, and in that time it may or may not re-encounter the error. | 34 | - int64_t bytes, BdrvRequestFlags read_flags, |
24 | success_or_failure="y" _send_qemu_cmd $QEMU_HANDLE \ | 35 | - BdrvRequestFlags write_flags); |
25 | "{'execute': 'block-job-cancel', | 36 | +int coroutine_fn GRAPH_RDLOCK |
26 | 'arguments': { 'device': 'testdisk', | 37 | +bdrv_co_copy_range(BdrvChild *src, int64_t src_offset, |
27 | 'force': true}}" \ | 38 | + BdrvChild *dst, int64_t dst_offset, |
28 | - "BLOCK_JOB_CANCELLED" "Assertion" | 39 | + int64_t bytes, BdrvRequestFlags read_flags, |
29 | + "BLOCK_JOB_CANCELLED" "Assertion" \ | 40 | + BdrvRequestFlags write_flags); |
30 | + | grep -v '"BLOCK_JOB_ERROR"' | 41 | |
31 | 42 | /* | |
32 | # success, all done | 43 | * "I/O or GS" API functions. These functions can run without |
33 | echo "*** done" | 44 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
34 | diff --git a/tests/qemu-iotests/229.out b/tests/qemu-iotests/229.out | 45 | index XXXXXXX..XXXXXXX 100644 |
35 | index XXXXXXX..XXXXXXX 100644 | 46 | --- a/include/block/block_int-common.h |
36 | --- a/tests/qemu-iotests/229.out | 47 | +++ b/include/block/block_int-common.h |
37 | +++ b/tests/qemu-iotests/229.out | 48 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
38 | @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 0 | 49 | * See the comment of bdrv_co_copy_range for the parameter and return value |
39 | 50 | * semantics. | |
40 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "testdisk"}} | 51 | */ |
41 | {"return": {}} | 52 | - int coroutine_fn (*bdrv_co_copy_range_from)(BlockDriverState *bs, |
42 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "testdisk", "operation": "write", "action": "stop"}} | 53 | - BdrvChild *src, |
43 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "testdisk"}} | 54 | - int64_t offset, |
44 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "testdisk", "len": 2097152, "offset": 1048576, "speed": 0, "type": "mirror"}} | 55 | - BdrvChild *dst, |
45 | *** done | 56 | - int64_t dst_offset, |
57 | - int64_t bytes, | ||
58 | - BdrvRequestFlags read_flags, | ||
59 | - BdrvRequestFlags write_flags); | ||
60 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_copy_range_from)( | ||
61 | + BlockDriverState *bs, BdrvChild *src, int64_t offset, | ||
62 | + BdrvChild *dst, int64_t dst_offset, int64_t bytes, | ||
63 | + BdrvRequestFlags read_flags, BdrvRequestFlags write_flags); | ||
64 | |||
65 | /* | ||
66 | * Map [offset, offset + nbytes) range onto a child of bs to copy data to, | ||
67 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
68 | * See the comment of bdrv_co_copy_range for the parameter and return value | ||
69 | * semantics. | ||
70 | */ | ||
71 | - int coroutine_fn (*bdrv_co_copy_range_to)(BlockDriverState *bs, | ||
72 | - BdrvChild *src, | ||
73 | - int64_t src_offset, | ||
74 | - BdrvChild *dst, | ||
75 | - int64_t dst_offset, | ||
76 | - int64_t bytes, | ||
77 | - BdrvRequestFlags read_flags, | ||
78 | - BdrvRequestFlags write_flags); | ||
79 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_copy_range_to)( | ||
80 | + BlockDriverState *bs, BdrvChild *src, int64_t src_offset, | ||
81 | + BdrvChild *dst, int64_t dst_offset, int64_t bytes, | ||
82 | + BdrvRequestFlags read_flags, BdrvRequestFlags write_flags); | ||
83 | |||
84 | /* | ||
85 | * Building block for bdrv_block_status[_above] and | ||
86 | diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h | ||
87 | index XXXXXXX..XXXXXXX 100644 | ||
88 | --- a/include/block/block_int-io.h | ||
89 | +++ b/include/block/block_int-io.h | ||
90 | @@ -XXX,XX +XXX,XX @@ void bdrv_dirty_bitmap_merge_internal(BdrvDirtyBitmap *dest, | ||
91 | void bdrv_inc_in_flight(BlockDriverState *bs); | ||
92 | void bdrv_dec_in_flight(BlockDriverState *bs); | ||
93 | |||
94 | -int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset, | ||
95 | - BdrvChild *dst, int64_t dst_offset, | ||
96 | - int64_t bytes, | ||
97 | - BdrvRequestFlags read_flags, | ||
98 | - BdrvRequestFlags write_flags); | ||
99 | -int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset, | ||
100 | - BdrvChild *dst, int64_t dst_offset, | ||
101 | - int64_t bytes, | ||
102 | - BdrvRequestFlags read_flags, | ||
103 | - BdrvRequestFlags write_flags); | ||
104 | +int coroutine_fn GRAPH_RDLOCK | ||
105 | +bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset, | ||
106 | + BdrvChild *dst, int64_t dst_offset, | ||
107 | + int64_t bytes, BdrvRequestFlags read_flags, | ||
108 | + BdrvRequestFlags write_flags); | ||
109 | +int coroutine_fn GRAPH_RDLOCK | ||
110 | +bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset, | ||
111 | + BdrvChild *dst, int64_t dst_offset, | ||
112 | + int64_t bytes, BdrvRequestFlags read_flags, | ||
113 | + BdrvRequestFlags write_flags); | ||
114 | |||
115 | int coroutine_fn bdrv_co_refresh_total_sectors(BlockDriverState *bs, | ||
116 | int64_t hint); | ||
117 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
118 | index XXXXXXX..XXXXXXX 100644 | ||
119 | --- a/block/block-backend.c | ||
120 | +++ b/block/block-backend.c | ||
121 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, | ||
122 | if (r) { | ||
123 | return r; | ||
124 | } | ||
125 | + | ||
126 | + GRAPH_RDLOCK_GUARD(); | ||
127 | return bdrv_co_copy_range(blk_in->root, off_in, | ||
128 | blk_out->root, off_out, | ||
129 | bytes, read_flags, write_flags); | ||
130 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
131 | index XXXXXXX..XXXXXXX 100644 | ||
132 | --- a/block/file-posix.c | ||
133 | +++ b/block/file-posix.c | ||
134 | @@ -XXX,XX +XXX,XX @@ static void raw_abort_perm_update(BlockDriverState *bs) | ||
135 | raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL); | ||
136 | } | ||
137 | |||
138 | -static int coroutine_fn raw_co_copy_range_from( | ||
139 | +static int coroutine_fn GRAPH_RDLOCK raw_co_copy_range_from( | ||
140 | BlockDriverState *bs, BdrvChild *src, int64_t src_offset, | ||
141 | BdrvChild *dst, int64_t dst_offset, int64_t bytes, | ||
142 | BdrvRequestFlags read_flags, BdrvRequestFlags write_flags) | ||
143 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_copy_range_from( | ||
144 | read_flags, write_flags); | ||
145 | } | ||
146 | |||
147 | -static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs, | ||
148 | - BdrvChild *src, | ||
149 | - int64_t src_offset, | ||
150 | - BdrvChild *dst, | ||
151 | - int64_t dst_offset, | ||
152 | - int64_t bytes, | ||
153 | - BdrvRequestFlags read_flags, | ||
154 | - BdrvRequestFlags write_flags) | ||
155 | +static int coroutine_fn GRAPH_RDLOCK | ||
156 | +raw_co_copy_range_to(BlockDriverState *bs, | ||
157 | + BdrvChild *src, int64_t src_offset, | ||
158 | + BdrvChild *dst, int64_t dst_offset, | ||
159 | + int64_t bytes, BdrvRequestFlags read_flags, | ||
160 | + BdrvRequestFlags write_flags) | ||
161 | { | ||
162 | RawPosixAIOData acb; | ||
163 | BDRVRawState *s = bs->opaque; | ||
164 | diff --git a/block/io.c b/block/io.c | ||
165 | index XXXXXXX..XXXXXXX 100644 | ||
166 | --- a/block/io.c | ||
167 | +++ b/block/io.c | ||
168 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn GRAPH_RDLOCK bdrv_co_copy_range_internal( | ||
169 | { | ||
170 | BdrvTrackedRequest req; | ||
171 | int ret; | ||
172 | + assert_bdrv_graph_readable(); | ||
173 | |||
174 | /* TODO We can support BDRV_REQ_NO_FALLBACK here */ | ||
175 | assert(!(read_flags & BDRV_REQ_NO_FALLBACK)); | ||
176 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, int64_t src_offset, | ||
177 | BdrvRequestFlags write_flags) | ||
178 | { | ||
179 | IO_CODE(); | ||
180 | - assume_graph_lock(); /* FIXME */ | ||
181 | + assert_bdrv_graph_readable(); | ||
182 | trace_bdrv_co_copy_range_from(src, src_offset, dst, dst_offset, bytes, | ||
183 | read_flags, write_flags); | ||
184 | return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset, | ||
185 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset, | ||
186 | BdrvRequestFlags write_flags) | ||
187 | { | ||
188 | IO_CODE(); | ||
189 | - assume_graph_lock(); /* FIXME */ | ||
190 | + assert_bdrv_graph_readable(); | ||
191 | trace_bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, | ||
192 | read_flags, write_flags); | ||
193 | return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset, | ||
194 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset, | ||
195 | BdrvRequestFlags write_flags) | ||
196 | { | ||
197 | IO_CODE(); | ||
198 | + assert_bdrv_graph_readable(); | ||
199 | + | ||
200 | return bdrv_co_copy_range_from(src, src_offset, | ||
201 | dst, dst_offset, | ||
202 | bytes, read_flags, write_flags); | ||
203 | diff --git a/block/iscsi.c b/block/iscsi.c | ||
204 | index XXXXXXX..XXXXXXX 100644 | ||
205 | --- a/block/iscsi.c | ||
206 | +++ b/block/iscsi.c | ||
207 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn iscsi_co_invalidate_cache(BlockDriverState *bs, | ||
208 | iscsi_allocmap_invalidate(iscsilun); | ||
209 | } | ||
210 | |||
211 | -static int coroutine_fn iscsi_co_copy_range_from(BlockDriverState *bs, | ||
212 | - BdrvChild *src, | ||
213 | - int64_t src_offset, | ||
214 | - BdrvChild *dst, | ||
215 | - int64_t dst_offset, | ||
216 | - int64_t bytes, | ||
217 | - BdrvRequestFlags read_flags, | ||
218 | - BdrvRequestFlags write_flags) | ||
219 | +static int coroutine_fn GRAPH_RDLOCK | ||
220 | +iscsi_co_copy_range_from(BlockDriverState *bs, | ||
221 | + BdrvChild *src, int64_t src_offset, | ||
222 | + BdrvChild *dst, int64_t dst_offset, | ||
223 | + int64_t bytes, BdrvRequestFlags read_flags, | ||
224 | + BdrvRequestFlags write_flags) | ||
225 | { | ||
226 | return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, | ||
227 | read_flags, write_flags); | ||
228 | @@ -XXX,XX +XXX,XX @@ static void iscsi_xcopy_data(struct iscsi_data *data, | ||
229 | src_lba, dst_lba); | ||
230 | } | ||
231 | |||
232 | -static int coroutine_fn iscsi_co_copy_range_to(BlockDriverState *bs, | ||
233 | - BdrvChild *src, | ||
234 | - int64_t src_offset, | ||
235 | - BdrvChild *dst, | ||
236 | - int64_t dst_offset, | ||
237 | - int64_t bytes, | ||
238 | - BdrvRequestFlags read_flags, | ||
239 | - BdrvRequestFlags write_flags) | ||
240 | +static int coroutine_fn GRAPH_RDLOCK | ||
241 | +iscsi_co_copy_range_to(BlockDriverState *bs, | ||
242 | + BdrvChild *src, int64_t src_offset, | ||
243 | + BdrvChild *dst, int64_t dst_offset, | ||
244 | + int64_t bytes, BdrvRequestFlags read_flags, | ||
245 | + BdrvRequestFlags write_flags) | ||
246 | { | ||
247 | IscsiLun *dst_lun = dst->bs->opaque; | ||
248 | IscsiLun *src_lun; | ||
249 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
250 | index XXXXXXX..XXXXXXX 100644 | ||
251 | --- a/block/qcow2.c | ||
252 | +++ b/block/qcow2.c | ||
253 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs, | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | -static int coroutine_fn | ||
258 | +static int coroutine_fn GRAPH_RDLOCK | ||
259 | qcow2_co_copy_range_from(BlockDriverState *bs, | ||
260 | BdrvChild *src, int64_t src_offset, | ||
261 | BdrvChild *dst, int64_t dst_offset, | ||
262 | @@ -XXX,XX +XXX,XX @@ out: | ||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | -static int coroutine_fn | ||
267 | +static int coroutine_fn GRAPH_RDLOCK | ||
268 | qcow2_co_copy_range_to(BlockDriverState *bs, | ||
269 | BdrvChild *src, int64_t src_offset, | ||
270 | BdrvChild *dst, int64_t dst_offset, | ||
271 | @@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_to(BlockDriverState *bs, | ||
272 | uint64_t host_offset; | ||
273 | QCowL2Meta *l2meta = NULL; | ||
274 | |||
275 | - assume_graph_lock(); /* FIXME */ | ||
276 | assert(!bs->encrypted); | ||
277 | |||
278 | qemu_co_mutex_lock(&s->lock); | ||
279 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
280 | index XXXXXXX..XXXXXXX 100644 | ||
281 | --- a/block/raw-format.c | ||
282 | +++ b/block/raw-format.c | ||
283 | @@ -XXX,XX +XXX,XX @@ static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo) | ||
284 | return bdrv_probe_geometry(bs->file->bs, geo); | ||
285 | } | ||
286 | |||
287 | -static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs, | ||
288 | - BdrvChild *src, | ||
289 | - int64_t src_offset, | ||
290 | - BdrvChild *dst, | ||
291 | - int64_t dst_offset, | ||
292 | - int64_t bytes, | ||
293 | - BdrvRequestFlags read_flags, | ||
294 | - BdrvRequestFlags write_flags) | ||
295 | +static int coroutine_fn GRAPH_RDLOCK | ||
296 | +raw_co_copy_range_from(BlockDriverState *bs, | ||
297 | + BdrvChild *src, int64_t src_offset, | ||
298 | + BdrvChild *dst, int64_t dst_offset, | ||
299 | + int64_t bytes, BdrvRequestFlags read_flags, | ||
300 | + BdrvRequestFlags write_flags) | ||
301 | { | ||
302 | int ret; | ||
303 | |||
304 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs, | ||
305 | bytes, read_flags, write_flags); | ||
306 | } | ||
307 | |||
308 | -static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs, | ||
309 | - BdrvChild *src, | ||
310 | - int64_t src_offset, | ||
311 | - BdrvChild *dst, | ||
312 | - int64_t dst_offset, | ||
313 | - int64_t bytes, | ||
314 | - BdrvRequestFlags read_flags, | ||
315 | - BdrvRequestFlags write_flags) | ||
316 | +static int coroutine_fn GRAPH_RDLOCK | ||
317 | +raw_co_copy_range_to(BlockDriverState *bs, | ||
318 | + BdrvChild *src, int64_t src_offset, | ||
319 | + BdrvChild *dst, int64_t dst_offset, | ||
320 | + int64_t bytes, BdrvRequestFlags read_flags, | ||
321 | + BdrvRequestFlags write_flags) | ||
322 | { | ||
323 | int ret; | ||
324 | |||
325 | diff --git a/qemu-img.c b/qemu-img.c | ||
326 | index XXXXXXX..XXXXXXX 100644 | ||
327 | --- a/qemu-img.c | ||
328 | +++ b/qemu-img.c | ||
329 | @@ -XXX,XX +XXX,XX @@ retry: | ||
330 | |||
331 | if (s->ret == -EINPROGRESS) { | ||
332 | if (copy_range) { | ||
333 | - ret = convert_co_copy_range(s, sector_num, n); | ||
334 | + WITH_GRAPH_RDLOCK_GUARD() { | ||
335 | + ret = convert_co_copy_range(s, sector_num, n); | ||
336 | + } | ||
337 | if (ret) { | ||
338 | s->copy_range = false; | ||
339 | goto retry; | ||
46 | -- | 340 | -- |
47 | 2.20.1 | 341 | 2.39.2 |
48 | |||
49 | diff view generated by jsdifflib |
1 | From: Peter Maydell <peter.maydell@linaro.org> | 1 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
---|---|---|---|
2 | 2 | Message-Id: <20230203152202.49054-16-kwolf@redhat.com> | |
3 | Currently qemu_uuid_bswap() takes a pointer to the QemuUUID to | 3 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
4 | be byte-swapped. This means it can't be used when the UUID | ||
5 | to be swapped is in a packed member of a struct. It's also | ||
6 | out of line with the general bswap*() functions we provide | ||
7 | in bswap.h, which take the value to be swapped and return it. | ||
8 | |||
9 | Make qemu_uuid_bswap() take a QemuUUID and return the swapped version. | ||
10 | |||
11 | This fixes some clang warnings about taking the address of | ||
12 | a packed struct member in block/vdi.c. | ||
13 | |||
14 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
15 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||
16 | Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | --- | 5 | --- |
19 | include/qemu/uuid.h | 2 +- | 6 | include/block/block_int-common.h | 12 +++++++----- |
20 | block/vdi.c | 16 ++++++++-------- | 7 | include/block/block_int-io.h | 8 ++++---- |
21 | hw/acpi/vmgenid.c | 6 ++---- | 8 | block/copy-before-write.c | 6 ++---- |
22 | tests/vmgenid-test.c | 2 +- | 9 | block/io.c | 2 ++ |
23 | util/uuid.c | 10 +++++----- | 10 | block/snapshot-access.c | 4 ++-- |
24 | 5 files changed, 17 insertions(+), 19 deletions(-) | 11 | 5 files changed, 17 insertions(+), 15 deletions(-) |
25 | 12 | ||
26 | diff --git a/include/qemu/uuid.h b/include/qemu/uuid.h | 13 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
27 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
28 | --- a/include/qemu/uuid.h | 15 | --- a/include/block/block_int-common.h |
29 | +++ b/include/qemu/uuid.h | 16 | +++ b/include/block/block_int-common.h |
30 | @@ -XXX,XX +XXX,XX @@ char *qemu_uuid_unparse_strdup(const QemuUUID *uuid); | 17 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
31 | 18 | * - receive the snapshot's actual length (which may differ from bs's | |
32 | int qemu_uuid_parse(const char *str, QemuUUID *uuid); | 19 | * length) |
33 | 20 | */ | |
34 | -void qemu_uuid_bswap(QemuUUID *uuid); | 21 | - int coroutine_fn (*bdrv_co_preadv_snapshot)(BlockDriverState *bs, |
35 | +QemuUUID qemu_uuid_bswap(QemuUUID uuid); | 22 | - int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset); |
36 | 23 | - int coroutine_fn (*bdrv_co_snapshot_block_status)(BlockDriverState *bs, | |
37 | #endif | 24 | - bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum, |
38 | diff --git a/block/vdi.c b/block/vdi.c | 25 | - int64_t *map, BlockDriverState **file); |
26 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_preadv_snapshot)( | ||
27 | + BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
28 | + QEMUIOVector *qiov, size_t qiov_offset); | ||
29 | + | ||
30 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_snapshot_block_status)( | ||
31 | + BlockDriverState *bs, bool want_zero, int64_t offset, int64_t bytes, | ||
32 | + int64_t *pnum, int64_t *map, BlockDriverState **file); | ||
33 | |||
34 | int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pdiscard_snapshot)( | ||
35 | BlockDriverState *bs, int64_t offset, int64_t bytes); | ||
36 | diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h | ||
39 | index XXXXXXX..XXXXXXX 100644 | 37 | index XXXXXXX..XXXXXXX 100644 |
40 | --- a/block/vdi.c | 38 | --- a/include/block/block_int-io.h |
41 | +++ b/block/vdi.c | 39 | +++ b/include/block/block_int-io.h |
42 | @@ -XXX,XX +XXX,XX @@ static void vdi_header_to_cpu(VdiHeader *header) | 40 | @@ -XXX,XX +XXX,XX @@ |
43 | header->block_extra = le32_to_cpu(header->block_extra); | 41 | * the I/O API. |
44 | header->blocks_in_image = le32_to_cpu(header->blocks_in_image); | 42 | */ |
45 | header->blocks_allocated = le32_to_cpu(header->blocks_allocated); | 43 | |
46 | - qemu_uuid_bswap(&header->uuid_image); | 44 | -int coroutine_fn bdrv_co_preadv_snapshot(BdrvChild *child, |
47 | - qemu_uuid_bswap(&header->uuid_last_snap); | 45 | +int coroutine_fn GRAPH_RDLOCK bdrv_co_preadv_snapshot(BdrvChild *child, |
48 | - qemu_uuid_bswap(&header->uuid_link); | 46 | int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset); |
49 | - qemu_uuid_bswap(&header->uuid_parent); | 47 | -int coroutine_fn bdrv_co_snapshot_block_status(BlockDriverState *bs, |
50 | + header->uuid_image = qemu_uuid_bswap(header->uuid_image); | 48 | - bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum, |
51 | + header->uuid_last_snap = qemu_uuid_bswap(header->uuid_last_snap); | 49 | - int64_t *map, BlockDriverState **file); |
52 | + header->uuid_link = qemu_uuid_bswap(header->uuid_link); | 50 | +int coroutine_fn GRAPH_RDLOCK bdrv_co_snapshot_block_status( |
53 | + header->uuid_parent = qemu_uuid_bswap(header->uuid_parent); | 51 | + BlockDriverState *bs, bool want_zero, int64_t offset, int64_t bytes, |
52 | + int64_t *pnum, int64_t *map, BlockDriverState **file); | ||
53 | int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard_snapshot(BlockDriverState *bs, | ||
54 | int64_t offset, int64_t bytes); | ||
55 | |||
56 | diff --git a/block/copy-before-write.c b/block/copy-before-write.c | ||
57 | index XXXXXXX..XXXXXXX 100644 | ||
58 | --- a/block/copy-before-write.c | ||
59 | +++ b/block/copy-before-write.c | ||
60 | @@ -XXX,XX +XXX,XX @@ cbw_snapshot_read_unlock(BlockDriverState *bs, BlockReq *req) | ||
61 | g_free(req); | ||
54 | } | 62 | } |
55 | 63 | ||
56 | static void vdi_header_to_le(VdiHeader *header) | 64 | -static coroutine_fn int |
57 | @@ -XXX,XX +XXX,XX @@ static void vdi_header_to_le(VdiHeader *header) | 65 | +static int coroutine_fn GRAPH_RDLOCK |
58 | header->block_extra = cpu_to_le32(header->block_extra); | 66 | cbw_co_preadv_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes, |
59 | header->blocks_in_image = cpu_to_le32(header->blocks_in_image); | 67 | QEMUIOVector *qiov, size_t qiov_offset) |
60 | header->blocks_allocated = cpu_to_le32(header->blocks_allocated); | 68 | { |
61 | - qemu_uuid_bswap(&header->uuid_image); | 69 | @@ -XXX,XX +XXX,XX @@ cbw_co_preadv_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes, |
62 | - qemu_uuid_bswap(&header->uuid_last_snap); | 70 | BdrvChild *file; |
63 | - qemu_uuid_bswap(&header->uuid_link); | 71 | int ret; |
64 | - qemu_uuid_bswap(&header->uuid_parent); | 72 | |
65 | + header->uuid_image = qemu_uuid_bswap(header->uuid_image); | 73 | - assume_graph_lock(); /* FIXME */ |
66 | + header->uuid_last_snap = qemu_uuid_bswap(header->uuid_last_snap); | 74 | - |
67 | + header->uuid_link = qemu_uuid_bswap(header->uuid_link); | 75 | /* TODO: upgrade to async loop using AioTask */ |
68 | + header->uuid_parent = qemu_uuid_bswap(header->uuid_parent); | 76 | while (bytes) { |
77 | int64_t cur_bytes; | ||
78 | @@ -XXX,XX +XXX,XX @@ cbw_co_preadv_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
79 | return 0; | ||
69 | } | 80 | } |
70 | 81 | ||
71 | static void vdi_header_print(VdiHeader *header) | 82 | -static int coroutine_fn |
72 | diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c | 83 | +static int coroutine_fn GRAPH_RDLOCK |
84 | cbw_co_snapshot_block_status(BlockDriverState *bs, | ||
85 | bool want_zero, int64_t offset, int64_t bytes, | ||
86 | int64_t *pnum, int64_t *map, | ||
87 | diff --git a/block/io.c b/block/io.c | ||
73 | index XXXXXXX..XXXXXXX 100644 | 88 | index XXXXXXX..XXXXXXX 100644 |
74 | --- a/hw/acpi/vmgenid.c | 89 | --- a/block/io.c |
75 | +++ b/hw/acpi/vmgenid.c | 90 | +++ b/block/io.c |
76 | @@ -XXX,XX +XXX,XX @@ void vmgenid_build_acpi(VmGenIdState *vms, GArray *table_data, GArray *guid, | 91 | @@ -XXX,XX +XXX,XX @@ bdrv_co_preadv_snapshot(BdrvChild *child, int64_t offset, int64_t bytes, |
77 | * first, since that's what the guest expects | 92 | BlockDriver *drv = bs->drv; |
78 | */ | 93 | int ret; |
79 | g_array_set_size(guid, VMGENID_FW_CFG_SIZE - ARRAY_SIZE(guid_le.data)); | 94 | IO_CODE(); |
80 | - guid_le = vms->guid; | 95 | + assert_bdrv_graph_readable(); |
81 | - qemu_uuid_bswap(&guid_le); | 96 | |
82 | + guid_le = qemu_uuid_bswap(vms->guid); | 97 | if (!drv) { |
83 | /* The GUID is written at a fixed offset into the fw_cfg file | 98 | return -ENOMEDIUM; |
84 | * in order to implement the "OVMF SDT Header probe suppressor" | 99 | @@ -XXX,XX +XXX,XX @@ bdrv_co_snapshot_block_status(BlockDriverState *bs, |
85 | * see docs/specs/vmgenid.txt for more details | 100 | BlockDriver *drv = bs->drv; |
86 | @@ -XXX,XX +XXX,XX @@ static void vmgenid_update_guest(VmGenIdState *vms) | 101 | int ret; |
87 | * however, will expect the fields to be little-endian. | 102 | IO_CODE(); |
88 | * Perform a byte swap immediately before writing. | 103 | + assert_bdrv_graph_readable(); |
89 | */ | 104 | |
90 | - guid_le = vms->guid; | 105 | if (!drv) { |
91 | - qemu_uuid_bswap(&guid_le); | 106 | return -ENOMEDIUM; |
92 | + guid_le = qemu_uuid_bswap(vms->guid); | 107 | diff --git a/block/snapshot-access.c b/block/snapshot-access.c |
93 | /* The GUID is written at a fixed offset into the fw_cfg file | ||
94 | * in order to implement the "OVMF SDT Header probe suppressor" | ||
95 | * see docs/specs/vmgenid.txt for more details. | ||
96 | diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c | ||
97 | index XXXXXXX..XXXXXXX 100644 | 108 | index XXXXXXX..XXXXXXX 100644 |
98 | --- a/tests/vmgenid-test.c | 109 | --- a/block/snapshot-access.c |
99 | +++ b/tests/vmgenid-test.c | 110 | +++ b/block/snapshot-access.c |
100 | @@ -XXX,XX +XXX,XX @@ static void read_guid_from_memory(QTestState *qts, QemuUUID *guid) | 111 | @@ -XXX,XX +XXX,XX @@ |
101 | /* The GUID is in little-endian format in the guest, while QEMU | 112 | #include "qemu/cutils.h" |
102 | * uses big-endian. Swap after reading. | 113 | #include "block/block_int.h" |
103 | */ | 114 | |
104 | - qemu_uuid_bswap(guid); | 115 | -static coroutine_fn int |
105 | + *guid = qemu_uuid_bswap(*guid); | 116 | +static int coroutine_fn GRAPH_RDLOCK |
117 | snapshot_access_co_preadv_part(BlockDriverState *bs, | ||
118 | int64_t offset, int64_t bytes, | ||
119 | QEMUIOVector *qiov, size_t qiov_offset, | ||
120 | @@ -XXX,XX +XXX,XX @@ snapshot_access_co_preadv_part(BlockDriverState *bs, | ||
121 | return bdrv_co_preadv_snapshot(bs->file, offset, bytes, qiov, qiov_offset); | ||
106 | } | 122 | } |
107 | 123 | ||
108 | static void read_guid_from_monitor(QTestState *qts, QemuUUID *guid) | 124 | -static int coroutine_fn |
109 | diff --git a/util/uuid.c b/util/uuid.c | 125 | +static int coroutine_fn GRAPH_RDLOCK |
110 | index XXXXXXX..XXXXXXX 100644 | 126 | snapshot_access_co_block_status(BlockDriverState *bs, |
111 | --- a/util/uuid.c | 127 | bool want_zero, int64_t offset, |
112 | +++ b/util/uuid.c | 128 | int64_t bytes, int64_t *pnum, |
113 | @@ -XXX,XX +XXX,XX @@ int qemu_uuid_parse(const char *str, QemuUUID *uuid) | ||
114 | |||
115 | /* Swap from UUID format endian (BE) to the opposite or vice versa. | ||
116 | */ | ||
117 | -void qemu_uuid_bswap(QemuUUID *uuid) | ||
118 | +QemuUUID qemu_uuid_bswap(QemuUUID uuid) | ||
119 | { | ||
120 | - assert(QEMU_PTR_IS_ALIGNED(uuid, sizeof(uint32_t))); | ||
121 | - bswap32s(&uuid->fields.time_low); | ||
122 | - bswap16s(&uuid->fields.time_mid); | ||
123 | - bswap16s(&uuid->fields.time_high_and_version); | ||
124 | + bswap32s(&uuid.fields.time_low); | ||
125 | + bswap16s(&uuid.fields.time_mid); | ||
126 | + bswap16s(&uuid.fields.time_high_and_version); | ||
127 | + return uuid; | ||
128 | } | ||
129 | -- | 129 | -- |
130 | 2.20.1 | 130 | 2.39.2 |
131 | |||
132 | diff view generated by jsdifflib |
1 | From: Peter Maydell <peter.maydell@linaro.org> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_co_create() need to hold a reader lock for the graph. | ||
2 | 3 | ||
3 | Taking the address of a field in a packed struct is a bad idea, because | 4 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
4 | it might not be actually aligned enough for that pointer type (and | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
5 | thus cause a crash on dereference on some host architectures). Newer | 6 | Message-Id: <20230203152202.49054-17-kwolf@redhat.com> |
6 | versions of clang warn about this. | 7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
7 | |||
8 | Instead of passing UUID related functions the address of a possibly | ||
9 | unaligned QemuUUID struct, use local variables and then copy to/from | ||
10 | the struct field as appropriate. | ||
11 | |||
12 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
13 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
14 | --- | 9 | --- |
15 | block/vdi.c | 38 +++++++++++++++++++++++++------------- | 10 | include/block/block-global-state.h | 14 ++++--- |
16 | 1 file changed, 25 insertions(+), 13 deletions(-) | 11 | include/block/block_int-common.h | 11 +++--- |
12 | block.c | 1 + | ||
13 | block/create.c | 9 ++++- | ||
14 | block/crypto.c | 7 ++-- | ||
15 | block/file-posix.c | 7 ++-- | ||
16 | block/file-win32.c | 7 ++-- | ||
17 | block/parallels.c | 7 ++-- | ||
18 | block/qcow.c | 6 +-- | ||
19 | block/qcow2.c | 7 ++-- | ||
20 | block/qed.c | 7 ++-- | ||
21 | block/raw-format.c | 7 ++-- | ||
22 | block/vdi.c | 7 ++-- | ||
23 | block/vhdx.c | 7 ++-- | ||
24 | block/vmdk.c | 63 ++++++++++++++---------------- | ||
25 | block/vpc.c | 7 ++-- | ||
26 | 16 files changed, 84 insertions(+), 90 deletions(-) | ||
17 | 27 | ||
28 | diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h | ||
29 | index XXXXXXX..XXXXXXX 100644 | ||
30 | --- a/include/block/block-global-state.h | ||
31 | +++ b/include/block/block-global-state.h | ||
32 | @@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_find_protocol(const char *filename, | ||
33 | Error **errp); | ||
34 | BlockDriver *bdrv_find_format(const char *format_name); | ||
35 | |||
36 | -int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename, | ||
37 | - QemuOpts *opts, Error **errp); | ||
38 | -int co_wrapper bdrv_create(BlockDriver *drv, const char *filename, | ||
39 | - QemuOpts *opts, Error **errp); | ||
40 | +int coroutine_fn GRAPH_RDLOCK | ||
41 | +bdrv_co_create(BlockDriver *drv, const char *filename, QemuOpts *opts, | ||
42 | + Error **errp); | ||
43 | |||
44 | -int coroutine_fn bdrv_co_create_file(const char *filename, QemuOpts *opts, | ||
45 | - Error **errp); | ||
46 | +int co_wrapper_bdrv_rdlock bdrv_create(BlockDriver *drv, const char *filename, | ||
47 | + QemuOpts *opts, Error **errp); | ||
48 | + | ||
49 | +int coroutine_fn GRAPH_RDLOCK | ||
50 | +bdrv_co_create_file(const char *filename, QemuOpts *opts, Error **errp); | ||
51 | |||
52 | BlockDriverState *bdrv_new(void); | ||
53 | int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, | ||
54 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
55 | index XXXXXXX..XXXXXXX 100644 | ||
56 | --- a/include/block/block_int-common.h | ||
57 | +++ b/include/block/block_int-common.h | ||
58 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
59 | Error **errp); | ||
60 | void (*bdrv_close)(BlockDriverState *bs); | ||
61 | |||
62 | - int coroutine_fn (*bdrv_co_create)(BlockdevCreateOptions *opts, | ||
63 | - Error **errp); | ||
64 | - int coroutine_fn (*bdrv_co_create_opts)(BlockDriver *drv, | ||
65 | - const char *filename, | ||
66 | - QemuOpts *opts, | ||
67 | - Error **errp); | ||
68 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_create)( | ||
69 | + BlockdevCreateOptions *opts, Error **errp); | ||
70 | + | ||
71 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_create_opts)( | ||
72 | + BlockDriver *drv, const char *filename, QemuOpts *opts, Error **errp); | ||
73 | |||
74 | int (*bdrv_amend_options)(BlockDriverState *bs, | ||
75 | QemuOpts *opts, | ||
76 | diff --git a/block.c b/block.c | ||
77 | index XXXXXXX..XXXXXXX 100644 | ||
78 | --- a/block.c | ||
79 | +++ b/block.c | ||
80 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename, | ||
81 | int ret; | ||
82 | GLOBAL_STATE_CODE(); | ||
83 | ERRP_GUARD(); | ||
84 | + assert_bdrv_graph_readable(); | ||
85 | |||
86 | if (!drv->bdrv_co_create_opts) { | ||
87 | error_setg(errp, "Driver '%s' does not support image creation", | ||
88 | diff --git a/block/create.c b/block/create.c | ||
89 | index XXXXXXX..XXXXXXX 100644 | ||
90 | --- a/block/create.c | ||
91 | +++ b/block/create.c | ||
92 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blockdev_create_run(Job *job, Error **errp) | ||
93 | int ret; | ||
94 | |||
95 | GLOBAL_STATE_CODE(); | ||
96 | + GRAPH_RDLOCK_GUARD(); | ||
97 | |||
98 | job_progress_set_remaining(&s->common, 1); | ||
99 | ret = s->drv->bdrv_co_create(s->opts, errp); | ||
100 | @@ -XXX,XX +XXX,XX @@ static const JobDriver blockdev_create_job_driver = { | ||
101 | .run = blockdev_create_run, | ||
102 | }; | ||
103 | |||
104 | +/* Checking whether the function is present doesn't require the graph lock */ | ||
105 | +static inline bool TSA_NO_TSA has_bdrv_co_create(BlockDriver *drv) | ||
106 | +{ | ||
107 | + return drv->bdrv_co_create; | ||
108 | +} | ||
109 | + | ||
110 | void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options, | ||
111 | Error **errp) | ||
112 | { | ||
113 | @@ -XXX,XX +XXX,XX @@ void qmp_blockdev_create(const char *job_id, BlockdevCreateOptions *options, | ||
114 | } | ||
115 | |||
116 | /* Error out if the driver doesn't support .bdrv_co_create */ | ||
117 | - if (!drv->bdrv_co_create) { | ||
118 | + if (!has_bdrv_co_create(drv)) { | ||
119 | error_setg(errp, "Driver does not support blockdev-create"); | ||
120 | return; | ||
121 | } | ||
122 | diff --git a/block/crypto.c b/block/crypto.c | ||
123 | index XXXXXXX..XXXXXXX 100644 | ||
124 | --- a/block/crypto.c | ||
125 | +++ b/block/crypto.c | ||
126 | @@ -XXX,XX +XXX,XX @@ fail: | ||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | -static int coroutine_fn block_crypto_co_create_opts_luks(BlockDriver *drv, | ||
131 | - const char *filename, | ||
132 | - QemuOpts *opts, | ||
133 | - Error **errp) | ||
134 | +static int coroutine_fn GRAPH_RDLOCK | ||
135 | +block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename, | ||
136 | + QemuOpts *opts, Error **errp) | ||
137 | { | ||
138 | QCryptoBlockCreateOptions *create_opts = NULL; | ||
139 | BlockDriverState *bs = NULL; | ||
140 | diff --git a/block/file-posix.c b/block/file-posix.c | ||
141 | index XXXXXXX..XXXXXXX 100644 | ||
142 | --- a/block/file-posix.c | ||
143 | +++ b/block/file-posix.c | ||
144 | @@ -XXX,XX +XXX,XX @@ out: | ||
145 | return result; | ||
146 | } | ||
147 | |||
148 | -static int coroutine_fn raw_co_create_opts(BlockDriver *drv, | ||
149 | - const char *filename, | ||
150 | - QemuOpts *opts, | ||
151 | - Error **errp) | ||
152 | +static int coroutine_fn GRAPH_RDLOCK | ||
153 | +raw_co_create_opts(BlockDriver *drv, const char *filename, | ||
154 | + QemuOpts *opts, Error **errp) | ||
155 | { | ||
156 | BlockdevCreateOptions options; | ||
157 | int64_t total_size = 0; | ||
158 | diff --git a/block/file-win32.c b/block/file-win32.c | ||
159 | index XXXXXXX..XXXXXXX 100644 | ||
160 | --- a/block/file-win32.c | ||
161 | +++ b/block/file-win32.c | ||
162 | @@ -XXX,XX +XXX,XX @@ static int raw_co_create(BlockdevCreateOptions *options, Error **errp) | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | -static int coroutine_fn raw_co_create_opts(BlockDriver *drv, | ||
167 | - const char *filename, | ||
168 | - QemuOpts *opts, | ||
169 | - Error **errp) | ||
170 | +static int coroutine_fn GRAPH_RDLOCK | ||
171 | +raw_co_create_opts(BlockDriver *drv, const char *filename, | ||
172 | + QemuOpts *opts, Error **errp) | ||
173 | { | ||
174 | BlockdevCreateOptions options; | ||
175 | int64_t total_size = 0; | ||
176 | diff --git a/block/parallels.c b/block/parallels.c | ||
177 | index XXXXXXX..XXXXXXX 100644 | ||
178 | --- a/block/parallels.c | ||
179 | +++ b/block/parallels.c | ||
180 | @@ -XXX,XX +XXX,XX @@ exit: | ||
181 | goto out; | ||
182 | } | ||
183 | |||
184 | -static int coroutine_fn parallels_co_create_opts(BlockDriver *drv, | ||
185 | - const char *filename, | ||
186 | - QemuOpts *opts, | ||
187 | - Error **errp) | ||
188 | +static int coroutine_fn GRAPH_RDLOCK | ||
189 | +parallels_co_create_opts(BlockDriver *drv, const char *filename, | ||
190 | + QemuOpts *opts, Error **errp) | ||
191 | { | ||
192 | BlockdevCreateOptions *create_options = NULL; | ||
193 | BlockDriverState *bs = NULL; | ||
194 | diff --git a/block/qcow.c b/block/qcow.c | ||
195 | index XXXXXXX..XXXXXXX 100644 | ||
196 | --- a/block/qcow.c | ||
197 | +++ b/block/qcow.c | ||
198 | @@ -XXX,XX +XXX,XX @@ exit: | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | -static int coroutine_fn qcow_co_create_opts(BlockDriver *drv, | ||
203 | - const char *filename, | ||
204 | - QemuOpts *opts, Error **errp) | ||
205 | +static int coroutine_fn GRAPH_RDLOCK | ||
206 | +qcow_co_create_opts(BlockDriver *drv, const char *filename, | ||
207 | + QemuOpts *opts, Error **errp) | ||
208 | { | ||
209 | BlockdevCreateOptions *create_options = NULL; | ||
210 | BlockDriverState *bs = NULL; | ||
211 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
212 | index XXXXXXX..XXXXXXX 100644 | ||
213 | --- a/block/qcow2.c | ||
214 | +++ b/block/qcow2.c | ||
215 | @@ -XXX,XX +XXX,XX @@ out: | ||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | -static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv, | ||
220 | - const char *filename, | ||
221 | - QemuOpts *opts, | ||
222 | - Error **errp) | ||
223 | +static int coroutine_fn GRAPH_RDLOCK | ||
224 | +qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts, | ||
225 | + Error **errp) | ||
226 | { | ||
227 | BlockdevCreateOptions *create_options = NULL; | ||
228 | QDict *qdict; | ||
229 | diff --git a/block/qed.c b/block/qed.c | ||
230 | index XXXXXXX..XXXXXXX 100644 | ||
231 | --- a/block/qed.c | ||
232 | +++ b/block/qed.c | ||
233 | @@ -XXX,XX +XXX,XX @@ out: | ||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | -static int coroutine_fn bdrv_qed_co_create_opts(BlockDriver *drv, | ||
238 | - const char *filename, | ||
239 | - QemuOpts *opts, | ||
240 | - Error **errp) | ||
241 | +static int coroutine_fn GRAPH_RDLOCK | ||
242 | +bdrv_qed_co_create_opts(BlockDriver *drv, const char *filename, | ||
243 | + QemuOpts *opts, Error **errp) | ||
244 | { | ||
245 | BlockdevCreateOptions *create_options = NULL; | ||
246 | QDict *qdict; | ||
247 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
248 | index XXXXXXX..XXXXXXX 100644 | ||
249 | --- a/block/raw-format.c | ||
250 | +++ b/block/raw-format.c | ||
251 | @@ -XXX,XX +XXX,XX @@ static int raw_has_zero_init(BlockDriverState *bs) | ||
252 | return bdrv_has_zero_init(bs->file->bs); | ||
253 | } | ||
254 | |||
255 | -static int coroutine_fn raw_co_create_opts(BlockDriver *drv, | ||
256 | - const char *filename, | ||
257 | - QemuOpts *opts, | ||
258 | - Error **errp) | ||
259 | +static int coroutine_fn GRAPH_RDLOCK | ||
260 | +raw_co_create_opts(BlockDriver *drv, const char *filename, | ||
261 | + QemuOpts *opts, Error **errp) | ||
262 | { | ||
263 | return bdrv_co_create_file(filename, opts, errp); | ||
264 | } | ||
18 | diff --git a/block/vdi.c b/block/vdi.c | 265 | diff --git a/block/vdi.c b/block/vdi.c |
19 | index XXXXXXX..XXXXXXX 100644 | 266 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/block/vdi.c | 267 | --- a/block/vdi.c |
21 | +++ b/block/vdi.c | 268 | +++ b/block/vdi.c |
22 | @@ -XXX,XX +XXX,XX @@ static void vdi_header_to_le(VdiHeader *header) | 269 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create(BlockdevCreateOptions *create_options, |
23 | 270 | return vdi_co_do_create(create_options, DEFAULT_CLUSTER_SIZE, errp); | |
24 | static void vdi_header_print(VdiHeader *header) | 271 | } |
25 | { | 272 | |
26 | - char uuid[37]; | 273 | -static int coroutine_fn vdi_co_create_opts(BlockDriver *drv, |
27 | + char uuidstr[37]; | 274 | - const char *filename, |
28 | + QemuUUID uuid; | 275 | - QemuOpts *opts, |
29 | logout("text %s", header->text); | 276 | - Error **errp) |
30 | logout("signature 0x%08x\n", header->signature); | 277 | +static int coroutine_fn GRAPH_RDLOCK |
31 | logout("header size 0x%04x\n", header->header_size); | 278 | +vdi_co_create_opts(BlockDriver *drv, const char *filename, |
32 | @@ -XXX,XX +XXX,XX @@ static void vdi_header_print(VdiHeader *header) | 279 | + QemuOpts *opts, Error **errp) |
33 | logout("block extra 0x%04x\n", header->block_extra); | 280 | { |
34 | logout("blocks tot. 0x%04x\n", header->blocks_in_image); | 281 | QDict *qdict = NULL; |
35 | logout("blocks all. 0x%04x\n", header->blocks_allocated); | 282 | BlockdevCreateOptions *create_options = NULL; |
36 | - qemu_uuid_unparse(&header->uuid_image, uuid); | 283 | diff --git a/block/vhdx.c b/block/vhdx.c |
37 | - logout("uuid image %s\n", uuid); | 284 | index XXXXXXX..XXXXXXX 100644 |
38 | - qemu_uuid_unparse(&header->uuid_last_snap, uuid); | 285 | --- a/block/vhdx.c |
39 | - logout("uuid snap %s\n", uuid); | 286 | +++ b/block/vhdx.c |
40 | - qemu_uuid_unparse(&header->uuid_link, uuid); | 287 | @@ -XXX,XX +XXX,XX @@ delete_and_exit: |
41 | - logout("uuid link %s\n", uuid); | 288 | return ret; |
42 | - qemu_uuid_unparse(&header->uuid_parent, uuid); | 289 | } |
43 | - logout("uuid parent %s\n", uuid); | 290 | |
44 | + uuid = header->uuid_image; | 291 | -static int coroutine_fn vhdx_co_create_opts(BlockDriver *drv, |
45 | + qemu_uuid_unparse(&uuid, uuidstr); | 292 | - const char *filename, |
46 | + logout("uuid image %s\n", uuidstr); | 293 | - QemuOpts *opts, |
47 | + uuid = header->uuid_last_snap; | 294 | - Error **errp) |
48 | + qemu_uuid_unparse(&uuid, uuidstr); | 295 | +static int coroutine_fn GRAPH_RDLOCK |
49 | + logout("uuid snap %s\n", uuidstr); | 296 | +vhdx_co_create_opts(BlockDriver *drv, const char *filename, |
50 | + uuid = header->uuid_link; | 297 | + QemuOpts *opts, Error **errp) |
51 | + qemu_uuid_unparse(&uuid, uuidstr); | 298 | { |
52 | + logout("uuid link %s\n", uuidstr); | 299 | BlockdevCreateOptions *create_options = NULL; |
53 | + uuid = header->uuid_parent; | 300 | QDict *qdict; |
54 | + qemu_uuid_unparse(&uuid, uuidstr); | 301 | diff --git a/block/vmdk.c b/block/vmdk.c |
55 | + logout("uuid parent %s\n", uuidstr); | 302 | index XXXXXXX..XXXXXXX 100644 |
56 | } | 303 | --- a/block/vmdk.c |
57 | 304 | +++ b/block/vmdk.c | |
58 | static int coroutine_fn vdi_co_check(BlockDriverState *bs, BdrvCheckResult *res, | 305 | @@ -XXX,XX +XXX,XX @@ exit: |
59 | @@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, | 306 | return ret; |
60 | size_t bmap_size; | 307 | } |
308 | |||
309 | -static int coroutine_fn vmdk_create_extent(const char *filename, | ||
310 | - int64_t filesize, bool flat, | ||
311 | - bool compress, bool zeroed_grain, | ||
312 | - BlockBackend **pbb, | ||
313 | - QemuOpts *opts, Error **errp) | ||
314 | +static int coroutine_fn GRAPH_RDLOCK | ||
315 | +vmdk_create_extent(const char *filename, int64_t filesize, bool flat, | ||
316 | + bool compress, bool zeroed_grain, BlockBackend **pbb, | ||
317 | + QemuOpts *opts, Error **errp) | ||
318 | { | ||
61 | int ret; | 319 | int ret; |
320 | BlockBackend *blk = NULL; | ||
321 | @@ -XXX,XX +XXX,XX @@ static int filename_decompose(const char *filename, char *path, char *prefix, | ||
322 | * non-split format. | ||
323 | * idx >= 1: get the n-th extent if in a split subformat | ||
324 | */ | ||
325 | -typedef BlockBackend * coroutine_fn (*vmdk_create_extent_fn)(int64_t size, | ||
326 | - int idx, | ||
327 | - bool flat, | ||
328 | - bool split, | ||
329 | - bool compress, | ||
330 | - bool zeroed_grain, | ||
331 | - void *opaque, | ||
332 | - Error **errp); | ||
333 | +typedef BlockBackend * coroutine_fn /* GRAPH_RDLOCK */ | ||
334 | + (*vmdk_create_extent_fn)(int64_t size, int idx, bool flat, bool split, | ||
335 | + bool compress, bool zeroed_grain, void *opaque, | ||
336 | + Error **errp); | ||
337 | |||
338 | static void vmdk_desc_add_extent(GString *desc, | ||
339 | const char *extent_line_fmt, | ||
340 | @@ -XXX,XX +XXX,XX @@ static void vmdk_desc_add_extent(GString *desc, | ||
341 | g_free(basename); | ||
342 | } | ||
343 | |||
344 | -static int coroutine_fn vmdk_co_do_create(int64_t size, | ||
345 | - BlockdevVmdkSubformat subformat, | ||
346 | - BlockdevVmdkAdapterType adapter_type, | ||
347 | - const char *backing_file, | ||
348 | - const char *hw_version, | ||
349 | - const char *toolsversion, | ||
350 | - bool compat6, | ||
351 | - bool zeroed_grain, | ||
352 | - vmdk_create_extent_fn extent_fn, | ||
353 | - void *opaque, | ||
354 | - Error **errp) | ||
355 | +static int coroutine_fn GRAPH_RDLOCK | ||
356 | +vmdk_co_do_create(int64_t size, | ||
357 | + BlockdevVmdkSubformat subformat, | ||
358 | + BlockdevVmdkAdapterType adapter_type, | ||
359 | + const char *backing_file, | ||
360 | + const char *hw_version, | ||
361 | + const char *toolsversion, | ||
362 | + bool compat6, | ||
363 | + bool zeroed_grain, | ||
364 | + vmdk_create_extent_fn extent_fn, | ||
365 | + void *opaque, | ||
366 | + Error **errp) | ||
367 | { | ||
368 | int extent_idx; | ||
369 | BlockBackend *blk = NULL; | ||
370 | @@ -XXX,XX +XXX,XX @@ typedef struct { | ||
371 | QemuOpts *opts; | ||
372 | } VMDKCreateOptsData; | ||
373 | |||
374 | -static BlockBackend * coroutine_fn vmdk_co_create_opts_cb(int64_t size, int idx, | ||
375 | - bool flat, bool split, bool compress, | ||
376 | - bool zeroed_grain, void *opaque, | ||
377 | - Error **errp) | ||
378 | +static BlockBackend * coroutine_fn GRAPH_RDLOCK | ||
379 | +vmdk_co_create_opts_cb(int64_t size, int idx, bool flat, bool split, | ||
380 | + bool compress, bool zeroed_grain, void *opaque, | ||
381 | + Error **errp) | ||
382 | { | ||
383 | BlockBackend *blk = NULL; | ||
384 | BlockDriverState *bs = NULL; | ||
385 | @@ -XXX,XX +XXX,XX @@ exit: | ||
386 | return blk; | ||
387 | } | ||
388 | |||
389 | -static int coroutine_fn vmdk_co_create_opts(BlockDriver *drv, | ||
390 | - const char *filename, | ||
391 | - QemuOpts *opts, | ||
392 | - Error **errp) | ||
393 | +static int coroutine_fn GRAPH_RDLOCK | ||
394 | +vmdk_co_create_opts(BlockDriver *drv, const char *filename, | ||
395 | + QemuOpts *opts, Error **errp) | ||
396 | { | ||
62 | Error *local_err = NULL; | 397 | Error *local_err = NULL; |
63 | + QemuUUID uuid_link, uuid_parent; | 398 | char *desc = NULL; |
64 | 399 | @@ -XXX,XX +XXX,XX @@ static BlockBackend * coroutine_fn vmdk_co_create_cb(int64_t size, int idx, | |
65 | bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | 400 | return blk; |
66 | false, errp); | 401 | } |
67 | @@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, | 402 | |
68 | goto fail; | 403 | -static int coroutine_fn vmdk_co_create(BlockdevCreateOptions *create_options, |
69 | } | 404 | - Error **errp) |
70 | 405 | +static int coroutine_fn GRAPH_RDLOCK | |
71 | + uuid_link = header.uuid_link; | 406 | +vmdk_co_create(BlockdevCreateOptions *create_options, Error **errp) |
72 | + uuid_parent = header.uuid_parent; | 407 | { |
73 | + | 408 | BlockdevCreateOptionsVmdk *opts; |
74 | if (header.disk_size % SECTOR_SIZE != 0) { | 409 | |
75 | /* 'VBoxManage convertfromraw' can create images with odd disk sizes. | 410 | diff --git a/block/vpc.c b/block/vpc.c |
76 | We accept them but round the disk size to the next multiple of | 411 | index XXXXXXX..XXXXXXX 100644 |
77 | @@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, | 412 | --- a/block/vpc.c |
78 | (uint64_t)header.blocks_in_image * header.block_size); | 413 | +++ b/block/vpc.c |
79 | ret = -ENOTSUP; | 414 | @@ -XXX,XX +XXX,XX @@ out: |
80 | goto fail; | 415 | return ret; |
81 | - } else if (!qemu_uuid_is_null(&header.uuid_link)) { | 416 | } |
82 | + } else if (!qemu_uuid_is_null(&uuid_link)) { | 417 | |
83 | error_setg(errp, "unsupported VDI image (non-NULL link UUID)"); | 418 | -static int coroutine_fn vpc_co_create_opts(BlockDriver *drv, |
84 | ret = -ENOTSUP; | 419 | - const char *filename, |
85 | goto fail; | 420 | - QemuOpts *opts, |
86 | - } else if (!qemu_uuid_is_null(&header.uuid_parent)) { | 421 | - Error **errp) |
87 | + } else if (!qemu_uuid_is_null(&uuid_parent)) { | 422 | +static int coroutine_fn GRAPH_RDLOCK |
88 | error_setg(errp, "unsupported VDI image (non-NULL parent UUID)"); | 423 | +vpc_co_create_opts(BlockDriver *drv, const char *filename, |
89 | ret = -ENOTSUP; | 424 | + QemuOpts *opts, Error **errp) |
90 | goto fail; | 425 | { |
91 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, | 426 | BlockdevCreateOptions *create_options = NULL; |
92 | BlockDriverState *bs_file = NULL; | 427 | QDict *qdict; |
93 | BlockBackend *blk = NULL; | ||
94 | uint32_t *bmap = NULL; | ||
95 | + QemuUUID uuid; | ||
96 | |||
97 | assert(create_options->driver == BLOCKDEV_DRIVER_VDI); | ||
98 | vdi_opts = &create_options->u.vdi; | ||
99 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, | ||
100 | if (image_type == VDI_TYPE_STATIC) { | ||
101 | header.blocks_allocated = blocks; | ||
102 | } | ||
103 | - qemu_uuid_generate(&header.uuid_image); | ||
104 | - qemu_uuid_generate(&header.uuid_last_snap); | ||
105 | + qemu_uuid_generate(&uuid); | ||
106 | + header.uuid_image = uuid; | ||
107 | + qemu_uuid_generate(&uuid); | ||
108 | + header.uuid_last_snap = uuid; | ||
109 | /* There is no need to set header.uuid_link or header.uuid_parent here. */ | ||
110 | if (VDI_DEBUG) { | ||
111 | vdi_header_print(&header); | ||
112 | -- | 428 | -- |
113 | 2.20.1 | 429 | 2.39.2 |
114 | |||
115 | diff view generated by jsdifflib |
1 | From: Alberto Garcia <berto@igalia.com> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_co_io_plug() and bdrv_co_io_unplug() need to hold a reader lock for | ||
3 | the graph. | ||
2 | 4 | ||
3 | This patch forbids attaching a disk to a SCSI device if its using a | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | different AioContext. Test case included. | 6 | Message-Id: <20230203152202.49054-18-kwolf@redhat.com> |
5 | 7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | |
6 | Signed-off-by: Alberto Garcia <berto@igalia.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | --- | 9 | --- |
9 | hw/scsi/virtio-scsi.c | 7 +++++++ | 10 | include/block/block-io.h | 4 ++-- |
10 | tests/qemu-iotests/240 | 22 ++++++++++++++++++++++ | 11 | include/block/block_int-common.h | 5 +++-- |
11 | tests/qemu-iotests/240.out | 20 ++++++++++++++++++++ | 12 | block/block-backend.c | 2 ++ |
12 | 3 files changed, 49 insertions(+) | 13 | block/io.c | 2 ++ |
14 | 4 files changed, 9 insertions(+), 4 deletions(-) | ||
13 | 15 | ||
14 | diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c | 16 | diff --git a/include/block/block-io.h b/include/block/block-io.h |
15 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/hw/scsi/virtio-scsi.c | 18 | --- a/include/block/block-io.h |
17 | +++ b/hw/scsi/virtio-scsi.c | 19 | +++ b/include/block/block-io.h |
18 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, | 20 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx); |
19 | SCSIDevice *sd = SCSI_DEVICE(dev); | 21 | |
20 | 22 | AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c); | |
21 | if (s->ctx && !s->dataplane_fenced) { | 23 | |
22 | + AioContext *ctx; | 24 | -void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs); |
23 | if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) { | 25 | -void coroutine_fn bdrv_co_io_unplug(BlockDriverState *bs); |
24 | return; | 26 | +void coroutine_fn GRAPH_RDLOCK bdrv_co_io_plug(BlockDriverState *bs); |
25 | } | 27 | +void coroutine_fn GRAPH_RDLOCK bdrv_co_io_unplug(BlockDriverState *bs); |
26 | + ctx = blk_get_aio_context(sd->conf.blk); | 28 | |
27 | + if (ctx != s->ctx && ctx != qemu_get_aio_context()) { | 29 | bool coroutine_fn bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, |
28 | + error_setg(errp, "Cannot attach a blockdev that is using " | 30 | const char *name, |
29 | + "a different iothread"); | 31 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
30 | + return; | ||
31 | + } | ||
32 | virtio_scsi_acquire(s); | ||
33 | blk_set_aio_context(sd->conf.blk, s->ctx); | ||
34 | virtio_scsi_release(s); | ||
35 | diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240 | ||
36 | index XXXXXXX..XXXXXXX 100755 | ||
37 | --- a/tests/qemu-iotests/240 | ||
38 | +++ b/tests/qemu-iotests/240 | ||
39 | @@ -XXX,XX +XXX,XX @@ run_qemu <<EOF | ||
40 | { "execute": "quit"} | ||
41 | EOF | ||
42 | |||
43 | +echo | ||
44 | +echo === Attach two SCSI disks using the same block device but different iothreads === | ||
45 | +echo | ||
46 | + | ||
47 | +run_qemu <<EOF | ||
48 | +{ "execute": "qmp_capabilities" } | ||
49 | +{ "execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true}} | ||
50 | +{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread0"}} | ||
51 | +{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread1"}} | ||
52 | +{ "execute": "device_add", "arguments": {"id": "scsi0", "driver": "${virtio_scsi}", "iothread": "iothread0"}} | ||
53 | +{ "execute": "device_add", "arguments": {"id": "scsi1", "driver": "${virtio_scsi}", "iothread": "iothread1"}} | ||
54 | +{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0", "bus": "scsi0.0"}} | ||
55 | +{ "execute": "device_add", "arguments": {"id": "scsi-hd1", "driver": "scsi-hd", "drive": "hd0", "bus": "scsi1.0"}} | ||
56 | +{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}} | ||
57 | +{ "execute": "device_add", "arguments": {"id": "scsi-hd1", "driver": "scsi-hd", "drive": "hd0", "bus": "scsi1.0"}} | ||
58 | +{ "execute": "device_del", "arguments": {"id": "scsi-hd1"}} | ||
59 | +{ "execute": "device_del", "arguments": {"id": "scsi0"}} | ||
60 | +{ "execute": "device_del", "arguments": {"id": "scsi1"}} | ||
61 | +{ "execute": "blockdev-del", "arguments": {"node-name": "hd0"}} | ||
62 | +{ "execute": "quit"} | ||
63 | +EOF | ||
64 | + | ||
65 | # success, all done | ||
66 | echo "*** done" | ||
67 | rm -f $seq.full | ||
68 | diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out | ||
69 | index XXXXXXX..XXXXXXX 100644 | 32 | index XXXXXXX..XXXXXXX 100644 |
70 | --- a/tests/qemu-iotests/240.out | 33 | --- a/include/block/block_int-common.h |
71 | +++ b/tests/qemu-iotests/240.out | 34 | +++ b/include/block/block_int-common.h |
72 | @@ -XXX,XX +XXX,XX @@ QMP_VERSION | 35 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
73 | {"return": {}} | 36 | BlkdebugEvent event); |
74 | {"return": {}} | 37 | |
75 | {"return": {}} | 38 | /* io queue for linux-aio */ |
76 | + | 39 | - void coroutine_fn (*bdrv_co_io_plug)(BlockDriverState *bs); |
77 | +=== Attach two SCSI disks using the same block device but different iothreads === | 40 | - void coroutine_fn (*bdrv_co_io_unplug)(BlockDriverState *bs); |
78 | + | 41 | + void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_io_plug)(BlockDriverState *bs); |
79 | +Testing: | 42 | + void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_io_unplug)( |
80 | +QMP_VERSION | 43 | + BlockDriverState *bs); |
81 | +{"return": {}} | 44 | |
82 | +{"return": {}} | 45 | /** |
83 | +{"return": {}} | 46 | * bdrv_drain_begin is called if implemented in the beginning of a |
84 | +{"return": {}} | 47 | diff --git a/block/block-backend.c b/block/block-backend.c |
85 | +{"return": {}} | 48 | index XXXXXXX..XXXXXXX 100644 |
86 | +{"return": {}} | 49 | --- a/block/block-backend.c |
87 | +{"return": {}} | 50 | +++ b/block/block-backend.c |
88 | +{"error": {"class": "GenericError", "desc": "Cannot attach a blockdev that is using a different iothread"}} | 51 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn blk_co_io_plug(BlockBackend *blk) |
89 | +{"return": {}} | 52 | { |
90 | +{"return": {}} | 53 | BlockDriverState *bs = blk_bs(blk); |
91 | +{"return": {}} | 54 | IO_CODE(); |
92 | +{"return": {}} | 55 | + GRAPH_RDLOCK_GUARD(); |
93 | +{"return": {}} | 56 | |
94 | +{"return": {}} | 57 | if (bs) { |
95 | +{"return": {}} | 58 | bdrv_co_io_plug(bs); |
96 | *** done | 59 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn blk_co_io_unplug(BlockBackend *blk) |
60 | { | ||
61 | BlockDriverState *bs = blk_bs(blk); | ||
62 | IO_CODE(); | ||
63 | + GRAPH_RDLOCK_GUARD(); | ||
64 | |||
65 | if (bs) { | ||
66 | bdrv_co_io_unplug(bs); | ||
67 | diff --git a/block/io.c b/block/io.c | ||
68 | index XXXXXXX..XXXXXXX 100644 | ||
69 | --- a/block/io.c | ||
70 | +++ b/block/io.c | ||
71 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs) | ||
72 | { | ||
73 | BdrvChild *child; | ||
74 | IO_CODE(); | ||
75 | + assert_bdrv_graph_readable(); | ||
76 | |||
77 | QLIST_FOREACH(child, &bs->children, next) { | ||
78 | bdrv_co_io_plug(child->bs); | ||
79 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_io_unplug(BlockDriverState *bs) | ||
80 | { | ||
81 | BdrvChild *child; | ||
82 | IO_CODE(); | ||
83 | + assert_bdrv_graph_readable(); | ||
84 | |||
85 | assert(bs->io_plugged); | ||
86 | if (qatomic_fetch_dec(&bs->io_plugged) == 1) { | ||
97 | -- | 87 | -- |
98 | 2.20.1 | 88 | 2.39.2 |
99 | |||
100 | diff view generated by jsdifflib |
1 | From: Alberto Garcia <berto@igalia.com> | 1 | From: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Refcount table entries have a field to store the offset of the | 3 | This adds GRAPH_RDLOCK annotations to declare that callers of |
4 | refcount block. The rest of the bits of the entry are currently | 4 | bdrv_co_is_inserted() need to hold a reader lock for the graph. |
5 | reserved. | ||
6 | 5 | ||
7 | The offset is always taken from the entry using REFT_OFFSET_MASK to | 6 | blk_is_inserted() is done as a co_wrapper_mixed_bdrv_rdlock (unlike most |
8 | ensure that we only use the bits that belong to that field. | 7 | other blk_* functions) because it is called a lot from other blk_co_*() |
8 | functions that already hold the lock. These calls go through | ||
9 | blk_is_available(), which becomes a co_wrapper_mixed_bdrv_rdlock, too, | ||
10 | for the same reason. | ||
9 | 11 | ||
10 | While that mask is used every time we read from the refcount table, it | 12 | Functions that run in a coroutine and can call bdrv_co_is_available() |
11 | is never used when we write to it. Due to the other constraints of the | 13 | directly are changed to do so, which results in better TSA coverage. |
12 | qcow2 format QEMU can never produce refcount block offsets that don't | ||
13 | fit in that field so any such offset when allocating a refcount block | ||
14 | would indicate a bug in QEMU. | ||
15 | 14 | ||
16 | Signed-off-by: Alberto Garcia <berto@igalia.com> | 15 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
17 | Reviewed-by: Eric Blake <eblake@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
17 | Message-Id: <20230203152202.49054-19-kwolf@redhat.com> | ||
18 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 19 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
19 | --- | 20 | --- |
20 | block/qcow2-refcount.c | 3 +++ | 21 | include/block/block-io.h | 4 ++-- |
21 | 1 file changed, 3 insertions(+) | 22 | include/block/block_int-common.h | 3 ++- |
23 | include/sysemu/block-backend-io.h | 7 ++++--- | ||
24 | block.c | 1 + | ||
25 | block/block-backend.c | 25 ++++++++++++++----------- | ||
26 | 5 files changed, 23 insertions(+), 17 deletions(-) | ||
22 | 27 | ||
23 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c | 28 | diff --git a/include/block/block-io.h b/include/block/block-io.h |
24 | index XXXXXXX..XXXXXXX 100644 | 29 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/block/qcow2-refcount.c | 30 | --- a/include/block/block-io.h |
26 | +++ b/block/qcow2-refcount.c | 31 | +++ b/include/block/block-io.h |
27 | @@ -XXX,XX +XXX,XX @@ static int alloc_refcount_block(BlockDriverState *bs, | 32 | @@ -XXX,XX +XXX,XX @@ bool bdrv_is_writable(BlockDriverState *bs); |
28 | return new_block; | 33 | bool bdrv_is_sg(BlockDriverState *bs); |
34 | int bdrv_get_flags(BlockDriverState *bs); | ||
35 | |||
36 | -bool coroutine_fn bdrv_co_is_inserted(BlockDriverState *bs); | ||
37 | -bool co_wrapper bdrv_is_inserted(BlockDriverState *bs); | ||
38 | +bool coroutine_fn GRAPH_RDLOCK bdrv_co_is_inserted(BlockDriverState *bs); | ||
39 | +bool co_wrapper_bdrv_rdlock bdrv_is_inserted(BlockDriverState *bs); | ||
40 | |||
41 | void coroutine_fn bdrv_co_lock_medium(BlockDriverState *bs, bool locked); | ||
42 | void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag); | ||
43 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
44 | index XXXXXXX..XXXXXXX 100644 | ||
45 | --- a/include/block/block_int-common.h | ||
46 | +++ b/include/block/block_int-common.h | ||
47 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
48 | BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos); | ||
49 | |||
50 | /* removable device specific */ | ||
51 | - bool coroutine_fn (*bdrv_co_is_inserted)(BlockDriverState *bs); | ||
52 | + bool coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_is_inserted)( | ||
53 | + BlockDriverState *bs); | ||
54 | void coroutine_fn (*bdrv_co_eject)(BlockDriverState *bs, bool eject_flag); | ||
55 | void coroutine_fn (*bdrv_co_lock_medium)(BlockDriverState *bs, bool locked); | ||
56 | |||
57 | diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h | ||
58 | index XXXXXXX..XXXXXXX 100644 | ||
59 | --- a/include/sysemu/block-backend-io.h | ||
60 | +++ b/include/sysemu/block-backend-io.h | ||
61 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, | ||
62 | void blk_inc_in_flight(BlockBackend *blk); | ||
63 | void blk_dec_in_flight(BlockBackend *blk); | ||
64 | |||
65 | -bool coroutine_fn blk_co_is_inserted(BlockBackend *blk); | ||
66 | -bool co_wrapper_mixed blk_is_inserted(BlockBackend *blk); | ||
67 | +bool coroutine_fn GRAPH_RDLOCK blk_co_is_inserted(BlockBackend *blk); | ||
68 | +bool co_wrapper_mixed_bdrv_rdlock blk_is_inserted(BlockBackend *blk); | ||
69 | |||
70 | -bool blk_is_available(BlockBackend *blk); | ||
71 | +bool coroutine_fn GRAPH_RDLOCK blk_co_is_available(BlockBackend *blk); | ||
72 | +bool co_wrapper_mixed_bdrv_rdlock blk_is_available(BlockBackend *blk); | ||
73 | |||
74 | void coroutine_fn blk_co_lock_medium(BlockBackend *blk, bool locked); | ||
75 | void co_wrapper blk_lock_medium(BlockBackend *blk, bool locked); | ||
76 | diff --git a/block.c b/block.c | ||
77 | index XXXXXXX..XXXXXXX 100644 | ||
78 | --- a/block.c | ||
79 | +++ b/block.c | ||
80 | @@ -XXX,XX +XXX,XX @@ bool coroutine_fn bdrv_co_is_inserted(BlockDriverState *bs) | ||
81 | BlockDriver *drv = bs->drv; | ||
82 | BdrvChild *child; | ||
83 | IO_CODE(); | ||
84 | + assert_bdrv_graph_readable(); | ||
85 | |||
86 | if (!drv) { | ||
87 | return false; | ||
88 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
89 | index XXXXXXX..XXXXXXX 100644 | ||
90 | --- a/block/block-backend.c | ||
91 | +++ b/block/block-backend.c | ||
92 | @@ -XXX,XX +XXX,XX @@ void blk_set_disable_request_queuing(BlockBackend *blk, bool disable) | ||
93 | blk->disable_request_queuing = disable; | ||
94 | } | ||
95 | |||
96 | -static coroutine_fn int blk_check_byte_request(BlockBackend *blk, | ||
97 | - int64_t offset, int64_t bytes) | ||
98 | +static int coroutine_fn GRAPH_RDLOCK | ||
99 | +blk_check_byte_request(BlockBackend *blk, int64_t offset, int64_t bytes) | ||
100 | { | ||
101 | int64_t len; | ||
102 | |||
103 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn int blk_check_byte_request(BlockBackend *blk, | ||
104 | return -EIO; | ||
29 | } | 105 | } |
30 | 106 | ||
31 | + /* The offset must fit in the offset field of the refcount table entry */ | 107 | - if (!blk_is_available(blk)) { |
32 | + assert((new_block & REFT_OFFSET_MASK) == new_block); | 108 | + if (!blk_co_is_available(blk)) { |
33 | + | 109 | return -ENOMEDIUM; |
34 | /* If we're allocating the block at offset 0 then something is wrong */ | 110 | } |
35 | if (new_block == 0) { | 111 | |
36 | qcow2_signal_corruption(bs, true, -1, -1, "Preventing invalid " | 112 | @@ -XXX,XX +XXX,XX @@ BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset, |
113 | int64_t coroutine_fn blk_co_getlength(BlockBackend *blk) | ||
114 | { | ||
115 | IO_CODE(); | ||
116 | + GRAPH_RDLOCK_GUARD(); | ||
117 | |||
118 | - if (!blk_is_available(blk)) { | ||
119 | + if (!blk_co_is_available(blk)) { | ||
120 | return -ENOMEDIUM; | ||
121 | } | ||
122 | |||
123 | @@ -XXX,XX +XXX,XX @@ void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr) | ||
124 | int64_t coroutine_fn blk_co_nb_sectors(BlockBackend *blk) | ||
125 | { | ||
126 | IO_CODE(); | ||
127 | + GRAPH_RDLOCK_GUARD(); | ||
128 | |||
129 | - if (!blk_is_available(blk)) { | ||
130 | + if (!blk_co_is_available(blk)) { | ||
131 | return -ENOMEDIUM; | ||
132 | } | ||
133 | |||
134 | @@ -XXX,XX +XXX,XX @@ blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf) | ||
135 | blk_wait_while_drained(blk); | ||
136 | GRAPH_RDLOCK_GUARD(); | ||
137 | |||
138 | - if (!blk_is_available(blk)) { | ||
139 | + if (!blk_co_is_available(blk)) { | ||
140 | return -ENOMEDIUM; | ||
141 | } | ||
142 | |||
143 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn blk_co_do_flush(BlockBackend *blk) | ||
144 | blk_wait_while_drained(blk); | ||
145 | GRAPH_RDLOCK_GUARD(); | ||
146 | |||
147 | - if (!blk_is_available(blk)) { | ||
148 | + if (!blk_co_is_available(blk)) { | ||
149 | return -ENOMEDIUM; | ||
150 | } | ||
151 | |||
152 | @@ -XXX,XX +XXX,XX @@ bool coroutine_fn blk_co_is_inserted(BlockBackend *blk) | ||
153 | { | ||
154 | BlockDriverState *bs = blk_bs(blk); | ||
155 | IO_CODE(); | ||
156 | + assert_bdrv_graph_readable(); | ||
157 | |||
158 | return bs && bdrv_co_is_inserted(bs); | ||
159 | } | ||
160 | |||
161 | -bool blk_is_available(BlockBackend *blk) | ||
162 | +bool coroutine_fn blk_co_is_available(BlockBackend *blk) | ||
163 | { | ||
164 | IO_CODE(); | ||
165 | - return blk_is_inserted(blk) && !blk_dev_is_tray_open(blk); | ||
166 | + return blk_co_is_inserted(blk) && !blk_dev_is_tray_open(blk); | ||
167 | } | ||
168 | |||
169 | void coroutine_fn blk_co_lock_medium(BlockBackend *blk, bool locked) | ||
170 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_truncate(BlockBackend *blk, int64_t offset, bool exact, | ||
171 | { | ||
172 | IO_OR_GS_CODE(); | ||
173 | GRAPH_RDLOCK_GUARD(); | ||
174 | - if (!blk_is_available(blk)) { | ||
175 | + if (!blk_co_is_available(blk)) { | ||
176 | error_setg(errp, "No medium inserted"); | ||
177 | return -ENOMEDIUM; | ||
178 | } | ||
179 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, | ||
180 | { | ||
181 | int r; | ||
182 | IO_CODE(); | ||
183 | + GRAPH_RDLOCK_GUARD(); | ||
184 | |||
185 | r = blk_check_byte_request(blk_in, off_in, bytes); | ||
186 | if (r) { | ||
187 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, | ||
188 | return r; | ||
189 | } | ||
190 | |||
191 | - GRAPH_RDLOCK_GUARD(); | ||
192 | return bdrv_co_copy_range(blk_in->root, off_in, | ||
193 | blk_out->root, off_out, | ||
194 | bytes, read_flags, write_flags); | ||
37 | -- | 195 | -- |
38 | 2.20.1 | 196 | 2.39.2 |
39 | |||
40 | diff view generated by jsdifflib |
1 | In the block layer, synchronous APIs are often implemented by creating a | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | coroutine that calls the asynchronous coroutine-based implementation and | 2 | bdrv_co_eject() and bdrv_co_lock_medium() need to hold a reader lock for |
3 | then waiting for completion with BDRV_POLL_WHILE(). | 3 | the graph. |
4 | 4 | ||
5 | For this to work with iothreads (more specifically, when the synchronous | 5 | Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
6 | API is called in a thread that is not the home thread of the block | 6 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | device, so that the coroutine will run in a different thread), we must | 7 | Message-Id: <20230203152202.49054-20-kwolf@redhat.com> |
8 | make sure to call aio_wait_kick() at the end of the operation. Many | 8 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
9 | places are missing this, so that BDRV_POLL_WHILE() keeps hanging even if | 9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | the condition has long become false. | 10 | --- |
11 | include/block/block-io.h | 7 +++++-- | ||
12 | include/block/block_int-common.h | 6 ++++-- | ||
13 | block.c | 2 ++ | ||
14 | block/block-backend.c | 2 ++ | ||
15 | block/copy-on-read.c | 6 ++++-- | ||
16 | block/filter-compress.c | 4 ++-- | ||
17 | block/raw-format.c | 6 ++++-- | ||
18 | 7 files changed, 23 insertions(+), 10 deletions(-) | ||
11 | 19 | ||
12 | Note that bdrv_dec_in_flight() involves an aio_wait_kick() call. This | 20 | diff --git a/include/block/block-io.h b/include/block/block-io.h |
13 | corresponds to the BDRV_POLL_WHILE() in the drain functions, but it is | 21 | index XXXXXXX..XXXXXXX 100644 |
14 | generally not enough for most other operations because they haven't set | 22 | --- a/include/block/block-io.h |
15 | the return value in the coroutine entry stub yet. To avoid race | 23 | +++ b/include/block/block-io.h |
16 | conditions there, we need to kick after setting the return value. | 24 | @@ -XXX,XX +XXX,XX @@ int bdrv_get_flags(BlockDriverState *bs); |
17 | 25 | bool coroutine_fn GRAPH_RDLOCK bdrv_co_is_inserted(BlockDriverState *bs); | |
18 | The race window is small enough that the problem doesn't usually surface | 26 | bool co_wrapper_bdrv_rdlock bdrv_is_inserted(BlockDriverState *bs); |
19 | in the common path. However, it does surface and causes easily | 27 | |
20 | reproducible hangs if the operation can return early before even calling | 28 | -void coroutine_fn bdrv_co_lock_medium(BlockDriverState *bs, bool locked); |
21 | bdrv_inc/dec_in_flight, which many of them do (trivial error or no-op | 29 | -void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag); |
22 | success paths). | 30 | +void coroutine_fn GRAPH_RDLOCK |
23 | 31 | +bdrv_co_lock_medium(BlockDriverState *bs, bool locked); | |
24 | The bug in bdrv_truncate(), bdrv_check() and bdrv_invalidate_cache() is | 32 | + |
25 | slightly different: These functions even neglected to schedule the | 33 | +void coroutine_fn GRAPH_RDLOCK |
26 | coroutine in the home thread of the node. This avoids the hang, but is | 34 | +bdrv_co_eject(BlockDriverState *bs, bool eject_flag); |
27 | obviously wrong, too. Fix those to schedule the coroutine in the right | 35 | |
28 | AioContext in addition to adding aio_wait_kick() calls. | 36 | const char *bdrv_get_format_name(BlockDriverState *bs); |
29 | 37 | ||
30 | Cc: qemu-stable@nongnu.org | 38 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
31 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 39 | index XXXXXXX..XXXXXXX 100644 |
32 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 40 | --- a/include/block/block_int-common.h |
33 | --- | 41 | +++ b/include/block/block_int-common.h |
34 | block.c | 6 +- | 42 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
35 | block/block-backend.c | 5 + | 43 | /* removable device specific */ |
36 | block/io.c | 8 +- | 44 | bool coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_is_inserted)( |
37 | block/nbd-client.c | 1 + | 45 | BlockDriverState *bs); |
38 | block/nvme.c | 1 + | 46 | - void coroutine_fn (*bdrv_co_eject)(BlockDriverState *bs, bool eject_flag); |
39 | block/qcow2.c | 1 + | 47 | - void coroutine_fn (*bdrv_co_lock_medium)(BlockDriverState *bs, bool locked); |
40 | block/qed.c | 1 + | 48 | + void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_eject)( |
41 | tests/test-block-iothread.c | 372 ++++++++++++++++++++++++++++++++++++ | 49 | + BlockDriverState *bs, bool eject_flag); |
42 | tests/Makefile.include | 2 + | 50 | + void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_lock_medium)( |
43 | 9 files changed, 394 insertions(+), 3 deletions(-) | 51 | + BlockDriverState *bs, bool locked); |
44 | create mode 100644 tests/test-block-iothread.c | 52 | |
45 | 53 | /* to control generic scsi devices */ | |
54 | BlockAIOCB *coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_aio_ioctl)( | ||
46 | diff --git a/block.c b/block.c | 55 | diff --git a/block.c b/block.c |
47 | index XXXXXXX..XXXXXXX 100644 | 56 | index XXXXXXX..XXXXXXX 100644 |
48 | --- a/block.c | 57 | --- a/block.c |
49 | +++ b/block.c | 58 | +++ b/block.c |
50 | @@ -XXX,XX +XXX,XX @@ static void bdrv_check_co_entry(void *opaque) | 59 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_eject(BlockDriverState *bs, bool eject_flag) |
51 | { | 60 | { |
52 | CheckCo *cco = opaque; | 61 | BlockDriver *drv = bs->drv; |
53 | cco->ret = bdrv_co_check(cco->bs, cco->res, cco->fix); | 62 | IO_CODE(); |
54 | + aio_wait_kick(); | 63 | + assert_bdrv_graph_readable(); |
55 | } | 64 | |
56 | 65 | if (drv && drv->bdrv_co_eject) { | |
57 | int bdrv_check(BlockDriverState *bs, | 66 | drv->bdrv_co_eject(bs, eject_flag); |
58 | @@ -XXX,XX +XXX,XX @@ int bdrv_check(BlockDriverState *bs, | 67 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_lock_medium(BlockDriverState *bs, bool locked) |
59 | bdrv_check_co_entry(&cco); | 68 | { |
60 | } else { | 69 | BlockDriver *drv = bs->drv; |
61 | co = qemu_coroutine_create(bdrv_check_co_entry, &cco); | 70 | IO_CODE(); |
62 | - qemu_coroutine_enter(co); | 71 | + assert_bdrv_graph_readable(); |
63 | + bdrv_coroutine_enter(bs, co); | 72 | trace_bdrv_lock_medium(bs, locked); |
64 | BDRV_POLL_WHILE(bs, cco.ret == -EINPROGRESS); | 73 | |
65 | } | 74 | if (drv && drv->bdrv_co_lock_medium) { |
66 | |||
67 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_invalidate_cache_co_entry(void *opaque) | ||
68 | InvalidateCacheCo *ico = opaque; | ||
69 | bdrv_co_invalidate_cache(ico->bs, ico->errp); | ||
70 | ico->done = true; | ||
71 | + aio_wait_kick(); | ||
72 | } | ||
73 | |||
74 | void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
75 | @@ -XXX,XX +XXX,XX @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp) | ||
76 | bdrv_invalidate_cache_co_entry(&ico); | ||
77 | } else { | ||
78 | co = qemu_coroutine_create(bdrv_invalidate_cache_co_entry, &ico); | ||
79 | - qemu_coroutine_enter(co); | ||
80 | + bdrv_coroutine_enter(bs, co); | ||
81 | BDRV_POLL_WHILE(bs, !ico.done); | ||
82 | } | ||
83 | } | ||
84 | diff --git a/block/block-backend.c b/block/block-backend.c | 75 | diff --git a/block/block-backend.c b/block/block-backend.c |
85 | index XXXXXXX..XXXXXXX 100644 | 76 | index XXXXXXX..XXXXXXX 100644 |
86 | --- a/block/block-backend.c | 77 | --- a/block/block-backend.c |
87 | +++ b/block/block-backend.c | 78 | +++ b/block/block-backend.c |
88 | @@ -XXX,XX +XXX,XX @@ static void blk_read_entry(void *opaque) | 79 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn blk_co_lock_medium(BlockBackend *blk, bool locked) |
89 | 80 | { | |
90 | rwco->ret = blk_co_preadv(rwco->blk, rwco->offset, qiov->size, | 81 | BlockDriverState *bs = blk_bs(blk); |
91 | qiov, rwco->flags); | 82 | IO_CODE(); |
92 | + aio_wait_kick(); | 83 | + GRAPH_RDLOCK_GUARD(); |
84 | |||
85 | if (bs) { | ||
86 | bdrv_co_lock_medium(bs, locked); | ||
87 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn blk_co_eject(BlockBackend *blk, bool eject_flag) | ||
88 | BlockDriverState *bs = blk_bs(blk); | ||
89 | char *id; | ||
90 | IO_CODE(); | ||
91 | + GRAPH_RDLOCK_GUARD(); | ||
92 | |||
93 | if (bs) { | ||
94 | bdrv_co_eject(bs, eject_flag); | ||
95 | diff --git a/block/copy-on-read.c b/block/copy-on-read.c | ||
96 | index XXXXXXX..XXXXXXX 100644 | ||
97 | --- a/block/copy-on-read.c | ||
98 | +++ b/block/copy-on-read.c | ||
99 | @@ -XXX,XX +XXX,XX @@ cor_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
93 | } | 100 | } |
94 | 101 | ||
95 | static void blk_write_entry(void *opaque) | 102 | |
96 | @@ -XXX,XX +XXX,XX @@ static void blk_write_entry(void *opaque) | 103 | -static void coroutine_fn cor_co_eject(BlockDriverState *bs, bool eject_flag) |
97 | 104 | +static void coroutine_fn GRAPH_RDLOCK | |
98 | rwco->ret = blk_co_pwritev(rwco->blk, rwco->offset, qiov->size, | 105 | +cor_co_eject(BlockDriverState *bs, bool eject_flag) |
99 | qiov, rwco->flags); | 106 | { |
100 | + aio_wait_kick(); | 107 | bdrv_co_eject(bs->file->bs, eject_flag); |
101 | } | 108 | } |
102 | 109 | ||
103 | static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf, | 110 | |
104 | @@ -XXX,XX +XXX,XX @@ static void blk_ioctl_entry(void *opaque) | 111 | -static void coroutine_fn cor_co_lock_medium(BlockDriverState *bs, bool locked) |
105 | 112 | +static void coroutine_fn GRAPH_RDLOCK | |
106 | rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset, | 113 | +cor_co_lock_medium(BlockDriverState *bs, bool locked) |
107 | qiov->iov[0].iov_base); | 114 | { |
108 | + aio_wait_kick(); | 115 | bdrv_co_lock_medium(bs->file->bs, locked); |
109 | } | 116 | } |
110 | 117 | diff --git a/block/filter-compress.c b/block/filter-compress.c | |
111 | int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf) | 118 | index XXXXXXX..XXXXXXX 100644 |
112 | @@ -XXX,XX +XXX,XX @@ static void blk_flush_entry(void *opaque) | 119 | --- a/block/filter-compress.c |
120 | +++ b/block/filter-compress.c | ||
121 | @@ -XXX,XX +XXX,XX @@ static void compress_refresh_limits(BlockDriverState *bs, Error **errp) | ||
122 | } | ||
123 | |||
124 | |||
125 | -static void coroutine_fn | ||
126 | +static void coroutine_fn GRAPH_RDLOCK | ||
127 | compress_co_eject(BlockDriverState *bs, bool eject_flag) | ||
113 | { | 128 | { |
114 | BlkRwCo *rwco = opaque; | 129 | bdrv_co_eject(bs->file->bs, eject_flag); |
115 | rwco->ret = blk_co_flush(rwco->blk); | ||
116 | + aio_wait_kick(); | ||
117 | } | 130 | } |
118 | 131 | ||
119 | int blk_flush(BlockBackend *blk) | 132 | |
120 | @@ -XXX,XX +XXX,XX @@ static void blk_pdiscard_entry(void *opaque) | 133 | -static void coroutine_fn |
121 | QEMUIOVector *qiov = rwco->iobuf; | 134 | +static void coroutine_fn GRAPH_RDLOCK |
122 | 135 | compress_co_lock_medium(BlockDriverState *bs, bool locked) | |
123 | rwco->ret = blk_co_pdiscard(rwco->blk, rwco->offset, qiov->size); | 136 | { |
124 | + aio_wait_kick(); | 137 | bdrv_co_lock_medium(bs->file->bs, locked); |
138 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
139 | index XXXXXXX..XXXXXXX 100644 | ||
140 | --- a/block/raw-format.c | ||
141 | +++ b/block/raw-format.c | ||
142 | @@ -XXX,XX +XXX,XX @@ raw_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, | ||
143 | return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp); | ||
125 | } | 144 | } |
126 | 145 | ||
127 | int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes) | 146 | -static void coroutine_fn raw_co_eject(BlockDriverState *bs, bool eject_flag) |
128 | diff --git a/block/io.c b/block/io.c | 147 | +static void coroutine_fn GRAPH_RDLOCK |
129 | index XXXXXXX..XXXXXXX 100644 | 148 | +raw_co_eject(BlockDriverState *bs, bool eject_flag) |
130 | --- a/block/io.c | 149 | { |
131 | +++ b/block/io.c | 150 | bdrv_co_eject(bs->file->bs, eject_flag); |
132 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque) | ||
133 | rwco->qiov->size, rwco->qiov, | ||
134 | rwco->flags); | ||
135 | } | ||
136 | + aio_wait_kick(); | ||
137 | } | 151 | } |
138 | 152 | ||
139 | /* | 153 | -static void coroutine_fn raw_co_lock_medium(BlockDriverState *bs, bool locked) |
140 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_block_status_above_co_entry(void *opaque) | 154 | +static void coroutine_fn GRAPH_RDLOCK |
141 | data->offset, data->bytes, | 155 | +raw_co_lock_medium(BlockDriverState *bs, bool locked) |
142 | data->pnum, data->map, data->file); | 156 | { |
143 | data->done = true; | 157 | bdrv_co_lock_medium(bs->file->bs, locked); |
144 | + aio_wait_kick(); | ||
145 | } | 158 | } |
146 | |||
147 | /* | ||
148 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_rw_vmstate_entry(void *opaque) | ||
149 | { | ||
150 | BdrvVmstateCo *co = opaque; | ||
151 | co->ret = bdrv_co_rw_vmstate(co->bs, co->qiov, co->pos, co->is_read); | ||
152 | + aio_wait_kick(); | ||
153 | } | ||
154 | |||
155 | static inline int | ||
156 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_flush_co_entry(void *opaque) | ||
157 | FlushCo *rwco = opaque; | ||
158 | |||
159 | rwco->ret = bdrv_co_flush(rwco->bs); | ||
160 | + aio_wait_kick(); | ||
161 | } | ||
162 | |||
163 | int coroutine_fn bdrv_co_flush(BlockDriverState *bs) | ||
164 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_pdiscard_co_entry(void *opaque) | ||
165 | DiscardCo *rwco = opaque; | ||
166 | |||
167 | rwco->ret = bdrv_co_pdiscard(rwco->child, rwco->offset, rwco->bytes); | ||
168 | + aio_wait_kick(); | ||
169 | } | ||
170 | |||
171 | int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes) | ||
172 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_truncate_co_entry(void *opaque) | ||
173 | TruncateCo *tco = opaque; | ||
174 | tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->prealloc, | ||
175 | tco->errp); | ||
176 | + aio_wait_kick(); | ||
177 | } | ||
178 | |||
179 | int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc, | ||
180 | @@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc, | ||
181 | bdrv_truncate_co_entry(&tco); | ||
182 | } else { | ||
183 | co = qemu_coroutine_create(bdrv_truncate_co_entry, &tco); | ||
184 | - qemu_coroutine_enter(co); | ||
185 | + bdrv_coroutine_enter(child->bs, co); | ||
186 | BDRV_POLL_WHILE(child->bs, tco.ret == NOT_DONE); | ||
187 | } | ||
188 | |||
189 | diff --git a/block/nbd-client.c b/block/nbd-client.c | ||
190 | index XXXXXXX..XXXXXXX 100644 | ||
191 | --- a/block/nbd-client.c | ||
192 | +++ b/block/nbd-client.c | ||
193 | @@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_read_reply_entry(void *opaque) | ||
194 | s->quit = true; | ||
195 | nbd_recv_coroutines_wake_all(s); | ||
196 | s->read_reply_co = NULL; | ||
197 | + aio_wait_kick(); | ||
198 | } | ||
199 | |||
200 | static int nbd_co_send_request(BlockDriverState *bs, | ||
201 | diff --git a/block/nvme.c b/block/nvme.c | ||
202 | index XXXXXXX..XXXXXXX 100644 | ||
203 | --- a/block/nvme.c | ||
204 | +++ b/block/nvme.c | ||
205 | @@ -XXX,XX +XXX,XX @@ static void nvme_cmd_sync_cb(void *opaque, int ret) | ||
206 | { | ||
207 | int *pret = opaque; | ||
208 | *pret = ret; | ||
209 | + aio_wait_kick(); | ||
210 | } | ||
211 | |||
212 | static int nvme_cmd_sync(BlockDriverState *bs, NVMeQueuePair *q, | ||
213 | diff --git a/block/qcow2.c b/block/qcow2.c | ||
214 | index XXXXXXX..XXXXXXX 100644 | ||
215 | --- a/block/qcow2.c | ||
216 | +++ b/block/qcow2.c | ||
217 | @@ -XXX,XX +XXX,XX @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags, | ||
218 | /* From bdrv_co_create. */ | ||
219 | qcow2_open_entry(&qoc); | ||
220 | } else { | ||
221 | + assert(qemu_get_current_aio_context() == qemu_get_aio_context()); | ||
222 | qemu_coroutine_enter(qemu_coroutine_create(qcow2_open_entry, &qoc)); | ||
223 | BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS); | ||
224 | } | ||
225 | diff --git a/block/qed.c b/block/qed.c | ||
226 | index XXXXXXX..XXXXXXX 100644 | ||
227 | --- a/block/qed.c | ||
228 | +++ b/block/qed.c | ||
229 | @@ -XXX,XX +XXX,XX @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags, | ||
230 | if (qemu_in_coroutine()) { | ||
231 | bdrv_qed_open_entry(&qoc); | ||
232 | } else { | ||
233 | + assert(qemu_get_current_aio_context() == qemu_get_aio_context()); | ||
234 | qemu_coroutine_enter(qemu_coroutine_create(bdrv_qed_open_entry, &qoc)); | ||
235 | BDRV_POLL_WHILE(bs, qoc.ret == -EINPROGRESS); | ||
236 | } | ||
237 | diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c | ||
238 | new file mode 100644 | ||
239 | index XXXXXXX..XXXXXXX | ||
240 | --- /dev/null | ||
241 | +++ b/tests/test-block-iothread.c | ||
242 | @@ -XXX,XX +XXX,XX @@ | ||
243 | +/* | ||
244 | + * Block tests for iothreads | ||
245 | + * | ||
246 | + * Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com> | ||
247 | + * | ||
248 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
249 | + * of this software and associated documentation files (the "Software"), to deal | ||
250 | + * in the Software without restriction, including without limitation the rights | ||
251 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
252 | + * copies of the Software, and to permit persons to whom the Software is | ||
253 | + * furnished to do so, subject to the following conditions: | ||
254 | + * | ||
255 | + * The above copyright notice and this permission notice shall be included in | ||
256 | + * all copies or substantial portions of the Software. | ||
257 | + * | ||
258 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
259 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
260 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
261 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
262 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
263 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
264 | + * THE SOFTWARE. | ||
265 | + */ | ||
266 | + | ||
267 | +#include "qemu/osdep.h" | ||
268 | +#include "block/block.h" | ||
269 | +#include "block/blockjob_int.h" | ||
270 | +#include "sysemu/block-backend.h" | ||
271 | +#include "qapi/error.h" | ||
272 | +#include "iothread.h" | ||
273 | + | ||
274 | +static int coroutine_fn bdrv_test_co_prwv(BlockDriverState *bs, | ||
275 | + uint64_t offset, uint64_t bytes, | ||
276 | + QEMUIOVector *qiov, int flags) | ||
277 | +{ | ||
278 | + return 0; | ||
279 | +} | ||
280 | + | ||
281 | +static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs, | ||
282 | + int64_t offset, int bytes) | ||
283 | +{ | ||
284 | + return 0; | ||
285 | +} | ||
286 | + | ||
287 | +static int coroutine_fn | ||
288 | +bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, | ||
289 | + PreallocMode prealloc, Error **errp) | ||
290 | +{ | ||
291 | + return 0; | ||
292 | +} | ||
293 | + | ||
294 | +static int coroutine_fn bdrv_test_co_block_status(BlockDriverState *bs, | ||
295 | + bool want_zero, | ||
296 | + int64_t offset, int64_t count, | ||
297 | + int64_t *pnum, int64_t *map, | ||
298 | + BlockDriverState **file) | ||
299 | +{ | ||
300 | + *pnum = count; | ||
301 | + return 0; | ||
302 | +} | ||
303 | + | ||
304 | +static BlockDriver bdrv_test = { | ||
305 | + .format_name = "test", | ||
306 | + .instance_size = 1, | ||
307 | + | ||
308 | + .bdrv_co_preadv = bdrv_test_co_prwv, | ||
309 | + .bdrv_co_pwritev = bdrv_test_co_prwv, | ||
310 | + .bdrv_co_pdiscard = bdrv_test_co_pdiscard, | ||
311 | + .bdrv_co_truncate = bdrv_test_co_truncate, | ||
312 | + .bdrv_co_block_status = bdrv_test_co_block_status, | ||
313 | +}; | ||
314 | + | ||
315 | +static void test_sync_op_pread(BdrvChild *c) | ||
316 | +{ | ||
317 | + uint8_t buf[512]; | ||
318 | + int ret; | ||
319 | + | ||
320 | + /* Success */ | ||
321 | + ret = bdrv_pread(c, 0, buf, sizeof(buf)); | ||
322 | + g_assert_cmpint(ret, ==, 512); | ||
323 | + | ||
324 | + /* Early error: Negative offset */ | ||
325 | + ret = bdrv_pread(c, -2, buf, sizeof(buf)); | ||
326 | + g_assert_cmpint(ret, ==, -EIO); | ||
327 | +} | ||
328 | + | ||
329 | +static void test_sync_op_pwrite(BdrvChild *c) | ||
330 | +{ | ||
331 | + uint8_t buf[512]; | ||
332 | + int ret; | ||
333 | + | ||
334 | + /* Success */ | ||
335 | + ret = bdrv_pwrite(c, 0, buf, sizeof(buf)); | ||
336 | + g_assert_cmpint(ret, ==, 512); | ||
337 | + | ||
338 | + /* Early error: Negative offset */ | ||
339 | + ret = bdrv_pwrite(c, -2, buf, sizeof(buf)); | ||
340 | + g_assert_cmpint(ret, ==, -EIO); | ||
341 | +} | ||
342 | + | ||
343 | +static void test_sync_op_blk_pread(BlockBackend *blk) | ||
344 | +{ | ||
345 | + uint8_t buf[512]; | ||
346 | + int ret; | ||
347 | + | ||
348 | + /* Success */ | ||
349 | + ret = blk_pread(blk, 0, buf, sizeof(buf)); | ||
350 | + g_assert_cmpint(ret, ==, 512); | ||
351 | + | ||
352 | + /* Early error: Negative offset */ | ||
353 | + ret = blk_pread(blk, -2, buf, sizeof(buf)); | ||
354 | + g_assert_cmpint(ret, ==, -EIO); | ||
355 | +} | ||
356 | + | ||
357 | +static void test_sync_op_blk_pwrite(BlockBackend *blk) | ||
358 | +{ | ||
359 | + uint8_t buf[512]; | ||
360 | + int ret; | ||
361 | + | ||
362 | + /* Success */ | ||
363 | + ret = blk_pwrite(blk, 0, buf, sizeof(buf), 0); | ||
364 | + g_assert_cmpint(ret, ==, 512); | ||
365 | + | ||
366 | + /* Early error: Negative offset */ | ||
367 | + ret = blk_pwrite(blk, -2, buf, sizeof(buf), 0); | ||
368 | + g_assert_cmpint(ret, ==, -EIO); | ||
369 | +} | ||
370 | + | ||
371 | +static void test_sync_op_load_vmstate(BdrvChild *c) | ||
372 | +{ | ||
373 | + uint8_t buf[512]; | ||
374 | + int ret; | ||
375 | + | ||
376 | + /* Error: Driver does not support snapshots */ | ||
377 | + ret = bdrv_load_vmstate(c->bs, buf, 0, sizeof(buf)); | ||
378 | + g_assert_cmpint(ret, ==, -ENOTSUP); | ||
379 | +} | ||
380 | + | ||
381 | +static void test_sync_op_save_vmstate(BdrvChild *c) | ||
382 | +{ | ||
383 | + uint8_t buf[512]; | ||
384 | + int ret; | ||
385 | + | ||
386 | + /* Error: Driver does not support snapshots */ | ||
387 | + ret = bdrv_save_vmstate(c->bs, buf, 0, sizeof(buf)); | ||
388 | + g_assert_cmpint(ret, ==, -ENOTSUP); | ||
389 | +} | ||
390 | + | ||
391 | +static void test_sync_op_pdiscard(BdrvChild *c) | ||
392 | +{ | ||
393 | + int ret; | ||
394 | + | ||
395 | + /* Normal success path */ | ||
396 | + c->bs->open_flags |= BDRV_O_UNMAP; | ||
397 | + ret = bdrv_pdiscard(c, 0, 512); | ||
398 | + g_assert_cmpint(ret, ==, 0); | ||
399 | + | ||
400 | + /* Early success: UNMAP not supported */ | ||
401 | + c->bs->open_flags &= ~BDRV_O_UNMAP; | ||
402 | + ret = bdrv_pdiscard(c, 0, 512); | ||
403 | + g_assert_cmpint(ret, ==, 0); | ||
404 | + | ||
405 | + /* Early error: Negative offset */ | ||
406 | + ret = bdrv_pdiscard(c, -2, 512); | ||
407 | + g_assert_cmpint(ret, ==, -EIO); | ||
408 | +} | ||
409 | + | ||
410 | +static void test_sync_op_blk_pdiscard(BlockBackend *blk) | ||
411 | +{ | ||
412 | + int ret; | ||
413 | + | ||
414 | + /* Early success: UNMAP not supported */ | ||
415 | + ret = blk_pdiscard(blk, 0, 512); | ||
416 | + g_assert_cmpint(ret, ==, 0); | ||
417 | + | ||
418 | + /* Early error: Negative offset */ | ||
419 | + ret = blk_pdiscard(blk, -2, 512); | ||
420 | + g_assert_cmpint(ret, ==, -EIO); | ||
421 | +} | ||
422 | + | ||
423 | +static void test_sync_op_truncate(BdrvChild *c) | ||
424 | +{ | ||
425 | + int ret; | ||
426 | + | ||
427 | + /* Normal success path */ | ||
428 | + ret = bdrv_truncate(c, 65536, PREALLOC_MODE_OFF, NULL); | ||
429 | + g_assert_cmpint(ret, ==, 0); | ||
430 | + | ||
431 | + /* Early error: Negative offset */ | ||
432 | + ret = bdrv_truncate(c, -2, PREALLOC_MODE_OFF, NULL); | ||
433 | + g_assert_cmpint(ret, ==, -EINVAL); | ||
434 | + | ||
435 | + /* Error: Read-only image */ | ||
436 | + c->bs->read_only = true; | ||
437 | + c->bs->open_flags &= ~BDRV_O_RDWR; | ||
438 | + | ||
439 | + ret = bdrv_truncate(c, 65536, PREALLOC_MODE_OFF, NULL); | ||
440 | + g_assert_cmpint(ret, ==, -EACCES); | ||
441 | + | ||
442 | + c->bs->read_only = false; | ||
443 | + c->bs->open_flags |= BDRV_O_RDWR; | ||
444 | +} | ||
445 | + | ||
446 | +static void test_sync_op_block_status(BdrvChild *c) | ||
447 | +{ | ||
448 | + int ret; | ||
449 | + int64_t n; | ||
450 | + | ||
451 | + /* Normal success path */ | ||
452 | + ret = bdrv_is_allocated(c->bs, 0, 65536, &n); | ||
453 | + g_assert_cmpint(ret, ==, 0); | ||
454 | + | ||
455 | + /* Early success: No driver support */ | ||
456 | + bdrv_test.bdrv_co_block_status = NULL; | ||
457 | + ret = bdrv_is_allocated(c->bs, 0, 65536, &n); | ||
458 | + g_assert_cmpint(ret, ==, 1); | ||
459 | + | ||
460 | + /* Early success: bytes = 0 */ | ||
461 | + ret = bdrv_is_allocated(c->bs, 0, 0, &n); | ||
462 | + g_assert_cmpint(ret, ==, 0); | ||
463 | + | ||
464 | + /* Early success: Offset > image size*/ | ||
465 | + ret = bdrv_is_allocated(c->bs, 0x1000000, 0x1000000, &n); | ||
466 | + g_assert_cmpint(ret, ==, 0); | ||
467 | +} | ||
468 | + | ||
469 | +static void test_sync_op_flush(BdrvChild *c) | ||
470 | +{ | ||
471 | + int ret; | ||
472 | + | ||
473 | + /* Normal success path */ | ||
474 | + ret = bdrv_flush(c->bs); | ||
475 | + g_assert_cmpint(ret, ==, 0); | ||
476 | + | ||
477 | + /* Early success: Read-only image */ | ||
478 | + c->bs->read_only = true; | ||
479 | + c->bs->open_flags &= ~BDRV_O_RDWR; | ||
480 | + | ||
481 | + ret = bdrv_flush(c->bs); | ||
482 | + g_assert_cmpint(ret, ==, 0); | ||
483 | + | ||
484 | + c->bs->read_only = false; | ||
485 | + c->bs->open_flags |= BDRV_O_RDWR; | ||
486 | +} | ||
487 | + | ||
488 | +static void test_sync_op_blk_flush(BlockBackend *blk) | ||
489 | +{ | ||
490 | + BlockDriverState *bs = blk_bs(blk); | ||
491 | + int ret; | ||
492 | + | ||
493 | + /* Normal success path */ | ||
494 | + ret = blk_flush(blk); | ||
495 | + g_assert_cmpint(ret, ==, 0); | ||
496 | + | ||
497 | + /* Early success: Read-only image */ | ||
498 | + bs->read_only = true; | ||
499 | + bs->open_flags &= ~BDRV_O_RDWR; | ||
500 | + | ||
501 | + ret = blk_flush(blk); | ||
502 | + g_assert_cmpint(ret, ==, 0); | ||
503 | + | ||
504 | + bs->read_only = false; | ||
505 | + bs->open_flags |= BDRV_O_RDWR; | ||
506 | +} | ||
507 | + | ||
508 | +static void test_sync_op_check(BdrvChild *c) | ||
509 | +{ | ||
510 | + BdrvCheckResult result; | ||
511 | + int ret; | ||
512 | + | ||
513 | + /* Error: Driver does not implement check */ | ||
514 | + ret = bdrv_check(c->bs, &result, 0); | ||
515 | + g_assert_cmpint(ret, ==, -ENOTSUP); | ||
516 | +} | ||
517 | + | ||
518 | +static void test_sync_op_invalidate_cache(BdrvChild *c) | ||
519 | +{ | ||
520 | + /* Early success: Image is not inactive */ | ||
521 | + bdrv_invalidate_cache(c->bs, NULL); | ||
522 | +} | ||
523 | + | ||
524 | + | ||
525 | +typedef struct SyncOpTest { | ||
526 | + const char *name; | ||
527 | + void (*fn)(BdrvChild *c); | ||
528 | + void (*blkfn)(BlockBackend *blk); | ||
529 | +} SyncOpTest; | ||
530 | + | ||
531 | +const SyncOpTest sync_op_tests[] = { | ||
532 | + { | ||
533 | + .name = "/sync-op/pread", | ||
534 | + .fn = test_sync_op_pread, | ||
535 | + .blkfn = test_sync_op_blk_pread, | ||
536 | + }, { | ||
537 | + .name = "/sync-op/pwrite", | ||
538 | + .fn = test_sync_op_pwrite, | ||
539 | + .blkfn = test_sync_op_blk_pwrite, | ||
540 | + }, { | ||
541 | + .name = "/sync-op/load_vmstate", | ||
542 | + .fn = test_sync_op_load_vmstate, | ||
543 | + }, { | ||
544 | + .name = "/sync-op/save_vmstate", | ||
545 | + .fn = test_sync_op_save_vmstate, | ||
546 | + }, { | ||
547 | + .name = "/sync-op/pdiscard", | ||
548 | + .fn = test_sync_op_pdiscard, | ||
549 | + .blkfn = test_sync_op_blk_pdiscard, | ||
550 | + }, { | ||
551 | + .name = "/sync-op/truncate", | ||
552 | + .fn = test_sync_op_truncate, | ||
553 | + }, { | ||
554 | + .name = "/sync-op/block_status", | ||
555 | + .fn = test_sync_op_block_status, | ||
556 | + }, { | ||
557 | + .name = "/sync-op/flush", | ||
558 | + .fn = test_sync_op_flush, | ||
559 | + .blkfn = test_sync_op_blk_flush, | ||
560 | + }, { | ||
561 | + .name = "/sync-op/check", | ||
562 | + .fn = test_sync_op_check, | ||
563 | + }, { | ||
564 | + .name = "/sync-op/invalidate_cache", | ||
565 | + .fn = test_sync_op_invalidate_cache, | ||
566 | + }, | ||
567 | +}; | ||
568 | + | ||
569 | +/* Test synchronous operations that run in a different iothread, so we have to | ||
570 | + * poll for the coroutine there to return. */ | ||
571 | +static void test_sync_op(const void *opaque) | ||
572 | +{ | ||
573 | + const SyncOpTest *t = opaque; | ||
574 | + IOThread *iothread = iothread_new(); | ||
575 | + AioContext *ctx = iothread_get_aio_context(iothread); | ||
576 | + BlockBackend *blk; | ||
577 | + BlockDriverState *bs; | ||
578 | + BdrvChild *c; | ||
579 | + | ||
580 | + blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | ||
581 | + bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort); | ||
582 | + bs->total_sectors = 65536 / BDRV_SECTOR_SIZE; | ||
583 | + blk_insert_bs(blk, bs, &error_abort); | ||
584 | + c = QLIST_FIRST(&bs->parents); | ||
585 | + | ||
586 | + blk_set_aio_context(blk, ctx); | ||
587 | + aio_context_acquire(ctx); | ||
588 | + t->fn(c); | ||
589 | + if (t->blkfn) { | ||
590 | + t->blkfn(blk); | ||
591 | + } | ||
592 | + aio_context_release(ctx); | ||
593 | + blk_set_aio_context(blk, qemu_get_aio_context()); | ||
594 | + | ||
595 | + bdrv_unref(bs); | ||
596 | + blk_unref(blk); | ||
597 | +} | ||
598 | + | ||
599 | +int main(int argc, char **argv) | ||
600 | +{ | ||
601 | + int i; | ||
602 | + | ||
603 | + bdrv_init(); | ||
604 | + qemu_init_main_loop(&error_abort); | ||
605 | + | ||
606 | + g_test_init(&argc, &argv, NULL); | ||
607 | + | ||
608 | + for (i = 0; i < ARRAY_SIZE(sync_op_tests); i++) { | ||
609 | + const SyncOpTest *t = &sync_op_tests[i]; | ||
610 | + g_test_add_data_func(t->name, t, test_sync_op); | ||
611 | + } | ||
612 | + | ||
613 | + return g_test_run(); | ||
614 | +} | ||
615 | diff --git a/tests/Makefile.include b/tests/Makefile.include | ||
616 | index XXXXXXX..XXXXXXX 100644 | ||
617 | --- a/tests/Makefile.include | ||
618 | +++ b/tests/Makefile.include | ||
619 | @@ -XXX,XX +XXX,XX @@ check-unit-y += tests/test-bdrv-drain$(EXESUF) | ||
620 | check-unit-y += tests/test-blockjob$(EXESUF) | ||
621 | check-unit-y += tests/test-blockjob-txn$(EXESUF) | ||
622 | check-unit-y += tests/test-block-backend$(EXESUF) | ||
623 | +check-unit-y += tests/test-block-iothread$(EXESUF) | ||
624 | check-unit-y += tests/test-image-locking$(EXESUF) | ||
625 | check-unit-y += tests/test-x86-cpuid$(EXESUF) | ||
626 | # all code tested by test-x86-cpuid is inside topology.h | ||
627 | @@ -XXX,XX +XXX,XX @@ tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(te | ||
628 | tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y) | ||
629 | tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y) | ||
630 | tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y) | ||
631 | +tests/test-block-iothread$(EXESUF): tests/test-block-iothread.o $(test-block-obj-y) $(test-util-obj-y) | ||
632 | tests/test-image-locking$(EXESUF): tests/test-image-locking.o $(test-block-obj-y) $(test-util-obj-y) | ||
633 | tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y) | ||
634 | tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y) | ||
635 | -- | 159 | -- |
636 | 2.20.1 | 160 | 2.39.2 |
637 | |||
638 | diff view generated by jsdifflib |
1 | Signed-off-by: Fam Zheng <famz@redhat.com> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_register_buf() and bdrv_unregister_buf() need to hold a reader lock | ||
3 | for the graph. | ||
4 | |||
5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
6 | Message-Id: <20230203152202.49054-21-kwolf@redhat.com> | ||
7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> | ||
2 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
3 | --- | 9 | --- |
4 | tests/qemu-iotests/237 | 233 +++++++++++++++++++++++++ | 10 | include/block/block_int-common.h | 7 ++++--- |
5 | tests/qemu-iotests/237.out | 347 +++++++++++++++++++++++++++++++++++++ | 11 | block/io.c | 14 ++++++++++---- |
6 | tests/qemu-iotests/group | 1 + | 12 | 2 files changed, 14 insertions(+), 7 deletions(-) |
7 | 3 files changed, 581 insertions(+) | ||
8 | create mode 100755 tests/qemu-iotests/237 | ||
9 | create mode 100644 tests/qemu-iotests/237.out | ||
10 | 13 | ||
11 | diff --git a/tests/qemu-iotests/237 b/tests/qemu-iotests/237 | 14 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
12 | new file mode 100755 | 15 | index XXXXXXX..XXXXXXX 100644 |
13 | index XXXXXXX..XXXXXXX | 16 | --- a/include/block/block_int-common.h |
14 | --- /dev/null | 17 | +++ b/include/block/block_int-common.h |
15 | +++ b/tests/qemu-iotests/237 | 18 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
16 | @@ -XXX,XX +XXX,XX @@ | 19 | * |
17 | +#!/usr/bin/env python | 20 | * Returns: true on success, false on failure |
18 | +# | 21 | */ |
19 | +# Test vmdk and file image creation | 22 | - bool (*bdrv_register_buf)(BlockDriverState *bs, void *host, size_t size, |
20 | +# | 23 | - Error **errp); |
21 | +# Copyright (C) 2018 Red Hat, Inc. | 24 | - void (*bdrv_unregister_buf)(BlockDriverState *bs, void *host, size_t size); |
22 | +# | 25 | + bool GRAPH_RDLOCK_PTR (*bdrv_register_buf)( |
23 | +# Creator/Owner: Kevin Wolf <kwolf@redhat.com> | 26 | + BlockDriverState *bs, void *host, size_t size, Error **errp); |
24 | +# | 27 | + void GRAPH_RDLOCK_PTR (*bdrv_unregister_buf)( |
25 | +# This program is free software; you can redistribute it and/or modify | 28 | + BlockDriverState *bs, void *host, size_t size); |
26 | +# it under the terms of the GNU General Public License as published by | 29 | |
27 | +# the Free Software Foundation; either version 2 of the License, or | 30 | /* |
28 | +# (at your option) any later version. | 31 | * This field is modified only under the BQL, and is part of |
29 | +# | 32 | diff --git a/block/io.c b/block/io.c |
30 | +# This program is distributed in the hope that it will be useful, | 33 | index XXXXXXX..XXXXXXX 100644 |
31 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | 34 | --- a/block/io.c |
32 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 35 | +++ b/block/io.c |
33 | +# GNU General Public License for more details. | 36 | @@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_io_unplug(BlockDriverState *bs) |
34 | +# | 37 | } |
35 | +# You should have received a copy of the GNU General Public License | 38 | |
36 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | 39 | /* Helper that undoes bdrv_register_buf() when it fails partway through */ |
37 | +# | 40 | -static void bdrv_register_buf_rollback(BlockDriverState *bs, |
41 | - void *host, | ||
42 | - size_t size, | ||
43 | - BdrvChild *final_child) | ||
44 | +static void GRAPH_RDLOCK | ||
45 | +bdrv_register_buf_rollback(BlockDriverState *bs, void *host, size_t size, | ||
46 | + BdrvChild *final_child) | ||
47 | { | ||
48 | BdrvChild *child; | ||
49 | |||
50 | + GLOBAL_STATE_CODE(); | ||
51 | + assert_bdrv_graph_readable(); | ||
38 | + | 52 | + |
39 | +import iotests | 53 | QLIST_FOREACH(child, &bs->children, next) { |
40 | +from iotests import imgfmt | 54 | if (child == final_child) { |
55 | break; | ||
56 | @@ -XXX,XX +XXX,XX @@ bool bdrv_register_buf(BlockDriverState *bs, void *host, size_t size, | ||
57 | BdrvChild *child; | ||
58 | |||
59 | GLOBAL_STATE_CODE(); | ||
60 | + GRAPH_RDLOCK_GUARD_MAINLOOP(); | ||
41 | + | 61 | + |
42 | +iotests.verify_image_format(supported_fmts=['vmdk']) | 62 | if (bs->drv && bs->drv->bdrv_register_buf) { |
63 | if (!bs->drv->bdrv_register_buf(bs, host, size, errp)) { | ||
64 | return false; | ||
65 | @@ -XXX,XX +XXX,XX @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host, size_t size) | ||
66 | BdrvChild *child; | ||
67 | |||
68 | GLOBAL_STATE_CODE(); | ||
69 | + GRAPH_RDLOCK_GUARD_MAINLOOP(); | ||
43 | + | 70 | + |
44 | +def blockdev_create(vm, options): | 71 | if (bs->drv && bs->drv->bdrv_unregister_buf) { |
45 | + result = vm.qmp_log('blockdev-create', job_id='job0', options=options) | 72 | bs->drv->bdrv_unregister_buf(bs, host, size); |
46 | + | 73 | } |
47 | + if 'return' in result: | ||
48 | + assert result['return'] == {} | ||
49 | + vm.run_job('job0') | ||
50 | + iotests.log("") | ||
51 | + | ||
52 | +with iotests.FilePath('t.vmdk') as disk_path, \ | ||
53 | + iotests.FilePath('t.vmdk.1') as extent1_path, \ | ||
54 | + iotests.FilePath('t.vmdk.2') as extent2_path, \ | ||
55 | + iotests.FilePath('t.vmdk.3') as extent3_path, \ | ||
56 | + iotests.VM() as vm: | ||
57 | + | ||
58 | + # | ||
59 | + # Successful image creation (defaults) | ||
60 | + # | ||
61 | + iotests.log("=== Successful image creation (defaults) ===") | ||
62 | + iotests.log("") | ||
63 | + | ||
64 | + size = 5 * 1024 * 1024 * 1024 | ||
65 | + | ||
66 | + vm.launch() | ||
67 | + blockdev_create(vm, { 'driver': 'file', | ||
68 | + 'filename': disk_path, | ||
69 | + 'size': 0 }) | ||
70 | + | ||
71 | + vm.qmp_log('blockdev-add', driver='file', filename=disk_path, | ||
72 | + node_name='imgfile') | ||
73 | + | ||
74 | + blockdev_create(vm, { 'driver': imgfmt, | ||
75 | + 'file': 'imgfile', | ||
76 | + 'size': size }) | ||
77 | + vm.shutdown() | ||
78 | + | ||
79 | + iotests.img_info_log(disk_path) | ||
80 | + | ||
81 | + # | ||
82 | + # Successful image creation (inline blockdev-add, explicit defaults) | ||
83 | + # | ||
84 | + iotests.log("=== Successful image creation (inline blockdev-add, explicit defaults) ===") | ||
85 | + iotests.log("") | ||
86 | + | ||
87 | + # Choose a different size to show that we got a new image | ||
88 | + size = 64 * 1024 * 1024 | ||
89 | + | ||
90 | + vm.launch() | ||
91 | + blockdev_create(vm, { 'driver': 'file', | ||
92 | + 'filename': disk_path, | ||
93 | + 'size': 0 }) | ||
94 | + | ||
95 | + blockdev_create(vm, { 'driver': imgfmt, | ||
96 | + 'file': { | ||
97 | + 'driver': 'file', | ||
98 | + 'filename': disk_path, | ||
99 | + }, | ||
100 | + 'size': size, | ||
101 | + 'extents': [], | ||
102 | + 'subformat': 'monolithicSparse', | ||
103 | + 'adapter-type': 'ide', | ||
104 | + 'hwversion': '4', | ||
105 | + 'zeroed-grain': False }) | ||
106 | + vm.shutdown() | ||
107 | + | ||
108 | + iotests.img_info_log(disk_path) | ||
109 | + | ||
110 | + # | ||
111 | + # Successful image creation (non-default options) | ||
112 | + # | ||
113 | + iotests.log("=== Successful image creation (with non-default options) ===") | ||
114 | + iotests.log("") | ||
115 | + | ||
116 | + # Choose a different size to show that we got a new image | ||
117 | + size = 32 * 1024 * 1024 | ||
118 | + | ||
119 | + vm.launch() | ||
120 | + blockdev_create(vm, { 'driver': 'file', | ||
121 | + 'filename': disk_path, | ||
122 | + 'size': 0 }) | ||
123 | + | ||
124 | + blockdev_create(vm, { 'driver': imgfmt, | ||
125 | + 'file': { | ||
126 | + 'driver': 'file', | ||
127 | + 'filename': disk_path, | ||
128 | + }, | ||
129 | + 'size': size, | ||
130 | + 'extents': [], | ||
131 | + 'subformat': 'monolithicSparse', | ||
132 | + 'adapter-type': 'buslogic', | ||
133 | + 'zeroed-grain': True }) | ||
134 | + vm.shutdown() | ||
135 | + | ||
136 | + iotests.img_info_log(disk_path) | ||
137 | + | ||
138 | + # | ||
139 | + # Invalid BlockdevRef | ||
140 | + # | ||
141 | + iotests.log("=== Invalid BlockdevRef ===") | ||
142 | + iotests.log("") | ||
143 | + | ||
144 | + vm.launch() | ||
145 | + blockdev_create(vm, { 'driver': imgfmt, | ||
146 | + 'file': "this doesn't exist", | ||
147 | + 'size': size }) | ||
148 | + vm.shutdown() | ||
149 | + | ||
150 | + # | ||
151 | + # Adapter types | ||
152 | + # | ||
153 | + | ||
154 | + iotests.log("=== Adapter types ===") | ||
155 | + iotests.log("") | ||
156 | + | ||
157 | + vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path)) | ||
158 | + | ||
159 | + # Valid | ||
160 | + iotests.log("== Valid adapter types ==") | ||
161 | + iotests.log("") | ||
162 | + | ||
163 | + vm.launch() | ||
164 | + for adapter_type in [ 'ide', 'buslogic', 'lsilogic', 'legacyESX' ]: | ||
165 | + blockdev_create(vm, { 'driver': imgfmt, | ||
166 | + 'file': 'node0', | ||
167 | + 'size': size, | ||
168 | + 'adapter-type': adapter_type }) | ||
169 | + vm.shutdown() | ||
170 | + | ||
171 | + # Invalid | ||
172 | + iotests.log("== Invalid adapter types ==") | ||
173 | + iotests.log("") | ||
174 | + | ||
175 | + vm.launch() | ||
176 | + for adapter_type in [ 'foo', 'IDE', 'legacyesx', 1 ]: | ||
177 | + blockdev_create(vm, { 'driver': imgfmt, | ||
178 | + 'file': 'node0', | ||
179 | + 'size': size, | ||
180 | + 'adapter-type': adapter_type }) | ||
181 | + vm.shutdown() | ||
182 | + | ||
183 | + # | ||
184 | + # Other subformats | ||
185 | + # | ||
186 | + iotests.log("=== Other subformats ===") | ||
187 | + iotests.log("") | ||
188 | + | ||
189 | + for path in [ extent1_path, extent2_path, extent3_path ]: | ||
190 | + msg = iotests.qemu_img_pipe('create', '-f', imgfmt, path, '0') | ||
191 | + iotests.log(msg, [iotests.filter_testfiles]) | ||
192 | + | ||
193 | + vm.add_blockdev('driver=file,filename=%s,node-name=ext1' % (extent1_path)) | ||
194 | + vm.add_blockdev('driver=file,filename=%s,node-name=ext2' % (extent2_path)) | ||
195 | + vm.add_blockdev('driver=file,filename=%s,node-name=ext3' % (extent3_path)) | ||
196 | + | ||
197 | + # Missing extent | ||
198 | + iotests.log("== Missing extent ==") | ||
199 | + iotests.log("") | ||
200 | + | ||
201 | + vm.launch() | ||
202 | + blockdev_create(vm, { 'driver': imgfmt, | ||
203 | + 'file': 'node0', | ||
204 | + 'size': size, | ||
205 | + 'subformat': 'monolithicFlat' }) | ||
206 | + vm.shutdown() | ||
207 | + | ||
208 | + # Correct extent | ||
209 | + iotests.log("== Correct extent ==") | ||
210 | + iotests.log("") | ||
211 | + | ||
212 | + vm.launch() | ||
213 | + blockdev_create(vm, { 'driver': imgfmt, | ||
214 | + 'file': 'node0', | ||
215 | + 'size': size, | ||
216 | + 'subformat': 'monolithicFlat', | ||
217 | + 'extents': ['ext1'] }) | ||
218 | + vm.shutdown() | ||
219 | + | ||
220 | + # Extra extent | ||
221 | + iotests.log("== Extra extent ==") | ||
222 | + iotests.log("") | ||
223 | + | ||
224 | + vm.launch() | ||
225 | + blockdev_create(vm, { 'driver': imgfmt, | ||
226 | + 'file': 'node0', | ||
227 | + 'size': 512, | ||
228 | + 'subformat': 'monolithicFlat', | ||
229 | + 'extents': ['ext1', 'ext2', 'ext3'] }) | ||
230 | + vm.shutdown() | ||
231 | + | ||
232 | + # Split formats | ||
233 | + iotests.log("== Split formats ==") | ||
234 | + iotests.log("") | ||
235 | + | ||
236 | + for size in [ 512, 1073741824, 2147483648, 5368709120 ]: | ||
237 | + for subfmt in [ 'twoGbMaxExtentFlat', 'twoGbMaxExtentSparse' ]: | ||
238 | + iotests.log("= %s %d =" % (subfmt, size)) | ||
239 | + iotests.log("") | ||
240 | + | ||
241 | + vm.launch() | ||
242 | + blockdev_create(vm, { 'driver': imgfmt, | ||
243 | + 'file': 'node0', | ||
244 | + 'size': size, | ||
245 | + 'subformat': subfmt, | ||
246 | + 'extents': ['ext1', 'ext2', 'ext3'] }) | ||
247 | + vm.shutdown() | ||
248 | + | ||
249 | + iotests.img_info_log(disk_path) | ||
250 | diff --git a/tests/qemu-iotests/237.out b/tests/qemu-iotests/237.out | ||
251 | new file mode 100644 | ||
252 | index XXXXXXX..XXXXXXX | ||
253 | --- /dev/null | ||
254 | +++ b/tests/qemu-iotests/237.out | ||
255 | @@ -XXX,XX +XXX,XX @@ | ||
256 | +=== Successful image creation (defaults) === | ||
257 | + | ||
258 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} | ||
259 | +{"return": {}} | ||
260 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
261 | +{"return": {}} | ||
262 | + | ||
263 | +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "node_name": "imgfile"}} | ||
264 | +{"return": {}} | ||
265 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "imgfile", "size": 5368709120}}} | ||
266 | +{"return": {}} | ||
267 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
268 | +{"return": {}} | ||
269 | + | ||
270 | +image: TEST_IMG | ||
271 | +file format: IMGFMT | ||
272 | +virtual size: 5.0G (5368709120 bytes) | ||
273 | +cluster_size: 65536 | ||
274 | +Format specific information: | ||
275 | + cid: XXXXXXXXXX | ||
276 | + parent cid: XXXXXXXXXX | ||
277 | + create type: monolithicSparse | ||
278 | + extents: | ||
279 | + [0]: | ||
280 | + virtual size: 5368709120 | ||
281 | + filename: TEST_IMG | ||
282 | + cluster size: 65536 | ||
283 | + format: | ||
284 | + | ||
285 | +=== Successful image creation (inline blockdev-add, explicit defaults) === | ||
286 | + | ||
287 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} | ||
288 | +{"return": {}} | ||
289 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
290 | +{"return": {}} | ||
291 | + | ||
292 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "hwversion": "4", "size": 67108864, "subformat": "monolithicSparse", "zeroed-grain": false}}} | ||
293 | +{"return": {}} | ||
294 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
295 | +{"return": {}} | ||
296 | + | ||
297 | +image: TEST_IMG | ||
298 | +file format: IMGFMT | ||
299 | +virtual size: 64M (67108864 bytes) | ||
300 | +cluster_size: 65536 | ||
301 | +Format specific information: | ||
302 | + cid: XXXXXXXXXX | ||
303 | + parent cid: XXXXXXXXXX | ||
304 | + create type: monolithicSparse | ||
305 | + extents: | ||
306 | + [0]: | ||
307 | + virtual size: 67108864 | ||
308 | + filename: TEST_IMG | ||
309 | + cluster size: 65536 | ||
310 | + format: | ||
311 | + | ||
312 | +=== Successful image creation (with non-default options) === | ||
313 | + | ||
314 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} | ||
315 | +{"return": {}} | ||
316 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
317 | +{"return": {}} | ||
318 | + | ||
319 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "size": 33554432, "subformat": "monolithicSparse", "zeroed-grain": true}}} | ||
320 | +{"return": {}} | ||
321 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
322 | +{"return": {}} | ||
323 | + | ||
324 | +image: TEST_IMG | ||
325 | +file format: IMGFMT | ||
326 | +virtual size: 32M (33554432 bytes) | ||
327 | +cluster_size: 65536 | ||
328 | +Format specific information: | ||
329 | + cid: XXXXXXXXXX | ||
330 | + parent cid: XXXXXXXXXX | ||
331 | + create type: monolithicSparse | ||
332 | + extents: | ||
333 | + [0]: | ||
334 | + virtual size: 33554432 | ||
335 | + filename: TEST_IMG | ||
336 | + cluster size: 65536 | ||
337 | + format: | ||
338 | + | ||
339 | +=== Invalid BlockdevRef === | ||
340 | + | ||
341 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "this doesn't exist", "size": 33554432}}} | ||
342 | +{"return": {}} | ||
343 | +Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist | ||
344 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
345 | +{"return": {}} | ||
346 | + | ||
347 | +=== Adapter types === | ||
348 | + | ||
349 | +== Valid adapter types == | ||
350 | + | ||
351 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "file": "node0", "size": 33554432}}} | ||
352 | +{"return": {}} | ||
353 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
354 | +{"return": {}} | ||
355 | + | ||
356 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "file": "node0", "size": 33554432}}} | ||
357 | +{"return": {}} | ||
358 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
359 | +{"return": {}} | ||
360 | + | ||
361 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "lsilogic", "driver": "vmdk", "file": "node0", "size": 33554432}}} | ||
362 | +{"return": {}} | ||
363 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
364 | +{"return": {}} | ||
365 | + | ||
366 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "legacyESX", "driver": "vmdk", "file": "node0", "size": 33554432}}} | ||
367 | +{"return": {}} | ||
368 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
369 | +{"return": {}} | ||
370 | + | ||
371 | +== Invalid adapter types == | ||
372 | + | ||
373 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "foo", "driver": "vmdk", "file": "node0", "size": 33554432}}} | ||
374 | +{"error": {"class": "GenericError", "desc": "Invalid parameter 'foo'"}} | ||
375 | + | ||
376 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "IDE", "driver": "vmdk", "file": "node0", "size": 33554432}}} | ||
377 | +{"error": {"class": "GenericError", "desc": "Invalid parameter 'IDE'"}} | ||
378 | + | ||
379 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "legacyesx", "driver": "vmdk", "file": "node0", "size": 33554432}}} | ||
380 | +{"error": {"class": "GenericError", "desc": "Invalid parameter 'legacyesx'"}} | ||
381 | + | ||
382 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": 1, "driver": "vmdk", "file": "node0", "size": 33554432}}} | ||
383 | +{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'options.adapter-type', expected: string"}} | ||
384 | + | ||
385 | +=== Other subformats === | ||
386 | + | ||
387 | +Formatting 'TEST_DIR/PID-t.vmdk.1', fmt=vmdk size=0 compat6=off hwversion=undefined | ||
388 | + | ||
389 | +Formatting 'TEST_DIR/PID-t.vmdk.2', fmt=vmdk size=0 compat6=off hwversion=undefined | ||
390 | + | ||
391 | +Formatting 'TEST_DIR/PID-t.vmdk.3', fmt=vmdk size=0 compat6=off hwversion=undefined | ||
392 | + | ||
393 | +== Missing extent == | ||
394 | + | ||
395 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}} | ||
396 | +{"return": {}} | ||
397 | +Job failed: Extent [0] not specified | ||
398 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
399 | +{"return": {}} | ||
400 | + | ||
401 | +== Correct extent == | ||
402 | + | ||
403 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}} | ||
404 | +{"return": {}} | ||
405 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
406 | +{"return": {}} | ||
407 | + | ||
408 | +== Extra extent == | ||
409 | + | ||
410 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "monolithicFlat"}}} | ||
411 | +{"return": {}} | ||
412 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
413 | +{"return": {}} | ||
414 | + | ||
415 | +== Split formats == | ||
416 | + | ||
417 | += twoGbMaxExtentFlat 512 = | ||
418 | + | ||
419 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentFlat"}}} | ||
420 | +{"return": {}} | ||
421 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
422 | +{"return": {}} | ||
423 | + | ||
424 | +image: TEST_IMG | ||
425 | +file format: IMGFMT | ||
426 | +virtual size: 512 (512 bytes) | ||
427 | +Format specific information: | ||
428 | + cid: XXXXXXXXXX | ||
429 | + parent cid: XXXXXXXXXX | ||
430 | + create type: twoGbMaxExtentFlat | ||
431 | + extents: | ||
432 | + [0]: | ||
433 | + virtual size: 512 | ||
434 | + filename: TEST_IMG.1 | ||
435 | + format: FLAT | ||
436 | + | ||
437 | += twoGbMaxExtentSparse 512 = | ||
438 | + | ||
439 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentSparse"}}} | ||
440 | +{"return": {}} | ||
441 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
442 | +{"return": {}} | ||
443 | + | ||
444 | +image: TEST_IMG | ||
445 | +file format: IMGFMT | ||
446 | +virtual size: 512 (512 bytes) | ||
447 | +cluster_size: 65536 | ||
448 | +Format specific information: | ||
449 | + cid: XXXXXXXXXX | ||
450 | + parent cid: XXXXXXXXXX | ||
451 | + create type: twoGbMaxExtentSparse | ||
452 | + extents: | ||
453 | + [0]: | ||
454 | + virtual size: 512 | ||
455 | + filename: TEST_IMG.1 | ||
456 | + cluster size: 65536 | ||
457 | + format: SPARSE | ||
458 | + | ||
459 | += twoGbMaxExtentFlat 1073741824 = | ||
460 | + | ||
461 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentFlat"}}} | ||
462 | +{"return": {}} | ||
463 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
464 | +{"return": {}} | ||
465 | + | ||
466 | +image: TEST_IMG | ||
467 | +file format: IMGFMT | ||
468 | +virtual size: 1.0G (1073741824 bytes) | ||
469 | +Format specific information: | ||
470 | + cid: XXXXXXXXXX | ||
471 | + parent cid: XXXXXXXXXX | ||
472 | + create type: twoGbMaxExtentFlat | ||
473 | + extents: | ||
474 | + [0]: | ||
475 | + virtual size: 1073741824 | ||
476 | + filename: TEST_IMG.1 | ||
477 | + format: FLAT | ||
478 | + | ||
479 | += twoGbMaxExtentSparse 1073741824 = | ||
480 | + | ||
481 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentSparse"}}} | ||
482 | +{"return": {}} | ||
483 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
484 | +{"return": {}} | ||
485 | + | ||
486 | +image: TEST_IMG | ||
487 | +file format: IMGFMT | ||
488 | +virtual size: 1.0G (1073741824 bytes) | ||
489 | +cluster_size: 65536 | ||
490 | +Format specific information: | ||
491 | + cid: XXXXXXXXXX | ||
492 | + parent cid: XXXXXXXXXX | ||
493 | + create type: twoGbMaxExtentSparse | ||
494 | + extents: | ||
495 | + [0]: | ||
496 | + virtual size: 1073741824 | ||
497 | + filename: TEST_IMG.1 | ||
498 | + cluster size: 65536 | ||
499 | + format: SPARSE | ||
500 | + | ||
501 | += twoGbMaxExtentFlat 2147483648 = | ||
502 | + | ||
503 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentFlat"}}} | ||
504 | +{"return": {}} | ||
505 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
506 | +{"return": {}} | ||
507 | + | ||
508 | +image: TEST_IMG | ||
509 | +file format: IMGFMT | ||
510 | +virtual size: 2.0G (2147483648 bytes) | ||
511 | +Format specific information: | ||
512 | + cid: XXXXXXXXXX | ||
513 | + parent cid: XXXXXXXXXX | ||
514 | + create type: twoGbMaxExtentFlat | ||
515 | + extents: | ||
516 | + [0]: | ||
517 | + virtual size: 2147483648 | ||
518 | + filename: TEST_IMG.1 | ||
519 | + format: FLAT | ||
520 | + | ||
521 | += twoGbMaxExtentSparse 2147483648 = | ||
522 | + | ||
523 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentSparse"}}} | ||
524 | +{"return": {}} | ||
525 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
526 | +{"return": {}} | ||
527 | + | ||
528 | +image: TEST_IMG | ||
529 | +file format: IMGFMT | ||
530 | +virtual size: 2.0G (2147483648 bytes) | ||
531 | +cluster_size: 65536 | ||
532 | +Format specific information: | ||
533 | + cid: XXXXXXXXXX | ||
534 | + parent cid: XXXXXXXXXX | ||
535 | + create type: twoGbMaxExtentSparse | ||
536 | + extents: | ||
537 | + [0]: | ||
538 | + virtual size: 2147483648 | ||
539 | + filename: TEST_IMG.1 | ||
540 | + cluster size: 65536 | ||
541 | + format: SPARSE | ||
542 | + | ||
543 | += twoGbMaxExtentFlat 5368709120 = | ||
544 | + | ||
545 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentFlat"}}} | ||
546 | +{"return": {}} | ||
547 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
548 | +{"return": {}} | ||
549 | + | ||
550 | +image: TEST_IMG | ||
551 | +file format: IMGFMT | ||
552 | +virtual size: 5.0G (5368709120 bytes) | ||
553 | +Format specific information: | ||
554 | + cid: XXXXXXXXXX | ||
555 | + parent cid: XXXXXXXXXX | ||
556 | + create type: twoGbMaxExtentFlat | ||
557 | + extents: | ||
558 | + [0]: | ||
559 | + virtual size: 2147483648 | ||
560 | + filename: TEST_IMG.1 | ||
561 | + format: FLAT | ||
562 | + [1]: | ||
563 | + virtual size: 2147483648 | ||
564 | + filename: TEST_IMG.2 | ||
565 | + format: FLAT | ||
566 | + [2]: | ||
567 | + virtual size: 1073741824 | ||
568 | + filename: TEST_IMG.3 | ||
569 | + format: FLAT | ||
570 | + | ||
571 | += twoGbMaxExtentSparse 5368709120 = | ||
572 | + | ||
573 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentSparse"}}} | ||
574 | +{"return": {}} | ||
575 | +{"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
576 | +{"return": {}} | ||
577 | + | ||
578 | +image: TEST_IMG | ||
579 | +file format: IMGFMT | ||
580 | +virtual size: 5.0G (5368709120 bytes) | ||
581 | +cluster_size: 65536 | ||
582 | +Format specific information: | ||
583 | + cid: XXXXXXXXXX | ||
584 | + parent cid: XXXXXXXXXX | ||
585 | + create type: twoGbMaxExtentSparse | ||
586 | + extents: | ||
587 | + [0]: | ||
588 | + virtual size: 2147483648 | ||
589 | + filename: TEST_IMG.1 | ||
590 | + cluster size: 65536 | ||
591 | + format: SPARSE | ||
592 | + [1]: | ||
593 | + virtual size: 2147483648 | ||
594 | + filename: TEST_IMG.2 | ||
595 | + cluster size: 65536 | ||
596 | + format: SPARSE | ||
597 | + [2]: | ||
598 | + virtual size: 1073741824 | ||
599 | + filename: TEST_IMG.3 | ||
600 | + cluster size: 65536 | ||
601 | + format: SPARSE | ||
602 | + | ||
603 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
604 | index XXXXXXX..XXXXXXX 100644 | ||
605 | --- a/tests/qemu-iotests/group | ||
606 | +++ b/tests/qemu-iotests/group | ||
607 | @@ -XXX,XX +XXX,XX @@ | ||
608 | 234 auto quick migration | ||
609 | 235 auto quick | ||
610 | 236 auto quick | ||
611 | +237 rw auto quick | ||
612 | 238 auto quick | ||
613 | 239 rw auto quick | ||
614 | -- | 74 | -- |
615 | 2.20.1 | 75 | 2.39.2 |
616 | |||
617 | diff view generated by jsdifflib |
1 | bdrv_co_invalidate_cache() clears the BDRV_O_INACTIVE flag before | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | actually activating a node so that the correct permissions etc. are | 2 | bdrv_co_delete_file() need to hold a reader lock for the graph. |
3 | taken. In case of errors, the flag must be restored so that the next | ||
4 | call to bdrv_co_invalidate_cache() retries activation. | ||
5 | 3 | ||
6 | Restoring the flag was missing in the error path for a failed | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
7 | parent->role->activate() call. The consequence is that this attempt to | 5 | Message-Id: <20230203152202.49054-22-kwolf@redhat.com> |
8 | activate all images correctly fails because we still set errp, however | 6 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
9 | on the next attempt BDRV_O_INACTIVE is already clear, so we return | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | success without actually retrying the failed action. | 8 | --- |
9 | include/block/block-io.h | 8 ++++++-- | ||
10 | include/block/block_int-common.h | 4 ++-- | ||
11 | block.c | 1 + | ||
12 | 3 files changed, 9 insertions(+), 4 deletions(-) | ||
11 | 13 | ||
12 | An example where this is observable in practice is migration to a QEMU | 14 | diff --git a/include/block/block-io.h b/include/block/block-io.h |
13 | instance that has a raw format block node attached to a guest device | 15 | index XXXXXXX..XXXXXXX 100644 |
14 | with share-rw=off (the default) while another process holds | 16 | --- a/include/block/block-io.h |
15 | BLK_PERM_WRITE for the same image. In this case, all activation steps | 17 | +++ b/include/block/block-io.h |
16 | before parent->role->activate() succeed because raw can tolerate other | 18 | @@ -XXX,XX +XXX,XX @@ int64_t co_wrapper bdrv_get_allocated_file_size(BlockDriverState *bs); |
17 | writers to the image. Only the parent callback (in particular | 19 | BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts, |
18 | blk_root_activate()) tries to implement the share-rw=on property and | 20 | BlockDriverState *in_bs, Error **errp); |
19 | requests exclusive write permissions. This fails when the migration | 21 | void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr); |
20 | completes and correctly displays an error. However, a manual 'cont' will | 22 | -int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp); |
21 | incorrectly resume the VM without calling blk_root_activate() again. | 23 | -void coroutine_fn bdrv_co_delete_file_noerr(BlockDriverState *bs); |
22 | 24 | + | |
23 | This case is described in more detail in the following bug report: | 25 | +int coroutine_fn GRAPH_RDLOCK |
24 | https://bugzilla.redhat.com/show_bug.cgi?id=1531888 | 26 | +bdrv_co_delete_file(BlockDriverState *bs, Error **errp); |
25 | 27 | + | |
26 | Fix this by correctly restoring the BDRV_O_INACTIVE flag in the error | 28 | +void coroutine_fn GRAPH_RDLOCK |
27 | path. | 29 | +bdrv_co_delete_file_noerr(BlockDriverState *bs); |
28 | 30 | ||
29 | Cc: qemu-stable@nongnu.org | 31 | |
30 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 32 | /* async block I/O */ |
31 | Tested-by: Markus Armbruster <armbru@redhat.com> | 33 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h |
32 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 34 | index XXXXXXX..XXXXXXX 100644 |
33 | --- | 35 | --- a/include/block/block_int-common.h |
34 | block.c | 1 + | 36 | +++ b/include/block/block_int-common.h |
35 | 1 file changed, 1 insertion(+) | 37 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { |
36 | 38 | int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_flush)(BlockDriverState *bs); | |
39 | |||
40 | /* Delete a created file. */ | ||
41 | - int coroutine_fn (*bdrv_co_delete_file)(BlockDriverState *bs, | ||
42 | - Error **errp); | ||
43 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_delete_file)( | ||
44 | + BlockDriverState *bs, Error **errp); | ||
45 | |||
46 | /* | ||
47 | * Flushes all data that was already written to the OS all the way down to | ||
37 | diff --git a/block.c b/block.c | 48 | diff --git a/block.c b/block.c |
38 | index XXXXXXX..XXXXXXX 100644 | 49 | index XXXXXXX..XXXXXXX 100644 |
39 | --- a/block.c | 50 | --- a/block.c |
40 | +++ b/block.c | 51 | +++ b/block.c |
41 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, | 52 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp) |
42 | if (parent->role->activate) { | 53 | |
43 | parent->role->activate(parent, &local_err); | 54 | IO_CODE(); |
44 | if (local_err) { | 55 | assert(bs != NULL); |
45 | + bs->open_flags |= BDRV_O_INACTIVE; | 56 | + assert_bdrv_graph_readable(); |
46 | error_propagate(errp, local_err); | 57 | |
47 | return; | 58 | if (!bs->drv) { |
48 | } | 59 | error_setg(errp, "Block node '%s' is not opened", bs->filename); |
49 | -- | 60 | -- |
50 | 2.20.1 | 61 | 2.39.2 |
51 | |||
52 | diff view generated by jsdifflib |
1 | From: Max Reitz <mreitz@redhat.com> | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | bdrv_*_dirty_bitmap() need to hold a reader lock for the graph. | ||
2 | 3 | ||
3 | This test waits for a MIGRATION event with status=completed on the | 4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
4 | source VM before querying the migration status on both source and | 5 | Message-Id: <20230203152202.49054-23-kwolf@redhat.com> |
5 | destination. However, just because the source says migration has | 6 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
6 | completed does not mean the destination thinks the same. Therefore, in | ||
7 | some cases, the destination VM may still report "active" instead of | ||
8 | "completed" when asked for its migration status. | ||
9 | |||
10 | Fix this by enabling migration events on both VMs and waiting until both | ||
11 | source and destination emit a status=completed MIGRATION event. | ||
12 | |||
13 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 8 | --- |
16 | tests/qemu-iotests/234 | 56 ++++++++++++++++++++------------------ | 9 | include/block/block-io.h | 14 ++++++-------- |
17 | tests/qemu-iotests/234.out | 10 +++++-- | 10 | include/block/block_int-common.h | 6 ++++-- |
18 | 2 files changed, 38 insertions(+), 28 deletions(-) | 11 | include/block/dirty-bitmap.h | 12 ++++++------ |
12 | block/dirty-bitmap.c | 2 ++ | ||
13 | 4 files changed, 18 insertions(+), 16 deletions(-) | ||
19 | 14 | ||
20 | diff --git a/tests/qemu-iotests/234 b/tests/qemu-iotests/234 | 15 | diff --git a/include/block/block-io.h b/include/block/block-io.h |
21 | index XXXXXXX..XXXXXXX 100755 | 16 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/tests/qemu-iotests/234 | 17 | --- a/include/block/block-io.h |
23 | +++ b/tests/qemu-iotests/234 | 18 | +++ b/include/block/block-io.h |
24 | @@ -XXX,XX +XXX,XX @@ import os | 19 | @@ -XXX,XX +XXX,XX @@ AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c); |
25 | iotests.verify_image_format(supported_fmts=['qcow2']) | 20 | void coroutine_fn GRAPH_RDLOCK bdrv_co_io_plug(BlockDriverState *bs); |
26 | iotests.verify_platform(['linux']) | 21 | void coroutine_fn GRAPH_RDLOCK bdrv_co_io_unplug(BlockDriverState *bs); |
27 | 22 | ||
28 | +def enable_migration_events(vm, name): | 23 | -bool coroutine_fn bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, |
29 | + iotests.log('Enabling migration QMP events on %s...' % name) | 24 | - const char *name, |
30 | + iotests.log(vm.qmp('migrate-set-capabilities', capabilities=[ | 25 | - uint32_t granularity, |
31 | + { | 26 | - Error **errp); |
32 | + 'capability': 'events', | 27 | -bool co_wrapper bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, |
33 | + 'state': True | 28 | - const char *name, |
34 | + } | 29 | - uint32_t granularity, |
35 | + ])) | 30 | - Error **errp); |
31 | +bool coroutine_fn GRAPH_RDLOCK | ||
32 | +bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, | ||
33 | + uint32_t granularity, Error **errp); | ||
34 | +bool co_wrapper_bdrv_rdlock | ||
35 | +bdrv_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, | ||
36 | + uint32_t granularity, Error **errp); | ||
37 | |||
38 | /** | ||
39 | * | ||
40 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
41 | index XXXXXXX..XXXXXXX 100644 | ||
42 | --- a/include/block/block_int-common.h | ||
43 | +++ b/include/block/block_int-common.h | ||
44 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
45 | void (*bdrv_drain_end)(BlockDriverState *bs); | ||
46 | |||
47 | bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs); | ||
48 | - bool coroutine_fn (*bdrv_co_can_store_new_dirty_bitmap)( | ||
36 | + | 49 | + |
37 | +def wait_migration(vm): | 50 | + bool coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_can_store_new_dirty_bitmap)( |
38 | + while True: | 51 | BlockDriverState *bs, const char *name, uint32_t granularity, |
39 | + event = vm.event_wait('MIGRATION') | 52 | Error **errp); |
40 | + iotests.log(event, filters=[iotests.filter_qmp_event]) | 53 | - int coroutine_fn (*bdrv_co_remove_persistent_dirty_bitmap)( |
41 | + if event['data']['status'] == 'completed': | ||
42 | + break | ||
43 | + | 54 | + |
44 | with iotests.FilePath('img') as img_path, \ | 55 | + int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_remove_persistent_dirty_bitmap)( |
45 | iotests.FilePath('backing') as backing_path, \ | 56 | BlockDriverState *bs, const char *name, Error **errp); |
46 | iotests.FilePath('mig_fifo_a') as fifo_a, \ | 57 | }; |
47 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('img') as img_path, \ | 58 | |
48 | .add_blockdev('%s,file=drive0-backing-file,node-name=drive0-backing' % (iotests.imgfmt)) | 59 | diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h |
49 | .launch()) | ||
50 | |||
51 | + enable_migration_events(vm_a, 'A') | ||
52 | + | ||
53 | iotests.log('Launching destination VM...') | ||
54 | (vm_b.add_blockdev('file,filename=%s,node-name=drive0-file' % (img_path)) | ||
55 | .add_blockdev('%s,file=drive0-file,node-name=drive0' % (iotests.imgfmt)) | ||
56 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('img') as img_path, \ | ||
57 | .add_incoming("exec: cat '%s'" % (fifo_a)) | ||
58 | .launch()) | ||
59 | |||
60 | + enable_migration_events(vm_b, 'B') | ||
61 | + | ||
62 | # Add a child node that was created after the parent node. The reverse case | ||
63 | # is covered by the -blockdev options above. | ||
64 | iotests.log(vm_a.qmp('blockdev-snapshot', node='drive0-backing', | ||
65 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('img') as img_path, \ | ||
66 | iotests.log(vm_b.qmp('blockdev-snapshot', node='drive0-backing', | ||
67 | overlay='drive0')) | ||
68 | |||
69 | - iotests.log('Enabling migration QMP events on A...') | ||
70 | - iotests.log(vm_a.qmp('migrate-set-capabilities', capabilities=[ | ||
71 | - { | ||
72 | - 'capability': 'events', | ||
73 | - 'state': True | ||
74 | - } | ||
75 | - ])) | ||
76 | - | ||
77 | iotests.log('Starting migration to B...') | ||
78 | iotests.log(vm_a.qmp('migrate', uri='exec:cat >%s' % (fifo_a))) | ||
79 | with iotests.Timeout(3, 'Migration does not complete'): | ||
80 | - while True: | ||
81 | - event = vm_a.event_wait('MIGRATION') | ||
82 | - iotests.log(event, filters=[iotests.filter_qmp_event]) | ||
83 | - if event['data']['status'] == 'completed': | ||
84 | - break | ||
85 | + # Wait for the source first (which includes setup=setup) | ||
86 | + wait_migration(vm_a) | ||
87 | + # Wait for the destination second (which does not) | ||
88 | + wait_migration(vm_b) | ||
89 | |||
90 | iotests.log(vm_a.qmp('query-migrate')['return']['status']) | ||
91 | iotests.log(vm_b.qmp('query-migrate')['return']['status']) | ||
92 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('img') as img_path, \ | ||
93 | .add_incoming("exec: cat '%s'" % (fifo_b)) | ||
94 | .launch()) | ||
95 | |||
96 | + enable_migration_events(vm_a, 'A') | ||
97 | + | ||
98 | iotests.log(vm_a.qmp('blockdev-snapshot', node='drive0-backing', | ||
99 | overlay='drive0')) | ||
100 | |||
101 | - iotests.log('Enabling migration QMP events on B...') | ||
102 | - iotests.log(vm_b.qmp('migrate-set-capabilities', capabilities=[ | ||
103 | - { | ||
104 | - 'capability': 'events', | ||
105 | - 'state': True | ||
106 | - } | ||
107 | - ])) | ||
108 | - | ||
109 | iotests.log('Starting migration back to A...') | ||
110 | iotests.log(vm_b.qmp('migrate', uri='exec:cat >%s' % (fifo_b))) | ||
111 | with iotests.Timeout(3, 'Migration does not complete'): | ||
112 | - while True: | ||
113 | - event = vm_b.event_wait('MIGRATION') | ||
114 | - iotests.log(event, filters=[iotests.filter_qmp_event]) | ||
115 | - if event['data']['status'] == 'completed': | ||
116 | - break | ||
117 | + # Wait for the source first (which includes setup=setup) | ||
118 | + wait_migration(vm_b) | ||
119 | + # Wait for the destination second (which does not) | ||
120 | + wait_migration(vm_a) | ||
121 | |||
122 | iotests.log(vm_a.qmp('query-migrate')['return']['status']) | ||
123 | iotests.log(vm_b.qmp('query-migrate')['return']['status']) | ||
124 | diff --git a/tests/qemu-iotests/234.out b/tests/qemu-iotests/234.out | ||
125 | index XXXXXXX..XXXXXXX 100644 | 60 | index XXXXXXX..XXXXXXX 100644 |
126 | --- a/tests/qemu-iotests/234.out | 61 | --- a/include/block/dirty-bitmap.h |
127 | +++ b/tests/qemu-iotests/234.out | 62 | +++ b/include/block/dirty-bitmap.h |
128 | @@ -XXX,XX +XXX,XX @@ | 63 | @@ -XXX,XX +XXX,XX @@ int bdrv_dirty_bitmap_check(const BdrvDirtyBitmap *bitmap, uint32_t flags, |
129 | Launching source VM... | 64 | void bdrv_release_dirty_bitmap(BdrvDirtyBitmap *bitmap); |
130 | +Enabling migration QMP events on A... | 65 | void bdrv_release_named_dirty_bitmaps(BlockDriverState *bs); |
131 | +{"return": {}} | 66 | |
132 | Launching destination VM... | 67 | -int coroutine_fn bdrv_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, |
133 | +Enabling migration QMP events on B... | 68 | - const char *name, |
134 | {"return": {}} | 69 | - Error **errp); |
135 | {"return": {}} | 70 | -int co_wrapper bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, |
136 | -Enabling migration QMP events on A... | 71 | - const char *name, |
137 | {"return": {}} | 72 | - Error **errp); |
138 | Starting migration to B... | 73 | +int coroutine_fn GRAPH_RDLOCK |
139 | {"return": {}} | 74 | +bdrv_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, |
140 | {"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | 75 | + Error **errp); |
141 | {"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | 76 | +int co_wrapper_bdrv_rdlock |
142 | {"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | 77 | +bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, |
143 | +{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | 78 | + Error **errp); |
144 | +{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | 79 | |
145 | completed | 80 | void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap); |
146 | completed | 81 | void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap); |
147 | {"return": {"running": false, "singlestep": false, "status": "postmigrate"}} | 82 | diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c |
148 | @@ -XXX,XX +XXX,XX @@ completed | 83 | index XXXXXXX..XXXXXXX 100644 |
149 | Add a second parent to drive0-file... | 84 | --- a/block/dirty-bitmap.c |
150 | {"return": {}} | 85 | +++ b/block/dirty-bitmap.c |
151 | Restart A with -incoming and second parent... | 86 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn |
152 | +Enabling migration QMP events on A... | 87 | bdrv_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name, |
153 | {"return": {}} | 88 | Error **errp) |
154 | -Enabling migration QMP events on B... | 89 | { |
155 | {"return": {}} | 90 | + assert_bdrv_graph_readable(); |
156 | Starting migration back to A... | 91 | if (bs->drv && bs->drv->bdrv_co_remove_persistent_dirty_bitmap) { |
157 | {"return": {}} | 92 | return bs->drv->bdrv_co_remove_persistent_dirty_bitmap(bs, name, errp); |
158 | {"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | 93 | } |
159 | {"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | 94 | @@ -XXX,XX +XXX,XX @@ bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name, |
160 | {"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | 95 | uint32_t granularity, Error **errp) |
161 | +{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | 96 | { |
162 | +{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | 97 | BlockDriver *drv = bs->drv; |
163 | completed | 98 | + assert_bdrv_graph_readable(); |
164 | completed | 99 | |
165 | {"return": {"running": true, "singlestep": false, "status": "running"}} | 100 | if (!drv) { |
101 | error_setg_errno(errp, ENOMEDIUM, | ||
166 | -- | 102 | -- |
167 | 2.20.1 | 103 | 2.39.2 |
168 | |||
169 | diff view generated by jsdifflib |
1 | If QEMU was configured with a driver in --block-drv-ro-whitelist, trying | 1 | This adds GRAPH_RDLOCK annotations to declare that callers of |
---|---|---|---|
2 | to use that driver read-write resulted in an error message even if | 2 | bdrv_co_refresh_total_sectors() need to hold a reader lock for the |
3 | auto-read-only=on was set. | 3 | graph. |
4 | |||
5 | Consider auto-read-only=on for the whitelist checking and use it to | ||
6 | automatically degrade to read-only for block drivers on the read-only | ||
7 | whitelist. | ||
8 | 4 | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 5 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | Reviewed-by: Eric Blake <eblake@redhat.com> | 6 | Message-Id: <20230203152202.49054-24-kwolf@redhat.com> |
11 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | 7 | Reviewed-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> |
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | --- | 9 | --- |
13 | block.c | 20 +++++++++++++------- | 10 | include/block/block-io.h | 8 ++++---- |
14 | 1 file changed, 13 insertions(+), 7 deletions(-) | 11 | include/block/block_int-common.h | 4 +++- |
12 | include/block/block_int-io.h | 7 ++++--- | ||
13 | block.c | 3 +++ | ||
14 | block/blkdebug.c | 3 ++- | ||
15 | block/blklogwrites.c | 3 ++- | ||
16 | block/blkreplay.c | 3 ++- | ||
17 | block/blkverify.c | 3 ++- | ||
18 | block/copy-on-read.c | 2 +- | ||
19 | block/crypto.c | 3 ++- | ||
20 | block/filter-compress.c | 3 ++- | ||
21 | block/mirror.c | 3 +++ | ||
22 | block/preallocate.c | 3 ++- | ||
23 | block/quorum.c | 3 ++- | ||
24 | block/raw-format.c | 3 ++- | ||
25 | block/replication.c | 3 ++- | ||
26 | block/stream.c | 8 +++++--- | ||
27 | block/throttle.c | 3 ++- | ||
28 | 18 files changed, 45 insertions(+), 23 deletions(-) | ||
15 | 29 | ||
30 | diff --git a/include/block/block-io.h b/include/block/block-io.h | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/include/block/block-io.h | ||
33 | +++ b/include/block/block-io.h | ||
34 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn GRAPH_RDLOCK | ||
35 | bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, | ||
36 | PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); | ||
37 | |||
38 | -int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs); | ||
39 | -int64_t co_wrapper_mixed bdrv_nb_sectors(BlockDriverState *bs); | ||
40 | +int64_t coroutine_fn GRAPH_RDLOCK bdrv_co_nb_sectors(BlockDriverState *bs); | ||
41 | +int64_t co_wrapper_mixed_bdrv_rdlock bdrv_nb_sectors(BlockDriverState *bs); | ||
42 | |||
43 | -int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs); | ||
44 | -int64_t co_wrapper_mixed bdrv_getlength(BlockDriverState *bs); | ||
45 | +int64_t coroutine_fn GRAPH_RDLOCK bdrv_co_getlength(BlockDriverState *bs); | ||
46 | +int64_t co_wrapper_mixed_bdrv_rdlock bdrv_getlength(BlockDriverState *bs); | ||
47 | |||
48 | int64_t coroutine_fn bdrv_co_get_allocated_file_size(BlockDriverState *bs); | ||
49 | int64_t co_wrapper bdrv_get_allocated_file_size(BlockDriverState *bs); | ||
50 | diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h | ||
51 | index XXXXXXX..XXXXXXX 100644 | ||
52 | --- a/include/block/block_int-common.h | ||
53 | +++ b/include/block/block_int-common.h | ||
54 | @@ -XXX,XX +XXX,XX @@ struct BlockDriver { | ||
55 | BlockDriverState *bs, int64_t offset, bool exact, | ||
56 | PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); | ||
57 | |||
58 | - int64_t coroutine_fn (*bdrv_co_getlength)(BlockDriverState *bs); | ||
59 | + int64_t coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_getlength)( | ||
60 | + BlockDriverState *bs); | ||
61 | + | ||
62 | int64_t coroutine_fn (*bdrv_co_get_allocated_file_size)( | ||
63 | BlockDriverState *bs); | ||
64 | |||
65 | diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h | ||
66 | index XXXXXXX..XXXXXXX 100644 | ||
67 | --- a/include/block/block_int-io.h | ||
68 | +++ b/include/block/block_int-io.h | ||
69 | @@ -XXX,XX +XXX,XX @@ bdrv_co_copy_range_to(BdrvChild *src, int64_t src_offset, | ||
70 | int64_t bytes, BdrvRequestFlags read_flags, | ||
71 | BdrvRequestFlags write_flags); | ||
72 | |||
73 | -int coroutine_fn bdrv_co_refresh_total_sectors(BlockDriverState *bs, | ||
74 | - int64_t hint); | ||
75 | -int co_wrapper_mixed | ||
76 | +int coroutine_fn GRAPH_RDLOCK | ||
77 | +bdrv_co_refresh_total_sectors(BlockDriverState *bs, int64_t hint); | ||
78 | + | ||
79 | +int co_wrapper_mixed_bdrv_rdlock | ||
80 | bdrv_refresh_total_sectors(BlockDriverState *bs, int64_t hint); | ||
81 | |||
82 | BdrvChild *bdrv_cow_child(BlockDriverState *bs); | ||
16 | diff --git a/block.c b/block.c | 83 | diff --git a/block.c b/block.c |
17 | index XXXXXXX..XXXXXXX 100644 | 84 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/block.c | 85 | --- a/block.c |
19 | +++ b/block.c | 86 | +++ b/block.c |
20 | @@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file, | 87 | @@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_refresh_total_sectors(BlockDriverState *bs, |
21 | bs->read_only = !(bs->open_flags & BDRV_O_RDWR); | 88 | { |
22 | 89 | BlockDriver *drv = bs->drv; | |
23 | if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) { | 90 | IO_CODE(); |
24 | - error_setg(errp, | 91 | + assert_bdrv_graph_readable(); |
25 | - !bs->read_only && bdrv_is_whitelisted(drv, true) | 92 | |
26 | - ? "Driver '%s' can only be used for read-only devices" | 93 | if (!drv) { |
27 | - : "Driver '%s' is not whitelisted", | 94 | return -ENOMEDIUM; |
28 | - drv->format_name); | 95 | @@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn bdrv_co_nb_sectors(BlockDriverState *bs) |
29 | - ret = -ENOTSUP; | 96 | { |
30 | - goto fail_opts; | 97 | BlockDriver *drv = bs->drv; |
31 | + if (!bs->read_only && bdrv_is_whitelisted(drv, true)) { | 98 | IO_CODE(); |
32 | + ret = bdrv_apply_auto_read_only(bs, NULL, NULL); | 99 | + assert_bdrv_graph_readable(); |
33 | + } else { | 100 | |
34 | + ret = -ENOTSUP; | 101 | if (!drv) |
35 | + } | 102 | return -ENOMEDIUM; |
36 | + if (ret < 0) { | 103 | @@ -XXX,XX +XXX,XX @@ int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs) |
37 | + error_setg(errp, | 104 | { |
38 | + !bs->read_only && bdrv_is_whitelisted(drv, true) | 105 | int64_t ret; |
39 | + ? "Driver '%s' can only be used for read-only devices" | 106 | IO_CODE(); |
40 | + : "Driver '%s' is not whitelisted", | 107 | + assert_bdrv_graph_readable(); |
41 | + drv->format_name); | 108 | |
42 | + goto fail_opts; | 109 | ret = bdrv_co_nb_sectors(bs); |
110 | if (ret < 0) { | ||
111 | diff --git a/block/blkdebug.c b/block/blkdebug.c | ||
112 | index XXXXXXX..XXXXXXX 100644 | ||
113 | --- a/block/blkdebug.c | ||
114 | +++ b/block/blkdebug.c | ||
115 | @@ -XXX,XX +XXX,XX @@ static bool blkdebug_debug_is_suspended(BlockDriverState *bs, const char *tag) | ||
116 | return false; | ||
117 | } | ||
118 | |||
119 | -static int64_t coroutine_fn blkdebug_co_getlength(BlockDriverState *bs) | ||
120 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
121 | +blkdebug_co_getlength(BlockDriverState *bs) | ||
122 | { | ||
123 | return bdrv_co_getlength(bs->file->bs); | ||
124 | } | ||
125 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | ||
126 | index XXXXXXX..XXXXXXX 100644 | ||
127 | --- a/block/blklogwrites.c | ||
128 | +++ b/block/blklogwrites.c | ||
129 | @@ -XXX,XX +XXX,XX @@ static void blk_log_writes_close(BlockDriverState *bs) | ||
130 | s->log_file = NULL; | ||
131 | } | ||
132 | |||
133 | -static int64_t coroutine_fn blk_log_writes_co_getlength(BlockDriverState *bs) | ||
134 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
135 | +blk_log_writes_co_getlength(BlockDriverState *bs) | ||
136 | { | ||
137 | return bdrv_co_getlength(bs->file->bs); | ||
138 | } | ||
139 | diff --git a/block/blkreplay.c b/block/blkreplay.c | ||
140 | index XXXXXXX..XXXXXXX 100644 | ||
141 | --- a/block/blkreplay.c | ||
142 | +++ b/block/blkreplay.c | ||
143 | @@ -XXX,XX +XXX,XX @@ fail: | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | -static int64_t coroutine_fn blkreplay_co_getlength(BlockDriverState *bs) | ||
148 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
149 | +blkreplay_co_getlength(BlockDriverState *bs) | ||
150 | { | ||
151 | return bdrv_co_getlength(bs->file->bs); | ||
152 | } | ||
153 | diff --git a/block/blkverify.c b/block/blkverify.c | ||
154 | index XXXXXXX..XXXXXXX 100644 | ||
155 | --- a/block/blkverify.c | ||
156 | +++ b/block/blkverify.c | ||
157 | @@ -XXX,XX +XXX,XX @@ static void blkverify_close(BlockDriverState *bs) | ||
158 | s->test_file = NULL; | ||
159 | } | ||
160 | |||
161 | -static int64_t coroutine_fn blkverify_co_getlength(BlockDriverState *bs) | ||
162 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
163 | +blkverify_co_getlength(BlockDriverState *bs) | ||
164 | { | ||
165 | BDRVBlkverifyState *s = bs->opaque; | ||
166 | |||
167 | diff --git a/block/copy-on-read.c b/block/copy-on-read.c | ||
168 | index XXXXXXX..XXXXXXX 100644 | ||
169 | --- a/block/copy-on-read.c | ||
170 | +++ b/block/copy-on-read.c | ||
171 | @@ -XXX,XX +XXX,XX @@ static void cor_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
172 | } | ||
173 | |||
174 | |||
175 | -static int64_t coroutine_fn cor_co_getlength(BlockDriverState *bs) | ||
176 | +static int64_t coroutine_fn GRAPH_RDLOCK cor_co_getlength(BlockDriverState *bs) | ||
177 | { | ||
178 | return bdrv_co_getlength(bs->file->bs); | ||
179 | } | ||
180 | diff --git a/block/crypto.c b/block/crypto.c | ||
181 | index XXXXXXX..XXXXXXX 100644 | ||
182 | --- a/block/crypto.c | ||
183 | +++ b/block/crypto.c | ||
184 | @@ -XXX,XX +XXX,XX @@ static void block_crypto_refresh_limits(BlockDriverState *bs, Error **errp) | ||
185 | } | ||
186 | |||
187 | |||
188 | -static int64_t coroutine_fn block_crypto_co_getlength(BlockDriverState *bs) | ||
189 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
190 | +block_crypto_co_getlength(BlockDriverState *bs) | ||
191 | { | ||
192 | BlockCrypto *crypto = bs->opaque; | ||
193 | int64_t len = bdrv_co_getlength(bs->file->bs); | ||
194 | diff --git a/block/filter-compress.c b/block/filter-compress.c | ||
195 | index XXXXXXX..XXXXXXX 100644 | ||
196 | --- a/block/filter-compress.c | ||
197 | +++ b/block/filter-compress.c | ||
198 | @@ -XXX,XX +XXX,XX @@ static int compress_open(BlockDriverState *bs, QDict *options, int flags, | ||
199 | } | ||
200 | |||
201 | |||
202 | -static int64_t coroutine_fn compress_co_getlength(BlockDriverState *bs) | ||
203 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
204 | +compress_co_getlength(BlockDriverState *bs) | ||
205 | { | ||
206 | return bdrv_co_getlength(bs->file->bs); | ||
207 | } | ||
208 | diff --git a/block/mirror.c b/block/mirror.c | ||
209 | index XXXXXXX..XXXXXXX 100644 | ||
210 | --- a/block/mirror.c | ||
211 | +++ b/block/mirror.c | ||
212 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp) | ||
213 | goto immediate_exit; | ||
214 | } | ||
215 | |||
216 | + bdrv_graph_co_rdlock(); | ||
217 | s->bdev_length = bdrv_co_getlength(bs); | ||
218 | + bdrv_graph_co_rdunlock(); | ||
219 | + | ||
220 | if (s->bdev_length < 0) { | ||
221 | ret = s->bdev_length; | ||
222 | goto immediate_exit; | ||
223 | diff --git a/block/preallocate.c b/block/preallocate.c | ||
224 | index XXXXXXX..XXXXXXX 100644 | ||
225 | --- a/block/preallocate.c | ||
226 | +++ b/block/preallocate.c | ||
227 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn GRAPH_RDLOCK preallocate_co_flush(BlockDriverState *bs) | ||
228 | return bdrv_co_flush(bs->file->bs); | ||
229 | } | ||
230 | |||
231 | -static int64_t coroutine_fn preallocate_co_getlength(BlockDriverState *bs) | ||
232 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
233 | +preallocate_co_getlength(BlockDriverState *bs) | ||
234 | { | ||
235 | int64_t ret; | ||
236 | BDRVPreallocateState *s = bs->opaque; | ||
237 | diff --git a/block/quorum.c b/block/quorum.c | ||
238 | index XXXXXXX..XXXXXXX 100644 | ||
239 | --- a/block/quorum.c | ||
240 | +++ b/block/quorum.c | ||
241 | @@ -XXX,XX +XXX,XX @@ quorum_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, | ||
242 | flags | BDRV_REQ_ZERO_WRITE); | ||
243 | } | ||
244 | |||
245 | -static int64_t coroutine_fn quorum_co_getlength(BlockDriverState *bs) | ||
246 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
247 | +quorum_co_getlength(BlockDriverState *bs) | ||
248 | { | ||
249 | BDRVQuorumState *s = bs->opaque; | ||
250 | int64_t result; | ||
251 | diff --git a/block/raw-format.c b/block/raw-format.c | ||
252 | index XXXXXXX..XXXXXXX 100644 | ||
253 | --- a/block/raw-format.c | ||
254 | +++ b/block/raw-format.c | ||
255 | @@ -XXX,XX +XXX,XX @@ raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) | ||
256 | return bdrv_co_pdiscard(bs->file, offset, bytes); | ||
257 | } | ||
258 | |||
259 | -static int64_t coroutine_fn raw_co_getlength(BlockDriverState *bs) | ||
260 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
261 | +raw_co_getlength(BlockDriverState *bs) | ||
262 | { | ||
263 | int64_t len; | ||
264 | BDRVRawState *s = bs->opaque; | ||
265 | diff --git a/block/replication.c b/block/replication.c | ||
266 | index XXXXXXX..XXXXXXX 100644 | ||
267 | --- a/block/replication.c | ||
268 | +++ b/block/replication.c | ||
269 | @@ -XXX,XX +XXX,XX @@ static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, | ||
270 | return; | ||
271 | } | ||
272 | |||
273 | -static int64_t coroutine_fn replication_co_getlength(BlockDriverState *bs) | ||
274 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
275 | +replication_co_getlength(BlockDriverState *bs) | ||
276 | { | ||
277 | return bdrv_co_getlength(bs->file->bs); | ||
278 | } | ||
279 | diff --git a/block/stream.c b/block/stream.c | ||
280 | index XXXXXXX..XXXXXXX 100644 | ||
281 | --- a/block/stream.c | ||
282 | +++ b/block/stream.c | ||
283 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_run(Job *job, Error **errp) | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | - len = bdrv_getlength(s->target_bs); | ||
288 | - if (len < 0) { | ||
289 | - return len; | ||
290 | + WITH_GRAPH_RDLOCK_GUARD() { | ||
291 | + len = bdrv_co_getlength(s->target_bs); | ||
292 | + if (len < 0) { | ||
293 | + return len; | ||
43 | + } | 294 | + } |
44 | } | 295 | } |
45 | 296 | job_progress_set_remaining(&s->common.job, len); | |
46 | /* bdrv_new() and bdrv_close() make it so */ | 297 | |
298 | diff --git a/block/throttle.c b/block/throttle.c | ||
299 | index XXXXXXX..XXXXXXX 100644 | ||
300 | --- a/block/throttle.c | ||
301 | +++ b/block/throttle.c | ||
302 | @@ -XXX,XX +XXX,XX @@ static void throttle_close(BlockDriverState *bs) | ||
303 | } | ||
304 | |||
305 | |||
306 | -static int64_t coroutine_fn throttle_co_getlength(BlockDriverState *bs) | ||
307 | +static int64_t coroutine_fn GRAPH_RDLOCK | ||
308 | +throttle_co_getlength(BlockDriverState *bs) | ||
309 | { | ||
310 | return bdrv_co_getlength(bs->file->bs); | ||
311 | } | ||
47 | -- | 312 | -- |
48 | 2.20.1 | 313 | 2.39.2 |
49 | |||
50 | diff view generated by jsdifflib |
1 | scsi-disk includes in the Device Identification VPD page, depending on | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | configuration amongst others, a vendor specific designator that consists | ||
3 | either of the serial number if given or the BlockBackend name (which is | ||
4 | a host detail that better shouldn't have been leaked to the guest, but | ||
5 | now we have to maintain it for compatibility). | ||
6 | 2 | ||
7 | With anonymous BlockBackends, i.e. scsi-disk devices constructed with | 3 | If requests are being processed in the IOThread when a SCSIDevice is |
8 | drive=<node-name>, and no serial number explicitly specified, this ends | 4 | unplugged, scsi_device_purge_requests() -> scsi_req_cancel_async() races |
9 | up as an empty string. If this happens to more than one disk, we have | 5 | with I/O completion callbacks. Both threads load and store req->aiocb. |
10 | accidentally signalled to the OS that this is a multipath setup, which | 6 | This can lead to assert(r->req.aiocb == NULL) failures and undefined |
11 | is obviously not what was intended. | 7 | behavior. |
12 | 8 | ||
13 | Instead of using an empty string for the vendor specific designator, | 9 | Protect r->req.aiocb with the AioContext lock to prevent the race. |
14 | simply leave out that designator, which makes Linux detect such setups | ||
15 | as separate disks again. | ||
16 | 10 | ||
11 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
12 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | Message-Id: <20230221212218.1378734-2-stefanha@redhat.com> | ||
17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 15 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
18 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
19 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
20 | --- | 16 | --- |
21 | hw/scsi/scsi-disk.c | 14 ++++++++------ | 17 | hw/scsi/scsi-disk.c | 23 ++++++++++++++++------- |
22 | 1 file changed, 8 insertions(+), 6 deletions(-) | 18 | hw/scsi/scsi-generic.c | 11 ++++++----- |
19 | 2 files changed, 22 insertions(+), 12 deletions(-) | ||
23 | 20 | ||
24 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c | 21 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c |
25 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/hw/scsi/scsi-disk.c | 23 | --- a/hw/scsi/scsi-disk.c |
27 | +++ b/hw/scsi/scsi-disk.c | 24 | +++ b/hw/scsi/scsi-disk.c |
28 | @@ -XXX,XX +XXX,XX @@ static int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) | 25 | @@ -XXX,XX +XXX,XX @@ static void scsi_aio_complete(void *opaque, int ret) |
29 | DPRINTF("Inquiry EVPD[Device identification] " | 26 | SCSIDiskReq *r = (SCSIDiskReq *)opaque; |
30 | "buffer size %zd\n", req->cmd.xfer); | 27 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
31 | 28 | ||
32 | - outbuf[buflen++] = 0x2; /* ASCII */ | 29 | + aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); |
33 | - outbuf[buflen++] = 0; /* not officially assigned */ | 30 | + |
34 | - outbuf[buflen++] = 0; /* reserved */ | 31 | assert(r->req.aiocb != NULL); |
35 | - outbuf[buflen++] = id_len; /* length of data following */ | 32 | r->req.aiocb = NULL; |
36 | - memcpy(outbuf + buflen, str, id_len); | 33 | - aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); |
37 | - buflen += id_len; | 34 | + |
38 | + if (id_len) { | 35 | if (scsi_disk_req_check_error(r, ret, true)) { |
39 | + outbuf[buflen++] = 0x2; /* ASCII */ | 36 | goto done; |
40 | + outbuf[buflen++] = 0; /* not officially assigned */ | 37 | } |
41 | + outbuf[buflen++] = 0; /* reserved */ | 38 | @@ -XXX,XX +XXX,XX @@ static void scsi_dma_complete(void *opaque, int ret) |
42 | + outbuf[buflen++] = id_len; /* length of data following */ | 39 | SCSIDiskReq *r = (SCSIDiskReq *)opaque; |
43 | + memcpy(outbuf + buflen, str, id_len); | 40 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
44 | + buflen += id_len; | 41 | |
45 | + } | 42 | + aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); |
46 | 43 | + | |
47 | if (s->qdev.wwn) { | 44 | assert(r->req.aiocb != NULL); |
48 | outbuf[buflen++] = 0x1; /* Binary */ | 45 | r->req.aiocb = NULL; |
46 | |||
47 | - aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); | ||
48 | if (ret < 0) { | ||
49 | block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); | ||
50 | } else { | ||
51 | @@ -XXX,XX +XXX,XX @@ static void scsi_read_complete(void *opaque, int ret) | ||
52 | SCSIDiskReq *r = (SCSIDiskReq *)opaque; | ||
53 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); | ||
54 | |||
55 | + aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); | ||
56 | + | ||
57 | assert(r->req.aiocb != NULL); | ||
58 | r->req.aiocb = NULL; | ||
59 | |||
60 | - aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); | ||
61 | if (ret < 0) { | ||
62 | block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); | ||
63 | } else { | ||
64 | @@ -XXX,XX +XXX,XX @@ static void scsi_do_read_cb(void *opaque, int ret) | ||
65 | SCSIDiskReq *r = (SCSIDiskReq *)opaque; | ||
66 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); | ||
67 | |||
68 | + aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); | ||
69 | + | ||
70 | assert (r->req.aiocb != NULL); | ||
71 | r->req.aiocb = NULL; | ||
72 | |||
73 | - aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); | ||
74 | if (ret < 0) { | ||
75 | block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); | ||
76 | } else { | ||
77 | @@ -XXX,XX +XXX,XX @@ static void scsi_write_complete(void * opaque, int ret) | ||
78 | SCSIDiskReq *r = (SCSIDiskReq *)opaque; | ||
79 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); | ||
80 | |||
81 | + aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); | ||
82 | + | ||
83 | assert (r->req.aiocb != NULL); | ||
84 | r->req.aiocb = NULL; | ||
85 | |||
86 | - aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); | ||
87 | if (ret < 0) { | ||
88 | block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct); | ||
89 | } else { | ||
90 | @@ -XXX,XX +XXX,XX @@ static void scsi_unmap_complete(void *opaque, int ret) | ||
91 | SCSIDiskReq *r = data->r; | ||
92 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); | ||
93 | |||
94 | + aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); | ||
95 | + | ||
96 | assert(r->req.aiocb != NULL); | ||
97 | r->req.aiocb = NULL; | ||
98 | |||
99 | - aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); | ||
100 | if (scsi_disk_req_check_error(r, ret, true)) { | ||
101 | scsi_req_unref(&r->req); | ||
102 | g_free(data); | ||
103 | @@ -XXX,XX +XXX,XX @@ static void scsi_write_same_complete(void *opaque, int ret) | ||
104 | SCSIDiskReq *r = data->r; | ||
105 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); | ||
106 | |||
107 | + aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); | ||
108 | + | ||
109 | assert(r->req.aiocb != NULL); | ||
110 | r->req.aiocb = NULL; | ||
111 | - aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); | ||
112 | + | ||
113 | if (scsi_disk_req_check_error(r, ret, true)) { | ||
114 | goto done; | ||
115 | } | ||
116 | diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c | ||
117 | index XXXXXXX..XXXXXXX 100644 | ||
118 | --- a/hw/scsi/scsi-generic.c | ||
119 | +++ b/hw/scsi/scsi-generic.c | ||
120 | @@ -XXX,XX +XXX,XX @@ static void scsi_command_complete(void *opaque, int ret) | ||
121 | SCSIGenericReq *r = (SCSIGenericReq *)opaque; | ||
122 | SCSIDevice *s = r->req.dev; | ||
123 | |||
124 | + aio_context_acquire(blk_get_aio_context(s->conf.blk)); | ||
125 | + | ||
126 | assert(r->req.aiocb != NULL); | ||
127 | r->req.aiocb = NULL; | ||
128 | |||
129 | - aio_context_acquire(blk_get_aio_context(s->conf.blk)); | ||
130 | scsi_command_complete_noio(r, ret); | ||
131 | aio_context_release(blk_get_aio_context(s->conf.blk)); | ||
132 | } | ||
133 | @@ -XXX,XX +XXX,XX @@ static void scsi_read_complete(void * opaque, int ret) | ||
134 | SCSIDevice *s = r->req.dev; | ||
135 | int len; | ||
136 | |||
137 | + aio_context_acquire(blk_get_aio_context(s->conf.blk)); | ||
138 | + | ||
139 | assert(r->req.aiocb != NULL); | ||
140 | r->req.aiocb = NULL; | ||
141 | |||
142 | - aio_context_acquire(blk_get_aio_context(s->conf.blk)); | ||
143 | - | ||
144 | if (ret || r->req.io_canceled) { | ||
145 | scsi_command_complete_noio(r, ret); | ||
146 | goto done; | ||
147 | @@ -XXX,XX +XXX,XX @@ static void scsi_write_complete(void * opaque, int ret) | ||
148 | |||
149 | trace_scsi_generic_write_complete(ret); | ||
150 | |||
151 | + aio_context_acquire(blk_get_aio_context(s->conf.blk)); | ||
152 | + | ||
153 | assert(r->req.aiocb != NULL); | ||
154 | r->req.aiocb = NULL; | ||
155 | |||
156 | - aio_context_acquire(blk_get_aio_context(s->conf.blk)); | ||
157 | - | ||
158 | if (ret || r->req.io_canceled) { | ||
159 | scsi_command_complete_noio(r, ret); | ||
160 | goto done; | ||
49 | -- | 161 | -- |
50 | 2.20.1 | 162 | 2.39.2 |
51 | |||
52 | diff view generated by jsdifflib |
1 | From: Alberto Garcia <berto@igalia.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This fixes a crash when attaching two disks with the same blockdev to | 3 | dma_blk_cb() only takes the AioContext lock around ->io_func(). That |
4 | a SCSI device that is using iothreads. Test case included. | 4 | means the rest of dma_blk_cb() is not protected. In particular, the |
5 | DMAAIOCB field accesses happen outside the lock. | ||
5 | 6 | ||
6 | Signed-off-by: Alberto Garcia <berto@igalia.com> | 7 | There is a race when the main loop thread holds the AioContext lock and |
8 | invokes scsi_device_purge_requests() -> bdrv_aio_cancel() -> | ||
9 | dma_aio_cancel() while an IOThread executes dma_blk_cb(). The dbs->acb | ||
10 | field determines how cancellation proceeds. If dma_aio_cancel() sees | ||
11 | dbs->acb == NULL while dma_blk_cb() is still running, the request can be | ||
12 | completed twice (-ECANCELED and the actual return value). | ||
13 | |||
14 | The following assertion can occur with virtio-scsi when an IOThread is | ||
15 | used: | ||
16 | |||
17 | ../hw/scsi/scsi-disk.c:368: scsi_dma_complete: Assertion `r->req.aiocb != NULL' failed. | ||
18 | |||
19 | Fix the race by holding the AioContext across dma_blk_cb(). Now | ||
20 | dma_aio_cancel() under the AioContext lock will not see | ||
21 | inconsistent/intermediate states. | ||
22 | |||
23 | Cc: Paolo Bonzini <pbonzini@redhat.com> | ||
24 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
25 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
26 | Message-Id: <20230221212218.1378734-3-stefanha@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 27 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
8 | --- | 28 | --- |
9 | hw/scsi/scsi-disk.c | 23 ++++++++++++++++++++--- | 29 | hw/scsi/scsi-disk.c | 4 +--- |
10 | tests/qemu-iotests/240 | 18 ++++++++++++++++++ | 30 | softmmu/dma-helpers.c | 12 +++++++----- |
11 | tests/qemu-iotests/240.out | 16 ++++++++++++++++ | 31 | 2 files changed, 8 insertions(+), 8 deletions(-) |
12 | 3 files changed, 54 insertions(+), 3 deletions(-) | ||
13 | 32 | ||
14 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c | 33 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c |
15 | index XXXXXXX..XXXXXXX 100644 | 34 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/hw/scsi/scsi-disk.c | 35 | --- a/hw/scsi/scsi-disk.c |
17 | +++ b/hw/scsi/scsi-disk.c | 36 | +++ b/hw/scsi/scsi-disk.c |
18 | @@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp) | 37 | @@ -XXX,XX +XXX,XX @@ done: |
19 | static void scsi_hd_realize(SCSIDevice *dev, Error **errp) | 38 | scsi_req_unref(&r->req); |
39 | } | ||
40 | |||
41 | +/* Called with AioContext lock held */ | ||
42 | static void scsi_dma_complete(void *opaque, int ret) | ||
20 | { | 43 | { |
21 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); | 44 | SCSIDiskReq *r = (SCSIDiskReq *)opaque; |
22 | + AioContext *ctx = NULL; | 45 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); |
23 | /* can happen for devices without drive. The error message for missing | 46 | |
24 | * backend will be issued in scsi_realize | 47 | - aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk)); |
25 | */ | 48 | - |
26 | if (s->qdev.conf.blk) { | 49 | assert(r->req.aiocb != NULL); |
27 | + ctx = blk_get_aio_context(s->qdev.conf.blk); | 50 | r->req.aiocb = NULL; |
28 | + aio_context_acquire(ctx); | 51 | |
29 | blkconf_blocksizes(&s->qdev.conf); | 52 | @@ -XXX,XX +XXX,XX @@ static void scsi_dma_complete(void *opaque, int ret) |
53 | block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct); | ||
30 | } | 54 | } |
31 | s->qdev.blocksize = s->qdev.conf.logical_block_size; | 55 | scsi_dma_complete_noio(r, ret); |
32 | @@ -XXX,XX +XXX,XX @@ static void scsi_hd_realize(SCSIDevice *dev, Error **errp) | 56 | - aio_context_release(blk_get_aio_context(s->qdev.conf.blk)); |
33 | s->product = g_strdup("QEMU HARDDISK"); | ||
34 | } | ||
35 | scsi_realize(&s->qdev, errp); | ||
36 | + if (ctx) { | ||
37 | + aio_context_release(ctx); | ||
38 | + } | ||
39 | } | 57 | } |
40 | 58 | ||
41 | static void scsi_cd_realize(SCSIDevice *dev, Error **errp) | 59 | static void scsi_read_complete_noio(SCSIDiskReq *r, int ret) |
60 | diff --git a/softmmu/dma-helpers.c b/softmmu/dma-helpers.c | ||
61 | index XXXXXXX..XXXXXXX 100644 | ||
62 | --- a/softmmu/dma-helpers.c | ||
63 | +++ b/softmmu/dma-helpers.c | ||
64 | @@ -XXX,XX +XXX,XX @@ static void dma_complete(DMAAIOCB *dbs, int ret) | ||
65 | static void dma_blk_cb(void *opaque, int ret) | ||
42 | { | 66 | { |
43 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); | 67 | DMAAIOCB *dbs = (DMAAIOCB *)opaque; |
44 | + AioContext *ctx; | 68 | + AioContext *ctx = dbs->ctx; |
45 | int ret; | 69 | dma_addr_t cur_addr, cur_len; |
46 | 70 | void *mem; | |
47 | if (!dev->conf.blk) { | 71 | |
48 | @@ -XXX,XX +XXX,XX @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp) | 72 | trace_dma_blk_cb(dbs, ret); |
49 | assert(ret == 0); | 73 | |
50 | } | ||
51 | |||
52 | + ctx = blk_get_aio_context(dev->conf.blk); | ||
53 | + aio_context_acquire(ctx); | 74 | + aio_context_acquire(ctx); |
54 | s->qdev.blocksize = 2048; | 75 | dbs->acb = NULL; |
55 | s->qdev.type = TYPE_ROM; | 76 | dbs->offset += dbs->iov.size; |
56 | s->features |= 1 << SCSI_DISK_F_REMOVABLE; | 77 | |
57 | @@ -XXX,XX +XXX,XX @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp) | 78 | if (dbs->sg_cur_index == dbs->sg->nsg || ret < 0) { |
58 | s->product = g_strdup("QEMU CD-ROM"); | 79 | dma_complete(dbs, ret); |
59 | } | ||
60 | scsi_realize(&s->qdev, errp); | ||
61 | + aio_context_release(ctx); | ||
62 | } | ||
63 | |||
64 | static void scsi_disk_realize(SCSIDevice *dev, Error **errp) | ||
65 | @@ -XXX,XX +XXX,XX @@ static int get_device_type(SCSIDiskState *s) | ||
66 | static void scsi_block_realize(SCSIDevice *dev, Error **errp) | ||
67 | { | ||
68 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); | ||
69 | + AioContext *ctx; | ||
70 | int sg_version; | ||
71 | int rc; | ||
72 | |||
73 | @@ -XXX,XX +XXX,XX @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) | ||
74 | "be removed in a future version"); | ||
75 | } | ||
76 | |||
77 | + ctx = blk_get_aio_context(s->qdev.conf.blk); | ||
78 | + aio_context_acquire(ctx); | ||
79 | + | ||
80 | /* check we are using a driver managing SG_IO (version 3 and after) */ | ||
81 | rc = blk_ioctl(s->qdev.conf.blk, SG_GET_VERSION_NUM, &sg_version); | ||
82 | if (rc < 0) { | ||
83 | @@ -XXX,XX +XXX,XX @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) | ||
84 | if (rc != -EPERM) { | ||
85 | error_append_hint(errp, "Is this a SCSI device?\n"); | ||
86 | } | ||
87 | - return; | 80 | - return; |
88 | + goto out; | 81 | + goto out; |
89 | } | 82 | } |
90 | if (sg_version < 30000) { | 83 | dma_blk_unmap(dbs); |
91 | error_setg(errp, "scsi generic interface too old"); | 84 | |
85 | @@ -XXX,XX +XXX,XX @@ static void dma_blk_cb(void *opaque, int ret) | ||
86 | |||
87 | if (dbs->iov.size == 0) { | ||
88 | trace_dma_map_wait(dbs); | ||
89 | - dbs->bh = aio_bh_new(dbs->ctx, reschedule_dma, dbs); | ||
90 | + dbs->bh = aio_bh_new(ctx, reschedule_dma, dbs); | ||
91 | cpu_register_map_client(dbs->bh); | ||
92 | - return; | 92 | - return; |
93 | + goto out; | 93 | + goto out; |
94 | } | 94 | } |
95 | 95 | ||
96 | /* get device type from INQUIRY data */ | 96 | if (!QEMU_IS_ALIGNED(dbs->iov.size, dbs->align)) { |
97 | rc = get_device_type(s); | 97 | @@ -XXX,XX +XXX,XX @@ static void dma_blk_cb(void *opaque, int ret) |
98 | if (rc < 0) { | 98 | QEMU_ALIGN_DOWN(dbs->iov.size, dbs->align)); |
99 | error_setg(errp, "INQUIRY failed"); | ||
100 | - return; | ||
101 | + goto out; | ||
102 | } | 99 | } |
103 | 100 | ||
104 | /* Make a guess for the block size, we'll fix it when the guest sends. | 101 | - aio_context_acquire(dbs->ctx); |
105 | @@ -XXX,XX +XXX,XX @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) | 102 | dbs->acb = dbs->io_func(dbs->offset, &dbs->iov, |
106 | 103 | dma_blk_cb, dbs, dbs->io_func_opaque); | |
107 | scsi_realize(&s->qdev, errp); | 104 | - aio_context_release(dbs->ctx); |
108 | scsi_generic_read_device_inquiry(&s->qdev); | 105 | assert(dbs->acb); |
109 | + | ||
110 | +out: | 106 | +out: |
111 | + aio_context_release(ctx); | 107 | + aio_context_release(ctx); |
112 | } | 108 | } |
113 | 109 | ||
114 | typedef struct SCSIBlockReq { | 110 | static void dma_aio_cancel(BlockAIOCB *acb) |
115 | diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240 | ||
116 | index XXXXXXX..XXXXXXX 100755 | ||
117 | --- a/tests/qemu-iotests/240 | ||
118 | +++ b/tests/qemu-iotests/240 | ||
119 | @@ -XXX,XX +XXX,XX @@ run_qemu <<EOF | ||
120 | { "execute": "quit"} | ||
121 | EOF | ||
122 | |||
123 | +echo | ||
124 | +echo === Attach two SCSI disks using the same block device and the same iothread === | ||
125 | +echo | ||
126 | + | ||
127 | +run_qemu <<EOF | ||
128 | +{ "execute": "qmp_capabilities" } | ||
129 | +{ "execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true}} | ||
130 | +{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread0"}} | ||
131 | +{ "execute": "device_add", "arguments": {"id": "scsi0", "driver": "${virtio_scsi}", "iothread": "iothread0"}} | ||
132 | +{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0"}} | ||
133 | +{ "execute": "device_add", "arguments": {"id": "scsi-hd1", "driver": "scsi-hd", "drive": "hd0"}} | ||
134 | +{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}} | ||
135 | +{ "execute": "device_del", "arguments": {"id": "scsi-hd1"}} | ||
136 | +{ "execute": "device_del", "arguments": {"id": "scsi0"}} | ||
137 | +{ "execute": "blockdev-del", "arguments": {"node-name": "hd0"}} | ||
138 | +{ "execute": "quit"} | ||
139 | +EOF | ||
140 | + | ||
141 | # success, all done | ||
142 | echo "*** done" | ||
143 | rm -f $seq.full | ||
144 | diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out | ||
145 | index XXXXXXX..XXXXXXX 100644 | ||
146 | --- a/tests/qemu-iotests/240.out | ||
147 | +++ b/tests/qemu-iotests/240.out | ||
148 | @@ -XXX,XX +XXX,XX @@ QA output created by 240 | ||
149 | |||
150 | === Unplug a SCSI disk and then plug it again === | ||
151 | |||
152 | +Testing: | ||
153 | +QMP_VERSION | ||
154 | +{"return": {}} | ||
155 | +{"return": {}} | ||
156 | +{"return": {}} | ||
157 | +{"return": {}} | ||
158 | +{"return": {}} | ||
159 | +{"return": {}} | ||
160 | +{"return": {}} | ||
161 | +{"return": {}} | ||
162 | +{"return": {}} | ||
163 | +{"return": {}} | ||
164 | +{"return": {}} | ||
165 | + | ||
166 | +=== Attach two SCSI disks using the same block device and the same iothread === | ||
167 | + | ||
168 | Testing: | ||
169 | QMP_VERSION | ||
170 | {"return": {}} | ||
171 | -- | 111 | -- |
172 | 2.20.1 | 112 | 2.39.2 |
173 | |||
174 | diff view generated by jsdifflib |
1 | From: Alberto Garcia <berto@igalia.com> | 1 | From: Stefan Hajnoczi <stefanha@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This fixes a crash when attaching a disk to a SCSI device using | 3 | When an IOThread is configured, the ctrl virtqueue is processed in the |
4 | iothreads, then detaching it and reattaching it again. Test case | 4 | IOThread. TMFs that reset SCSI devices are currently called directly |
5 | included. | 5 | from the IOThread and trigger an assertion failure in blk_drain() from |
6 | 6 | the following call stack: | |
7 | Signed-off-by: Alberto Garcia <berto@igalia.com> | 7 | |
8 | virtio_scsi_handle_ctrl_req -> virtio_scsi_do_tmf -> device_code_reset | ||
9 | -> scsi_disk_reset -> scsi_device_purge_requests -> blk_drain | ||
10 | |||
11 | ../block/block-backend.c:1780: void blk_drain(BlockBackend *): Assertion `qemu_in_main_thread()' failed. | ||
12 | |||
13 | The blk_drain() function is not designed to be called from an IOThread | ||
14 | because it needs the Big QEMU Lock (BQL). | ||
15 | |||
16 | This patch defers TMFs that reset SCSI devices to a Bottom Half (BH) | ||
17 | that runs in the main loop thread under the BQL. This way it's safe to | ||
18 | call blk_drain() and the assertion failure is avoided. | ||
19 | |||
20 | Introduce s->tmf_bh_list for tracking TMF requests that have been | ||
21 | deferred to the BH. When the BH runs it will grab the entire list and | ||
22 | process all requests. Care must be taken to clear the list when the | ||
23 | virtio-scsi device is reset or unrealized. Otherwise deferred TMF | ||
24 | requests could execute later and lead to use-after-free or other | ||
25 | undefined behavior. | ||
26 | |||
27 | The s->resetting counter that's used by TMFs that reset SCSI devices is | ||
28 | accessed from multiple threads. This patch makes that explicit by using | ||
29 | atomic accessor functions. With this patch applied the counter is only | ||
30 | modified by the main loop thread under the BQL but can be read by any | ||
31 | thread. | ||
32 | |||
33 | Reported-by: Qing Wang <qinwang@redhat.com> | ||
34 | Cc: Paolo Bonzini <pbonzini@redhat.com> | ||
35 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
36 | Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
37 | Message-Id: <20230221212218.1378734-4-stefanha@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 38 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | --- | 39 | --- |
10 | hw/scsi/virtio-scsi.c | 6 +++ | 40 | include/hw/virtio/virtio-scsi.h | 11 ++- |
11 | tests/qemu-iotests/240 | 89 ++++++++++++++++++++++++++++++++++++++ | 41 | hw/scsi/virtio-scsi.c | 169 +++++++++++++++++++++++++------- |
12 | tests/qemu-iotests/240.out | 18 ++++++++ | 42 | 2 files changed, 143 insertions(+), 37 deletions(-) |
13 | tests/qemu-iotests/group | 1 + | 43 | |
14 | 4 files changed, 114 insertions(+) | 44 | diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h |
15 | create mode 100755 tests/qemu-iotests/240 | 45 | index XXXXXXX..XXXXXXX 100644 |
16 | create mode 100644 tests/qemu-iotests/240.out | 46 | --- a/include/hw/virtio/virtio-scsi.h |
17 | 47 | +++ b/include/hw/virtio/virtio-scsi.h | |
48 | @@ -XXX,XX +XXX,XX @@ struct VirtIOSCSICommon { | ||
49 | VirtQueue **cmd_vqs; | ||
50 | }; | ||
51 | |||
52 | +struct VirtIOSCSIReq; | ||
53 | + | ||
54 | struct VirtIOSCSI { | ||
55 | VirtIOSCSICommon parent_obj; | ||
56 | |||
57 | SCSIBus bus; | ||
58 | - int resetting; | ||
59 | + int resetting; /* written from main loop thread, read from any thread */ | ||
60 | bool events_dropped; | ||
61 | |||
62 | + /* | ||
63 | + * TMFs deferred to main loop BH. These fields are protected by | ||
64 | + * virtio_scsi_acquire(). | ||
65 | + */ | ||
66 | + QEMUBH *tmf_bh; | ||
67 | + QTAILQ_HEAD(, VirtIOSCSIReq) tmf_bh_list; | ||
68 | + | ||
69 | /* Fields for dataplane below */ | ||
70 | AioContext *ctx; /* one iothread per virtio-scsi-pci for now */ | ||
71 | |||
18 | diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c | 72 | diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c |
19 | index XXXXXXX..XXXXXXX 100644 | 73 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/hw/scsi/virtio-scsi.c | 74 | --- a/hw/scsi/virtio-scsi.c |
21 | +++ b/hw/scsi/virtio-scsi.c | 75 | +++ b/hw/scsi/virtio-scsi.c |
22 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev, | 76 | @@ -XXX,XX +XXX,XX @@ typedef struct VirtIOSCSIReq { |
23 | virtio_scsi_release(s); | 77 | QEMUSGList qsgl; |
78 | QEMUIOVector resp_iov; | ||
79 | |||
80 | - union { | ||
81 | - /* Used for two-stage request submission */ | ||
82 | - QTAILQ_ENTRY(VirtIOSCSIReq) next; | ||
83 | + /* Used for two-stage request submission and TMFs deferred to BH */ | ||
84 | + QTAILQ_ENTRY(VirtIOSCSIReq) next; | ||
85 | |||
86 | - /* Used for cancellation of request during TMFs */ | ||
87 | - int remaining; | ||
88 | - }; | ||
89 | + /* Used for cancellation of request during TMFs */ | ||
90 | + int remaining; | ||
91 | |||
92 | SCSIRequest *sreq; | ||
93 | size_t resp_size; | ||
94 | @@ -XXX,XX +XXX,XX @@ static inline void virtio_scsi_ctx_check(VirtIOSCSI *s, SCSIDevice *d) | ||
24 | } | 95 | } |
25 | |||
26 | + if (s->ctx) { | ||
27 | + virtio_scsi_acquire(s); | ||
28 | + blk_set_aio_context(sd->conf.blk, qemu_get_aio_context()); | ||
29 | + virtio_scsi_release(s); | ||
30 | + } | ||
31 | + | ||
32 | qdev_simple_device_unplug_cb(hotplug_dev, dev, errp); | ||
33 | } | 96 | } |
34 | 97 | ||
35 | diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240 | 98 | +static void virtio_scsi_do_one_tmf_bh(VirtIOSCSIReq *req) |
36 | new file mode 100755 | ||
37 | index XXXXXXX..XXXXXXX | ||
38 | --- /dev/null | ||
39 | +++ b/tests/qemu-iotests/240 | ||
40 | @@ -XXX,XX +XXX,XX @@ | ||
41 | +#!/bin/bash | ||
42 | +# | ||
43 | +# Test hot plugging and unplugging with iothreads | ||
44 | +# | ||
45 | +# Copyright (C) 2019 Igalia, S.L. | ||
46 | +# Author: Alberto Garcia <berto@igalia.com> | ||
47 | +# | ||
48 | +# This program is free software; you can redistribute it and/or modify | ||
49 | +# it under the terms of the GNU General Public License as published by | ||
50 | +# the Free Software Foundation; either version 2 of the License, or | ||
51 | +# (at your option) any later version. | ||
52 | +# | ||
53 | +# This program is distributed in the hope that it will be useful, | ||
54 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
55 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
56 | +# GNU General Public License for more details. | ||
57 | +# | ||
58 | +# You should have received a copy of the GNU General Public License | ||
59 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
60 | +# | ||
61 | + | ||
62 | +# creator | ||
63 | +owner=berto@igalia.com | ||
64 | + | ||
65 | +seq=`basename $0` | ||
66 | +echo "QA output created by $seq" | ||
67 | + | ||
68 | +status=1 # failure is the default! | ||
69 | + | ||
70 | +# get standard environment, filters and checks | ||
71 | +. ./common.rc | ||
72 | +. ./common.filter | ||
73 | + | ||
74 | +_supported_fmt generic | ||
75 | +_supported_proto generic | ||
76 | +_supported_os Linux | ||
77 | + | ||
78 | +do_run_qemu() | ||
79 | +{ | 99 | +{ |
80 | + echo Testing: "$@" | 100 | + VirtIOSCSI *s = req->dev; |
81 | + $QEMU -nographic -qmp stdio -serial none "$@" | 101 | + SCSIDevice *d = virtio_scsi_device_get(s, req->req.tmf.lun); |
82 | + echo | 102 | + BusChild *kid; |
103 | + int target; | ||
104 | + | ||
105 | + switch (req->req.tmf.subtype) { | ||
106 | + case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET: | ||
107 | + if (!d) { | ||
108 | + req->resp.tmf.response = VIRTIO_SCSI_S_BAD_TARGET; | ||
109 | + goto out; | ||
110 | + } | ||
111 | + if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) { | ||
112 | + req->resp.tmf.response = VIRTIO_SCSI_S_INCORRECT_LUN; | ||
113 | + goto out; | ||
114 | + } | ||
115 | + qatomic_inc(&s->resetting); | ||
116 | + device_cold_reset(&d->qdev); | ||
117 | + qatomic_dec(&s->resetting); | ||
118 | + break; | ||
119 | + | ||
120 | + case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: | ||
121 | + target = req->req.tmf.lun[1]; | ||
122 | + qatomic_inc(&s->resetting); | ||
123 | + | ||
124 | + rcu_read_lock(); | ||
125 | + QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) { | ||
126 | + SCSIDevice *d1 = SCSI_DEVICE(kid->child); | ||
127 | + if (d1->channel == 0 && d1->id == target) { | ||
128 | + device_cold_reset(&d1->qdev); | ||
129 | + } | ||
130 | + } | ||
131 | + rcu_read_unlock(); | ||
132 | + | ||
133 | + qatomic_dec(&s->resetting); | ||
134 | + break; | ||
135 | + | ||
136 | + default: | ||
137 | + g_assert_not_reached(); | ||
138 | + break; | ||
139 | + } | ||
140 | + | ||
141 | +out: | ||
142 | + object_unref(OBJECT(d)); | ||
143 | + | ||
144 | + virtio_scsi_acquire(s); | ||
145 | + virtio_scsi_complete_req(req); | ||
146 | + virtio_scsi_release(s); | ||
83 | +} | 147 | +} |
84 | + | 148 | + |
85 | +# Remove QMP events from (pretty-printed) output. Doesn't handle | 149 | +/* Some TMFs must be processed from the main loop thread */ |
86 | +# nested dicts correctly, but we don't get any of those in this test. | 150 | +static void virtio_scsi_do_tmf_bh(void *opaque) |
87 | +_filter_qmp_events() | ||
88 | +{ | 151 | +{ |
89 | + tr '\n' '\t' | sed -e \ | 152 | + VirtIOSCSI *s = opaque; |
90 | + 's/{\s*"timestamp":\s*{[^}]*},\s*"event":[^,}]*\(,\s*"data":\s*{[^}]*}\)\?\s*}\s*//g' \ | 153 | + QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); |
91 | + | tr '\t' '\n' | 154 | + VirtIOSCSIReq *req; |
155 | + VirtIOSCSIReq *tmp; | ||
156 | + | ||
157 | + GLOBAL_STATE_CODE(); | ||
158 | + | ||
159 | + virtio_scsi_acquire(s); | ||
160 | + | ||
161 | + QTAILQ_FOREACH_SAFE(req, &s->tmf_bh_list, next, tmp) { | ||
162 | + QTAILQ_REMOVE(&s->tmf_bh_list, req, next); | ||
163 | + QTAILQ_INSERT_TAIL(&reqs, req, next); | ||
164 | + } | ||
165 | + | ||
166 | + qemu_bh_delete(s->tmf_bh); | ||
167 | + s->tmf_bh = NULL; | ||
168 | + | ||
169 | + virtio_scsi_release(s); | ||
170 | + | ||
171 | + QTAILQ_FOREACH_SAFE(req, &reqs, next, tmp) { | ||
172 | + QTAILQ_REMOVE(&reqs, req, next); | ||
173 | + virtio_scsi_do_one_tmf_bh(req); | ||
174 | + } | ||
92 | +} | 175 | +} |
93 | + | 176 | + |
94 | +run_qemu() | 177 | +static void virtio_scsi_reset_tmf_bh(VirtIOSCSI *s) |
95 | +{ | 178 | +{ |
96 | + do_run_qemu "$@" 2>&1 | _filter_qmp | _filter_qmp_events | 179 | + VirtIOSCSIReq *req; |
180 | + VirtIOSCSIReq *tmp; | ||
181 | + | ||
182 | + GLOBAL_STATE_CODE(); | ||
183 | + | ||
184 | + virtio_scsi_acquire(s); | ||
185 | + | ||
186 | + if (s->tmf_bh) { | ||
187 | + qemu_bh_delete(s->tmf_bh); | ||
188 | + s->tmf_bh = NULL; | ||
189 | + } | ||
190 | + | ||
191 | + QTAILQ_FOREACH_SAFE(req, &s->tmf_bh_list, next, tmp) { | ||
192 | + QTAILQ_REMOVE(&s->tmf_bh_list, req, next); | ||
193 | + | ||
194 | + /* SAM-6 6.3.2 Hard reset */ | ||
195 | + req->resp.tmf.response = VIRTIO_SCSI_S_TARGET_FAILURE; | ||
196 | + virtio_scsi_complete_req(req); | ||
197 | + } | ||
198 | + | ||
199 | + virtio_scsi_release(s); | ||
97 | +} | 200 | +} |
98 | + | 201 | + |
99 | +case "$QEMU_DEFAULT_MACHINE" in | 202 | +static void virtio_scsi_defer_tmf_to_bh(VirtIOSCSIReq *req) |
100 | + s390-ccw-virtio) | 203 | +{ |
101 | + virtio_scsi=virtio-scsi-ccw | 204 | + VirtIOSCSI *s = req->dev; |
102 | + ;; | 205 | + |
103 | + *) | 206 | + QTAILQ_INSERT_TAIL(&s->tmf_bh_list, req, next); |
104 | + virtio_scsi=virtio-scsi-pci | 207 | + |
105 | + ;; | 208 | + if (!s->tmf_bh) { |
106 | +esac | 209 | + s->tmf_bh = qemu_bh_new(virtio_scsi_do_tmf_bh, s); |
107 | + | 210 | + qemu_bh_schedule(s->tmf_bh); |
108 | +echo | 211 | + } |
109 | +echo === Unplug a SCSI disk and then plug it again === | 212 | +} |
110 | +echo | 213 | + |
111 | + | 214 | /* Return 0 if the request is ready to be completed and return to guest; |
112 | +run_qemu <<EOF | 215 | * -EINPROGRESS if the request is submitted and will be completed later, in the |
113 | +{ "execute": "qmp_capabilities" } | 216 | * case of async cancellation. */ |
114 | +{ "execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0"}} | 217 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) |
115 | +{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread0"}} | 218 | { |
116 | +{ "execute": "device_add", "arguments": {"id": "scsi0", "driver": "${virtio_scsi}", "iothread": "iothread0"}} | 219 | SCSIDevice *d = virtio_scsi_device_get(s, req->req.tmf.lun); |
117 | +{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0"}} | 220 | SCSIRequest *r, *next; |
118 | +{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}} | 221 | - BusChild *kid; |
119 | +{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0"}} | 222 | - int target; |
120 | +{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}} | 223 | int ret = 0; |
121 | +{ "execute": "device_del", "arguments": {"id": "scsi0"}} | 224 | |
122 | +{ "execute": "blockdev-del", "arguments": {"node-name": "hd0"}} | 225 | virtio_scsi_ctx_check(s, d); |
123 | +{ "execute": "quit"} | 226 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) |
124 | +EOF | 227 | break; |
125 | + | 228 | |
126 | +# success, all done | 229 | case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET: |
127 | +echo "*** done" | 230 | - if (!d) { |
128 | +rm -f $seq.full | 231 | - goto fail; |
129 | +status=0 | 232 | - } |
130 | diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out | 233 | - if (d->lun != virtio_scsi_get_lun(req->req.tmf.lun)) { |
131 | new file mode 100644 | 234 | - goto incorrect_lun; |
132 | index XXXXXXX..XXXXXXX | 235 | - } |
133 | --- /dev/null | 236 | - s->resetting++; |
134 | +++ b/tests/qemu-iotests/240.out | 237 | - device_cold_reset(&d->qdev); |
135 | @@ -XXX,XX +XXX,XX @@ | 238 | - s->resetting--; |
136 | +QA output created by 240 | 239 | + case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: |
137 | + | 240 | + virtio_scsi_defer_tmf_to_bh(req); |
138 | +=== Unplug a SCSI disk and then plug it again === | 241 | + ret = -EINPROGRESS; |
139 | + | 242 | break; |
140 | +Testing: | 243 | |
141 | +QMP_VERSION | 244 | case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET: |
142 | +{"return": {}} | 245 | @@ -XXX,XX +XXX,XX @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) |
143 | +{"return": {}} | 246 | } |
144 | +{"return": {}} | 247 | break; |
145 | +{"return": {}} | 248 | |
146 | +{"return": {}} | 249 | - case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: |
147 | +{"return": {}} | 250 | - target = req->req.tmf.lun[1]; |
148 | +{"return": {}} | 251 | - s->resetting++; |
149 | +{"return": {}} | 252 | - |
150 | +{"return": {}} | 253 | - rcu_read_lock(); |
151 | +{"return": {}} | 254 | - QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) { |
152 | +{"return": {}} | 255 | - SCSIDevice *d1 = SCSI_DEVICE(kid->child); |
153 | +*** done | 256 | - if (d1->channel == 0 && d1->id == target) { |
154 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | 257 | - device_cold_reset(&d1->qdev); |
155 | index XXXXXXX..XXXXXXX 100644 | 258 | - } |
156 | --- a/tests/qemu-iotests/group | 259 | - } |
157 | +++ b/tests/qemu-iotests/group | 260 | - rcu_read_unlock(); |
158 | @@ -XXX,XX +XXX,XX @@ | 261 | - |
159 | 237 rw auto quick | 262 | - s->resetting--; |
160 | 238 auto quick | 263 | - break; |
161 | 239 rw auto quick | 264 | - |
162 | +240 auto quick | 265 | case VIRTIO_SCSI_T_TMF_CLEAR_ACA: |
266 | default: | ||
267 | req->resp.tmf.response = VIRTIO_SCSI_S_FUNCTION_REJECTED; | ||
268 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_request_cancelled(SCSIRequest *r) | ||
269 | if (!req) { | ||
270 | return; | ||
271 | } | ||
272 | - if (req->dev->resetting) { | ||
273 | + if (qatomic_read(&req->dev->resetting)) { | ||
274 | req->resp.cmd.response = VIRTIO_SCSI_S_RESET; | ||
275 | } else { | ||
276 | req->resp.cmd.response = VIRTIO_SCSI_S_ABORTED; | ||
277 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_reset(VirtIODevice *vdev) | ||
278 | VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); | ||
279 | |||
280 | assert(!s->dataplane_started); | ||
281 | - s->resetting++; | ||
282 | + | ||
283 | + virtio_scsi_reset_tmf_bh(s); | ||
284 | + | ||
285 | + qatomic_inc(&s->resetting); | ||
286 | bus_cold_reset(BUS(&s->bus)); | ||
287 | - s->resetting--; | ||
288 | + qatomic_dec(&s->resetting); | ||
289 | |||
290 | vs->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE; | ||
291 | vs->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE; | ||
292 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) | ||
293 | VirtIOSCSI *s = VIRTIO_SCSI(dev); | ||
294 | Error *err = NULL; | ||
295 | |||
296 | + QTAILQ_INIT(&s->tmf_bh_list); | ||
297 | + | ||
298 | virtio_scsi_common_realize(dev, | ||
299 | virtio_scsi_handle_ctrl, | ||
300 | virtio_scsi_handle_event, | ||
301 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_device_unrealize(DeviceState *dev) | ||
302 | { | ||
303 | VirtIOSCSI *s = VIRTIO_SCSI(dev); | ||
304 | |||
305 | + virtio_scsi_reset_tmf_bh(s); | ||
306 | + | ||
307 | qbus_set_hotplug_handler(BUS(&s->bus), NULL); | ||
308 | virtio_scsi_common_unrealize(dev); | ||
309 | } | ||
163 | -- | 310 | -- |
164 | 2.20.1 | 311 | 2.39.2 |
165 | |||
166 | diff view generated by jsdifflib |
1 | From: yuchenlin <npes87184@gmail.com> | 1 | From: Or Ozeri <oro@il.ibm.com> |
---|---|---|---|
2 | 2 | ||
3 | Recently, some bugs in dmg file have been fixed. To prevent reading dmg | 3 | Signed-off-by: Or Ozeri <oro@il.ibm.com> |
4 | is broken someday in the future, add a simple test which ensures the | 4 | Message-Id: <20230129113120.722708-2-oro@oro.sl.cloud9.ibm.com> |
5 | conversion from dmg to raw should not hang or face any I/O error. | 5 | Reviewed-by: Ilya Dryomov <idryomov@gmail.com> |
6 | 6 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | |
7 | Signed-off-by: yuchenlin <npes87184@gmail.com> | ||
8 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
10 | --- | 8 | --- |
11 | tests/qemu-iotests/239 | 53 ++++++++++++++++++ | 9 | block/rbd.c | 16 ++++++---------- |
12 | tests/qemu-iotests/239.out | 4 ++ | 10 | 1 file changed, 6 insertions(+), 10 deletions(-) |
13 | tests/qemu-iotests/check | 7 +++ | ||
14 | tests/qemu-iotests/group | 1 + | ||
15 | .../sample_images/simple-dmg.dmg.bz2 | Bin 0 -> 3479 bytes | ||
16 | 5 files changed, 65 insertions(+) | ||
17 | create mode 100755 tests/qemu-iotests/239 | ||
18 | create mode 100644 tests/qemu-iotests/239.out | ||
19 | create mode 100644 tests/qemu-iotests/sample_images/simple-dmg.dmg.bz2 | ||
20 | 11 | ||
21 | diff --git a/tests/qemu-iotests/239 b/tests/qemu-iotests/239 | 12 | diff --git a/block/rbd.c b/block/rbd.c |
22 | new file mode 100755 | ||
23 | index XXXXXXX..XXXXXXX | ||
24 | --- /dev/null | ||
25 | +++ b/tests/qemu-iotests/239 | ||
26 | @@ -XXX,XX +XXX,XX @@ | ||
27 | +#!/bin/bash | ||
28 | +# | ||
29 | +# Test case for dmg | ||
30 | +# | ||
31 | +# Copyright (C) 2019 yuchenlin <npes87184@gmail.com> | ||
32 | +# | ||
33 | +# This program is free software; you can redistribute it and/or modify | ||
34 | +# it under the terms of the GNU General Public License as published by | ||
35 | +# the Free Software Foundation; either version 2 of the License, or | ||
36 | +# (at your option) any later version. | ||
37 | +# | ||
38 | +# This program is distributed in the hope that it will be useful, | ||
39 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
40 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
41 | +# GNU General Public License for more details. | ||
42 | +# | ||
43 | +# You should have received a copy of the GNU General Public License | ||
44 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
45 | +# | ||
46 | + | ||
47 | +# creator | ||
48 | +owner=npes87184@gmail.com | ||
49 | + | ||
50 | +seq=`basename $0` | ||
51 | +echo "QA output created by $seq" | ||
52 | + | ||
53 | +status=1 # failure is the default! | ||
54 | + | ||
55 | +_cleanup() | ||
56 | +{ | ||
57 | + rm -f "$TEST_IMG.raw" | ||
58 | + _cleanup_test_img | ||
59 | +} | ||
60 | +trap "_cleanup; exit \$status" 0 1 2 3 15 | ||
61 | + | ||
62 | +# get standard environment, filters and checks | ||
63 | +. ./common.rc | ||
64 | + | ||
65 | +_supported_fmt dmg | ||
66 | +_supported_proto file | ||
67 | +_supported_os Linux | ||
68 | + | ||
69 | +echo | ||
70 | +echo "== Testing conversion to raw should success ==" | ||
71 | +_use_sample_img simple-dmg.dmg.bz2 | ||
72 | +if ! $QEMU_IMG convert -f $IMGFMT -O raw "$TEST_IMG" "$TEST_IMG.raw" ; then | ||
73 | + exit 1 | ||
74 | +fi | ||
75 | + | ||
76 | +# success, all done | ||
77 | +echo "*** done" | ||
78 | +rm -f $seq.full | ||
79 | +status=0 | ||
80 | diff --git a/tests/qemu-iotests/239.out b/tests/qemu-iotests/239.out | ||
81 | new file mode 100644 | ||
82 | index XXXXXXX..XXXXXXX | ||
83 | --- /dev/null | ||
84 | +++ b/tests/qemu-iotests/239.out | ||
85 | @@ -XXX,XX +XXX,XX @@ | ||
86 | +QA output created by 239 | ||
87 | + | ||
88 | +== Testing conversion to raw should success == | ||
89 | +*** done | ||
90 | diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check | ||
91 | index XXXXXXX..XXXXXXX 100755 | ||
92 | --- a/tests/qemu-iotests/check | ||
93 | +++ b/tests/qemu-iotests/check | ||
94 | @@ -XXX,XX +XXX,XX @@ image format options | ||
95 | -vhdx test vhdx | ||
96 | -vmdk test vmdk | ||
97 | -luks test luks | ||
98 | + -dmg test dmg | ||
99 | |||
100 | image protocol options | ||
101 | -file test file (default) | ||
102 | @@ -XXX,XX +XXX,XX @@ testlist options | ||
103 | xpand=false | ||
104 | ;; | ||
105 | |||
106 | + -dmg) | ||
107 | + IMGFMT=dmg | ||
108 | + IMGFMT_GENERIC=false | ||
109 | + xpand=false | ||
110 | + ;; | ||
111 | + | ||
112 | -qed) | ||
113 | IMGFMT=qed | ||
114 | xpand=false | ||
115 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
116 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
117 | --- a/tests/qemu-iotests/group | 14 | --- a/block/rbd.c |
118 | +++ b/tests/qemu-iotests/group | 15 | +++ b/block/rbd.c |
119 | @@ -XXX,XX +XXX,XX @@ | 16 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_format(rbd_image_t image, |
120 | 235 auto quick | 17 | { |
121 | 236 auto quick | 18 | int r = 0; |
122 | 238 auto quick | 19 | g_autofree char *passphrase = NULL; |
123 | +239 rw auto quick | 20 | - size_t passphrase_len; |
124 | diff --git a/tests/qemu-iotests/sample_images/simple-dmg.dmg.bz2 b/tests/qemu-iotests/sample_images/simple-dmg.dmg.bz2 | 21 | rbd_encryption_format_t format; |
125 | new file mode 100644 | 22 | rbd_encryption_options_t opts; |
126 | index XXXXXXX..XXXXXXX | 23 | rbd_encryption_luks1_format_options_t luks_opts; |
127 | GIT binary patch | 24 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_format(rbd_image_t image, |
128 | literal 3479 | 25 | opts_size = sizeof(luks_opts); |
129 | zcmV;I4QTR0T4*^jL0KkKS(36)s{k7pfB*mg|NsC0|NsC0|NsC0|NsC0|Ns5}|NsC0 | 26 | r = qemu_rbd_convert_luks_create_options( |
130 | z|NsC0|Nr0#eji@i`+e|w_jjtUioUNn9=bhi?FYz+8lea^Pt`n6Q`GfM=uI^|rccqR | 27 | qapi_RbdEncryptionCreateOptionsLUKS_base(&encrypt->u.luks), |
131 | z#)^4QQ(&j0^vx-<6U8+BMo&{rPgMO9KU6<bdYee{L&A*HX-%dfJg1{mX^f|mdZ(%S | 28 | - &luks_opts.alg, &passphrase, &passphrase_len, errp); |
132 | zYHDfZWgn$BPgL<R4Jqj~+M0TvOq0bPDe8Glf++<WdYU|=X+1Rn(<i9%Lp2zh4IZY3 | 29 | + &luks_opts.alg, &passphrase, &luks_opts.passphrase_size, |
133 | zjXgCzA?gg9Q$~!`&}h@t^qy1H^iL_WjXgCzK-!HSQ%^=sO&L8COn}g7>K>tx+G-x7 | 30 | + errp); |
134 | zKxhH7gFqfr)EbhWqfmN7Xqi0_(|U$T%^~Te(<9O!s(P57)gFnX(HMqCnW^apCLkWB | 31 | if (r < 0) { |
135 | zfB?c`7=Y8$P|yP*p{9YL8X6e}jSLZ{Kmat*Y9I=F1s<p9DB4Cq^#`bE4Ff^74GlCj | 32 | return r; |
136 | z05tUmngG$D8fXFP0MPXVMoj}i&;S4$8UdgN)B`|zgFpae5-JoYqMnhSqz_5zX!RaX | 33 | } |
137 | zN@?n8p`%8PJdIB%dW@MKrbdHIo}+1?O{io&O{DTNL5K|i44$J2gHSf0dW_JG15ZRS | 34 | luks_opts.passphrase = passphrase; |
138 | zO#>jv(V%IjnFNxA1T<(7k~Y;aPez3F!fB&IWZEW%)byHqn^PtYN0c*2G<pJPF%2|& | 35 | - luks_opts.passphrase_size = passphrase_len; |
139 | zjXg~oX{V%Vqb8bZplqPgw1%2w9-*VtQR*}r00xGQ4G24kA+jG=o`xW*WTQp80#*@D | 36 | break; |
140 | zGI^@e0Fq218g7gWKQ0-!!d?<+0Zg$VQi&#k#L$@->*ZllN2a;wYb5Z@K!FpiLKS04 | 37 | } |
141 | zAXF_RNbYzNTvjprs6=NSa4=(xVBCm>1#>twBnc>5NRuJv+UXVcw)$K?45Ra5gMtys | 38 | case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: { |
142 | z5#=tTi{6o_Dolm>AW0*9z$7i33Gt*7^pYSUXUfIy=|9=(Y5F2D)W#);#I!)dBq)W~ | 39 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_format(rbd_image_t image, |
143 | zrFlJ*pf<%<p!?|?K4A)WKmn>vEyY-2j;_z6FzSi8mQn!dfdGLU#z+u}O%{xk@FlI` | 40 | r = qemu_rbd_convert_luks_create_options( |
144 | z^B@Tz!-52v0~!WxwY>yM5j2L!wDW07lb>SjKuGF1Bv7*3#(>;&j=WH?%<2(%C(%mi | 41 | qapi_RbdEncryptionCreateOptionsLUKS2_base( |
145 | z3SK&{tsN6|F+h=$fRF|SAT&YV;=$CM8UPyf&KPGXD@;hw?Ie+ur$Ms`<R|DnF>?n= | 42 | &encrypt->u.luks2), |
146 | z=TVuCRg<`%CTS#rC3Rqi{8+-#G7{}$If&w>{u-}tqnXQGZ1vrDn(W+-ydtwD_5(m9 | 43 | - &luks2_opts.alg, &passphrase, &passphrase_len, errp); |
147 | zUlJm4YF$|a547Ok)VNY_1&|O<rL!z~wcz}tQxE~Dj4cXB5;0mM5(lt%*IA;POn}RT | 44 | + &luks2_opts.alg, &passphrase, &luks2_opts.passphrase_size, |
148 | z;6QRRmFhId9Am|k#g{Q@hX6cXxi&WKM_|eXL97PF^DAB*Vbz~zQKTvZ??`1m>?|T) | 45 | + errp); |
149 | z42v8J{j@}JBoR7501!b0TQLa}5=%fGiZ01vc2PsfW3IL_R4y29^38$G<bvvm5nFd0 | 46 | if (r < 0) { |
150 | zCwO?LU{=bViG0S0Zh^;{@n#!Kdu|V}*6A@n-bN2myQ=@_`vaVL_~0ObLdRRH{)&n2 | 47 | return r; |
151 | zWjQqZq-v&|Sm)GU$5#3E-aM@MWEDTSJ=WXyvX!Ka^MIpH)wR_6>N@}eFEu8;#~W3O | 48 | } |
152 | zhYo*p2)1qo0FWCdNC$P6JWDI)lRL3RsCq~;CddNVfDeUAK|}zQbl`V}JlvEcUSn8M | 49 | luks2_opts.passphrase = passphrase; |
153 | zpVIf%kFZ>u>OO0J!nRehCj34b&G%X*%F`iNsN=6_pV&CdsRu0CM-x>qqFshZ5Cm<o | 50 | - luks2_opts.passphrase_size = passphrase_len; |
154 | zjS+4gAk-oc*IeI*Cm4uELVya|XwQV9;aJZ7Mzx<=On?m(0@tY~UQVHbY{wZn;D)7@ | 51 | break; |
155 | z(k#N&X0YCEm2rAN!X56ASS+#z7ao9>#cE(tAoIY<O8RkL;gL@lE`rM`9JnB2CEx^z | 52 | } |
156 | z6c8i@0n%FhZje3Zxg#iF@R@T1Isa_wb*LjCgn+!DWDcYQh#WxZLepa#PQjgE{rMz? | 53 | default: { |
157 | zBq1<j2VVpX$Xd;K6V+q_hhHJtdWTbjuPi#R=(f&lykmQl$pDZgP%wm~nI*Ni#z^FO | 54 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image, |
158 | zE-eT!OaQHD1y1DHB8`9}p<+T&reFk;4s}MH%)0IXH1auiL(e%0z#SY_Q4bA>;2;n; | 55 | { |
159 | z>6lWK8VC|iQ`TBT@eh_haUvW?s0F~|jWOEDBrNGaBoJh|LX9lsM4vqVlOYszX7pdA | 56 | int r = 0; |
160 | z{D&2t%ysWP&xa%2Q6LEk#Gf-=1UdvZ5a1%=kY@b_PJ?B`u>CaLI&B7em_7b|;n=Za | 57 | g_autofree char *passphrase = NULL; |
161 | zp~fR)pUI5+fvC#Km(lVCNpb=XW#mzCYrKf$7gM(TqYzYBKqz54qqz-xcv$fGQrdYy | 58 | - size_t passphrase_len; |
162 | zRD%pqsY(=-5JXlPYst2Xv=#sccTUb6A-KFq8XNZ`G)4wExi9zHxBO=zO;AbFM}`M! | 59 | rbd_encryption_luks1_format_options_t luks_opts; |
163 | zOk?+aXaO;H02oI0Bn>Mv09F(z2D>5BS#O#$P6Hjd6boVGU|fj(_>6Wj@RrKIn;8EB | 60 | rbd_encryption_luks2_format_options_t luks2_opts; |
164 | zble1^sy2Z1#DvynHzELF0f+`WC;nB6;l*sYRsG&{OT)PkEN{C-fC@>voA`)pYKBGR | 61 | rbd_encryption_format_t format; |
165 | zy0qd5hS(-IOAKl(iXY}a|K}p1?TmbyuKT-Qeer)gFKD88^Tpxr*kmLy;0FL}C&d#` | 62 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image, |
166 | zQ|v00fv3#W*mSyZs|-K<h+d6pNO}MT^KN@JOgvk`m2@p1X~U$!#uswfANXB%a*2}d | 63 | opts_size = sizeof(luks_opts); |
167 | zwEVT6lZMv@K`D!LB_I^fo)latwZp8vy|3yBt&R41ACiQf!d~t-ftA7uBb30|`l#aR | 64 | r = qemu_rbd_convert_luks_options( |
168 | zSAZd~7y#5rmLOyX5*DtKB=1^~pw$7YjAzU-OkBe`h(K#GCV;6Q6}-9*#6ZQEesARr | 65 | qapi_RbdEncryptionOptionsLUKS_base(&encrypt->u.luks), |
169 | zwQh_HsY@9IS)I<~d1n7@4@41T%tXY@5h1NOcGB0n$$P2^q!Iwg96-Ypa~Me&Mkg03 | 66 | - &passphrase, &passphrase_len, errp); |
170 | zx4>{zsMn+fmSxpq9<;PGzUke*7{Vc;ba?~~Fp@>uleN{!WoS8VmG%z%nuX9{w6QC^ | 67 | + &passphrase, &luks_opts.passphrase_size, errp); |
171 | z>cY}_BnH5wp)m6ur<d4axiRctR|XVPR-dd0=6w1P3>Z5+Eu`$-#pj&flXy9V9wq!p | 68 | if (r < 0) { |
172 | zo^)}9fQDYjW6Ab;cYA9~3Cm@szFUBpm=2bWB#w0?id*4t_2g7y|0*g1ylSPW9s834 | 69 | return r; |
173 | ztjELX^xWJGpL*3Qc>%uRKQna>8~ayaq=0g~k?u90E|+R&pb}xi6sAxgk{0I9Tdk7g | 70 | } |
174 | zC&mCT7%%O`$bs$IGS?S?7$DVck$e==@QS_=nF(o3(InF7Dn=3k=Ls-^Fw9D7{(U3k | 71 | luks_opts.passphrase = passphrase; |
175 | zK*%{w#OE;-n}5J@QnW~k0W^>q6Frr!p|88#+Wy;ioe~<*h=i%&J;)%alO@Pegg+7j | 72 | - luks_opts.passphrase_size = passphrase_len; |
176 | zs``QTeEyD)x7p(92)N`E@8T8H#s^c%*24OW;aGvPuVQef*wBsRpU@6A_g9zdDt9$k | 73 | break; |
177 | z2zRm#rdLi0A^}Fb?sXZ{X@%WaZzShTNF-5=Fu)3i@t^qa`TwT<VRADXi9j*Cww!Bk | 74 | } |
178 | z$ofZn`qc*}gV@O>ucE88qh>EN`Jdw+s*<*u-@$9+o1#_6XJ989lqI=az!E}P5riY* | 75 | case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: { |
179 | zHPwYH$BT`e?rVGc3nGpD(|bD_E!3{ti_*;NZZ0isXL2=SVRX$Ti~X!dedY#W1K<$# | 76 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image, |
180 | zh_IvD035p;=Ek~DC$}ZJd(G3-dd#k6CG#xgT;mmS6+SLid1tQO-9<Sl@O^GuLUz-u | 77 | opts_size = sizeof(luks2_opts); |
181 | z417&euHAlM4ypAfeUp|&``-9llf#`5`nX06abKLfN@~l%nAq{U{u*UfSI+fFc$+Nq | 78 | r = qemu_rbd_convert_luks_options( |
182 | zjSkQ*mer2Rs5nuStK%0w;knBzMKh|{QO!^DPwP)t^4~w3qnO*hZDo{4^>~P#9iv%f | 79 | qapi_RbdEncryptionOptionsLUKS2_base(&encrypt->u.luks2), |
183 | zd!`qvbczBF)AAe0yE+WI*}DYOL2J~*ZCc}JWiu0LShw&6`-5`^SkNJY!gsi|e-MHy | 80 | - &passphrase, &passphrase_len, errp); |
184 | zZlN9Lb5NbuT7S&4oY6v}13BpeQ|?u0c*7n)Ku*p%ZDF?$7zjKXj(9#K?tO1dMW=8& | 81 | + &passphrase, &luks2_opts.passphrase_size, errp); |
185 | z;MDsGo0=CLWp{b5$Kk0kxAl*^l^ziX<28c4->Ed%#N16IrySH$q`4%gn}5ksr>_0H | 82 | if (r < 0) { |
186 | zs-;Y4Bb7U_pNGMK075wJ%DahB2ArR=jC`2UWMe`ID;mPgA25l6GVc9>Rqybi7N6(i | 83 | return r; |
187 | z3BcjbfprP7Ivcy%+Vs~Z6Hw>JB!kJcD>mdTThTpO$(fg`Ds7pY<YTYWgmqU8=Xlve | 84 | } |
188 | zCriGy+iG;z+{{27v*;>N4BN<|%(+#T+h1sdgPjUAWN73ki+$-%j_&6PZ$I2$HnSEa | 85 | luks2_opts.passphrase = passphrase; |
189 | zQ?n{BB*A3zmlLHvH@o+ZJm1NSC9(?ka<7OppIcAi{V`Nj+^8SL!ywYLI$v(ivC_){ | 86 | - luks2_opts.passphrase_size = passphrase_len; |
190 | z5anb)=MQS%<PN>hUHR@_HKDhdDPf*Hm`w^E{GT!Yq<}Hg8Ia{?PyA70;yx8nD^~B| | 87 | break; |
191 | zjuGESS<A^!S2=(y_Dz2Z3)U+>*z1(bcT1?|;LuVOg&xLebEk(1uB(fZJN&W3!xADj | 88 | } |
192 | zQD;ugVYYpOt=NBu$Bi07WcepgHm6q}1y>vxs^oJetK;=ix$9i9M#>O`?6X2pJoXi; | 89 | default: { |
193 | z#0mlFG2eK~z-yqErVC2`l5B&)s}jKZMRZxCyQ0^?cp$L5J>4{eoCysx+#X0J?r^+C | ||
194 | z#R8d5A5=5V#(QMr1?kT}qh|eQ8{a94K6_Sq=vcWz&WH@!TREj$F3%=NwMQ3YR-$or | ||
195 | zlXmr#8-D_(N;#e;g#CE1WYh8byF-ojSdtGh>P8pbz39Ew5qWHa^1-M77ji{7P>_<c | ||
196 | FP^-7hd6WPE | ||
197 | |||
198 | literal 0 | ||
199 | HcmV?d00001 | ||
200 | |||
201 | -- | 90 | -- |
202 | 2.20.1 | 91 | 2.39.2 |
203 | |||
204 | diff view generated by jsdifflib |
1 | From: Fam Zheng <famz@redhat.com> | 1 | From: Or Ozeri <oro@il.ibm.com> |
---|---|---|---|
2 | 2 | ||
3 | This makes VMDK support blockdev-create. The implementation reuses the | 3 | Ceph RBD encryption API required specifying the encryption format |
4 | image creation code in vmdk_co_create_opts which now acceptes a callback | 4 | for loading encryption. The supported formats were LUKS (v1) and LUKS2. |
5 | pointer to "retrieve" BlockBackend pointers from the caller. This way we | ||
6 | separate the logic between file/extent acquisition and initialization. | ||
7 | 5 | ||
8 | The QAPI command parameters are mostly the same as the old create_opts | 6 | Starting from Reef release, RBD also supports loading with "luks-any" format, |
9 | except the dropped legacy @compat6 switch, which is redundant with | 7 | which works for both versions of LUKS. |
10 | @hwversion. | ||
11 | 8 | ||
12 | Signed-off-by: Fam Zheng <famz@redhat.com> | 9 | This commit extends the qemu rbd driver API to enable qemu users to use |
13 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | 10 | this luks-any wildcard format. |
11 | |||
12 | Signed-off-by: Or Ozeri <oro@il.ibm.com> | ||
13 | Message-Id: <20230129113120.722708-3-oro@oro.sl.cloud9.ibm.com> | ||
14 | Reviewed-by: Ilya Dryomov <idryomov@gmail.com> | ||
15 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 16 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
15 | --- | 17 | --- |
16 | qapi/block-core.json | 70 +++++++ | 18 | qapi/block-core.json | 16 ++++++++++++++-- |
17 | qapi/qapi-schema.json | 16 +- | 19 | block/rbd.c | 19 +++++++++++++++++++ |
18 | block/vmdk.c | 448 ++++++++++++++++++++++++++++++------------ | 20 | 2 files changed, 33 insertions(+), 2 deletions(-) |
19 | 3 files changed, 400 insertions(+), 134 deletions(-) | ||
20 | 21 | ||
21 | diff --git a/qapi/block-core.json b/qapi/block-core.json | 22 | diff --git a/qapi/block-core.json b/qapi/block-core.json |
22 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
23 | --- a/qapi/block-core.json | 24 | --- a/qapi/block-core.json |
24 | +++ b/qapi/block-core.json | 25 | +++ b/qapi/block-core.json |
25 | @@ -XXX,XX +XXX,XX @@ | 26 | @@ -XXX,XX +XXX,XX @@ |
26 | 'size': 'size', | 27 | ## |
27 | '*cluster-size' : 'size' } } | 28 | # @RbdImageEncryptionFormat: |
29 | # | ||
30 | +# @luks-any: Used for opening either luks or luks2 (Since 8.0) | ||
31 | +# | ||
32 | # Since: 6.1 | ||
33 | ## | ||
34 | { 'enum': 'RbdImageEncryptionFormat', | ||
35 | - 'data': [ 'luks', 'luks2' ] } | ||
36 | + 'data': [ 'luks', 'luks2', 'luks-any' ] } | ||
37 | |||
38 | ## | ||
39 | # @RbdEncryptionOptionsLUKSBase: | ||
40 | @@ -XXX,XX +XXX,XX @@ | ||
41 | 'base': 'RbdEncryptionOptionsLUKSBase', | ||
42 | 'data': { } } | ||
28 | 43 | ||
29 | +## | 44 | +## |
30 | +# @BlockdevVmdkSubformat: | 45 | +# @RbdEncryptionOptionsLUKSAny: |
31 | +# | 46 | +# |
32 | +# Subformat options for VMDK images | 47 | +# Since: 8.0 |
33 | +# | ||
34 | +# @monolithicSparse: Single file image with sparse cluster allocation | ||
35 | +# | ||
36 | +# @monolithicFlat: Single flat data image and a descriptor file | ||
37 | +# | ||
38 | +# @twoGbMaxExtentSparse: Data is split into 2GB (per virtual LBA) sparse extent | ||
39 | +# files, in addition to a descriptor file | ||
40 | +# | ||
41 | +# @twoGbMaxExtentFlat: Data is split into 2GB (per virtual LBA) flat extent | ||
42 | +# files, in addition to a descriptor file | ||
43 | +# | ||
44 | +# @streamOptimized: Single file image sparse cluster allocation, optimized | ||
45 | +# for streaming over network. | ||
46 | +# | ||
47 | +# Since: 4.0 | ||
48 | +## | 48 | +## |
49 | +{ 'enum': 'BlockdevVmdkSubformat', | 49 | +{ 'struct': 'RbdEncryptionOptionsLUKSAny', |
50 | + 'data': [ 'monolithicSparse', 'monolithicFlat', 'twoGbMaxExtentSparse', | 50 | + 'base': 'RbdEncryptionOptionsLUKSBase', |
51 | + 'twoGbMaxExtentFlat', 'streamOptimized'] } | 51 | + 'data': { } } |
52 | + | ||
53 | +## | ||
54 | +# @BlockdevVmdkAdapterType: | ||
55 | +# | ||
56 | +# Adapter type info for VMDK images | ||
57 | +# | ||
58 | +# Since: 4.0 | ||
59 | +## | ||
60 | +{ 'enum': 'BlockdevVmdkAdapterType', | ||
61 | + 'data': [ 'ide', 'buslogic', 'lsilogic', 'legacyESX'] } | ||
62 | + | ||
63 | +## | ||
64 | +# @BlockdevCreateOptionsVmdk: | ||
65 | +# | ||
66 | +# Driver specific image creation options for VMDK. | ||
67 | +# | ||
68 | +# @file Where to store the new image file. This refers to the image | ||
69 | +# file for monolithcSparse and streamOptimized format, or the | ||
70 | +# descriptor file for other formats. | ||
71 | +# @size Size of the virtual disk in bytes | ||
72 | +# @extents Where to store the data extents. Required for monolithcFlat, | ||
73 | +# twoGbMaxExtentSparse and twoGbMaxExtentFlat formats. For | ||
74 | +# monolithicFlat, only one entry is required; for | ||
75 | +# twoGbMaxExtent* formats, the number of entries required is | ||
76 | +# calculated as extent_number = virtual_size / 2GB. | ||
77 | +# @subformat The subformat of the VMDK image. Default: "monolithicSparse". | ||
78 | +# @backing-file The path of backing file. Default: no backing file is used. | ||
79 | +# @adapter-type The adapter type used to fill in the descriptor. Default: ide. | ||
80 | +# @hwversion Hardware version. The meaningful options are "4" or "6". | ||
81 | +# Default: "4". | ||
82 | +# @zeroed-grain Whether to enable zeroed-grain feature for sparse subformats. | ||
83 | +# Default: false. | ||
84 | +# | ||
85 | +# Since: 4.0 | ||
86 | +## | ||
87 | +{ 'struct': 'BlockdevCreateOptionsVmdk', | ||
88 | + 'data': { 'file': 'BlockdevRef', | ||
89 | + 'size': 'size', | ||
90 | + '*extents': ['BlockdevRef'], | ||
91 | + '*subformat': 'BlockdevVmdkSubformat', | ||
92 | + '*backing-file': 'str', | ||
93 | + '*adapter-type': 'BlockdevVmdkAdapterType', | ||
94 | + '*hwversion': 'str', | ||
95 | + '*zeroed-grain': 'bool' } } | ||
96 | + | ||
97 | + | 52 | + |
98 | ## | 53 | ## |
99 | # @SheepdogRedundancyType: | 54 | # @RbdEncryptionCreateOptionsLUKS: |
100 | # | 55 | # |
101 | @@ -XXX,XX +XXX,XX @@ | 56 | @@ -XXX,XX +XXX,XX @@ |
102 | 'ssh': 'BlockdevCreateOptionsSsh', | 57 | 'base': { 'format': 'RbdImageEncryptionFormat' }, |
103 | 'vdi': 'BlockdevCreateOptionsVdi', | 58 | 'discriminator': 'format', |
104 | 'vhdx': 'BlockdevCreateOptionsVhdx', | 59 | 'data': { 'luks': 'RbdEncryptionOptionsLUKS', |
105 | + 'vmdk': 'BlockdevCreateOptionsVmdk', | 60 | - 'luks2': 'RbdEncryptionOptionsLUKS2' } } |
106 | 'vpc': 'BlockdevCreateOptionsVpc' | 61 | + 'luks2': 'RbdEncryptionOptionsLUKS2', |
107 | } } | 62 | + 'luks-any': 'RbdEncryptionOptionsLUKSAny'} } |
108 | 63 | ||
109 | diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json | 64 | ## |
65 | # @RbdEncryptionCreateOptions: | ||
66 | diff --git a/block/rbd.c b/block/rbd.c | ||
110 | index XXXXXXX..XXXXXXX 100644 | 67 | index XXXXXXX..XXXXXXX 100644 |
111 | --- a/qapi/qapi-schema.json | 68 | --- a/block/rbd.c |
112 | +++ b/qapi/qapi-schema.json | 69 | +++ b/block/rbd.c |
113 | @@ -XXX,XX +XXX,XX @@ | 70 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image, |
114 | 'query-tpm-types', | 71 | g_autofree char *passphrase = NULL; |
115 | 'ringbuf-read' ], | 72 | rbd_encryption_luks1_format_options_t luks_opts; |
116 | 'name-case-whitelist': [ | 73 | rbd_encryption_luks2_format_options_t luks2_opts; |
117 | - 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status | 74 | +#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2 |
118 | - 'CpuInfoMIPS', # PC, visible through query-cpu | 75 | + rbd_encryption_luks_format_options_t luks_any_opts; |
119 | - 'CpuInfoTricore', # PC, visible through query-cpu | 76 | +#endif |
120 | - 'QapiErrorClass', # all members, visible through errors | 77 | rbd_encryption_format_t format; |
121 | - 'UuidInfo', # UUID, visible through query-uuid | 78 | rbd_encryption_options_t opts; |
122 | - 'X86CPURegister32', # all members, visible indirectly through qom-get | 79 | size_t opts_size; |
123 | - 'q_obj_CpuInfo-base' # CPU, visible through query-cpu | 80 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image, |
124 | + 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status | 81 | luks2_opts.passphrase = passphrase; |
125 | + 'CpuInfoMIPS', # PC, visible through query-cpu | 82 | break; |
126 | + 'CpuInfoTricore', # PC, visible through query-cpu | ||
127 | + 'BlockdevVmdkSubformat', # all members, to match VMDK spec spellings | ||
128 | + 'BlockdevVmdkAdapterType', # legacyESX, to match VMDK spec spellings | ||
129 | + 'QapiErrorClass', # all members, visible through errors | ||
130 | + 'UuidInfo', # UUID, visible through query-uuid | ||
131 | + 'X86CPURegister32', # all members, visible indirectly through qom-get | ||
132 | + 'q_obj_CpuInfo-base' # CPU, visible through query-cpu | ||
133 | ] } } | ||
134 | |||
135 | # Documentation generated with qapi-gen.py is in source order, with | ||
136 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
137 | index XXXXXXX..XXXXXXX 100644 | ||
138 | --- a/block/vmdk.c | ||
139 | +++ b/block/vmdk.c | ||
140 | @@ -XXX,XX +XXX,XX @@ static int filename_decompose(const char *filename, char *path, char *prefix, | ||
141 | return VMDK_OK; | ||
142 | } | ||
143 | |||
144 | -static int coroutine_fn vmdk_co_create_opts(const char *filename, QemuOpts *opts, | ||
145 | - Error **errp) | ||
146 | +/* | ||
147 | + * idx == 0: get or create the descriptor file (also the image file if in a | ||
148 | + * non-split format. | ||
149 | + * idx >= 1: get the n-th extent if in a split subformat | ||
150 | + */ | ||
151 | +typedef BlockBackend *(*vmdk_create_extent_fn)(int64_t size, | ||
152 | + int idx, | ||
153 | + bool flat, | ||
154 | + bool split, | ||
155 | + bool compress, | ||
156 | + bool zeroed_grain, | ||
157 | + void *opaque, | ||
158 | + Error **errp); | ||
159 | + | ||
160 | +static void vmdk_desc_add_extent(GString *desc, | ||
161 | + const char *extent_line_fmt, | ||
162 | + int64_t size, const char *filename) | ||
163 | +{ | ||
164 | + char *basename = g_path_get_basename(filename); | ||
165 | + | ||
166 | + g_string_append_printf(desc, extent_line_fmt, | ||
167 | + DIV_ROUND_UP(size, BDRV_SECTOR_SIZE), basename); | ||
168 | + g_free(basename); | ||
169 | +} | ||
170 | + | ||
171 | +static int coroutine_fn vmdk_co_do_create(int64_t size, | ||
172 | + BlockdevVmdkSubformat subformat, | ||
173 | + BlockdevVmdkAdapterType adapter_type, | ||
174 | + const char *backing_file, | ||
175 | + const char *hw_version, | ||
176 | + bool compat6, | ||
177 | + bool zeroed_grain, | ||
178 | + vmdk_create_extent_fn extent_fn, | ||
179 | + void *opaque, | ||
180 | + Error **errp) | ||
181 | { | ||
182 | - int idx = 0; | ||
183 | - BlockBackend *new_blk = NULL; | ||
184 | + int extent_idx; | ||
185 | + BlockBackend *blk = NULL; | ||
186 | Error *local_err = NULL; | ||
187 | char *desc = NULL; | ||
188 | - int64_t total_size = 0, filesize; | ||
189 | - char *adapter_type = NULL; | ||
190 | - char *backing_file = NULL; | ||
191 | - char *hw_version = NULL; | ||
192 | - char *fmt = NULL; | ||
193 | int ret = 0; | ||
194 | bool flat, split, compress; | ||
195 | GString *ext_desc_lines; | ||
196 | - char *path = g_malloc0(PATH_MAX); | ||
197 | - char *prefix = g_malloc0(PATH_MAX); | ||
198 | - char *postfix = g_malloc0(PATH_MAX); | ||
199 | - char *desc_line = g_malloc0(BUF_SIZE); | ||
200 | - char *ext_filename = g_malloc0(PATH_MAX); | ||
201 | - char *desc_filename = g_malloc0(PATH_MAX); | ||
202 | const int64_t split_size = 0x80000000; /* VMDK has constant split size */ | ||
203 | - const char *desc_extent_line; | ||
204 | + int64_t extent_size; | ||
205 | + int64_t created_size = 0; | ||
206 | + const char *extent_line_fmt; | ||
207 | char *parent_desc_line = g_malloc0(BUF_SIZE); | ||
208 | uint32_t parent_cid = 0xffffffff; | ||
209 | uint32_t number_heads = 16; | ||
210 | - bool zeroed_grain = false; | ||
211 | uint32_t desc_offset = 0, desc_len; | ||
212 | const char desc_template[] = | ||
213 | "# Disk DescriptorFile\n" | ||
214 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_create_opts(const char *filename, QemuOpts *opts | ||
215 | |||
216 | ext_desc_lines = g_string_new(NULL); | ||
217 | |||
218 | - if (filename_decompose(filename, path, prefix, postfix, PATH_MAX, errp)) { | ||
219 | - ret = -EINVAL; | ||
220 | - goto exit; | ||
221 | - } | ||
222 | /* Read out options */ | ||
223 | - total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), | ||
224 | - BDRV_SECTOR_SIZE); | ||
225 | - adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE); | ||
226 | - backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); | ||
227 | - hw_version = qemu_opt_get_del(opts, BLOCK_OPT_HWVERSION); | ||
228 | - if (qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false)) { | ||
229 | - if (strcmp(hw_version, "undefined")) { | ||
230 | + if (compat6) { | ||
231 | + if (hw_version) { | ||
232 | error_setg(errp, | ||
233 | "compat6 cannot be enabled with hwversion set"); | ||
234 | ret = -EINVAL; | ||
235 | goto exit; | ||
236 | } | 83 | } |
237 | - g_free(hw_version); | 84 | +#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2 |
238 | - hw_version = g_strdup("6"); | 85 | + case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY: { |
239 | - } | 86 | + memset(&luks_any_opts, 0, sizeof(luks_any_opts)); |
240 | - if (strcmp(hw_version, "undefined") == 0) { | 87 | + format = RBD_ENCRYPTION_FORMAT_LUKS; |
241 | - g_free(hw_version); | 88 | + opts = &luks_any_opts; |
242 | - hw_version = g_strdup("4"); | 89 | + opts_size = sizeof(luks_any_opts); |
243 | + hw_version = "6"; | 90 | + r = qemu_rbd_convert_luks_options( |
244 | } | 91 | + qapi_RbdEncryptionOptionsLUKSAny_base(&encrypt->u.luks_any), |
245 | - fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); | 92 | + &passphrase, &luks_any_opts.passphrase_size, errp); |
246 | - if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false)) { | 93 | + if (r < 0) { |
247 | - zeroed_grain = true; | 94 | + return r; |
248 | + if (!hw_version) { | 95 | + } |
249 | + hw_version = "4"; | 96 | + luks_any_opts.passphrase = passphrase; |
250 | } | 97 | + break; |
251 | |||
252 | - if (!adapter_type) { | ||
253 | - adapter_type = g_strdup("ide"); | ||
254 | - } else if (strcmp(adapter_type, "ide") && | ||
255 | - strcmp(adapter_type, "buslogic") && | ||
256 | - strcmp(adapter_type, "lsilogic") && | ||
257 | - strcmp(adapter_type, "legacyESX")) { | ||
258 | - error_setg(errp, "Unknown adapter type: '%s'", adapter_type); | ||
259 | - ret = -EINVAL; | ||
260 | - goto exit; | ||
261 | - } | ||
262 | - if (strcmp(adapter_type, "ide") != 0) { | ||
263 | + if (adapter_type != BLOCKDEV_VMDK_ADAPTER_TYPE_IDE) { | ||
264 | /* that's the number of heads with which vmware operates when | ||
265 | creating, exporting, etc. vmdk files with a non-ide adapter type */ | ||
266 | number_heads = 255; | ||
267 | } | ||
268 | - if (!fmt) { | ||
269 | - /* Default format to monolithicSparse */ | ||
270 | - fmt = g_strdup("monolithicSparse"); | ||
271 | - } else if (strcmp(fmt, "monolithicFlat") && | ||
272 | - strcmp(fmt, "monolithicSparse") && | ||
273 | - strcmp(fmt, "twoGbMaxExtentSparse") && | ||
274 | - strcmp(fmt, "twoGbMaxExtentFlat") && | ||
275 | - strcmp(fmt, "streamOptimized")) { | ||
276 | - error_setg(errp, "Unknown subformat: '%s'", fmt); | ||
277 | - ret = -EINVAL; | ||
278 | - goto exit; | ||
279 | - } | ||
280 | - split = !(strcmp(fmt, "twoGbMaxExtentFlat") && | ||
281 | - strcmp(fmt, "twoGbMaxExtentSparse")); | ||
282 | - flat = !(strcmp(fmt, "monolithicFlat") && | ||
283 | - strcmp(fmt, "twoGbMaxExtentFlat")); | ||
284 | - compress = !strcmp(fmt, "streamOptimized"); | ||
285 | + split = (subformat == BLOCKDEV_VMDK_SUBFORMAT_TWOGBMAXEXTENTFLAT) || | ||
286 | + (subformat == BLOCKDEV_VMDK_SUBFORMAT_TWOGBMAXEXTENTSPARSE); | ||
287 | + flat = (subformat == BLOCKDEV_VMDK_SUBFORMAT_MONOLITHICFLAT) || | ||
288 | + (subformat == BLOCKDEV_VMDK_SUBFORMAT_TWOGBMAXEXTENTFLAT); | ||
289 | + compress = subformat == BLOCKDEV_VMDK_SUBFORMAT_STREAMOPTIMIZED; | ||
290 | + | ||
291 | if (flat) { | ||
292 | - desc_extent_line = "RW %" PRId64 " FLAT \"%s\" 0\n"; | ||
293 | + extent_line_fmt = "RW %" PRId64 " FLAT \"%s\" 0\n"; | ||
294 | } else { | ||
295 | - desc_extent_line = "RW %" PRId64 " SPARSE \"%s\"\n"; | ||
296 | + extent_line_fmt = "RW %" PRId64 " SPARSE \"%s\"\n"; | ||
297 | } | ||
298 | if (flat && backing_file) { | ||
299 | error_setg(errp, "Flat image can't have backing file"); | ||
300 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_create_opts(const char *filename, QemuOpts *opts | ||
301 | ret = -ENOTSUP; | ||
302 | goto exit; | ||
303 | } | ||
304 | + | ||
305 | + /* Create extents */ | ||
306 | + if (split) { | ||
307 | + extent_size = split_size; | ||
308 | + } else { | ||
309 | + extent_size = size; | ||
310 | + } | ||
311 | + if (!split && !flat) { | ||
312 | + created_size = extent_size; | ||
313 | + } else { | ||
314 | + created_size = 0; | ||
315 | + } | ||
316 | + /* Get the descriptor file BDS */ | ||
317 | + blk = extent_fn(created_size, 0, flat, split, compress, zeroed_grain, | ||
318 | + opaque, errp); | ||
319 | + if (!blk) { | ||
320 | + ret = -EIO; | ||
321 | + goto exit; | ||
322 | + } | ||
323 | + if (!split && !flat) { | ||
324 | + vmdk_desc_add_extent(ext_desc_lines, extent_line_fmt, created_size, | ||
325 | + blk_bs(blk)->filename); | ||
326 | + } | ||
327 | + | ||
328 | if (backing_file) { | ||
329 | - BlockBackend *blk; | ||
330 | + BlockBackend *backing; | ||
331 | char *full_backing = g_new0(char, PATH_MAX); | ||
332 | - bdrv_get_full_backing_filename_from_filename(filename, backing_file, | ||
333 | + bdrv_get_full_backing_filename_from_filename(blk_bs(blk)->filename, backing_file, | ||
334 | full_backing, PATH_MAX, | ||
335 | &local_err); | ||
336 | if (local_err) { | ||
337 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_create_opts(const char *filename, QemuOpts *opts | ||
338 | goto exit; | ||
339 | } | ||
340 | |||
341 | - blk = blk_new_open(full_backing, NULL, NULL, | ||
342 | - BDRV_O_NO_BACKING, errp); | ||
343 | + backing = blk_new_open(full_backing, NULL, NULL, | ||
344 | + BDRV_O_NO_BACKING, errp); | ||
345 | g_free(full_backing); | ||
346 | - if (blk == NULL) { | ||
347 | + if (backing == NULL) { | ||
348 | ret = -EIO; | ||
349 | goto exit; | ||
350 | } | ||
351 | - if (strcmp(blk_bs(blk)->drv->format_name, "vmdk")) { | ||
352 | - blk_unref(blk); | ||
353 | + if (strcmp(blk_bs(backing)->drv->format_name, "vmdk")) { | ||
354 | + error_setg(errp, "Invalid backing file format: %s. Must be vmdk", | ||
355 | + blk_bs(backing)->drv->format_name); | ||
356 | + blk_unref(backing); | ||
357 | ret = -EINVAL; | ||
358 | goto exit; | ||
359 | } | ||
360 | - ret = vmdk_read_cid(blk_bs(blk), 0, &parent_cid); | ||
361 | - blk_unref(blk); | ||
362 | + ret = vmdk_read_cid(blk_bs(backing), 0, &parent_cid); | ||
363 | + blk_unref(backing); | ||
364 | if (ret) { | ||
365 | + error_setg(errp, "Failed to read parent CID"); | ||
366 | goto exit; | ||
367 | } | ||
368 | snprintf(parent_desc_line, BUF_SIZE, | ||
369 | "parentFileNameHint=\"%s\"", backing_file); | ||
370 | } | ||
371 | - | ||
372 | - /* Create extents */ | ||
373 | - filesize = total_size; | ||
374 | - while (filesize > 0) { | ||
375 | - int64_t size = filesize; | ||
376 | - | ||
377 | - if (split && size > split_size) { | ||
378 | - size = split_size; | ||
379 | - } | ||
380 | - if (split) { | ||
381 | - snprintf(desc_filename, PATH_MAX, "%s-%c%03d%s", | ||
382 | - prefix, flat ? 'f' : 's', ++idx, postfix); | ||
383 | - } else if (flat) { | ||
384 | - snprintf(desc_filename, PATH_MAX, "%s-flat%s", prefix, postfix); | ||
385 | - } else { | ||
386 | - snprintf(desc_filename, PATH_MAX, "%s%s", prefix, postfix); | ||
387 | - } | ||
388 | - snprintf(ext_filename, PATH_MAX, "%s%s", path, desc_filename); | ||
389 | - | ||
390 | - if (vmdk_create_extent(ext_filename, size, | ||
391 | - flat, compress, zeroed_grain, NULL, opts, errp)) { | ||
392 | + extent_idx = 1; | ||
393 | + while (created_size < size) { | ||
394 | + BlockBackend *extent_blk; | ||
395 | + int64_t cur_size = MIN(size - created_size, extent_size); | ||
396 | + extent_blk = extent_fn(cur_size, extent_idx, flat, split, compress, | ||
397 | + zeroed_grain, opaque, errp); | ||
398 | + if (!extent_blk) { | ||
399 | ret = -EINVAL; | ||
400 | goto exit; | ||
401 | } | ||
402 | - filesize -= size; | ||
403 | - | ||
404 | - /* Format description line */ | ||
405 | - snprintf(desc_line, BUF_SIZE, | ||
406 | - desc_extent_line, size / BDRV_SECTOR_SIZE, desc_filename); | ||
407 | - g_string_append(ext_desc_lines, desc_line); | ||
408 | + vmdk_desc_add_extent(ext_desc_lines, extent_line_fmt, cur_size, | ||
409 | + blk_bs(extent_blk)->filename); | ||
410 | + created_size += cur_size; | ||
411 | + extent_idx++; | ||
412 | + blk_unref(extent_blk); | ||
413 | } | ||
414 | /* generate descriptor file */ | ||
415 | desc = g_strdup_printf(desc_template, | ||
416 | g_random_int(), | ||
417 | parent_cid, | ||
418 | - fmt, | ||
419 | + BlockdevVmdkSubformat_str(subformat), | ||
420 | parent_desc_line, | ||
421 | ext_desc_lines->str, | ||
422 | hw_version, | ||
423 | - total_size / | ||
424 | + size / | ||
425 | (int64_t)(63 * number_heads * BDRV_SECTOR_SIZE), | ||
426 | number_heads, | ||
427 | - adapter_type); | ||
428 | + BlockdevVmdkAdapterType_str(adapter_type)); | ||
429 | desc_len = strlen(desc); | ||
430 | /* the descriptor offset = 0x200 */ | ||
431 | if (!split && !flat) { | ||
432 | desc_offset = 0x200; | ||
433 | - } else { | ||
434 | - ret = bdrv_create_file(filename, opts, &local_err); | ||
435 | + } | ||
436 | + | ||
437 | + ret = blk_pwrite(blk, desc_offset, desc, desc_len, 0); | ||
438 | + if (ret < 0) { | ||
439 | + error_setg_errno(errp, -ret, "Could not write description"); | ||
440 | + goto exit; | ||
441 | + } | ||
442 | + /* bdrv_pwrite write padding zeros to align to sector, we don't need that | ||
443 | + * for description file */ | ||
444 | + if (desc_offset == 0) { | ||
445 | + ret = blk_truncate(blk, desc_len, PREALLOC_MODE_OFF, errp); | ||
446 | if (ret < 0) { | ||
447 | - error_propagate(errp, local_err); | ||
448 | goto exit; | ||
449 | } | ||
450 | } | ||
451 | + ret = 0; | ||
452 | +exit: | ||
453 | + if (blk) { | ||
454 | + blk_unref(blk); | ||
455 | + } | ||
456 | + g_free(desc); | ||
457 | + g_free(parent_desc_line); | ||
458 | + g_string_free(ext_desc_lines, true); | ||
459 | + return ret; | ||
460 | +} | ||
461 | |||
462 | - new_blk = blk_new_open(filename, NULL, NULL, | ||
463 | - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, | ||
464 | - &local_err); | ||
465 | - if (new_blk == NULL) { | ||
466 | - error_propagate(errp, local_err); | ||
467 | - ret = -EIO; | ||
468 | +typedef struct { | ||
469 | + char *path; | ||
470 | + char *prefix; | ||
471 | + char *postfix; | ||
472 | + QemuOpts *opts; | ||
473 | +} VMDKCreateOptsData; | ||
474 | + | ||
475 | +static BlockBackend *vmdk_co_create_opts_cb(int64_t size, int idx, | ||
476 | + bool flat, bool split, bool compress, | ||
477 | + bool zeroed_grain, void *opaque, | ||
478 | + Error **errp) | ||
479 | +{ | ||
480 | + BlockBackend *blk = NULL; | ||
481 | + BlockDriverState *bs = NULL; | ||
482 | + VMDKCreateOptsData *data = opaque; | ||
483 | + char *ext_filename = NULL; | ||
484 | + char *rel_filename = NULL; | ||
485 | + | ||
486 | + if (idx == 0) { | ||
487 | + rel_filename = g_strdup_printf("%s%s", data->prefix, data->postfix); | ||
488 | + } else if (split) { | ||
489 | + rel_filename = g_strdup_printf("%s-%c%03d%s", | ||
490 | + data->prefix, | ||
491 | + flat ? 'f' : 's', idx, data->postfix); | ||
492 | + } else { | ||
493 | + assert(idx == 1); | ||
494 | + rel_filename = g_strdup_printf("%s-flat%s", data->prefix, data->postfix); | ||
495 | + } | ||
496 | + | ||
497 | + ext_filename = g_strdup_printf("%s%s", data->path, rel_filename); | ||
498 | + g_free(rel_filename); | ||
499 | + | ||
500 | + if (vmdk_create_extent(ext_filename, size, | ||
501 | + flat, compress, zeroed_grain, &blk, data->opts, | ||
502 | + errp)) { | ||
503 | goto exit; | ||
504 | } | ||
505 | + bdrv_unref(bs); | ||
506 | +exit: | ||
507 | + g_free(ext_filename); | ||
508 | + return blk; | ||
509 | +} | ||
510 | |||
511 | - blk_set_allow_write_beyond_eof(new_blk, true); | ||
512 | +static int coroutine_fn vmdk_co_create_opts(const char *filename, QemuOpts *opts, | ||
513 | + Error **errp) | ||
514 | +{ | ||
515 | + Error *local_err = NULL; | ||
516 | + char *desc = NULL; | ||
517 | + int64_t total_size = 0; | ||
518 | + char *adapter_type = NULL; | ||
519 | + BlockdevVmdkAdapterType adapter_type_enum; | ||
520 | + char *backing_file = NULL; | ||
521 | + char *hw_version = NULL; | ||
522 | + char *fmt = NULL; | ||
523 | + BlockdevVmdkSubformat subformat; | ||
524 | + int ret = 0; | ||
525 | + char *path = g_malloc0(PATH_MAX); | ||
526 | + char *prefix = g_malloc0(PATH_MAX); | ||
527 | + char *postfix = g_malloc0(PATH_MAX); | ||
528 | + char *desc_line = g_malloc0(BUF_SIZE); | ||
529 | + char *ext_filename = g_malloc0(PATH_MAX); | ||
530 | + char *desc_filename = g_malloc0(PATH_MAX); | ||
531 | + char *parent_desc_line = g_malloc0(BUF_SIZE); | ||
532 | + bool zeroed_grain; | ||
533 | + bool compat6; | ||
534 | + VMDKCreateOptsData data; | ||
535 | |||
536 | - ret = blk_pwrite(new_blk, desc_offset, desc, desc_len, 0); | ||
537 | - if (ret < 0) { | ||
538 | - error_setg_errno(errp, -ret, "Could not write description"); | ||
539 | + if (filename_decompose(filename, path, prefix, postfix, PATH_MAX, errp)) { | ||
540 | + ret = -EINVAL; | ||
541 | goto exit; | ||
542 | } | ||
543 | - /* bdrv_pwrite write padding zeros to align to sector, we don't need that | ||
544 | - * for description file */ | ||
545 | - if (desc_offset == 0) { | ||
546 | - ret = blk_truncate(new_blk, desc_len, PREALLOC_MODE_OFF, errp); | ||
547 | + /* Read out options */ | ||
548 | + total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), | ||
549 | + BDRV_SECTOR_SIZE); | ||
550 | + adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE); | ||
551 | + backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); | ||
552 | + hw_version = qemu_opt_get_del(opts, BLOCK_OPT_HWVERSION); | ||
553 | + compat6 = qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false); | ||
554 | + if (strcmp(hw_version, "undefined") == 0) { | ||
555 | + g_free(hw_version); | ||
556 | + hw_version = g_strdup("4"); | ||
557 | } | ||
558 | -exit: | ||
559 | - if (new_blk) { | ||
560 | - blk_unref(new_blk); | ||
561 | + fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); | ||
562 | + zeroed_grain = qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false); | ||
563 | + | ||
564 | + if (adapter_type) { | ||
565 | + adapter_type_enum = qapi_enum_parse(&BlockdevVmdkAdapterType_lookup, | ||
566 | + adapter_type, | ||
567 | + BLOCKDEV_VMDK_ADAPTER_TYPE_IDE, | ||
568 | + &local_err); | ||
569 | + if (local_err) { | ||
570 | + error_propagate(errp, local_err); | ||
571 | + ret = -EINVAL; | ||
572 | + goto exit; | ||
573 | + } | 98 | + } |
574 | + } else { | 99 | +#endif |
575 | + adapter_type_enum = BLOCKDEV_VMDK_ADAPTER_TYPE_IDE; | 100 | default: { |
576 | } | 101 | r = -ENOTSUP; |
577 | + | 102 | error_setg_errno( |
578 | + if (!fmt) { | ||
579 | + /* Default format to monolithicSparse */ | ||
580 | + subformat = BLOCKDEV_VMDK_SUBFORMAT_MONOLITHICSPARSE; | ||
581 | + } else { | ||
582 | + subformat = qapi_enum_parse(&BlockdevVmdkSubformat_lookup, | ||
583 | + fmt, | ||
584 | + BLOCKDEV_VMDK_SUBFORMAT_MONOLITHICSPARSE, | ||
585 | + &local_err); | ||
586 | + if (local_err) { | ||
587 | + error_propagate(errp, local_err); | ||
588 | + ret = -EINVAL; | ||
589 | + goto exit; | ||
590 | + } | ||
591 | + } | ||
592 | + data = (VMDKCreateOptsData){ | ||
593 | + .prefix = prefix, | ||
594 | + .postfix = postfix, | ||
595 | + .path = path, | ||
596 | + .opts = opts, | ||
597 | + }; | ||
598 | + ret = vmdk_co_do_create(total_size, subformat, adapter_type_enum, | ||
599 | + backing_file, hw_version, compat6, zeroed_grain, | ||
600 | + vmdk_co_create_opts_cb, &data, errp); | ||
601 | + | ||
602 | +exit: | ||
603 | g_free(adapter_type); | ||
604 | g_free(backing_file); | ||
605 | g_free(hw_version); | ||
606 | @@ -XXX,XX +XXX,XX @@ exit: | ||
607 | g_free(ext_filename); | ||
608 | g_free(desc_filename); | ||
609 | g_free(parent_desc_line); | ||
610 | - g_string_free(ext_desc_lines, true); | ||
611 | + return ret; | ||
612 | +} | ||
613 | + | ||
614 | +static BlockBackend *vmdk_co_create_cb(int64_t size, int idx, | ||
615 | + bool flat, bool split, bool compress, | ||
616 | + bool zeroed_grain, void *opaque, | ||
617 | + Error **errp) | ||
618 | +{ | ||
619 | + int ret; | ||
620 | + BlockDriverState *bs; | ||
621 | + BlockBackend *blk; | ||
622 | + BlockdevCreateOptionsVmdk *opts = opaque; | ||
623 | + | ||
624 | + if (idx == 0) { | ||
625 | + bs = bdrv_open_blockdev_ref(opts->file, errp); | ||
626 | + } else { | ||
627 | + int i; | ||
628 | + BlockdevRefList *list = opts->extents; | ||
629 | + for (i = 1; i < idx; i++) { | ||
630 | + if (!list || !list->next) { | ||
631 | + error_setg(errp, "Extent [%d] not specified", i); | ||
632 | + return NULL; | ||
633 | + } | ||
634 | + list = list->next; | ||
635 | + } | ||
636 | + if (!list) { | ||
637 | + error_setg(errp, "Extent [%d] not specified", idx - 1); | ||
638 | + return NULL; | ||
639 | + } | ||
640 | + bs = bdrv_open_blockdev_ref(list->value, errp); | ||
641 | + } | ||
642 | + if (!bs) { | ||
643 | + return NULL; | ||
644 | + } | ||
645 | + blk = blk_new(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE, | ||
646 | + BLK_PERM_ALL); | ||
647 | + if (blk_insert_bs(blk, bs, errp)) { | ||
648 | + bdrv_unref(bs); | ||
649 | + return NULL; | ||
650 | + } | ||
651 | + blk_set_allow_write_beyond_eof(blk, true); | ||
652 | + bdrv_unref(bs); | ||
653 | + | ||
654 | + ret = vmdk_init_extent(blk, size, flat, compress, zeroed_grain, errp); | ||
655 | + if (ret) { | ||
656 | + blk_unref(blk); | ||
657 | + blk = NULL; | ||
658 | + } | ||
659 | + return blk; | ||
660 | +} | ||
661 | + | ||
662 | +static int coroutine_fn vmdk_co_create(BlockdevCreateOptions *create_options, | ||
663 | + Error **errp) | ||
664 | +{ | ||
665 | + int ret; | ||
666 | + BlockdevCreateOptionsVmdk *opts; | ||
667 | + | ||
668 | + opts = &create_options->u.vmdk; | ||
669 | + | ||
670 | + /* Validate options */ | ||
671 | + if (!QEMU_IS_ALIGNED(opts->size, BDRV_SECTOR_SIZE)) { | ||
672 | + error_setg(errp, "Image size must be a multiple of 512 bytes"); | ||
673 | + ret = -EINVAL; | ||
674 | + goto out; | ||
675 | + } | ||
676 | + | ||
677 | + ret = vmdk_co_do_create(opts->size, | ||
678 | + opts->subformat, | ||
679 | + opts->adapter_type, | ||
680 | + opts->backing_file, | ||
681 | + opts->hwversion, | ||
682 | + false, | ||
683 | + opts->zeroed_grain, | ||
684 | + vmdk_co_create_cb, | ||
685 | + opts, errp); | ||
686 | + return ret; | ||
687 | + | ||
688 | +out: | ||
689 | return ret; | ||
690 | } | ||
691 | |||
692 | @@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vmdk = { | ||
693 | .bdrv_co_pwrite_zeroes = vmdk_co_pwrite_zeroes, | ||
694 | .bdrv_close = vmdk_close, | ||
695 | .bdrv_co_create_opts = vmdk_co_create_opts, | ||
696 | + .bdrv_co_create = vmdk_co_create, | ||
697 | .bdrv_co_flush_to_disk = vmdk_co_flush, | ||
698 | .bdrv_co_block_status = vmdk_co_block_status, | ||
699 | .bdrv_get_allocated_file_size = vmdk_get_allocated_file_size, | ||
700 | -- | 103 | -- |
701 | 2.20.1 | 104 | 2.39.2 |
702 | |||
703 | diff view generated by jsdifflib |
1 | Clarify that the number of extents provided in BlockdevCreateOptionsVmdk | 1 | From: Or Ozeri <oro@il.ibm.com> |
---|---|---|---|
2 | must match the number of extents that will actually be used. Providing | 2 | |
3 | more extents will result in an error now. | 3 | Starting from ceph Reef, RBD has built-in support for layered encryption, |
4 | 4 | where each ancestor image (in a cloned image setting) can be possibly | |
5 | This requires adapting the test case to provide the right number of | 5 | encrypted using a unique passphrase. |
6 | extents. | 6 | |
7 | 7 | A new function, rbd_encryption_load2, was added to librbd API. | |
8 | This new function supports an array of passphrases (via "spec" structs). | ||
9 | |||
10 | This commit extends the qemu rbd driver API to use this new librbd API, | ||
11 | in order to support this new layered encryption feature. | ||
12 | |||
13 | Signed-off-by: Or Ozeri <oro@il.ibm.com> | ||
14 | Message-Id: <20230129113120.722708-4-oro@oro.sl.cloud9.ibm.com> | ||
15 | Reviewed-by: Ilya Dryomov <idryomov@gmail.com> | ||
16 | Reviewed-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | 17 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
9 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | ||
10 | --- | 18 | --- |
11 | qapi/block-core.json | 3 ++- | 19 | qapi/block-core.json | 11 +++- |
12 | block/vmdk.c | 29 ++++++++++++++++++++++++----- | 20 | block/rbd.c | 153 ++++++++++++++++++++++++++++++++++++++++++- |
13 | tests/qemu-iotests/237 | 6 +++++- | 21 | 2 files changed, 162 insertions(+), 2 deletions(-) |
14 | tests/qemu-iotests/237.out | 13 +++++++------ | ||
15 | 4 files changed, 38 insertions(+), 13 deletions(-) | ||
16 | 22 | ||
17 | diff --git a/qapi/block-core.json b/qapi/block-core.json | 23 | diff --git a/qapi/block-core.json b/qapi/block-core.json |
18 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/qapi/block-core.json | 25 | --- a/qapi/block-core.json |
20 | +++ b/qapi/block-core.json | 26 | +++ b/qapi/block-core.json |
21 | @@ -XXX,XX +XXX,XX @@ | 27 | @@ -XXX,XX +XXX,XX @@ |
22 | # twoGbMaxExtentSparse and twoGbMaxExtentFlat formats. For | 28 | ## |
23 | # monolithicFlat, only one entry is required; for | 29 | # @RbdEncryptionOptions: |
24 | # twoGbMaxExtent* formats, the number of entries required is | 30 | # |
25 | -# calculated as extent_number = virtual_size / 2GB. | 31 | +# @format: Encryption format. |
26 | +# calculated as extent_number = virtual_size / 2GB. Providing | 32 | +# |
27 | +# more extents than will be used is an error. | 33 | +# @parent: Parent image encryption options (for cloned images). |
28 | # @subformat The subformat of the VMDK image. Default: "monolithicSparse". | 34 | +# Can be left unspecified if this cloned image is encrypted |
29 | # @backing-file The path of backing file. Default: no backing file is used. | 35 | +# using the same format and secret as its parent image (i.e. |
30 | # @adapter-type The adapter type used to fill in the descriptor. Default: ide. | 36 | +# not explicitly formatted) or if its parent image is not |
31 | diff --git a/block/vmdk.c b/block/vmdk.c | 37 | +# encrypted. (Since 8.0) |
38 | +# | ||
39 | # Since: 6.1 | ||
40 | ## | ||
41 | { 'union': 'RbdEncryptionOptions', | ||
42 | - 'base': { 'format': 'RbdImageEncryptionFormat' }, | ||
43 | + 'base': { 'format': 'RbdImageEncryptionFormat', | ||
44 | + '*parent': 'RbdEncryptionOptions' }, | ||
45 | 'discriminator': 'format', | ||
46 | 'data': { 'luks': 'RbdEncryptionOptionsLUKS', | ||
47 | 'luks2': 'RbdEncryptionOptionsLUKS2', | ||
48 | diff --git a/block/rbd.c b/block/rbd.c | ||
32 | index XXXXXXX..XXXXXXX 100644 | 49 | index XXXXXXX..XXXXXXX 100644 |
33 | --- a/block/vmdk.c | 50 | --- a/block/rbd.c |
34 | +++ b/block/vmdk.c | 51 | +++ b/block/rbd.c |
35 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_do_create(int64_t size, | 52 | @@ -XXX,XX +XXX,XX @@ static const char rbd_luks2_header_verification[ |
36 | { | 53 | 'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2 |
37 | int extent_idx; | 54 | }; |
38 | BlockBackend *blk = NULL; | 55 | |
39 | + BlockBackend *extent_blk; | 56 | +static const char rbd_layered_luks_header_verification[ |
40 | Error *local_err = NULL; | 57 | + RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = { |
41 | char *desc = NULL; | 58 | + 'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 1 |
42 | int ret = 0; | 59 | +}; |
43 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_do_create(int64_t size, | 60 | + |
61 | +static const char rbd_layered_luks2_header_verification[ | ||
62 | + RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = { | ||
63 | + 'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 2 | ||
64 | +}; | ||
65 | + | ||
66 | typedef enum { | ||
67 | RBD_AIO_READ, | ||
68 | RBD_AIO_WRITE, | ||
69 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_encryption_load(rbd_image_t image, | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | + | ||
74 | +#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2 | ||
75 | +static int qemu_rbd_encryption_load2(rbd_image_t image, | ||
76 | + RbdEncryptionOptions *encrypt, | ||
77 | + Error **errp) | ||
78 | +{ | ||
79 | + int r = 0; | ||
80 | + int encrypt_count = 1; | ||
81 | + int i; | ||
82 | + RbdEncryptionOptions *curr_encrypt; | ||
83 | + rbd_encryption_spec_t *specs; | ||
84 | + rbd_encryption_luks1_format_options_t *luks_opts; | ||
85 | + rbd_encryption_luks2_format_options_t *luks2_opts; | ||
86 | + rbd_encryption_luks_format_options_t *luks_any_opts; | ||
87 | + | ||
88 | + /* count encryption options */ | ||
89 | + for (curr_encrypt = encrypt->parent; curr_encrypt; | ||
90 | + curr_encrypt = curr_encrypt->parent) { | ||
91 | + ++encrypt_count; | ||
92 | + } | ||
93 | + | ||
94 | + specs = g_new0(rbd_encryption_spec_t, encrypt_count); | ||
95 | + | ||
96 | + curr_encrypt = encrypt; | ||
97 | + for (i = 0; i < encrypt_count; ++i) { | ||
98 | + switch (curr_encrypt->format) { | ||
99 | + case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: { | ||
100 | + specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS1; | ||
101 | + | ||
102 | + luks_opts = g_new0(rbd_encryption_luks1_format_options_t, 1); | ||
103 | + specs[i].opts = luks_opts; | ||
104 | + specs[i].opts_size = sizeof(*luks_opts); | ||
105 | + | ||
106 | + r = qemu_rbd_convert_luks_options( | ||
107 | + qapi_RbdEncryptionOptionsLUKS_base( | ||
108 | + &curr_encrypt->u.luks), | ||
109 | + (char **)&luks_opts->passphrase, | ||
110 | + &luks_opts->passphrase_size, | ||
111 | + errp); | ||
112 | + break; | ||
113 | + } | ||
114 | + case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: { | ||
115 | + specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS2; | ||
116 | + | ||
117 | + luks2_opts = g_new0(rbd_encryption_luks2_format_options_t, 1); | ||
118 | + specs[i].opts = luks2_opts; | ||
119 | + specs[i].opts_size = sizeof(*luks2_opts); | ||
120 | + | ||
121 | + r = qemu_rbd_convert_luks_options( | ||
122 | + qapi_RbdEncryptionOptionsLUKS2_base( | ||
123 | + &curr_encrypt->u.luks2), | ||
124 | + (char **)&luks2_opts->passphrase, | ||
125 | + &luks2_opts->passphrase_size, | ||
126 | + errp); | ||
127 | + break; | ||
128 | + } | ||
129 | + case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY: { | ||
130 | + specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS; | ||
131 | + | ||
132 | + luks_any_opts = g_new0(rbd_encryption_luks_format_options_t, 1); | ||
133 | + specs[i].opts = luks_any_opts; | ||
134 | + specs[i].opts_size = sizeof(*luks_any_opts); | ||
135 | + | ||
136 | + r = qemu_rbd_convert_luks_options( | ||
137 | + qapi_RbdEncryptionOptionsLUKSAny_base( | ||
138 | + &curr_encrypt->u.luks_any), | ||
139 | + (char **)&luks_any_opts->passphrase, | ||
140 | + &luks_any_opts->passphrase_size, | ||
141 | + errp); | ||
142 | + break; | ||
143 | + } | ||
144 | + default: { | ||
145 | + r = -ENOTSUP; | ||
146 | + error_setg_errno( | ||
147 | + errp, -r, "unknown image encryption format: %u", | ||
148 | + curr_encrypt->format); | ||
149 | + } | ||
150 | + } | ||
151 | + | ||
152 | + if (r < 0) { | ||
153 | + goto exit; | ||
154 | + } | ||
155 | + | ||
156 | + curr_encrypt = curr_encrypt->parent; | ||
157 | + } | ||
158 | + | ||
159 | + r = rbd_encryption_load2(image, specs, encrypt_count); | ||
160 | + if (r < 0) { | ||
161 | + error_setg_errno(errp, -r, "layered encryption load fail"); | ||
162 | + goto exit; | ||
163 | + } | ||
164 | + | ||
165 | +exit: | ||
166 | + for (i = 0; i < encrypt_count; ++i) { | ||
167 | + if (!specs[i].opts) { | ||
168 | + break; | ||
169 | + } | ||
170 | + | ||
171 | + switch (specs[i].format) { | ||
172 | + case RBD_ENCRYPTION_FORMAT_LUKS1: { | ||
173 | + luks_opts = specs[i].opts; | ||
174 | + g_free((void *)luks_opts->passphrase); | ||
175 | + break; | ||
176 | + } | ||
177 | + case RBD_ENCRYPTION_FORMAT_LUKS2: { | ||
178 | + luks2_opts = specs[i].opts; | ||
179 | + g_free((void *)luks2_opts->passphrase); | ||
180 | + break; | ||
181 | + } | ||
182 | + case RBD_ENCRYPTION_FORMAT_LUKS: { | ||
183 | + luks_any_opts = specs[i].opts; | ||
184 | + g_free((void *)luks_any_opts->passphrase); | ||
185 | + break; | ||
186 | + } | ||
187 | + } | ||
188 | + | ||
189 | + g_free(specs[i].opts); | ||
190 | + } | ||
191 | + g_free(specs); | ||
192 | + return r; | ||
193 | +} | ||
194 | +#endif | ||
195 | #endif | ||
196 | |||
197 | /* FIXME Deprecate and remove keypairs or make it available in QMP. */ | ||
198 | @@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, | ||
199 | |||
200 | if (opts->encrypt) { | ||
201 | #ifdef LIBRBD_SUPPORTS_ENCRYPTION | ||
202 | - r = qemu_rbd_encryption_load(s->image, opts->encrypt, errp); | ||
203 | + if (opts->encrypt->parent) { | ||
204 | +#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2 | ||
205 | + r = qemu_rbd_encryption_load2(s->image, opts->encrypt, errp); | ||
206 | +#else | ||
207 | + r = -ENOTSUP; | ||
208 | + error_setg(errp, "RBD library does not support layered encryption"); | ||
209 | +#endif | ||
210 | + } else { | ||
211 | + r = qemu_rbd_encryption_load(s->image, opts->encrypt, errp); | ||
212 | + } | ||
213 | if (r < 0) { | ||
214 | goto failed_post_open; | ||
215 | } | ||
216 | @@ -XXX,XX +XXX,XX @@ static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs, | ||
217 | spec_info->u.rbd.data->encryption_format = | ||
218 | RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2; | ||
219 | spec_info->u.rbd.data->has_encryption_format = true; | ||
220 | + } else if (memcmp(buf, rbd_layered_luks_header_verification, | ||
221 | + RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) { | ||
222 | + spec_info->u.rbd.data->encryption_format = | ||
223 | + RBD_IMAGE_ENCRYPTION_FORMAT_LUKS; | ||
224 | + spec_info->u.rbd.data->has_encryption_format = true; | ||
225 | + } else if (memcmp(buf, rbd_layered_luks2_header_verification, | ||
226 | + RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) { | ||
227 | + spec_info->u.rbd.data->encryption_format = | ||
228 | + RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2; | ||
229 | + spec_info->u.rbd.data->has_encryption_format = true; | ||
230 | } else { | ||
231 | spec_info->u.rbd.data->has_encryption_format = false; | ||
44 | } | 232 | } |
45 | extent_idx = 1; | ||
46 | while (created_size < size) { | ||
47 | - BlockBackend *extent_blk; | ||
48 | int64_t cur_size = MIN(size - created_size, extent_size); | ||
49 | extent_blk = extent_fn(cur_size, extent_idx, flat, split, compress, | ||
50 | zeroed_grain, opaque, errp); | ||
51 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_do_create(int64_t size, | ||
52 | extent_idx++; | ||
53 | blk_unref(extent_blk); | ||
54 | } | ||
55 | + | ||
56 | + /* Check whether we got excess extents */ | ||
57 | + extent_blk = extent_fn(-1, extent_idx, flat, split, compress, zeroed_grain, | ||
58 | + opaque, NULL); | ||
59 | + if (extent_blk) { | ||
60 | + blk_unref(extent_blk); | ||
61 | + error_setg(errp, "List of extents contains unused extents"); | ||
62 | + ret = -EINVAL; | ||
63 | + goto exit; | ||
64 | + } | ||
65 | + | ||
66 | /* generate descriptor file */ | ||
67 | desc = g_strdup_printf(desc_template, | ||
68 | g_random_int(), | ||
69 | @@ -XXX,XX +XXX,XX @@ static BlockBackend *vmdk_co_create_opts_cb(int64_t size, int idx, | ||
70 | char *ext_filename = NULL; | ||
71 | char *rel_filename = NULL; | ||
72 | |||
73 | + /* We're done, don't create excess extents. */ | ||
74 | + if (size == -1) { | ||
75 | + assert(errp == NULL); | ||
76 | + return NULL; | ||
77 | + } | ||
78 | + | ||
79 | if (idx == 0) { | ||
80 | rel_filename = g_strdup_printf("%s%s", data->prefix, data->postfix); | ||
81 | } else if (split) { | ||
82 | @@ -XXX,XX +XXX,XX @@ static BlockBackend *vmdk_co_create_cb(int64_t size, int idx, | ||
83 | blk_set_allow_write_beyond_eof(blk, true); | ||
84 | bdrv_unref(bs); | ||
85 | |||
86 | - ret = vmdk_init_extent(blk, size, flat, compress, zeroed_grain, errp); | ||
87 | - if (ret) { | ||
88 | - blk_unref(blk); | ||
89 | - blk = NULL; | ||
90 | + if (size != -1) { | ||
91 | + ret = vmdk_init_extent(blk, size, flat, compress, zeroed_grain, errp); | ||
92 | + if (ret) { | ||
93 | + blk_unref(blk); | ||
94 | + blk = NULL; | ||
95 | + } | ||
96 | } | ||
97 | return blk; | ||
98 | } | ||
99 | diff --git a/tests/qemu-iotests/237 b/tests/qemu-iotests/237 | ||
100 | index XXXXXXX..XXXXXXX 100755 | ||
101 | --- a/tests/qemu-iotests/237 | ||
102 | +++ b/tests/qemu-iotests/237 | ||
103 | @@ -XXX,XX +XXX,XX @@ | ||
104 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
105 | # | ||
106 | |||
107 | +import math | ||
108 | import iotests | ||
109 | from iotests import imgfmt | ||
110 | |||
111 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.vmdk') as disk_path, \ | ||
112 | iotests.log("= %s %d =" % (subfmt, size)) | ||
113 | iotests.log("") | ||
114 | |||
115 | + num_extents = math.ceil(size / 2.0**31) | ||
116 | + extents = [ "ext%d" % (i) for i in range(1, num_extents + 1) ] | ||
117 | + | ||
118 | vm.launch() | ||
119 | blockdev_create(vm, { 'driver': imgfmt, | ||
120 | 'file': 'node0', | ||
121 | 'size': size, | ||
122 | 'subformat': subfmt, | ||
123 | - 'extents': ['ext1', 'ext2', 'ext3'] }) | ||
124 | + 'extents': extents }) | ||
125 | vm.shutdown() | ||
126 | |||
127 | iotests.img_info_log(disk_path) | ||
128 | diff --git a/tests/qemu-iotests/237.out b/tests/qemu-iotests/237.out | ||
129 | index XXXXXXX..XXXXXXX 100644 | ||
130 | --- a/tests/qemu-iotests/237.out | ||
131 | +++ b/tests/qemu-iotests/237.out | ||
132 | @@ -XXX,XX +XXX,XX @@ Job failed: Extent [0] not specified | ||
133 | |||
134 | {"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "monolithicFlat"}}} | ||
135 | {"return": {}} | ||
136 | +Job failed: List of extents contains unused extents | ||
137 | {"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
138 | {"return": {}} | ||
139 | |||
140 | @@ -XXX,XX +XXX,XX @@ Job failed: Extent [0] not specified | ||
141 | |||
142 | = twoGbMaxExtentFlat 512 = | ||
143 | |||
144 | -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentFlat"}}} | ||
145 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentFlat"}}} | ||
146 | {"return": {}} | ||
147 | {"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
148 | {"return": {}} | ||
149 | @@ -XXX,XX +XXX,XX @@ Format specific information: | ||
150 | |||
151 | = twoGbMaxExtentSparse 512 = | ||
152 | |||
153 | -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentSparse"}}} | ||
154 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentSparse"}}} | ||
155 | {"return": {}} | ||
156 | {"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
157 | {"return": {}} | ||
158 | @@ -XXX,XX +XXX,XX @@ Format specific information: | ||
159 | |||
160 | = twoGbMaxExtentFlat 1073741824 = | ||
161 | |||
162 | -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentFlat"}}} | ||
163 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentFlat"}}} | ||
164 | {"return": {}} | ||
165 | {"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
166 | {"return": {}} | ||
167 | @@ -XXX,XX +XXX,XX @@ Format specific information: | ||
168 | |||
169 | = twoGbMaxExtentSparse 1073741824 = | ||
170 | |||
171 | -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentSparse"}}} | ||
172 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentSparse"}}} | ||
173 | {"return": {}} | ||
174 | {"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
175 | {"return": {}} | ||
176 | @@ -XXX,XX +XXX,XX @@ Format specific information: | ||
177 | |||
178 | = twoGbMaxExtentFlat 2147483648 = | ||
179 | |||
180 | -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentFlat"}}} | ||
181 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentFlat"}}} | ||
182 | {"return": {}} | ||
183 | {"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
184 | {"return": {}} | ||
185 | @@ -XXX,XX +XXX,XX @@ Format specific information: | ||
186 | |||
187 | = twoGbMaxExtentSparse 2147483648 = | ||
188 | |||
189 | -{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentSparse"}}} | ||
190 | +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentSparse"}}} | ||
191 | {"return": {}} | ||
192 | {"execute": "job-dismiss", "arguments": {"id": "job0"}} | ||
193 | {"return": {}} | ||
194 | -- | 233 | -- |
195 | 2.20.1 | 234 | 2.39.2 |
196 | |||
197 | diff view generated by jsdifflib |