1 | The following changes since commit cfe6c547690b06fbce54a6d0f7b05dd7f18e36ea: | 1 | The following changes since commit 931892e8a691a8a4151cc5fe1e13c14294bb28fb: |
---|---|---|---|
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 remote-tracking branch 'remotes/rth/tags/pull-s390-20170623' into staging (2017-06-23 18:11:48 +0100) |
4 | 4 | ||
5 | are available in the Git repository at: | 5 | are available in the git repository at: |
6 | |||
6 | 7 | ||
7 | git://repo.or.cz/qemu/kevin.git tags/for-upstream | 8 | git://repo.or.cz/qemu/kevin.git tags/for-upstream |
8 | 9 | ||
9 | for you to fetch changes up to 7471a649fc3a391dd497297013fb2525ca9821ba: | 10 | for you to fetch changes up to 704e41ba789ad88158f051eee648d7087beffac7: |
10 | 11 | ||
11 | scsi-disk: Add device_id property (2019-02-01 13:48:11 +0100) | 12 | Merge remote-tracking branch 'mreitz/tags/pull-block-2017-06-26' into queue-block (2017-06-26 14:57:27 +0200) |
13 | |||
14 | v2: | ||
15 | - Dropped "virtio-pci: use ioeventfd even when KVM is disabled" | ||
12 | 16 | ||
13 | ---------------------------------------------------------------- | 17 | ---------------------------------------------------------------- |
14 | Block layer patches: | ||
15 | 18 | ||
16 | - vmdk: Support for blockdev-create | 19 | Block layer patches |
17 | - block: Apply auto-read-only for ro-whitelist drivers | ||
18 | - virtio-scsi: Fixes related to attaching/detaching iothreads | ||
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 | 20 | ||
26 | ---------------------------------------------------------------- | 21 | ---------------------------------------------------------------- |
27 | Alberto Garcia (7): | 22 | Alberto Garcia (9): |
28 | mirror: Release the dirty bitmap if mirror_start_job() fails | 23 | throttle: Update throttle-groups.c documentation |
29 | mirror: Block the source BlockDriverState in mirror_start_job() | 24 | qcow2: Remove unused Error variable in do_perform_cow() |
30 | qcow2: Assert that refcount block offsets fit in the refcount table | 25 | qcow2: Use unsigned int for both members of Qcow2COWRegion |
31 | virtio-scsi: Move BlockBackend back to the main AioContext on unplug | 26 | qcow2: Make perform_cow() call do_perform_cow() twice |
32 | scsi-disk: Acquire the AioContext in scsi_*_realize() | 27 | qcow2: Split do_perform_cow() into _read(), _encrypt() and _write() |
33 | virtio-scsi: Forbid devices with different iothreads sharing a blockdev | 28 | qcow2: Allow reading both COW regions with only one request |
34 | qtest.py: Wait for the result of qtest commands | 29 | qcow2: Pass a QEMUIOVector to do_perform_cow_{read,write}() |
30 | qcow2: Merge the writing of the COW regions with the guest data | ||
31 | qcow2: Use offset_into_cluster() and offset_to_l2_index() | ||
35 | 32 | ||
36 | Fam Zheng (3): | 33 | Kevin Wolf (37): |
37 | vmdk: Refactor vmdk_create_extent | 34 | commit: Fix completion with extra reference |
38 | vmdk: Implement .bdrv_co_create callback | 35 | qemu-iotests: Allow starting new qemu after cleanup |
39 | iotests: Filter cid numbers in VMDK extent info | 36 | qemu-iotests: Test exiting qemu with running job |
37 | doc: Document generic -blockdev options | ||
38 | doc: Document driver-specific -blockdev options | ||
39 | qed: Use bottom half to resume waiting requests | ||
40 | qed: Make qed_read_table() synchronous | ||
41 | qed: Remove callback from qed_read_table() | ||
42 | qed: Remove callback from qed_read_l2_table() | ||
43 | qed: Remove callback from qed_find_cluster() | ||
44 | qed: Make qed_read_backing_file() synchronous | ||
45 | qed: Make qed_copy_from_backing_file() synchronous | ||
46 | qed: Remove callback from qed_copy_from_backing_file() | ||
47 | qed: Make qed_write_header() synchronous | ||
48 | qed: Remove callback from qed_write_header() | ||
49 | qed: Make qed_write_table() synchronous | ||
50 | qed: Remove GenericCB | ||
51 | qed: Remove callback from qed_write_table() | ||
52 | qed: Make qed_aio_read_data() synchronous | ||
53 | qed: Make qed_aio_write_main() synchronous | ||
54 | qed: Inline qed_commit_l2_update() | ||
55 | qed: Add return value to qed_aio_write_l1_update() | ||
56 | qed: Add return value to qed_aio_write_l2_update() | ||
57 | qed: Add return value to qed_aio_write_main() | ||
58 | qed: Add return value to qed_aio_write_cow() | ||
59 | qed: Add return value to qed_aio_write_inplace/alloc() | ||
60 | qed: Add return value to qed_aio_read/write_data() | ||
61 | qed: Remove ret argument from qed_aio_next_io() | ||
62 | qed: Remove recursion in qed_aio_next_io() | ||
63 | qed: Implement .bdrv_co_readv/writev | ||
64 | qed: Use CoQueue for serialising allocations | ||
65 | qed: Simplify request handling | ||
66 | qed: Use a coroutine for need_check_timer | ||
67 | qed: Add coroutine_fn to I/O path functions | ||
68 | qed: Use bdrv_co_* for coroutine_fns | ||
69 | block: Remove bdrv_aio_readv/writev/flush() | ||
70 | Merge remote-tracking branch 'mreitz/tags/pull-block-2017-06-26' into queue-block | ||
40 | 71 | ||
41 | John Snow (1): | 72 | Manos Pitsidianakis (1): |
42 | iotests/236: fix transaction kwarg order | 73 | block: change variable names in BlockDriverState |
43 | 74 | ||
44 | Kevin Wolf (7): | 75 | Max Reitz (3): |
45 | block: Fix hangs in synchronous APIs with iothreads | 76 | blkdebug: Catch bs->exact_filename overflow |
46 | iotests: Add VMDK tests for blockdev-create | 77 | blkverify: Catch bs->exact_filename overflow |
47 | vmdk: Reject excess extents in blockdev-create | 78 | block: Do not strcmp() with NULL uri->scheme |
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 | 79 | ||
53 | Markus Armbruster (2): | 80 | Stefan Hajnoczi (9): |
54 | block: Replace qdict_put() by qdict_put_obj() where appropriate | 81 | block: count bdrv_co_rw_vmstate() requests |
55 | block: Eliminate the S_1KiB, S_2KiB, ... macros | 82 | block: use BDRV_POLL_WHILE() in bdrv_rw_vmstate() |
83 | migration: avoid recursive AioContext locking in save_vmstate() | ||
84 | migration: use bdrv_drain_all_begin/end() instead bdrv_drain_all() | ||
85 | migration: hold AioContext lock for loadvm qemu_fclose() | ||
86 | qemu-iotests: 068: extract _qemu() function | ||
87 | qemu-iotests: 068: use -drive/-device instead of -hda | ||
88 | qemu-iotests: 068: test iothread mode | ||
89 | qemu-img: don't shadow opts variable in img_dd() | ||
56 | 90 | ||
57 | Max Reitz (2): | 91 | Stephen Bates (1): |
58 | iotests: Make 234 stable | 92 | nvme: Add support for Read Data and Write Data in CMBs. |
59 | iotests: Filter second BLOCK_JOB_ERROR from 229 | ||
60 | 93 | ||
61 | Peter Maydell (3): | 94 | sochin.jiang (1): |
62 | block/vpc: Don't take address of fields in packed structs | 95 | fix: avoid an infinite loop or a dangling pointer problem in img_commit |
63 | block/vdi: Don't take address of fields in packed structs | ||
64 | uuid: Make qemu_uuid_bswap() take and return a QemuUUID | ||
65 | 96 | ||
66 | Thomas Huth (1): | 97 | block/Makefile.objs | 2 +- |
67 | block: Remove blk_attach_dev_legacy() / legacy_dev code | 98 | block/blkdebug.c | 46 +-- |
99 | block/blkreplay.c | 8 +- | ||
100 | block/blkverify.c | 12 +- | ||
101 | block/block-backend.c | 22 +- | ||
102 | block/commit.c | 7 + | ||
103 | block/file-posix.c | 34 +- | ||
104 | block/io.c | 240 ++----------- | ||
105 | block/iscsi.c | 20 +- | ||
106 | block/mirror.c | 8 +- | ||
107 | block/nbd-client.c | 8 +- | ||
108 | block/nbd-client.h | 4 +- | ||
109 | block/nbd.c | 6 +- | ||
110 | block/nfs.c | 2 +- | ||
111 | block/qcow2-cluster.c | 201 ++++++++--- | ||
112 | block/qcow2.c | 94 +++-- | ||
113 | block/qcow2.h | 11 +- | ||
114 | block/qed-cluster.c | 124 +++---- | ||
115 | block/qed-gencb.c | 33 -- | ||
116 | block/qed-table.c | 261 +++++--------- | ||
117 | block/qed.c | 779 ++++++++++++++++------------------------- | ||
118 | block/qed.h | 54 +-- | ||
119 | block/raw-format.c | 8 +- | ||
120 | block/rbd.c | 4 +- | ||
121 | block/sheepdog.c | 12 +- | ||
122 | block/ssh.c | 2 +- | ||
123 | block/throttle-groups.c | 2 +- | ||
124 | block/trace-events | 3 - | ||
125 | blockjob.c | 4 +- | ||
126 | hw/block/nvme.c | 83 +++-- | ||
127 | hw/block/nvme.h | 1 + | ||
128 | include/block/block.h | 16 +- | ||
129 | include/block/block_int.h | 6 +- | ||
130 | include/block/blockjob.h | 18 + | ||
131 | include/sysemu/block-backend.h | 20 +- | ||
132 | migration/savevm.c | 32 +- | ||
133 | qemu-img.c | 29 +- | ||
134 | qemu-io-cmds.c | 46 +-- | ||
135 | qemu-options.hx | 221 ++++++++++-- | ||
136 | tests/qemu-iotests/068 | 37 +- | ||
137 | tests/qemu-iotests/068.out | 11 +- | ||
138 | tests/qemu-iotests/185 | 206 +++++++++++ | ||
139 | tests/qemu-iotests/185.out | 59 ++++ | ||
140 | tests/qemu-iotests/common.qemu | 3 + | ||
141 | tests/qemu-iotests/group | 1 + | ||
142 | 45 files changed, 1476 insertions(+), 1324 deletions(-) | ||
143 | delete mode 100644 block/qed-gencb.c | ||
144 | create mode 100755 tests/qemu-iotests/185 | ||
145 | create mode 100644 tests/qemu-iotests/185.out | ||
68 | 146 | ||
69 | yuchenlin (1): | ||
70 | qemu-iotests: add test case for dmg | ||
71 | |||
72 | qapi/block-core.json | 71 +++ | ||
73 | qapi/qapi-schema.json | 16 +- | ||
74 | block/qcow2.h | 10 +- | ||
75 | include/qemu/units.h | 73 --- | ||
76 | include/qemu/uuid.h | 2 +- | ||
77 | include/sysemu/block-backend.h | 5 +- | ||
78 | block.c | 27 +- | ||
79 | block/blklogwrites.c | 5 +- | ||
80 | block/block-backend.c | 59 +-- | ||
81 | block/io.c | 8 +- | ||
82 | block/mirror.c | 11 + | ||
83 | block/nbd-client.c | 1 + | ||
84 | block/nvme.c | 1 + | ||
85 | block/qcow2-refcount.c | 3 + | ||
86 | block/qcow2.c | 1 + | ||
87 | block/qed.c | 1 + | ||
88 | block/vdi.c | 57 ++- | ||
89 | block/vmdk.c | 532 +++++++++++++++------ | ||
90 | block/vpc.c | 4 +- | ||
91 | hw/acpi/vmgenid.c | 6 +- | ||
92 | hw/scsi/scsi-disk.c | 59 ++- | ||
93 | hw/scsi/virtio-scsi.c | 13 + | ||
94 | tests/test-block-iothread.c | 372 ++++++++++++++ | ||
95 | tests/vmgenid-test.c | 2 +- | ||
96 | util/uuid.c | 10 +- | ||
97 | scripts/qtest.py | 6 + | ||
98 | tests/Makefile.include | 2 + | ||
99 | tests/qemu-iotests/141.out | 4 +- | ||
100 | tests/qemu-iotests/229 | 6 +- | ||
101 | tests/qemu-iotests/229.out | 1 - | ||
102 | tests/qemu-iotests/234 | 56 ++- | ||
103 | tests/qemu-iotests/234.out | 10 +- | ||
104 | tests/qemu-iotests/236.out | 56 +-- | ||
105 | tests/qemu-iotests/237 | 237 +++++++++ | ||
106 | tests/qemu-iotests/237.out | 348 ++++++++++++++ | ||
107 | tests/qemu-iotests/239 | 53 ++ | ||
108 | tests/qemu-iotests/239.out | 4 + | ||
109 | tests/qemu-iotests/240 | 129 +++++ | ||
110 | tests/qemu-iotests/240.out | 54 +++ | ||
111 | tests/qemu-iotests/check | 7 + | ||
112 | tests/qemu-iotests/common.filter | 1 + | ||
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 |
Deleted patch | |||
---|---|---|---|
1 | From: Alberto Garcia <berto@igalia.com> | ||
2 | 1 | ||
3 | At the moment I don't see how to make this function fail after the | ||
4 | dirty bitmap has been created, but if that was possible then we would | ||
5 | hit the assert(QLIST_EMPTY(&bs->dirty_bitmaps)) in bdrv_close(). | ||
6 | |||
7 | Signed-off-by: Alberto Garcia <berto@igalia.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | ||
10 | block/mirror.c | 3 +++ | ||
11 | 1 file changed, 3 insertions(+) | ||
12 | |||
13 | diff --git a/block/mirror.c b/block/mirror.c | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/block/mirror.c | ||
16 | +++ b/block/mirror.c | ||
17 | @@ -XXX,XX +XXX,XX @@ fail: | ||
18 | g_free(s->replaces); | ||
19 | blk_unref(s->target); | ||
20 | bs_opaque->job = NULL; | ||
21 | + if (s->dirty_bitmap) { | ||
22 | + bdrv_release_dirty_bitmap(bs, s->dirty_bitmap); | ||
23 | + } | ||
24 | job_early_fail(&s->common.job); | ||
25 | } | ||
26 | |||
27 | -- | ||
28 | 2.20.1 | ||
29 | |||
30 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Alberto Garcia <berto@igalia.com> | ||
2 | 1 | ||
3 | The mirror_start_job() function used for the commit-active job blocks | ||
4 | the source, target and all intermediate nodes for the duration of the | ||
5 | job. | ||
6 | |||
7 | target <- intermediate <- source | ||
8 | |||
9 | Since 4ef85a9c2339 this function creates a dummy mirror_top_bs that | ||
10 | goes on top of the source node, and it is this dummy node that gets | ||
11 | blocked instead. The source node is never blocked or added to the | ||
12 | job's list of nodes. | ||
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> | ||
41 | --- | ||
42 | block/mirror.c | 8 ++++++++ | ||
43 | tests/qemu-iotests/141.out | 4 ++-- | ||
44 | 2 files changed, 10 insertions(+), 2 deletions(-) | ||
45 | |||
46 | diff --git a/block/mirror.c b/block/mirror.c | ||
47 | index XXXXXXX..XXXXXXX 100644 | ||
48 | --- a/block/mirror.c | ||
49 | +++ b/block/mirror.c | ||
50 | @@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs, | ||
51 | goto fail; | ||
52 | } | ||
53 | |||
54 | + ret = block_job_add_bdrv(&s->common, "source", bs, 0, | ||
55 | + BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE | | ||
56 | + BLK_PERM_CONSISTENT_READ, | ||
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 | -- | ||
88 | 2.20.1 | ||
89 | |||
90 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Alberto Garcia <berto@igalia.com> | ||
2 | 1 | ||
3 | Refcount table entries have a field to store the offset of the | ||
4 | refcount block. The rest of the bits of the entry are currently | ||
5 | reserved. | ||
6 | |||
7 | The offset is always taken from the entry using REFT_OFFSET_MASK to | ||
8 | ensure that we only use the bits that belong to that field. | ||
9 | |||
10 | While that mask is used every time we read from the refcount table, it | ||
11 | is never used when we write to it. Due to the other constraints of the | ||
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 | |||
16 | Signed-off-by: Alberto Garcia <berto@igalia.com> | ||
17 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
18 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
19 | --- | ||
20 | block/qcow2-refcount.c | 3 +++ | ||
21 | 1 file changed, 3 insertions(+) | ||
22 | |||
23 | diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c | ||
24 | index XXXXXXX..XXXXXXX 100644 | ||
25 | --- a/block/qcow2-refcount.c | ||
26 | +++ b/block/qcow2-refcount.c | ||
27 | @@ -XXX,XX +XXX,XX @@ static int alloc_refcount_block(BlockDriverState *bs, | ||
28 | return new_block; | ||
29 | } | ||
30 | |||
31 | + /* The offset must fit in the offset field of the refcount table entry */ | ||
32 | + assert((new_block & REFT_OFFSET_MASK) == new_block); | ||
33 | + | ||
34 | /* If we're allocating the block at offset 0 then something is wrong */ | ||
35 | if (new_block == 0) { | ||
36 | qcow2_signal_corruption(bs, true, -1, -1, "Preventing invalid " | ||
37 | -- | ||
38 | 2.20.1 | ||
39 | |||
40 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: yuchenlin <npes87184@gmail.com> | ||
2 | 1 | ||
3 | Recently, some bugs in dmg file have been fixed. To prevent reading dmg | ||
4 | is broken someday in the future, add a simple test which ensures the | ||
5 | conversion from dmg to raw should not hang or face any I/O error. | ||
6 | |||
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> | ||
10 | --- | ||
11 | tests/qemu-iotests/239 | 53 ++++++++++++++++++ | ||
12 | tests/qemu-iotests/239.out | 4 ++ | ||
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 | |||
21 | diff --git a/tests/qemu-iotests/239 b/tests/qemu-iotests/239 | ||
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 | ||
117 | --- a/tests/qemu-iotests/group | ||
118 | +++ b/tests/qemu-iotests/group | ||
119 | @@ -XXX,XX +XXX,XX @@ | ||
120 | 235 auto quick | ||
121 | 236 auto quick | ||
122 | 238 auto quick | ||
123 | +239 rw auto quick | ||
124 | diff --git a/tests/qemu-iotests/sample_images/simple-dmg.dmg.bz2 b/tests/qemu-iotests/sample_images/simple-dmg.dmg.bz2 | ||
125 | new file mode 100644 | ||
126 | index XXXXXXX..XXXXXXX | ||
127 | GIT binary patch | ||
128 | literal 3479 | ||
129 | zcmV;I4QTR0T4*^jL0KkKS(36)s{k7pfB*mg|NsC0|NsC0|NsC0|NsC0|Ns5}|NsC0 | ||
130 | z|NsC0|Nr0#eji@i`+e|w_jjtUioUNn9=bhi?FYz+8lea^Pt`n6Q`GfM=uI^|rccqR | ||
131 | z#)^4QQ(&j0^vx-<6U8+BMo&{rPgMO9KU6<bdYee{L&A*HX-%dfJg1{mX^f|mdZ(%S | ||
132 | zYHDfZWgn$BPgL<R4Jqj~+M0TvOq0bPDe8Glf++<WdYU|=X+1Rn(<i9%Lp2zh4IZY3 | ||
133 | zjXgCzA?gg9Q$~!`&}h@t^qy1H^iL_WjXgCzK-!HSQ%^=sO&L8COn}g7>K>tx+G-x7 | ||
134 | zKxhH7gFqfr)EbhWqfmN7Xqi0_(|U$T%^~Te(<9O!s(P57)gFnX(HMqCnW^apCLkWB | ||
135 | zfB?c`7=Y8$P|yP*p{9YL8X6e}jSLZ{Kmat*Y9I=F1s<p9DB4Cq^#`bE4Ff^74GlCj | ||
136 | z05tUmngG$D8fXFP0MPXVMoj}i&;S4$8UdgN)B`|zgFpae5-JoYqMnhSqz_5zX!RaX | ||
137 | zN@?n8p`%8PJdIB%dW@MKrbdHIo}+1?O{io&O{DTNL5K|i44$J2gHSf0dW_JG15ZRS | ||
138 | zO#>jv(V%IjnFNxA1T<(7k~Y;aPez3F!fB&IWZEW%)byHqn^PtYN0c*2G<pJPF%2|& | ||
139 | zjXg~oX{V%Vqb8bZplqPgw1%2w9-*VtQR*}r00xGQ4G24kA+jG=o`xW*WTQp80#*@D | ||
140 | zGI^@e0Fq218g7gWKQ0-!!d?<+0Zg$VQi&#k#L$@->*ZllN2a;wYb5Z@K!FpiLKS04 | ||
141 | zAXF_RNbYzNTvjprs6=NSa4=(xVBCm>1#>twBnc>5NRuJv+UXVcw)$K?45Ra5gMtys | ||
142 | z5#=tTi{6o_Dolm>AW0*9z$7i33Gt*7^pYSUXUfIy=|9=(Y5F2D)W#);#I!)dBq)W~ | ||
143 | zrFlJ*pf<%<p!?|?K4A)WKmn>vEyY-2j;_z6FzSi8mQn!dfdGLU#z+u}O%{xk@FlI` | ||
144 | z^B@Tz!-52v0~!WxwY>yM5j2L!wDW07lb>SjKuGF1Bv7*3#(>;&j=WH?%<2(%C(%mi | ||
145 | z3SK&{tsN6|F+h=$fRF|SAT&YV;=$CM8UPyf&KPGXD@;hw?Ie+ur$Ms`<R|DnF>?n= | ||
146 | z=TVuCRg<`%CTS#rC3Rqi{8+-#G7{}$If&w>{u-}tqnXQGZ1vrDn(W+-ydtwD_5(m9 | ||
147 | zUlJm4YF$|a547Ok)VNY_1&|O<rL!z~wcz}tQxE~Dj4cXB5;0mM5(lt%*IA;POn}RT | ||
148 | z;6QRRmFhId9Am|k#g{Q@hX6cXxi&WKM_|eXL97PF^DAB*Vbz~zQKTvZ??`1m>?|T) | ||
149 | z42v8J{j@}JBoR7501!b0TQLa}5=%fGiZ01vc2PsfW3IL_R4y29^38$G<bvvm5nFd0 | ||
150 | zCwO?LU{=bViG0S0Zh^;{@n#!Kdu|V}*6A@n-bN2myQ=@_`vaVL_~0ObLdRRH{)&n2 | ||
151 | zWjQqZq-v&|Sm)GU$5#3E-aM@MWEDTSJ=WXyvX!Ka^MIpH)wR_6>N@}eFEu8;#~W3O | ||
152 | zhYo*p2)1qo0FWCdNC$P6JWDI)lRL3RsCq~;CddNVfDeUAK|}zQbl`V}JlvEcUSn8M | ||
153 | zpVIf%kFZ>u>OO0J!nRehCj34b&G%X*%F`iNsN=6_pV&CdsRu0CM-x>qqFshZ5Cm<o | ||
154 | zjS+4gAk-oc*IeI*Cm4uELVya|XwQV9;aJZ7Mzx<=On?m(0@tY~UQVHbY{wZn;D)7@ | ||
155 | z(k#N&X0YCEm2rAN!X56ASS+#z7ao9>#cE(tAoIY<O8RkL;gL@lE`rM`9JnB2CEx^z | ||
156 | z6c8i@0n%FhZje3Zxg#iF@R@T1Isa_wb*LjCgn+!DWDcYQh#WxZLepa#PQjgE{rMz? | ||
157 | zBq1<j2VVpX$Xd;K6V+q_hhHJtdWTbjuPi#R=(f&lykmQl$pDZgP%wm~nI*Ni#z^FO | ||
158 | zE-eT!OaQHD1y1DHB8`9}p<+T&reFk;4s}MH%)0IXH1auiL(e%0z#SY_Q4bA>;2;n; | ||
159 | z>6lWK8VC|iQ`TBT@eh_haUvW?s0F~|jWOEDBrNGaBoJh|LX9lsM4vqVlOYszX7pdA | ||
160 | z{D&2t%ysWP&xa%2Q6LEk#Gf-=1UdvZ5a1%=kY@b_PJ?B`u>CaLI&B7em_7b|;n=Za | ||
161 | zp~fR)pUI5+fvC#Km(lVCNpb=XW#mzCYrKf$7gM(TqYzYBKqz54qqz-xcv$fGQrdYy | ||
162 | zRD%pqsY(=-5JXlPYst2Xv=#sccTUb6A-KFq8XNZ`G)4wExi9zHxBO=zO;AbFM}`M! | ||
163 | zOk?+aXaO;H02oI0Bn>Mv09F(z2D>5BS#O#$P6Hjd6boVGU|fj(_>6Wj@RrKIn;8EB | ||
164 | zble1^sy2Z1#DvynHzELF0f+`WC;nB6;l*sYRsG&{OT)PkEN{C-fC@>voA`)pYKBGR | ||
165 | zy0qd5hS(-IOAKl(iXY}a|K}p1?TmbyuKT-Qeer)gFKD88^Tpxr*kmLy;0FL}C&d#` | ||
166 | zQ|v00fv3#W*mSyZs|-K<h+d6pNO}MT^KN@JOgvk`m2@p1X~U$!#uswfANXB%a*2}d | ||
167 | zwEVT6lZMv@K`D!LB_I^fo)latwZp8vy|3yBt&R41ACiQf!d~t-ftA7uBb30|`l#aR | ||
168 | zSAZd~7y#5rmLOyX5*DtKB=1^~pw$7YjAzU-OkBe`h(K#GCV;6Q6}-9*#6ZQEesARr | ||
169 | zwQh_HsY@9IS)I<~d1n7@4@41T%tXY@5h1NOcGB0n$$P2^q!Iwg96-Ypa~Me&Mkg03 | ||
170 | zx4>{zsMn+fmSxpq9<;PGzUke*7{Vc;ba?~~Fp@>uleN{!WoS8VmG%z%nuX9{w6QC^ | ||
171 | z>cY}_BnH5wp)m6ur<d4axiRctR|XVPR-dd0=6w1P3>Z5+Eu`$-#pj&flXy9V9wq!p | ||
172 | zo^)}9fQDYjW6Ab;cYA9~3Cm@szFUBpm=2bWB#w0?id*4t_2g7y|0*g1ylSPW9s834 | ||
173 | ztjELX^xWJGpL*3Qc>%uRKQna>8~ayaq=0g~k?u90E|+R&pb}xi6sAxgk{0I9Tdk7g | ||
174 | zC&mCT7%%O`$bs$IGS?S?7$DVck$e==@QS_=nF(o3(InF7Dn=3k=Ls-^Fw9D7{(U3k | ||
175 | zK*%{w#OE;-n}5J@QnW~k0W^>q6Frr!p|88#+Wy;ioe~<*h=i%&J;)%alO@Pegg+7j | ||
176 | zs``QTeEyD)x7p(92)N`E@8T8H#s^c%*24OW;aGvPuVQef*wBsRpU@6A_g9zdDt9$k | ||
177 | z2zRm#rdLi0A^}Fb?sXZ{X@%WaZzShTNF-5=Fu)3i@t^qa`TwT<VRADXi9j*Cww!Bk | ||
178 | z$ofZn`qc*}gV@O>ucE88qh>EN`Jdw+s*<*u-@$9+o1#_6XJ989lqI=az!E}P5riY* | ||
179 | zHPwYH$BT`e?rVGc3nGpD(|bD_E!3{ti_*;NZZ0isXL2=SVRX$Ti~X!dedY#W1K<$# | ||
180 | zh_IvD035p;=Ek~DC$}ZJd(G3-dd#k6CG#xgT;mmS6+SLid1tQO-9<Sl@O^GuLUz-u | ||
181 | z417&euHAlM4ypAfeUp|&``-9llf#`5`nX06abKLfN@~l%nAq{U{u*UfSI+fFc$+Nq | ||
182 | zjSkQ*mer2Rs5nuStK%0w;knBzMKh|{QO!^DPwP)t^4~w3qnO*hZDo{4^>~P#9iv%f | ||
183 | zd!`qvbczBF)AAe0yE+WI*}DYOL2J~*ZCc}JWiu0LShw&6`-5`^SkNJY!gsi|e-MHy | ||
184 | zZlN9Lb5NbuT7S&4oY6v}13BpeQ|?u0c*7n)Ku*p%ZDF?$7zjKXj(9#K?tO1dMW=8& | ||
185 | z;MDsGo0=CLWp{b5$Kk0kxAl*^l^ziX<28c4->Ed%#N16IrySH$q`4%gn}5ksr>_0H | ||
186 | zs-;Y4Bb7U_pNGMK075wJ%DahB2ArR=jC`2UWMe`ID;mPgA25l6GVc9>Rqybi7N6(i | ||
187 | z3BcjbfprP7Ivcy%+Vs~Z6Hw>JB!kJcD>mdTThTpO$(fg`Ds7pY<YTYWgmqU8=Xlve | ||
188 | zCriGy+iG;z+{{27v*;>N4BN<|%(+#T+h1sdgPjUAWN73ki+$-%j_&6PZ$I2$HnSEa | ||
189 | zQ?n{BB*A3zmlLHvH@o+ZJm1NSC9(?ka<7OppIcAi{V`Nj+^8SL!ywYLI$v(ivC_){ | ||
190 | z5anb)=MQS%<PN>hUHR@_HKDhdDPf*Hm`w^E{GT!Yq<}Hg8Ia{?PyA70;yx8nD^~B| | ||
191 | zjuGESS<A^!S2=(y_Dz2Z3)U+>*z1(bcT1?|;LuVOg&xLebEk(1uB(fZJN&W3!xADj | ||
192 | zQD;ugVYYpOt=NBu$Bi07WcepgHm6q}1y>vxs^oJetK;=ix$9i9M#>O`?6X2pJoXi; | ||
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 | -- | ||
202 | 2.20.1 | ||
203 | |||
204 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Markus Armbruster <armbru@redhat.com> | ||
2 | 1 | ||
3 | Patch created mechanically by rerunning: | ||
4 | |||
5 | $ spatch --sp-file scripts/coccinelle/qobject.cocci \ | ||
6 | --macro-file scripts/cocci-macro-file.h \ | ||
7 | --dir block --in-place | ||
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> | ||
13 | --- | ||
14 | block/blklogwrites.c | 5 ++--- | ||
15 | 1 file changed, 2 insertions(+), 3 deletions(-) | ||
16 | |||
17 | diff --git a/block/blklogwrites.c b/block/blklogwrites.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/block/blklogwrites.c | ||
20 | +++ b/block/blklogwrites.c | ||
21 | @@ -XXX,XX +XXX,XX @@ static void blk_log_writes_refresh_filename(BlockDriverState *bs, | ||
22 | qdict_put_str(opts, "driver", "blklogwrites"); | ||
23 | |||
24 | qobject_ref(bs->file->bs->full_open_options); | ||
25 | - qdict_put_obj(opts, "file", QOBJECT(bs->file->bs->full_open_options)); | ||
26 | + qdict_put(opts, "file", bs->file->bs->full_open_options); | ||
27 | qobject_ref(s->log_file->bs->full_open_options); | ||
28 | - qdict_put_obj(opts, "log", | ||
29 | - QOBJECT(s->log_file->bs->full_open_options)); | ||
30 | + qdict_put(opts, "log", s->log_file->bs->full_open_options); | ||
31 | qdict_put_int(opts, "log-sector-size", s->sectorsize); | ||
32 | |||
33 | bs->full_open_options = opts; | ||
34 | -- | ||
35 | 2.20.1 | ||
36 | |||
37 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | In the block layer, synchronous APIs are often implemented by creating a | ||
2 | coroutine that calls the asynchronous coroutine-based implementation and | ||
3 | then waiting for completion with BDRV_POLL_WHILE(). | ||
4 | 1 | ||
5 | For this to work with iothreads (more specifically, when the synchronous | ||
6 | API is called in a thread that is not the home thread of the block | ||
7 | device, so that the coroutine will run in a different thread), we must | ||
8 | make sure to call aio_wait_kick() at the end of the operation. Many | ||
9 | places are missing this, so that BDRV_POLL_WHILE() keeps hanging even if | ||
10 | the condition has long become false. | ||
11 | |||
12 | Note that bdrv_dec_in_flight() involves an aio_wait_kick() call. This | ||
13 | corresponds to the BDRV_POLL_WHILE() in the drain functions, but it is | ||
14 | generally not enough for most other operations because they haven't set | ||
15 | the return value in the coroutine entry stub yet. To avoid race | ||
16 | conditions there, we need to kick after setting the return value. | ||
17 | |||
18 | The race window is small enough that the problem doesn't usually surface | ||
19 | in the common path. However, it does surface and causes easily | ||
20 | reproducible hangs if the operation can return early before even calling | ||
21 | bdrv_inc/dec_in_flight, which many of them do (trivial error or no-op | ||
22 | success paths). | ||
23 | |||
24 | The bug in bdrv_truncate(), bdrv_check() and bdrv_invalidate_cache() is | ||
25 | slightly different: These functions even neglected to schedule the | ||
26 | coroutine in the home thread of the node. This avoids the hang, but is | ||
27 | obviously wrong, too. Fix those to schedule the coroutine in the right | ||
28 | AioContext in addition to adding aio_wait_kick() calls. | ||
29 | |||
30 | Cc: qemu-stable@nongnu.org | ||
31 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
32 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
33 | --- | ||
34 | block.c | 6 +- | ||
35 | block/block-backend.c | 5 + | ||
36 | block/io.c | 8 +- | ||
37 | block/nbd-client.c | 1 + | ||
38 | block/nvme.c | 1 + | ||
39 | block/qcow2.c | 1 + | ||
40 | block/qed.c | 1 + | ||
41 | tests/test-block-iothread.c | 372 ++++++++++++++++++++++++++++++++++++ | ||
42 | tests/Makefile.include | 2 + | ||
43 | 9 files changed, 394 insertions(+), 3 deletions(-) | ||
44 | create mode 100644 tests/test-block-iothread.c | ||
45 | |||
46 | diff --git a/block.c b/block.c | ||
47 | index XXXXXXX..XXXXXXX 100644 | ||
48 | --- a/block.c | ||
49 | +++ b/block.c | ||
50 | @@ -XXX,XX +XXX,XX @@ static void bdrv_check_co_entry(void *opaque) | ||
51 | { | ||
52 | CheckCo *cco = opaque; | ||
53 | cco->ret = bdrv_co_check(cco->bs, cco->res, cco->fix); | ||
54 | + aio_wait_kick(); | ||
55 | } | ||
56 | |||
57 | int bdrv_check(BlockDriverState *bs, | ||
58 | @@ -XXX,XX +XXX,XX @@ int bdrv_check(BlockDriverState *bs, | ||
59 | bdrv_check_co_entry(&cco); | ||
60 | } else { | ||
61 | co = qemu_coroutine_create(bdrv_check_co_entry, &cco); | ||
62 | - qemu_coroutine_enter(co); | ||
63 | + bdrv_coroutine_enter(bs, co); | ||
64 | BDRV_POLL_WHILE(bs, cco.ret == -EINPROGRESS); | ||
65 | } | ||
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 | ||
85 | index XXXXXXX..XXXXXXX 100644 | ||
86 | --- a/block/block-backend.c | ||
87 | +++ b/block/block-backend.c | ||
88 | @@ -XXX,XX +XXX,XX @@ static void blk_read_entry(void *opaque) | ||
89 | |||
90 | rwco->ret = blk_co_preadv(rwco->blk, rwco->offset, qiov->size, | ||
91 | qiov, rwco->flags); | ||
92 | + aio_wait_kick(); | ||
93 | } | ||
94 | |||
95 | static void blk_write_entry(void *opaque) | ||
96 | @@ -XXX,XX +XXX,XX @@ static void blk_write_entry(void *opaque) | ||
97 | |||
98 | rwco->ret = blk_co_pwritev(rwco->blk, rwco->offset, qiov->size, | ||
99 | qiov, rwco->flags); | ||
100 | + aio_wait_kick(); | ||
101 | } | ||
102 | |||
103 | static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf, | ||
104 | @@ -XXX,XX +XXX,XX @@ static void blk_ioctl_entry(void *opaque) | ||
105 | |||
106 | rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset, | ||
107 | qiov->iov[0].iov_base); | ||
108 | + aio_wait_kick(); | ||
109 | } | ||
110 | |||
111 | int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf) | ||
112 | @@ -XXX,XX +XXX,XX @@ static void blk_flush_entry(void *opaque) | ||
113 | { | ||
114 | BlkRwCo *rwco = opaque; | ||
115 | rwco->ret = blk_co_flush(rwco->blk); | ||
116 | + aio_wait_kick(); | ||
117 | } | ||
118 | |||
119 | int blk_flush(BlockBackend *blk) | ||
120 | @@ -XXX,XX +XXX,XX @@ static void blk_pdiscard_entry(void *opaque) | ||
121 | QEMUIOVector *qiov = rwco->iobuf; | ||
122 | |||
123 | rwco->ret = blk_co_pdiscard(rwco->blk, rwco->offset, qiov->size); | ||
124 | + aio_wait_kick(); | ||
125 | } | ||
126 | |||
127 | int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes) | ||
128 | diff --git a/block/io.c b/block/io.c | ||
129 | index XXXXXXX..XXXXXXX 100644 | ||
130 | --- a/block/io.c | ||
131 | +++ b/block/io.c | ||
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 | } | ||
138 | |||
139 | /* | ||
140 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_block_status_above_co_entry(void *opaque) | ||
141 | data->offset, data->bytes, | ||
142 | data->pnum, data->map, data->file); | ||
143 | data->done = true; | ||
144 | + aio_wait_kick(); | ||
145 | } | ||
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 | -- | ||
636 | 2.20.1 | ||
637 | |||
638 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Max Reitz <mreitz@redhat.com> | ||
2 | 1 | ||
3 | This test waits for a MIGRATION event with status=completed on the | ||
4 | source VM before querying the migration status on both source and | ||
5 | destination. However, just because the source says migration has | ||
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> | ||
15 | --- | ||
16 | tests/qemu-iotests/234 | 56 ++++++++++++++++++++------------------ | ||
17 | tests/qemu-iotests/234.out | 10 +++++-- | ||
18 | 2 files changed, 38 insertions(+), 28 deletions(-) | ||
19 | |||
20 | diff --git a/tests/qemu-iotests/234 b/tests/qemu-iotests/234 | ||
21 | index XXXXXXX..XXXXXXX 100755 | ||
22 | --- a/tests/qemu-iotests/234 | ||
23 | +++ b/tests/qemu-iotests/234 | ||
24 | @@ -XXX,XX +XXX,XX @@ import os | ||
25 | iotests.verify_image_format(supported_fmts=['qcow2']) | ||
26 | iotests.verify_platform(['linux']) | ||
27 | |||
28 | +def enable_migration_events(vm, name): | ||
29 | + iotests.log('Enabling migration QMP events on %s...' % name) | ||
30 | + iotests.log(vm.qmp('migrate-set-capabilities', capabilities=[ | ||
31 | + { | ||
32 | + 'capability': 'events', | ||
33 | + 'state': True | ||
34 | + } | ||
35 | + ])) | ||
36 | + | ||
37 | +def wait_migration(vm): | ||
38 | + while True: | ||
39 | + event = vm.event_wait('MIGRATION') | ||
40 | + iotests.log(event, filters=[iotests.filter_qmp_event]) | ||
41 | + if event['data']['status'] == 'completed': | ||
42 | + break | ||
43 | + | ||
44 | with iotests.FilePath('img') as img_path, \ | ||
45 | iotests.FilePath('backing') as backing_path, \ | ||
46 | iotests.FilePath('mig_fifo_a') as fifo_a, \ | ||
47 | @@ -XXX,XX +XXX,XX @@ with iotests.FilePath('img') as img_path, \ | ||
48 | .add_blockdev('%s,file=drive0-backing-file,node-name=drive0-backing' % (iotests.imgfmt)) | ||
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 | ||
126 | --- a/tests/qemu-iotests/234.out | ||
127 | +++ b/tests/qemu-iotests/234.out | ||
128 | @@ -XXX,XX +XXX,XX @@ | ||
129 | Launching source VM... | ||
130 | +Enabling migration QMP events on A... | ||
131 | +{"return": {}} | ||
132 | Launching destination VM... | ||
133 | +Enabling migration QMP events on B... | ||
134 | {"return": {}} | ||
135 | {"return": {}} | ||
136 | -Enabling migration QMP events on A... | ||
137 | {"return": {}} | ||
138 | Starting migration to B... | ||
139 | {"return": {}} | ||
140 | {"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | ||
141 | {"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | ||
142 | {"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | ||
143 | +{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | ||
144 | +{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | ||
145 | completed | ||
146 | completed | ||
147 | {"return": {"running": false, "singlestep": false, "status": "postmigrate"}} | ||
148 | @@ -XXX,XX +XXX,XX @@ completed | ||
149 | Add a second parent to drive0-file... | ||
150 | {"return": {}} | ||
151 | Restart A with -incoming and second parent... | ||
152 | +Enabling migration QMP events on A... | ||
153 | {"return": {}} | ||
154 | -Enabling migration QMP events on B... | ||
155 | {"return": {}} | ||
156 | Starting migration back to A... | ||
157 | {"return": {}} | ||
158 | {"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | ||
159 | {"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | ||
160 | {"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | ||
161 | +{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | ||
162 | +{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} | ||
163 | completed | ||
164 | completed | ||
165 | {"return": {"running": true, "singlestep": false, "status": "running"}} | ||
166 | -- | ||
167 | 2.20.1 | ||
168 | |||
169 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Fam Zheng <famz@redhat.com> | ||
2 | 1 | ||
3 | The extracted vmdk_init_extent takes a BlockBackend object and | ||
4 | initializes the format metadata. It is the common part between "qemu-img | ||
5 | create" and "blockdev-create". | ||
6 | |||
7 | Add a "BlockBackend *pbb" parameter to vmdk_create_extent, to return the | ||
8 | opened BB to the caller in the next patch. | ||
9 | |||
10 | Signed-off-by: Fam Zheng <famz@redhat.com> | ||
11 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | ||
12 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
13 | --- | ||
14 | block/vmdk.c | 69 ++++++++++++++++++++++++++++++++-------------------- | ||
15 | 1 file changed, 43 insertions(+), 26 deletions(-) | ||
16 | |||
17 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/block/vmdk.c | ||
20 | +++ b/block/vmdk.c | ||
21 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_pwrite_zeroes(BlockDriverState *bs, | ||
22 | return ret; | ||
23 | } | ||
24 | |||
25 | -static int vmdk_create_extent(const char *filename, int64_t filesize, | ||
26 | - bool flat, bool compress, bool zeroed_grain, | ||
27 | - QemuOpts *opts, Error **errp) | ||
28 | +static int vmdk_init_extent(BlockBackend *blk, | ||
29 | + int64_t filesize, bool flat, | ||
30 | + bool compress, bool zeroed_grain, | ||
31 | + Error **errp) | ||
32 | { | ||
33 | int ret, i; | ||
34 | - BlockBackend *blk = NULL; | ||
35 | VMDK4Header header; | ||
36 | - Error *local_err = NULL; | ||
37 | uint32_t tmp, magic, grains, gd_sectors, gt_size, gt_count; | ||
38 | uint32_t *gd_buf = NULL; | ||
39 | int gd_buf_size; | ||
40 | |||
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 | -- | ||
125 | 2.20.1 | ||
126 | |||
127 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Fam Zheng <famz@redhat.com> | ||
2 | 1 | ||
3 | This makes VMDK support blockdev-create. The implementation reuses the | ||
4 | image creation code in vmdk_co_create_opts which now acceptes a callback | ||
5 | pointer to "retrieve" BlockBackend pointers from the caller. This way we | ||
6 | separate the logic between file/extent acquisition and initialization. | ||
7 | |||
8 | The QAPI command parameters are mostly the same as the old create_opts | ||
9 | except the dropped legacy @compat6 switch, which is redundant with | ||
10 | @hwversion. | ||
11 | |||
12 | Signed-off-by: Fam Zheng <famz@redhat.com> | ||
13 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | ||
14 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
15 | --- | ||
16 | qapi/block-core.json | 70 +++++++ | ||
17 | qapi/qapi-schema.json | 16 +- | ||
18 | block/vmdk.c | 448 ++++++++++++++++++++++++++++++------------ | ||
19 | 3 files changed, 400 insertions(+), 134 deletions(-) | ||
20 | |||
21 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
22 | index XXXXXXX..XXXXXXX 100644 | ||
23 | --- a/qapi/block-core.json | ||
24 | +++ b/qapi/block-core.json | ||
25 | @@ -XXX,XX +XXX,XX @@ | ||
26 | 'size': 'size', | ||
27 | '*cluster-size' : 'size' } } | ||
28 | |||
29 | +## | ||
30 | +# @BlockdevVmdkSubformat: | ||
31 | +# | ||
32 | +# Subformat options for VMDK images | ||
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 | +## | ||
49 | +{ 'enum': 'BlockdevVmdkSubformat', | ||
50 | + 'data': [ 'monolithicSparse', 'monolithicFlat', 'twoGbMaxExtentSparse', | ||
51 | + 'twoGbMaxExtentFlat', 'streamOptimized'] } | ||
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 | + | ||
98 | ## | ||
99 | # @SheepdogRedundancyType: | ||
100 | # | ||
101 | @@ -XXX,XX +XXX,XX @@ | ||
102 | 'ssh': 'BlockdevCreateOptionsSsh', | ||
103 | 'vdi': 'BlockdevCreateOptionsVdi', | ||
104 | 'vhdx': 'BlockdevCreateOptionsVhdx', | ||
105 | + 'vmdk': 'BlockdevCreateOptionsVmdk', | ||
106 | 'vpc': 'BlockdevCreateOptionsVpc' | ||
107 | } } | ||
108 | |||
109 | diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json | ||
110 | index XXXXXXX..XXXXXXX 100644 | ||
111 | --- a/qapi/qapi-schema.json | ||
112 | +++ b/qapi/qapi-schema.json | ||
113 | @@ -XXX,XX +XXX,XX @@ | ||
114 | 'query-tpm-types', | ||
115 | 'ringbuf-read' ], | ||
116 | 'name-case-whitelist': [ | ||
117 | - 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status | ||
118 | - 'CpuInfoMIPS', # PC, visible through query-cpu | ||
119 | - 'CpuInfoTricore', # PC, visible through query-cpu | ||
120 | - 'QapiErrorClass', # all members, visible through errors | ||
121 | - 'UuidInfo', # UUID, visible through query-uuid | ||
122 | - 'X86CPURegister32', # all members, visible indirectly through qom-get | ||
123 | - 'q_obj_CpuInfo-base' # CPU, visible through query-cpu | ||
124 | + 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status | ||
125 | + 'CpuInfoMIPS', # PC, visible through query-cpu | ||
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 | } | ||
237 | - g_free(hw_version); | ||
238 | - hw_version = g_strdup("6"); | ||
239 | - } | ||
240 | - if (strcmp(hw_version, "undefined") == 0) { | ||
241 | - g_free(hw_version); | ||
242 | - hw_version = g_strdup("4"); | ||
243 | + hw_version = "6"; | ||
244 | } | ||
245 | - fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); | ||
246 | - if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false)) { | ||
247 | - zeroed_grain = true; | ||
248 | + if (!hw_version) { | ||
249 | + hw_version = "4"; | ||
250 | } | ||
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 | + } | ||
574 | + } else { | ||
575 | + adapter_type_enum = BLOCKDEV_VMDK_ADAPTER_TYPE_IDE; | ||
576 | } | ||
577 | + | ||
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 | -- | ||
701 | 2.20.1 | ||
702 | |||
703 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Fam Zheng <famz@redhat.com> | ||
2 | 1 | ||
3 | Signed-off-by: Fam Zheng <famz@redhat.com> | ||
4 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
5 | --- | ||
6 | tests/qemu-iotests/common.filter | 1 + | ||
7 | tests/qemu-iotests/iotests.py | 1 + | ||
8 | 2 files changed, 2 insertions(+) | ||
9 | |||
10 | diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter | ||
11 | index XXXXXXX..XXXXXXX 100644 | ||
12 | --- a/tests/qemu-iotests/common.filter | ||
13 | +++ b/tests/qemu-iotests/common.filter | ||
14 | @@ -XXX,XX +XXX,XX @@ _filter_img_info() | ||
15 | -e "/table_size: [0-9]\\+/d" \ | ||
16 | -e "/compat: '[^']*'/d" \ | ||
17 | -e "/compat6: \\(on\\|off\\)/d" \ | ||
18 | + -e "s/cid: [0-9]\+/cid: XXXXXXXXXX/" \ | ||
19 | -e "/static: \\(on\\|off\\)/d" \ | ||
20 | -e "/zeroed_grain: \\(on\\|off\\)/d" \ | ||
21 | -e "/subformat: '[^']*'/d" \ | ||
22 | diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py | ||
23 | index XXXXXXX..XXXXXXX 100644 | ||
24 | --- a/tests/qemu-iotests/iotests.py | ||
25 | +++ b/tests/qemu-iotests/iotests.py | ||
26 | @@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename): | ||
27 | .replace(imgfmt, 'IMGFMT') | ||
28 | line = re.sub('iters: [0-9]+', 'iters: XXX', line) | ||
29 | line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line) | ||
30 | + line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line) | ||
31 | lines.append(line) | ||
32 | return '\n'.join(lines) | ||
33 | |||
34 | -- | ||
35 | 2.20.1 | ||
36 | |||
37 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | Signed-off-by: Fam Zheng <famz@redhat.com> | ||
2 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
3 | --- | ||
4 | tests/qemu-iotests/237 | 233 +++++++++++++++++++++++++ | ||
5 | tests/qemu-iotests/237.out | 347 +++++++++++++++++++++++++++++++++++++ | ||
6 | tests/qemu-iotests/group | 1 + | ||
7 | 3 files changed, 581 insertions(+) | ||
8 | create mode 100755 tests/qemu-iotests/237 | ||
9 | create mode 100644 tests/qemu-iotests/237.out | ||
10 | 1 | ||
11 | diff --git a/tests/qemu-iotests/237 b/tests/qemu-iotests/237 | ||
12 | new file mode 100755 | ||
13 | index XXXXXXX..XXXXXXX | ||
14 | --- /dev/null | ||
15 | +++ b/tests/qemu-iotests/237 | ||
16 | @@ -XXX,XX +XXX,XX @@ | ||
17 | +#!/usr/bin/env python | ||
18 | +# | ||
19 | +# Test vmdk and file image creation | ||
20 | +# | ||
21 | +# Copyright (C) 2018 Red Hat, Inc. | ||
22 | +# | ||
23 | +# Creator/Owner: Kevin Wolf <kwolf@redhat.com> | ||
24 | +# | ||
25 | +# This program is free software; you can redistribute it and/or modify | ||
26 | +# it under the terms of the GNU General Public License as published by | ||
27 | +# the Free Software Foundation; either version 2 of the License, or | ||
28 | +# (at your option) any later version. | ||
29 | +# | ||
30 | +# This program is distributed in the hope that it will be useful, | ||
31 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
32 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
33 | +# GNU General Public License for more details. | ||
34 | +# | ||
35 | +# You should have received a copy of the GNU General Public License | ||
36 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
37 | +# | ||
38 | + | ||
39 | +import iotests | ||
40 | +from iotests import imgfmt | ||
41 | + | ||
42 | +iotests.verify_image_format(supported_fmts=['vmdk']) | ||
43 | + | ||
44 | +def blockdev_create(vm, options): | ||
45 | + result = vm.qmp_log('blockdev-create', job_id='job0', options=options) | ||
46 | + | ||
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 | -- | ||
615 | 2.20.1 | ||
616 | |||
617 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | Clarify that the number of extents provided in BlockdevCreateOptionsVmdk | ||
2 | must match the number of extents that will actually be used. Providing | ||
3 | more extents will result in an error now. | ||
4 | 1 | ||
5 | This requires adapting the test case to provide the right number of | ||
6 | extents. | ||
7 | |||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | ||
10 | --- | ||
11 | qapi/block-core.json | 3 ++- | ||
12 | block/vmdk.c | 29 ++++++++++++++++++++++++----- | ||
13 | tests/qemu-iotests/237 | 6 +++++- | ||
14 | tests/qemu-iotests/237.out | 13 +++++++------ | ||
15 | 4 files changed, 38 insertions(+), 13 deletions(-) | ||
16 | |||
17 | diff --git a/qapi/block-core.json b/qapi/block-core.json | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/qapi/block-core.json | ||
20 | +++ b/qapi/block-core.json | ||
21 | @@ -XXX,XX +XXX,XX @@ | ||
22 | # twoGbMaxExtentSparse and twoGbMaxExtentFlat formats. For | ||
23 | # monolithicFlat, only one entry is required; for | ||
24 | # twoGbMaxExtent* formats, the number of entries required is | ||
25 | -# calculated as extent_number = virtual_size / 2GB. | ||
26 | +# calculated as extent_number = virtual_size / 2GB. Providing | ||
27 | +# more extents than will be used is an error. | ||
28 | # @subformat The subformat of the VMDK image. Default: "monolithicSparse". | ||
29 | # @backing-file The path of backing file. Default: no backing file is used. | ||
30 | # @adapter-type The adapter type used to fill in the descriptor. Default: ide. | ||
31 | diff --git a/block/vmdk.c b/block/vmdk.c | ||
32 | index XXXXXXX..XXXXXXX 100644 | ||
33 | --- a/block/vmdk.c | ||
34 | +++ b/block/vmdk.c | ||
35 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_do_create(int64_t size, | ||
36 | { | ||
37 | int extent_idx; | ||
38 | BlockBackend *blk = NULL; | ||
39 | + BlockBackend *extent_blk; | ||
40 | Error *local_err = NULL; | ||
41 | char *desc = NULL; | ||
42 | int ret = 0; | ||
43 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_do_create(int64_t size, | ||
44 | } | ||
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 | -- | ||
195 | 2.20.1 | ||
196 | |||
197 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Peter Maydell <peter.maydell@linaro.org> | ||
2 | 1 | ||
3 | Taking the address of a field in a packed struct is a bad idea, because | ||
4 | it might not be actually aligned enough for that pointer type (and | ||
5 | thus cause a crash on dereference on some host architectures). Newer | ||
6 | versions of clang warn about this. Avoid the bug by generating the | ||
7 | UUID into a local variable which is definitely safely aligned and | ||
8 | then copying it into place. | ||
9 | |||
10 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | --- | ||
13 | block/vpc.c | 4 +++- | ||
14 | 1 file changed, 3 insertions(+), 1 deletion(-) | ||
15 | |||
16 | diff --git a/block/vpc.c b/block/vpc.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/block/vpc.c | ||
19 | +++ b/block/vpc.c | ||
20 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts, | ||
21 | int64_t total_size; | ||
22 | int disk_type; | ||
23 | int ret = -EIO; | ||
24 | + QemuUUID uuid; | ||
25 | |||
26 | assert(opts->driver == BLOCKDEV_DRIVER_VPC); | ||
27 | vpc_opts = &opts->u.vpc; | ||
28 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts, | ||
29 | |||
30 | footer->type = cpu_to_be32(disk_type); | ||
31 | |||
32 | - qemu_uuid_generate(&footer->uuid); | ||
33 | + qemu_uuid_generate(&uuid); | ||
34 | + footer->uuid = uuid; | ||
35 | |||
36 | footer->checksum = cpu_to_be32(vpc_checksum(buf, HEADER_SIZE)); | ||
37 | |||
38 | -- | ||
39 | 2.20.1 | ||
40 | |||
41 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Peter Maydell <peter.maydell@linaro.org> | ||
2 | 1 | ||
3 | Taking the address of a field in a packed struct is a bad idea, because | ||
4 | it might not be actually aligned enough for that pointer type (and | ||
5 | thus cause a crash on dereference on some host architectures). Newer | ||
6 | versions of clang warn about this. | ||
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> | ||
14 | --- | ||
15 | block/vdi.c | 38 +++++++++++++++++++++++++------------- | ||
16 | 1 file changed, 25 insertions(+), 13 deletions(-) | ||
17 | |||
18 | diff --git a/block/vdi.c b/block/vdi.c | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/block/vdi.c | ||
21 | +++ b/block/vdi.c | ||
22 | @@ -XXX,XX +XXX,XX @@ static void vdi_header_to_le(VdiHeader *header) | ||
23 | |||
24 | static void vdi_header_print(VdiHeader *header) | ||
25 | { | ||
26 | - char uuid[37]; | ||
27 | + char uuidstr[37]; | ||
28 | + QemuUUID uuid; | ||
29 | logout("text %s", header->text); | ||
30 | logout("signature 0x%08x\n", header->signature); | ||
31 | logout("header size 0x%04x\n", header->header_size); | ||
32 | @@ -XXX,XX +XXX,XX @@ static void vdi_header_print(VdiHeader *header) | ||
33 | logout("block extra 0x%04x\n", header->block_extra); | ||
34 | logout("blocks tot. 0x%04x\n", header->blocks_in_image); | ||
35 | logout("blocks all. 0x%04x\n", header->blocks_allocated); | ||
36 | - qemu_uuid_unparse(&header->uuid_image, uuid); | ||
37 | - logout("uuid image %s\n", uuid); | ||
38 | - qemu_uuid_unparse(&header->uuid_last_snap, uuid); | ||
39 | - logout("uuid snap %s\n", uuid); | ||
40 | - qemu_uuid_unparse(&header->uuid_link, uuid); | ||
41 | - logout("uuid link %s\n", uuid); | ||
42 | - qemu_uuid_unparse(&header->uuid_parent, uuid); | ||
43 | - logout("uuid parent %s\n", uuid); | ||
44 | + uuid = header->uuid_image; | ||
45 | + qemu_uuid_unparse(&uuid, uuidstr); | ||
46 | + logout("uuid image %s\n", uuidstr); | ||
47 | + uuid = header->uuid_last_snap; | ||
48 | + qemu_uuid_unparse(&uuid, uuidstr); | ||
49 | + logout("uuid snap %s\n", uuidstr); | ||
50 | + uuid = header->uuid_link; | ||
51 | + qemu_uuid_unparse(&uuid, uuidstr); | ||
52 | + logout("uuid link %s\n", uuidstr); | ||
53 | + uuid = header->uuid_parent; | ||
54 | + qemu_uuid_unparse(&uuid, uuidstr); | ||
55 | + logout("uuid parent %s\n", uuidstr); | ||
56 | } | ||
57 | |||
58 | static int coroutine_fn vdi_co_check(BlockDriverState *bs, BdrvCheckResult *res, | ||
59 | @@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, | ||
60 | size_t bmap_size; | ||
61 | int ret; | ||
62 | Error *local_err = NULL; | ||
63 | + QemuUUID uuid_link, uuid_parent; | ||
64 | |||
65 | bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, | ||
66 | false, errp); | ||
67 | @@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, | ||
68 | goto fail; | ||
69 | } | ||
70 | |||
71 | + uuid_link = header.uuid_link; | ||
72 | + uuid_parent = header.uuid_parent; | ||
73 | + | ||
74 | if (header.disk_size % SECTOR_SIZE != 0) { | ||
75 | /* 'VBoxManage convertfromraw' can create images with odd disk sizes. | ||
76 | We accept them but round the disk size to the next multiple of | ||
77 | @@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags, | ||
78 | (uint64_t)header.blocks_in_image * header.block_size); | ||
79 | ret = -ENOTSUP; | ||
80 | goto fail; | ||
81 | - } else if (!qemu_uuid_is_null(&header.uuid_link)) { | ||
82 | + } else if (!qemu_uuid_is_null(&uuid_link)) { | ||
83 | error_setg(errp, "unsupported VDI image (non-NULL link UUID)"); | ||
84 | ret = -ENOTSUP; | ||
85 | goto fail; | ||
86 | - } else if (!qemu_uuid_is_null(&header.uuid_parent)) { | ||
87 | + } else if (!qemu_uuid_is_null(&uuid_parent)) { | ||
88 | error_setg(errp, "unsupported VDI image (non-NULL parent UUID)"); | ||
89 | ret = -ENOTSUP; | ||
90 | goto fail; | ||
91 | @@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, | ||
92 | BlockDriverState *bs_file = NULL; | ||
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 | -- | ||
113 | 2.20.1 | ||
114 | |||
115 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Peter Maydell <peter.maydell@linaro.org> | ||
2 | 1 | ||
3 | Currently qemu_uuid_bswap() takes a pointer to the QemuUUID to | ||
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> | ||
18 | --- | ||
19 | include/qemu/uuid.h | 2 +- | ||
20 | block/vdi.c | 16 ++++++++-------- | ||
21 | hw/acpi/vmgenid.c | 6 ++---- | ||
22 | tests/vmgenid-test.c | 2 +- | ||
23 | util/uuid.c | 10 +++++----- | ||
24 | 5 files changed, 17 insertions(+), 19 deletions(-) | ||
25 | |||
26 | diff --git a/include/qemu/uuid.h b/include/qemu/uuid.h | ||
27 | index XXXXXXX..XXXXXXX 100644 | ||
28 | --- a/include/qemu/uuid.h | ||
29 | +++ b/include/qemu/uuid.h | ||
30 | @@ -XXX,XX +XXX,XX @@ char *qemu_uuid_unparse_strdup(const QemuUUID *uuid); | ||
31 | |||
32 | int qemu_uuid_parse(const char *str, QemuUUID *uuid); | ||
33 | |||
34 | -void qemu_uuid_bswap(QemuUUID *uuid); | ||
35 | +QemuUUID qemu_uuid_bswap(QemuUUID uuid); | ||
36 | |||
37 | #endif | ||
38 | diff --git a/block/vdi.c b/block/vdi.c | ||
39 | index XXXXXXX..XXXXXXX 100644 | ||
40 | --- a/block/vdi.c | ||
41 | +++ b/block/vdi.c | ||
42 | @@ -XXX,XX +XXX,XX @@ static void vdi_header_to_cpu(VdiHeader *header) | ||
43 | header->block_extra = le32_to_cpu(header->block_extra); | ||
44 | header->blocks_in_image = le32_to_cpu(header->blocks_in_image); | ||
45 | header->blocks_allocated = le32_to_cpu(header->blocks_allocated); | ||
46 | - qemu_uuid_bswap(&header->uuid_image); | ||
47 | - qemu_uuid_bswap(&header->uuid_last_snap); | ||
48 | - qemu_uuid_bswap(&header->uuid_link); | ||
49 | - qemu_uuid_bswap(&header->uuid_parent); | ||
50 | + header->uuid_image = qemu_uuid_bswap(header->uuid_image); | ||
51 | + header->uuid_last_snap = qemu_uuid_bswap(header->uuid_last_snap); | ||
52 | + header->uuid_link = qemu_uuid_bswap(header->uuid_link); | ||
53 | + header->uuid_parent = qemu_uuid_bswap(header->uuid_parent); | ||
54 | } | ||
55 | |||
56 | static void vdi_header_to_le(VdiHeader *header) | ||
57 | @@ -XXX,XX +XXX,XX @@ static void vdi_header_to_le(VdiHeader *header) | ||
58 | header->block_extra = cpu_to_le32(header->block_extra); | ||
59 | header->blocks_in_image = cpu_to_le32(header->blocks_in_image); | ||
60 | header->blocks_allocated = cpu_to_le32(header->blocks_allocated); | ||
61 | - qemu_uuid_bswap(&header->uuid_image); | ||
62 | - qemu_uuid_bswap(&header->uuid_last_snap); | ||
63 | - qemu_uuid_bswap(&header->uuid_link); | ||
64 | - qemu_uuid_bswap(&header->uuid_parent); | ||
65 | + header->uuid_image = qemu_uuid_bswap(header->uuid_image); | ||
66 | + header->uuid_last_snap = qemu_uuid_bswap(header->uuid_last_snap); | ||
67 | + header->uuid_link = qemu_uuid_bswap(header->uuid_link); | ||
68 | + header->uuid_parent = qemu_uuid_bswap(header->uuid_parent); | ||
69 | } | ||
70 | |||
71 | static void vdi_header_print(VdiHeader *header) | ||
72 | diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c | ||
73 | index XXXXXXX..XXXXXXX 100644 | ||
74 | --- a/hw/acpi/vmgenid.c | ||
75 | +++ b/hw/acpi/vmgenid.c | ||
76 | @@ -XXX,XX +XXX,XX @@ void vmgenid_build_acpi(VmGenIdState *vms, GArray *table_data, GArray *guid, | ||
77 | * first, since that's what the guest expects | ||
78 | */ | ||
79 | g_array_set_size(guid, VMGENID_FW_CFG_SIZE - ARRAY_SIZE(guid_le.data)); | ||
80 | - guid_le = vms->guid; | ||
81 | - qemu_uuid_bswap(&guid_le); | ||
82 | + guid_le = qemu_uuid_bswap(vms->guid); | ||
83 | /* The GUID is written at a fixed offset into the fw_cfg file | ||
84 | * in order to implement the "OVMF SDT Header probe suppressor" | ||
85 | * see docs/specs/vmgenid.txt for more details | ||
86 | @@ -XXX,XX +XXX,XX @@ static void vmgenid_update_guest(VmGenIdState *vms) | ||
87 | * however, will expect the fields to be little-endian. | ||
88 | * Perform a byte swap immediately before writing. | ||
89 | */ | ||
90 | - guid_le = vms->guid; | ||
91 | - qemu_uuid_bswap(&guid_le); | ||
92 | + guid_le = qemu_uuid_bswap(vms->guid); | ||
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 | ||
98 | --- a/tests/vmgenid-test.c | ||
99 | +++ b/tests/vmgenid-test.c | ||
100 | @@ -XXX,XX +XXX,XX @@ static void read_guid_from_memory(QTestState *qts, QemuUUID *guid) | ||
101 | /* The GUID is in little-endian format in the guest, while QEMU | ||
102 | * uses big-endian. Swap after reading. | ||
103 | */ | ||
104 | - qemu_uuid_bswap(guid); | ||
105 | + *guid = qemu_uuid_bswap(*guid); | ||
106 | } | ||
107 | |||
108 | static void read_guid_from_monitor(QTestState *qts, QemuUUID *guid) | ||
109 | diff --git a/util/uuid.c b/util/uuid.c | ||
110 | index XXXXXXX..XXXXXXX 100644 | ||
111 | --- a/util/uuid.c | ||
112 | +++ b/util/uuid.c | ||
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 | -- | ||
130 | 2.20.1 | ||
131 | |||
132 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | If QEMU was configured with a driver in --block-drv-ro-whitelist, trying | ||
2 | to use that driver read-write resulted in an error message even if | ||
3 | auto-read-only=on was set. | ||
4 | 1 | ||
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 | |||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
11 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
12 | --- | ||
13 | block.c | 20 +++++++++++++------- | ||
14 | 1 file changed, 13 insertions(+), 7 deletions(-) | ||
15 | |||
16 | diff --git a/block.c b/block.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/block.c | ||
19 | +++ b/block.c | ||
20 | @@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file, | ||
21 | bs->read_only = !(bs->open_flags & BDRV_O_RDWR); | ||
22 | |||
23 | if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, bs->read_only)) { | ||
24 | - error_setg(errp, | ||
25 | - !bs->read_only && bdrv_is_whitelisted(drv, true) | ||
26 | - ? "Driver '%s' can only be used for read-only devices" | ||
27 | - : "Driver '%s' is not whitelisted", | ||
28 | - drv->format_name); | ||
29 | - ret = -ENOTSUP; | ||
30 | - goto fail_opts; | ||
31 | + if (!bs->read_only && bdrv_is_whitelisted(drv, true)) { | ||
32 | + ret = bdrv_apply_auto_read_only(bs, NULL, NULL); | ||
33 | + } else { | ||
34 | + ret = -ENOTSUP; | ||
35 | + } | ||
36 | + if (ret < 0) { | ||
37 | + error_setg(errp, | ||
38 | + !bs->read_only && bdrv_is_whitelisted(drv, true) | ||
39 | + ? "Driver '%s' can only be used for read-only devices" | ||
40 | + : "Driver '%s' is not whitelisted", | ||
41 | + drv->format_name); | ||
42 | + goto fail_opts; | ||
43 | + } | ||
44 | } | ||
45 | |||
46 | /* bdrv_new() and bdrv_close() make it so */ | ||
47 | -- | ||
48 | 2.20.1 | ||
49 | |||
50 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Thomas Huth <thuth@redhat.com> | ||
2 | 1 | ||
3 | The last user of blk_attach_dev_legacy() was the code in xen_disk which | ||
4 | has recently been reworked. Now there is no user for this legacy function | ||
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 | |||
9 | Signed-off-by: Thomas Huth <thuth@redhat.com> | ||
10 | Reviewed-by: Stefano Garzarella <sgarzare@redhat.com> | ||
11 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
12 | --- | ||
13 | include/sysemu/block-backend.h | 5 ++-- | ||
14 | block/block-backend.c | 54 ++++++---------------------------- | ||
15 | 2 files changed, 11 insertions(+), 48 deletions(-) | ||
16 | |||
17 | diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/include/sysemu/block-backend.h | ||
20 | +++ b/include/sysemu/block-backend.h | ||
21 | @@ -XXX,XX +XXX,XX @@ void blk_iostatus_disable(BlockBackend *blk); | ||
22 | void blk_iostatus_reset(BlockBackend *blk); | ||
23 | void blk_iostatus_set_err(BlockBackend *blk, int error); | ||
24 | int blk_attach_dev(BlockBackend *blk, DeviceState *dev); | ||
25 | -void blk_attach_dev_legacy(BlockBackend *blk, void *dev); | ||
26 | -void blk_detach_dev(BlockBackend *blk, void *dev); | ||
27 | -void *blk_get_attached_dev(BlockBackend *blk); | ||
28 | +void blk_detach_dev(BlockBackend *blk, DeviceState *dev); | ||
29 | +DeviceState *blk_get_attached_dev(BlockBackend *blk); | ||
30 | char *blk_get_attached_dev_id(BlockBackend *blk); | ||
31 | BlockBackend *blk_by_dev(void *dev); | ||
32 | BlockBackend *blk_by_qdev_id(const char *id, Error **errp); | ||
33 | diff --git a/block/block-backend.c b/block/block-backend.c | ||
34 | index XXXXXXX..XXXXXXX 100644 | ||
35 | --- a/block/block-backend.c | ||
36 | +++ b/block/block-backend.c | ||
37 | @@ -XXX,XX +XXX,XX @@ struct BlockBackend { | ||
38 | QTAILQ_ENTRY(BlockBackend) monitor_link; /* for monitor_block_backends */ | ||
39 | BlockBackendPublic public; | ||
40 | |||
41 | - void *dev; /* attached device model, if any */ | ||
42 | - bool legacy_dev; /* true if dev is not a DeviceState */ | ||
43 | - /* TODO change to DeviceState when all users are qdevified */ | ||
44 | + DeviceState *dev; /* attached device model, if any */ | ||
45 | const BlockDevOps *dev_ops; | ||
46 | void *dev_opaque; | ||
47 | |||
48 | @@ -XXX,XX +XXX,XX @@ void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm) | ||
49 | *shared_perm = blk->shared_perm; | ||
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; | ||
69 | } | ||
70 | |||
71 | -/* | ||
72 | - * Attach device model @dev to @blk. | ||
73 | - * Return 0 on success, -EBUSY when a device model is attached already. | ||
74 | - */ | ||
75 | -int blk_attach_dev(BlockBackend *blk, DeviceState *dev) | ||
76 | -{ | ||
77 | - return blk_do_attach_dev(blk, dev); | ||
78 | -} | ||
79 | - | ||
80 | -/* | ||
81 | - * Attach device model @dev to @blk. | ||
82 | - * @blk must not have a device model attached already. | ||
83 | - * TODO qdevified devices don't use this, remove when devices are qdevified | ||
84 | - */ | ||
85 | -void blk_attach_dev_legacy(BlockBackend *blk, void *dev) | ||
86 | -{ | ||
87 | - if (blk_do_attach_dev(blk, dev) < 0) { | ||
88 | - abort(); | ||
89 | - } | ||
90 | - blk->legacy_dev = true; | ||
91 | -} | ||
92 | - | ||
93 | /* | ||
94 | * Detach device model @dev from @blk. | ||
95 | * @dev must be currently attached to @blk. | ||
96 | */ | ||
97 | -void blk_detach_dev(BlockBackend *blk, void *dev) | ||
98 | -/* TODO change to DeviceState *dev when all users are qdevified */ | ||
99 | +void blk_detach_dev(BlockBackend *blk, DeviceState *dev) | ||
100 | { | ||
101 | assert(blk->dev == dev); | ||
102 | blk->dev = NULL; | ||
103 | @@ -XXX,XX +XXX,XX @@ void blk_detach_dev(BlockBackend *blk, void *dev) | ||
104 | /* | ||
105 | * Return the device model attached to @blk if any, else null. | ||
106 | */ | ||
107 | -void *blk_get_attached_dev(BlockBackend *blk) | ||
108 | -/* TODO change to return DeviceState * when all users are qdevified */ | ||
109 | +DeviceState *blk_get_attached_dev(BlockBackend *blk) | ||
110 | { | ||
111 | return blk->dev; | ||
112 | } | ||
113 | @@ -XXX,XX +XXX,XX @@ void *blk_get_attached_dev(BlockBackend *blk) | ||
114 | * device attached to the BlockBackend. */ | ||
115 | char *blk_get_attached_dev_id(BlockBackend *blk) | ||
116 | { | ||
117 | - DeviceState *dev; | ||
118 | - | ||
119 | - assert(!blk->legacy_dev); | ||
120 | - dev = blk->dev; | ||
121 | + DeviceState *dev = blk->dev; | ||
122 | |||
123 | if (!dev) { | ||
124 | return g_strdup(""); | ||
125 | @@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_dev(void *dev) | ||
126 | void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops, | ||
127 | void *opaque) | ||
128 | { | ||
129 | - /* All drivers that use blk_set_dev_ops() are qdevified and we want to keep | ||
130 | - * it that way, so we can assume blk->dev, if present, is a DeviceState if | ||
131 | - * blk->dev_ops is set. Non-device users may use dev_ops without device. */ | ||
132 | - assert(!blk->legacy_dev); | ||
133 | - | ||
134 | blk->dev_ops = ops; | ||
135 | blk->dev_opaque = opaque; | ||
136 | |||
137 | @@ -XXX,XX +XXX,XX @@ void blk_dev_change_media_cb(BlockBackend *blk, bool load, Error **errp) | ||
138 | bool tray_was_open, tray_is_open; | ||
139 | Error *local_err = NULL; | ||
140 | |||
141 | - assert(!blk->legacy_dev); | ||
142 | - | ||
143 | tray_was_open = blk_dev_is_tray_open(blk); | ||
144 | blk->dev_ops->change_media_cb(blk->dev_opaque, load, &local_err); | ||
145 | if (local_err) { | ||
146 | @@ -XXX,XX +XXX,XX @@ void blk_eject(BlockBackend *blk, bool eject_flag) | ||
147 | BlockDriverState *bs = blk_bs(blk); | ||
148 | char *id; | ||
149 | |||
150 | - /* blk_eject is only called by qdevified devices */ | ||
151 | - assert(!blk->legacy_dev); | ||
152 | - | ||
153 | if (bs) { | ||
154 | bdrv_eject(bs, eject_flag); | ||
155 | } | ||
156 | -- | ||
157 | 2.20.1 | ||
158 | |||
159 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Markus Armbruster <armbru@redhat.com> | ||
2 | 1 | ||
3 | We define 54 macros for the powers of two >= 1024. We use six, in six | ||
4 | macro definitions. Four of them could just as well use the common MiB | ||
5 | macro, so do that. The remaining two can't, because they get passed | ||
6 | to stringify. Replace the macro by the literal number there. | ||
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 | |||
11 | This effectively reverts commit 540b8492618 and 1240ac558d3. | ||
12 | |||
13 | Signed-off-by: Markus Armbruster <armbru@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> | ||
18 | --- | ||
19 | block/qcow2.h | 10 +++--- | ||
20 | include/qemu/units.h | 73 -------------------------------------------- | ||
21 | block/vdi.c | 3 +- | ||
22 | 3 files changed, 7 insertions(+), 79 deletions(-) | ||
23 | |||
24 | diff --git a/block/qcow2.h b/block/qcow2.h | ||
25 | index XXXXXXX..XXXXXXX 100644 | ||
26 | --- a/block/qcow2.h | ||
27 | +++ b/block/qcow2.h | ||
28 | @@ -XXX,XX +XXX,XX @@ | ||
29 | |||
30 | /* 8 MB refcount table is enough for 2 PB images at 64k cluster size | ||
31 | * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */ | ||
32 | -#define QCOW_MAX_REFTABLE_SIZE S_8MiB | ||
33 | +#define QCOW_MAX_REFTABLE_SIZE (8 * MiB) | ||
34 | |||
35 | /* 32 MB L1 table is enough for 2 PB images at 64k cluster size | ||
36 | * (128 GB for 512 byte clusters, 2 EB for 2 MB clusters) */ | ||
37 | -#define QCOW_MAX_L1_SIZE S_32MiB | ||
38 | +#define QCOW_MAX_L1_SIZE (32 * MiB) | ||
39 | |||
40 | /* Allow for an average of 1k per snapshot table entry, should be plenty of | ||
41 | * space for snapshot names and IDs */ | ||
42 | @@ -XXX,XX +XXX,XX @@ | ||
43 | #define MIN_REFCOUNT_CACHE_SIZE 4 /* clusters */ | ||
44 | |||
45 | #ifdef CONFIG_LINUX | ||
46 | -#define DEFAULT_L2_CACHE_MAX_SIZE S_32MiB | ||
47 | +#define DEFAULT_L2_CACHE_MAX_SIZE (32 * MiB) | ||
48 | #define DEFAULT_CACHE_CLEAN_INTERVAL 600 /* seconds */ | ||
49 | #else | ||
50 | -#define DEFAULT_L2_CACHE_MAX_SIZE S_8MiB | ||
51 | +#define DEFAULT_L2_CACHE_MAX_SIZE (8 * MiB) | ||
52 | /* Cache clean interval is currently available only on Linux, so must be 0 */ | ||
53 | #define DEFAULT_CACHE_CLEAN_INTERVAL 0 | ||
54 | #endif | ||
55 | |||
56 | -#define DEFAULT_CLUSTER_SIZE S_64KiB | ||
57 | +#define DEFAULT_CLUSTER_SIZE 65536 | ||
58 | |||
59 | #define QCOW2_OPT_LAZY_REFCOUNTS "lazy-refcounts" | ||
60 | #define QCOW2_OPT_DISCARD_REQUEST "pass-discard-request" | ||
61 | diff --git a/include/qemu/units.h b/include/qemu/units.h | ||
62 | index XXXXXXX..XXXXXXX 100644 | ||
63 | --- a/include/qemu/units.h | ||
64 | +++ b/include/qemu/units.h | ||
65 | @@ -XXX,XX +XXX,XX @@ | ||
66 | #define PiB (INT64_C(1) << 50) | ||
67 | #define EiB (INT64_C(1) << 60) | ||
68 | |||
69 | -/* | ||
70 | - * The following lookup table is intended to be used when a literal string of | ||
71 | - * the number of bytes is required (for example if it needs to be stringified). | ||
72 | - * It can also be used for generic shortcuts of power-of-two sizes. | ||
73 | - * This table is generated using the AWK script below: | ||
74 | - * | ||
75 | - * BEGIN { | ||
76 | - * suffix="KMGTPE"; | ||
77 | - * for(i=10; i<64; i++) { | ||
78 | - * val=2**i; | ||
79 | - * s=substr(suffix, int(i/10), 1); | ||
80 | - * n=2**(i%10); | ||
81 | - * pad=21-int(log(n)/log(10)); | ||
82 | - * printf("#define S_%d%siB %*d\n", n, s, pad, val); | ||
83 | - * } | ||
84 | - * } | ||
85 | - */ | ||
86 | - | ||
87 | -#define S_1KiB 1024 | ||
88 | -#define S_2KiB 2048 | ||
89 | -#define S_4KiB 4096 | ||
90 | -#define S_8KiB 8192 | ||
91 | -#define S_16KiB 16384 | ||
92 | -#define S_32KiB 32768 | ||
93 | -#define S_64KiB 65536 | ||
94 | -#define S_128KiB 131072 | ||
95 | -#define S_256KiB 262144 | ||
96 | -#define S_512KiB 524288 | ||
97 | -#define S_1MiB 1048576 | ||
98 | -#define S_2MiB 2097152 | ||
99 | -#define S_4MiB 4194304 | ||
100 | -#define S_8MiB 8388608 | ||
101 | -#define S_16MiB 16777216 | ||
102 | -#define S_32MiB 33554432 | ||
103 | -#define S_64MiB 67108864 | ||
104 | -#define S_128MiB 134217728 | ||
105 | -#define S_256MiB 268435456 | ||
106 | -#define S_512MiB 536870912 | ||
107 | -#define S_1GiB 1073741824 | ||
108 | -#define S_2GiB 2147483648 | ||
109 | -#define S_4GiB 4294967296 | ||
110 | -#define S_8GiB 8589934592 | ||
111 | -#define S_16GiB 17179869184 | ||
112 | -#define S_32GiB 34359738368 | ||
113 | -#define S_64GiB 68719476736 | ||
114 | -#define S_128GiB 137438953472 | ||
115 | -#define S_256GiB 274877906944 | ||
116 | -#define S_512GiB 549755813888 | ||
117 | -#define S_1TiB 1099511627776 | ||
118 | -#define S_2TiB 2199023255552 | ||
119 | -#define S_4TiB 4398046511104 | ||
120 | -#define S_8TiB 8796093022208 | ||
121 | -#define S_16TiB 17592186044416 | ||
122 | -#define S_32TiB 35184372088832 | ||
123 | -#define S_64TiB 70368744177664 | ||
124 | -#define S_128TiB 140737488355328 | ||
125 | -#define S_256TiB 281474976710656 | ||
126 | -#define S_512TiB 562949953421312 | ||
127 | -#define S_1PiB 1125899906842624 | ||
128 | -#define S_2PiB 2251799813685248 | ||
129 | -#define S_4PiB 4503599627370496 | ||
130 | -#define S_8PiB 9007199254740992 | ||
131 | -#define S_16PiB 18014398509481984 | ||
132 | -#define S_32PiB 36028797018963968 | ||
133 | -#define S_64PiB 72057594037927936 | ||
134 | -#define S_128PiB 144115188075855872 | ||
135 | -#define S_256PiB 288230376151711744 | ||
136 | -#define S_512PiB 576460752303423488 | ||
137 | -#define S_1EiB 1152921504606846976 | ||
138 | -#define S_2EiB 2305843009213693952 | ||
139 | -#define S_4EiB 4611686018427387904 | ||
140 | -#define S_8EiB 9223372036854775808 | ||
141 | - | ||
142 | #endif | ||
143 | diff --git a/block/vdi.c b/block/vdi.c | ||
144 | index XXXXXXX..XXXXXXX 100644 | ||
145 | --- a/block/vdi.c | ||
146 | +++ b/block/vdi.c | ||
147 | @@ -XXX,XX +XXX,XX @@ | ||
148 | #define BLOCK_OPT_STATIC "static" | ||
149 | |||
150 | #define SECTOR_SIZE 512 | ||
151 | -#define DEFAULT_CLUSTER_SIZE S_1MiB | ||
152 | +#define DEFAULT_CLUSTER_SIZE 1048576 | ||
153 | +/* Note: can't use 1 * MiB, because it's passed to stringify() */ | ||
154 | |||
155 | #if defined(CONFIG_VDI_DEBUG) | ||
156 | #define VDI_DEBUG 1 | ||
157 | -- | ||
158 | 2.20.1 | ||
159 | |||
160 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Alberto Garcia <berto@igalia.com> | ||
2 | 1 | ||
3 | This fixes a crash when attaching a disk to a SCSI device using | ||
4 | iothreads, then detaching it and reattaching it again. Test case | ||
5 | included. | ||
6 | |||
7 | Signed-off-by: Alberto Garcia <berto@igalia.com> | ||
8 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
9 | --- | ||
10 | hw/scsi/virtio-scsi.c | 6 +++ | ||
11 | tests/qemu-iotests/240 | 89 ++++++++++++++++++++++++++++++++++++++ | ||
12 | tests/qemu-iotests/240.out | 18 ++++++++ | ||
13 | tests/qemu-iotests/group | 1 + | ||
14 | 4 files changed, 114 insertions(+) | ||
15 | create mode 100755 tests/qemu-iotests/240 | ||
16 | create mode 100644 tests/qemu-iotests/240.out | ||
17 | |||
18 | diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/hw/scsi/virtio-scsi.c | ||
21 | +++ b/hw/scsi/virtio-scsi.c | ||
22 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev, | ||
23 | virtio_scsi_release(s); | ||
24 | } | ||
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 | } | ||
34 | |||
35 | diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240 | ||
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 | +{ | ||
80 | + echo Testing: "$@" | ||
81 | + $QEMU -nographic -qmp stdio -serial none "$@" | ||
82 | + echo | ||
83 | +} | ||
84 | + | ||
85 | +# Remove QMP events from (pretty-printed) output. Doesn't handle | ||
86 | +# nested dicts correctly, but we don't get any of those in this test. | ||
87 | +_filter_qmp_events() | ||
88 | +{ | ||
89 | + tr '\n' '\t' | sed -e \ | ||
90 | + 's/{\s*"timestamp":\s*{[^}]*},\s*"event":[^,}]*\(,\s*"data":\s*{[^}]*}\)\?\s*}\s*//g' \ | ||
91 | + | tr '\t' '\n' | ||
92 | +} | ||
93 | + | ||
94 | +run_qemu() | ||
95 | +{ | ||
96 | + do_run_qemu "$@" 2>&1 | _filter_qmp | _filter_qmp_events | ||
97 | +} | ||
98 | + | ||
99 | +case "$QEMU_DEFAULT_MACHINE" in | ||
100 | + s390-ccw-virtio) | ||
101 | + virtio_scsi=virtio-scsi-ccw | ||
102 | + ;; | ||
103 | + *) | ||
104 | + virtio_scsi=virtio-scsi-pci | ||
105 | + ;; | ||
106 | +esac | ||
107 | + | ||
108 | +echo | ||
109 | +echo === Unplug a SCSI disk and then plug it again === | ||
110 | +echo | ||
111 | + | ||
112 | +run_qemu <<EOF | ||
113 | +{ "execute": "qmp_capabilities" } | ||
114 | +{ "execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0"}} | ||
115 | +{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread0"}} | ||
116 | +{ "execute": "device_add", "arguments": {"id": "scsi0", "driver": "${virtio_scsi}", "iothread": "iothread0"}} | ||
117 | +{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0"}} | ||
118 | +{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}} | ||
119 | +{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0"}} | ||
120 | +{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}} | ||
121 | +{ "execute": "device_del", "arguments": {"id": "scsi0"}} | ||
122 | +{ "execute": "blockdev-del", "arguments": {"node-name": "hd0"}} | ||
123 | +{ "execute": "quit"} | ||
124 | +EOF | ||
125 | + | ||
126 | +# success, all done | ||
127 | +echo "*** done" | ||
128 | +rm -f $seq.full | ||
129 | +status=0 | ||
130 | diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out | ||
131 | new file mode 100644 | ||
132 | index XXXXXXX..XXXXXXX | ||
133 | --- /dev/null | ||
134 | +++ b/tests/qemu-iotests/240.out | ||
135 | @@ -XXX,XX +XXX,XX @@ | ||
136 | +QA output created by 240 | ||
137 | + | ||
138 | +=== Unplug a SCSI disk and then plug it again === | ||
139 | + | ||
140 | +Testing: | ||
141 | +QMP_VERSION | ||
142 | +{"return": {}} | ||
143 | +{"return": {}} | ||
144 | +{"return": {}} | ||
145 | +{"return": {}} | ||
146 | +{"return": {}} | ||
147 | +{"return": {}} | ||
148 | +{"return": {}} | ||
149 | +{"return": {}} | ||
150 | +{"return": {}} | ||
151 | +{"return": {}} | ||
152 | +{"return": {}} | ||
153 | +*** done | ||
154 | diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group | ||
155 | index XXXXXXX..XXXXXXX 100644 | ||
156 | --- a/tests/qemu-iotests/group | ||
157 | +++ b/tests/qemu-iotests/group | ||
158 | @@ -XXX,XX +XXX,XX @@ | ||
159 | 237 rw auto quick | ||
160 | 238 auto quick | ||
161 | 239 rw auto quick | ||
162 | +240 auto quick | ||
163 | -- | ||
164 | 2.20.1 | ||
165 | |||
166 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Alberto Garcia <berto@igalia.com> | ||
2 | 1 | ||
3 | This fixes a crash when attaching two disks with the same blockdev to | ||
4 | a SCSI device that is using iothreads. Test case included. | ||
5 | |||
6 | Signed-off-by: Alberto Garcia <berto@igalia.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | hw/scsi/scsi-disk.c | 23 ++++++++++++++++++++--- | ||
10 | tests/qemu-iotests/240 | 18 ++++++++++++++++++ | ||
11 | tests/qemu-iotests/240.out | 16 ++++++++++++++++ | ||
12 | 3 files changed, 54 insertions(+), 3 deletions(-) | ||
13 | |||
14 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/hw/scsi/scsi-disk.c | ||
17 | +++ b/hw/scsi/scsi-disk.c | ||
18 | @@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp) | ||
19 | static void scsi_hd_realize(SCSIDevice *dev, Error **errp) | ||
20 | { | ||
21 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); | ||
22 | + AioContext *ctx = NULL; | ||
23 | /* can happen for devices without drive. The error message for missing | ||
24 | * backend will be issued in scsi_realize | ||
25 | */ | ||
26 | if (s->qdev.conf.blk) { | ||
27 | + ctx = blk_get_aio_context(s->qdev.conf.blk); | ||
28 | + aio_context_acquire(ctx); | ||
29 | blkconf_blocksizes(&s->qdev.conf); | ||
30 | } | ||
31 | s->qdev.blocksize = s->qdev.conf.logical_block_size; | ||
32 | @@ -XXX,XX +XXX,XX @@ static void scsi_hd_realize(SCSIDevice *dev, Error **errp) | ||
33 | s->product = g_strdup("QEMU HARDDISK"); | ||
34 | } | ||
35 | scsi_realize(&s->qdev, errp); | ||
36 | + if (ctx) { | ||
37 | + aio_context_release(ctx); | ||
38 | + } | ||
39 | } | ||
40 | |||
41 | static void scsi_cd_realize(SCSIDevice *dev, Error **errp) | ||
42 | { | ||
43 | SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); | ||
44 | + AioContext *ctx; | ||
45 | int ret; | ||
46 | |||
47 | if (!dev->conf.blk) { | ||
48 | @@ -XXX,XX +XXX,XX @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp) | ||
49 | assert(ret == 0); | ||
50 | } | ||
51 | |||
52 | + ctx = blk_get_aio_context(dev->conf.blk); | ||
53 | + aio_context_acquire(ctx); | ||
54 | s->qdev.blocksize = 2048; | ||
55 | s->qdev.type = TYPE_ROM; | ||
56 | s->features |= 1 << SCSI_DISK_F_REMOVABLE; | ||
57 | @@ -XXX,XX +XXX,XX @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp) | ||
58 | s->product = g_strdup("QEMU CD-ROM"); | ||
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; | ||
88 | + goto out; | ||
89 | } | ||
90 | if (sg_version < 30000) { | ||
91 | error_setg(errp, "scsi generic interface too old"); | ||
92 | - return; | ||
93 | + goto out; | ||
94 | } | ||
95 | |||
96 | /* get device type from INQUIRY data */ | ||
97 | rc = get_device_type(s); | ||
98 | if (rc < 0) { | ||
99 | error_setg(errp, "INQUIRY failed"); | ||
100 | - return; | ||
101 | + goto out; | ||
102 | } | ||
103 | |||
104 | /* Make a guess for the block size, we'll fix it when the guest sends. | ||
105 | @@ -XXX,XX +XXX,XX @@ static void scsi_block_realize(SCSIDevice *dev, Error **errp) | ||
106 | |||
107 | scsi_realize(&s->qdev, errp); | ||
108 | scsi_generic_read_device_inquiry(&s->qdev); | ||
109 | + | ||
110 | +out: | ||
111 | + aio_context_release(ctx); | ||
112 | } | ||
113 | |||
114 | typedef struct SCSIBlockReq { | ||
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 | -- | ||
172 | 2.20.1 | ||
173 | |||
174 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Alberto Garcia <berto@igalia.com> | ||
2 | 1 | ||
3 | This patch forbids attaching a disk to a SCSI device if its using a | ||
4 | different AioContext. Test case included. | ||
5 | |||
6 | Signed-off-by: Alberto Garcia <berto@igalia.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | hw/scsi/virtio-scsi.c | 7 +++++++ | ||
10 | tests/qemu-iotests/240 | 22 ++++++++++++++++++++++ | ||
11 | tests/qemu-iotests/240.out | 20 ++++++++++++++++++++ | ||
12 | 3 files changed, 49 insertions(+) | ||
13 | |||
14 | diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/hw/scsi/virtio-scsi.c | ||
17 | +++ b/hw/scsi/virtio-scsi.c | ||
18 | @@ -XXX,XX +XXX,XX @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, | ||
19 | SCSIDevice *sd = SCSI_DEVICE(dev); | ||
20 | |||
21 | if (s->ctx && !s->dataplane_fenced) { | ||
22 | + AioContext *ctx; | ||
23 | if (blk_op_is_blocked(sd->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) { | ||
24 | return; | ||
25 | } | ||
26 | + ctx = blk_get_aio_context(sd->conf.blk); | ||
27 | + if (ctx != s->ctx && ctx != qemu_get_aio_context()) { | ||
28 | + error_setg(errp, "Cannot attach a blockdev that is using " | ||
29 | + "a different iothread"); | ||
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 | ||
70 | --- a/tests/qemu-iotests/240.out | ||
71 | +++ b/tests/qemu-iotests/240.out | ||
72 | @@ -XXX,XX +XXX,XX @@ QMP_VERSION | ||
73 | {"return": {}} | ||
74 | {"return": {}} | ||
75 | {"return": {}} | ||
76 | + | ||
77 | +=== Attach two SCSI disks using the same block device but different iothreads === | ||
78 | + | ||
79 | +Testing: | ||
80 | +QMP_VERSION | ||
81 | +{"return": {}} | ||
82 | +{"return": {}} | ||
83 | +{"return": {}} | ||
84 | +{"return": {}} | ||
85 | +{"return": {}} | ||
86 | +{"return": {}} | ||
87 | +{"return": {}} | ||
88 | +{"error": {"class": "GenericError", "desc": "Cannot attach a blockdev that is using a different iothread"}} | ||
89 | +{"return": {}} | ||
90 | +{"return": {}} | ||
91 | +{"return": {}} | ||
92 | +{"return": {}} | ||
93 | +{"return": {}} | ||
94 | +{"return": {}} | ||
95 | +{"return": {}} | ||
96 | *** done | ||
97 | -- | ||
98 | 2.20.1 | ||
99 | |||
100 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Max Reitz <mreitz@redhat.com> | ||
2 | 1 | ||
3 | Without this filter, this test sometimes fails. | ||
4 | |||
5 | Signed-off-by: Max Reitz <mreitz@redhat.com> | ||
6 | Reviewed-by: John Snow <jsnow@redhat.com> | ||
7 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
8 | --- | ||
9 | tests/qemu-iotests/229 | 6 +++++- | ||
10 | tests/qemu-iotests/229.out | 1 - | ||
11 | 2 files changed, 5 insertions(+), 2 deletions(-) | ||
12 | |||
13 | diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229 | ||
14 | index XXXXXXX..XXXXXXX 100755 | ||
15 | --- a/tests/qemu-iotests/229 | ||
16 | +++ b/tests/qemu-iotests/229 | ||
17 | @@ -XXX,XX +XXX,XX @@ echo | ||
18 | echo '=== Force cancel job paused in error state ===' | ||
19 | echo | ||
20 | |||
21 | +# Filter out BLOCK_JOB_ERROR events because they may or may not occur. | ||
22 | +# Cancelling the job means resuming it for a bit before it is actually | ||
23 | +# aborted, and in that time it may or may not re-encounter the error. | ||
24 | success_or_failure="y" _send_qemu_cmd $QEMU_HANDLE \ | ||
25 | "{'execute': 'block-job-cancel', | ||
26 | 'arguments': { 'device': 'testdisk', | ||
27 | 'force': true}}" \ | ||
28 | - "BLOCK_JOB_CANCELLED" "Assertion" | ||
29 | + "BLOCK_JOB_CANCELLED" "Assertion" \ | ||
30 | + | grep -v '"BLOCK_JOB_ERROR"' | ||
31 | |||
32 | # success, all done | ||
33 | echo "*** done" | ||
34 | diff --git a/tests/qemu-iotests/229.out b/tests/qemu-iotests/229.out | ||
35 | index XXXXXXX..XXXXXXX 100644 | ||
36 | --- a/tests/qemu-iotests/229.out | ||
37 | +++ b/tests/qemu-iotests/229.out | ||
38 | @@ -XXX,XX +XXX,XX @@ wrote 2097152/2097152 bytes at offset 0 | ||
39 | |||
40 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "testdisk"}} | ||
41 | {"return": {}} | ||
42 | -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "testdisk", "operation": "write", "action": "stop"}} | ||
43 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "testdisk"}} | ||
44 | {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "testdisk", "len": 2097152, "offset": 1048576, "speed": 0, "type": "mirror"}} | ||
45 | *** done | ||
46 | -- | ||
47 | 2.20.1 | ||
48 | |||
49 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: John Snow <jsnow@redhat.com> | ||
2 | 1 | ||
3 | It's not enough to order the kwargs for consistent QMP log output, | ||
4 | we must also sort any sub-dictionaries in lists that appear as values. | ||
5 | |||
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> | ||
11 | --- | ||
12 | tests/qemu-iotests/236.out | 56 +++++++++++++++++------------------ | ||
13 | tests/qemu-iotests/iotests.py | 21 ++++++------- | ||
14 | 2 files changed, 39 insertions(+), 38 deletions(-) | ||
15 | |||
16 | diff --git a/tests/qemu-iotests/236.out b/tests/qemu-iotests/236.out | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/tests/qemu-iotests/236.out | ||
19 | +++ b/tests/qemu-iotests/236.out | ||
20 | @@ -XXX,XX +XXX,XX @@ write -P0xcd 0x3ff0000 64k | ||
21 | "actions": [ | ||
22 | { | ||
23 | "data": { | ||
24 | - "node": "drive0", | ||
25 | - "name": "bitmapB" | ||
26 | + "name": "bitmapB", | ||
27 | + "node": "drive0" | ||
28 | }, | ||
29 | "type": "block-dirty-bitmap-disable" | ||
30 | }, | ||
31 | { | ||
32 | "data": { | ||
33 | - "node": "drive0", | ||
34 | + "granularity": 65536, | ||
35 | "name": "bitmapC", | ||
36 | - "granularity": 65536 | ||
37 | + "node": "drive0" | ||
38 | }, | ||
39 | "type": "block-dirty-bitmap-add" | ||
40 | }, | ||
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 | -- | ||
203 | 2.20.1 | ||
204 | |||
205 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | bdrv_co_invalidate_cache() clears the BDRV_O_INACTIVE flag before | ||
2 | actually activating a node so that the correct permissions etc. are | ||
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 | 1 | ||
6 | Restoring the flag was missing in the error path for a failed | ||
7 | parent->role->activate() call. The consequence is that this attempt to | ||
8 | activate all images correctly fails because we still set errp, however | ||
9 | on the next attempt BDRV_O_INACTIVE is already clear, so we return | ||
10 | success without actually retrying the failed action. | ||
11 | |||
12 | An example where this is observable in practice is migration to a QEMU | ||
13 | instance that has a raw format block node attached to a guest device | ||
14 | with share-rw=off (the default) while another process holds | ||
15 | BLK_PERM_WRITE for the same image. In this case, all activation steps | ||
16 | before parent->role->activate() succeed because raw can tolerate other | ||
17 | writers to the image. Only the parent callback (in particular | ||
18 | blk_root_activate()) tries to implement the share-rw=on property and | ||
19 | requests exclusive write permissions. This fails when the migration | ||
20 | completes and correctly displays an error. However, a manual 'cont' will | ||
21 | incorrectly resume the VM without calling blk_root_activate() again. | ||
22 | |||
23 | This case is described in more detail in the following bug report: | ||
24 | https://bugzilla.redhat.com/show_bug.cgi?id=1531888 | ||
25 | |||
26 | Fix this by correctly restoring the BDRV_O_INACTIVE flag in the error | ||
27 | path. | ||
28 | |||
29 | Cc: qemu-stable@nongnu.org | ||
30 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
31 | Tested-by: Markus Armbruster <armbru@redhat.com> | ||
32 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
33 | --- | ||
34 | block.c | 1 + | ||
35 | 1 file changed, 1 insertion(+) | ||
36 | |||
37 | diff --git a/block.c b/block.c | ||
38 | index XXXXXXX..XXXXXXX 100644 | ||
39 | --- a/block.c | ||
40 | +++ b/block.c | ||
41 | @@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, | ||
42 | if (parent->role->activate) { | ||
43 | parent->role->activate(parent, &local_err); | ||
44 | if (local_err) { | ||
45 | + bs->open_flags |= BDRV_O_INACTIVE; | ||
46 | error_propagate(errp, local_err); | ||
47 | return; | ||
48 | } | ||
49 | -- | ||
50 | 2.20.1 | ||
51 | |||
52 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | From: Alberto Garcia <berto@igalia.com> | ||
2 | 1 | ||
3 | The cmd() method of the QEMUQtestProtocol class sends a qtest command | ||
4 | to QEMU but doesn't wait for the return message ("OK", "FAIL", "ERR"). | ||
5 | Because of this, it can return control to the caller before the | ||
6 | command has actually finished. | ||
7 | |||
8 | In cases like clock_step or clock_set this means that cmd() can return | ||
9 | before all the timers triggered by the clock change have been fired. | ||
10 | This can be fixed by making cmd() wait for the output of the qtest | ||
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> | ||
19 | --- | ||
20 | scripts/qtest.py | 6 ++++++ | ||
21 | 1 file changed, 6 insertions(+) | ||
22 | |||
23 | diff --git a/scripts/qtest.py b/scripts/qtest.py | ||
24 | index XXXXXXX..XXXXXXX 100644 | ||
25 | --- a/scripts/qtest.py | ||
26 | +++ b/scripts/qtest.py | ||
27 | @@ -XXX,XX +XXX,XX @@ class QEMUQtestProtocol(object): | ||
28 | """ | ||
29 | self._address = address | ||
30 | self._sock = self._get_sock() | ||
31 | + self._sockfile = None | ||
32 | if server: | ||
33 | self._sock.bind(self._address) | ||
34 | self._sock.listen(1) | ||
35 | @@ -XXX,XX +XXX,XX @@ class QEMUQtestProtocol(object): | ||
36 | @raise socket.error on socket connection errors | ||
37 | """ | ||
38 | self._sock.connect(self._address) | ||
39 | + self._sockfile = self._sock.makefile() | ||
40 | |||
41 | def accept(self): | ||
42 | """ | ||
43 | @@ -XXX,XX +XXX,XX @@ class QEMUQtestProtocol(object): | ||
44 | @raise socket.error on socket connection errors | ||
45 | """ | ||
46 | self._sock, _ = self._sock.accept() | ||
47 | + self._sockfile = self._sock.makefile() | ||
48 | |||
49 | def cmd(self, qtest_cmd): | ||
50 | """ | ||
51 | @@ -XXX,XX +XXX,XX @@ class QEMUQtestProtocol(object): | ||
52 | @param qtest_cmd: qtest command text to be sent | ||
53 | """ | ||
54 | self._sock.sendall((qtest_cmd + "\n").encode('utf-8')) | ||
55 | + resp = self._sockfile.readline() | ||
56 | + return resp | ||
57 | |||
58 | def close(self): | ||
59 | self._sock.close() | ||
60 | + self._sockfile.close() | ||
61 | |||
62 | def settimeout(self, timeout): | ||
63 | self._sock.settimeout(timeout) | ||
64 | -- | ||
65 | 2.20.1 | ||
66 | |||
67 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | scsi-disk includes in the Device Identification VPD page, depending on | ||
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 | 1 | ||
7 | With anonymous BlockBackends, i.e. scsi-disk devices constructed with | ||
8 | drive=<node-name>, and no serial number explicitly specified, this ends | ||
9 | up as an empty string. If this happens to more than one disk, we have | ||
10 | accidentally signalled to the OS that this is a multipath setup, which | ||
11 | is obviously not what was intended. | ||
12 | |||
13 | Instead of using an empty string for the vendor specific designator, | ||
14 | simply leave out that designator, which makes Linux detect such setups | ||
15 | as separate disks again. | ||
16 | |||
17 | 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 | --- | ||
21 | hw/scsi/scsi-disk.c | 14 ++++++++------ | ||
22 | 1 file changed, 8 insertions(+), 6 deletions(-) | ||
23 | |||
24 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c | ||
25 | index XXXXXXX..XXXXXXX 100644 | ||
26 | --- a/hw/scsi/scsi-disk.c | ||
27 | +++ b/hw/scsi/scsi-disk.c | ||
28 | @@ -XXX,XX +XXX,XX @@ static int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) | ||
29 | DPRINTF("Inquiry EVPD[Device identification] " | ||
30 | "buffer size %zd\n", req->cmd.xfer); | ||
31 | |||
32 | - outbuf[buflen++] = 0x2; /* ASCII */ | ||
33 | - outbuf[buflen++] = 0; /* not officially assigned */ | ||
34 | - outbuf[buflen++] = 0; /* reserved */ | ||
35 | - outbuf[buflen++] = id_len; /* length of data following */ | ||
36 | - memcpy(outbuf + buflen, str, id_len); | ||
37 | - buflen += id_len; | ||
38 | + if (id_len) { | ||
39 | + outbuf[buflen++] = 0x2; /* ASCII */ | ||
40 | + outbuf[buflen++] = 0; /* not officially assigned */ | ||
41 | + outbuf[buflen++] = 0; /* reserved */ | ||
42 | + outbuf[buflen++] = id_len; /* length of data following */ | ||
43 | + memcpy(outbuf + buflen, str, id_len); | ||
44 | + buflen += id_len; | ||
45 | + } | ||
46 | |||
47 | if (s->qdev.wwn) { | ||
48 | outbuf[buflen++] = 0x1; /* Binary */ | ||
49 | -- | ||
50 | 2.20.1 | ||
51 | |||
52 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | The new device_id property specifies which value to use for the vendor | ||
2 | specific designator in the Device Identification VPD page. | ||
3 | 1 | ||
4 | In particular, this is necessary for libvirt to maintain guest ABI | ||
5 | compatibility when no serial number is given and a VM is switched from | ||
6 | -drive (where the BlockBackend name is used) to -blockdev (where the | ||
7 | vendor specific designator is left out by default). | ||
8 | |||
9 | Signed-off-by: Kevin Wolf <kwolf@redhat.com> | ||
10 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
11 | --- | ||
12 | hw/scsi/scsi-disk.c | 24 ++++++++++++++++-------- | ||
13 | 1 file changed, 16 insertions(+), 8 deletions(-) | ||
14 | |||
15 | diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/hw/scsi/scsi-disk.c | ||
18 | +++ b/hw/scsi/scsi-disk.c | ||
19 | @@ -XXX,XX +XXX,XX @@ typedef struct SCSIDiskState | ||
20 | char *serial; | ||
21 | char *vendor; | ||
22 | char *product; | ||
23 | + char *device_id; | ||
24 | bool tray_open; | ||
25 | bool tray_locked; | ||
26 | /* | ||
27 | @@ -XXX,XX +XXX,XX @@ static int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) | ||
28 | |||
29 | case 0x83: /* Device identification page, mandatory */ | ||
30 | { | ||
31 | - const char *str = s->serial ?: blk_name(s->qdev.conf.blk); | ||
32 | - int max_len = s->serial ? 20 : 255 - 8; | ||
33 | - int id_len = strlen(str); | ||
34 | + int id_len = s->device_id ? MIN(strlen(s->device_id), 255 - 8) : 0; | ||
35 | |||
36 | - if (id_len > max_len) { | ||
37 | - id_len = max_len; | ||
38 | - } | ||
39 | DPRINTF("Inquiry EVPD[Device identification] " | ||
40 | "buffer size %zd\n", req->cmd.xfer); | ||
41 | |||
42 | @@ -XXX,XX +XXX,XX @@ static int scsi_disk_emulate_vpd_page(SCSIRequest *req, uint8_t *outbuf) | ||
43 | outbuf[buflen++] = 0; /* not officially assigned */ | ||
44 | outbuf[buflen++] = 0; /* reserved */ | ||
45 | outbuf[buflen++] = id_len; /* length of data following */ | ||
46 | - memcpy(outbuf + buflen, str, id_len); | ||
47 | + memcpy(outbuf + buflen, s->device_id, id_len); | ||
48 | buflen += id_len; | ||
49 | } | ||
50 | |||
51 | @@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp) | ||
52 | if (!s->vendor) { | ||
53 | s->vendor = g_strdup("QEMU"); | ||
54 | } | ||
55 | + if (!s->device_id) { | ||
56 | + if (s->serial) { | ||
57 | + s->device_id = g_strdup_printf("%.20s", s->serial); | ||
58 | + } else { | ||
59 | + const char *str = blk_name(s->qdev.conf.blk); | ||
60 | + if (str && *str) { | ||
61 | + s->device_id = g_strdup(str); | ||
62 | + } | ||
63 | + } | ||
64 | + } | ||
65 | |||
66 | if (blk_is_sg(s->qdev.conf.blk)) { | ||
67 | error_setg(errp, "unwanted /dev/sg*"); | ||
68 | @@ -XXX,XX +XXX,XX @@ static const TypeInfo scsi_disk_base_info = { | ||
69 | DEFINE_PROP_STRING("ver", SCSIDiskState, version), \ | ||
70 | DEFINE_PROP_STRING("serial", SCSIDiskState, serial), \ | ||
71 | DEFINE_PROP_STRING("vendor", SCSIDiskState, vendor), \ | ||
72 | - DEFINE_PROP_STRING("product", SCSIDiskState, product) | ||
73 | + DEFINE_PROP_STRING("product", SCSIDiskState, product), \ | ||
74 | + DEFINE_PROP_STRING("device_id", SCSIDiskState, device_id) | ||
75 | + | ||
76 | |||
77 | static Property scsi_hd_properties[] = { | ||
78 | DEFINE_SCSI_DISK_PROPERTIES(), | ||
79 | -- | ||
80 | 2.20.1 | ||
81 | |||
82 | diff view generated by jsdifflib |