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