1
The following changes since commit f17783e706ab9c7b3a2b69cf48e4f0ba40664f54:
1
The following changes since commit 497d415d76b9f59fcae27f22df1ca2c3fa4df64e:
2
2
3
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20191220' into staging (2020-01-03 18:50:33 +0000)
3
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20201008-1' into staging (2020-10-08 21:41:20 +0100)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://github.com/XanClic/qemu.git tags/pull-block-2020-01-06
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to 503ca1262bab2c11c533a4816d1ff4297d4f58a6:
9
for you to fetch changes up to e969c7b045c90368bc3a5db3479e70b6f0ecb828:
10
10
11
backup-top: Begin drain earlier (2020-01-06 14:26:23 +0100)
11
iotests: add commit top->base cases to 274 (2020-10-09 14:32:24 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
14
Pull request
15
- Minor fixes and tests from the freeze period (too minor to be included
15
16
in 4.2)
16
This pull request includes the vhost-user-blk server by Coiby Xu, the block
17
- Allow many bash iotests to test qcow2's external data file feature
17
coroutine code generator by Vladimir Sementsov-Ogievskiy, nvme block driver
18
- Add compress filter driver
18
statistics by Philippe Mathieu-Daudé, and cleanups/fixes/additions to the
19
- Fix Python iotests after 6f6e1698a6
19
vhost-user-blk server by me.
20
- Fix for the backup job
21
20
22
----------------------------------------------------------------
21
----------------------------------------------------------------
23
Andrey Shinkevich (3):
24
block: introduce compress filter driver
25
qcow2: Allow writing compressed data of multiple clusters
26
tests/qemu-iotests: add case to write compressed data of multiple
27
clusters
28
22
29
Max Reitz (28):
23
Coiby Xu (7):
30
block: Add bdrv_qapi_perm_to_blk_perm()
24
libvhost-user: Allow vu_message_read to be replaced
31
block: Use bdrv_qapi_perm_to_blk_perm()
25
libvhost-user: remove watch for kick_fd when de-initialize vu-dev
32
blkdebug: Allow taking/unsharing permissions
26
util/vhost-user-server: generic vhost user server
33
iotests: Add @error to wait_until_completed
27
block: move logical block size check function to a common utility
34
iotests: Add test for failing mirror complete
28
function
35
iotests: s/qocw2/qcow2/
29
block/export: vhost-user block device backend server
36
iotests/qcow2.py: Add dump-header-exts
30
test: new qTest case to test the vhost-user-blk-server
37
iotests/qcow2.py: Split feature fields into bits
31
MAINTAINERS: Add vhost-user block device backend server maintainer
38
iotests: Add _filter_json_filename
39
iotests: Filter refcount_order in 036
40
iotests: Replace IMGOPTS by _unsupported_imgopts
41
iotests: Drop compat=1.1 in 050
42
iotests: Let _make_test_img parse its parameters
43
iotests: Add -o and --no-opts to _make_test_img
44
iotests: Inject space into -ocompat=0.10 in 051
45
iotests: Replace IMGOPTS= by -o
46
iotests: Replace IMGOPTS='' by --no-opts
47
iotests: Drop IMGOPTS use in 267
48
iotests: Avoid qemu-img create
49
iotests: Use _rm_test_img for deleting test images
50
iotests: Avoid cp/mv of test images
51
iotests: Make 091 work with data_file
52
iotests: Make 110 work with data_file
53
iotests: Make 137 work with data_file
54
iotests: Make 198 work with data_file
55
iotests: Disable data_file where it cannot be used
56
iotests: Allow check -o data_file
57
backup-top: Begin drain earlier
58
59
PanNengyuan (1):
60
throttle-groups: fix memory leak in throttle_group_set_limit:
61
32
62
Philippe Mathieu-Daudé (1):
33
Philippe Mathieu-Daudé (1):
63
tests/qemu-iotests: Update tests to recent desugarized -accel option
34
block/nvme: Add driver statistics for access alignment and hw errors
64
35
65
Vladimir Sementsov-Ogievskiy (1):
36
Stefan Hajnoczi (17):
66
qcow2-bitmaps: fix qcow2_can_store_new_dirty_bitmap
37
util/vhost-user-server: s/fileds/fields/ typo fix
38
util/vhost-user-server: drop unnecessary QOM cast
39
util/vhost-user-server: drop unnecessary watch deletion
40
block/export: consolidate request structs into VuBlockReq
41
util/vhost-user-server: drop unused DevicePanicNotifier
42
util/vhost-user-server: fix memory leak in vu_message_read()
43
util/vhost-user-server: check EOF when reading payload
44
util/vhost-user-server: rework vu_client_trip() coroutine lifecycle
45
block/export: report flush errors
46
block/export: convert vhost-user-blk server to block export API
47
util/vhost-user-server: move header to include/
48
util/vhost-user-server: use static library in meson.build
49
qemu-storage-daemon: avoid compiling blockdev_ss twice
50
block: move block exports to libblockdev
51
block/export: add iothread and fixed-iothread options
52
block/export: add vhost-user-blk multi-queue support
53
tests/qtest: add multi-queue test case to vhost-user-blk-test
67
54
68
block.c | 47 +++++----
55
Vladimir Sementsov-Ogievskiy (5):
69
block/Makefile.objs | 1 +
56
block/io: fix bdrv_co_block_status_above
70
block/backup-top.c | 4 +-
57
block/io: bdrv_common_block_status_above: support include_base
71
block/blkdebug.c | 93 ++++++++++++++++-
58
block/io: bdrv_common_block_status_above: support bs == base
72
block/filter-compress.c | 168 +++++++++++++++++++++++++++++++
59
block/io: fix bdrv_is_allocated_above
73
block/qcow2-bitmap.c | 41 ++++----
60
iotests: add commit top->base cases to 274
74
block/qcow2.c | 102 ++++++++++++++-----
61
75
block/throttle-groups.c | 4 +-
62
MAINTAINERS | 10 +
76
include/block/block.h | 1 +
63
qapi/block-core.json | 24 +-
77
qapi/block-core.json | 24 ++++-
64
qapi/block-export.json | 36 +-
78
tests/qemu-iotests/007 | 5 +-
65
block/coroutines.h | 2 +
79
tests/qemu-iotests/014 | 2 +
66
block/export/vhost-user-blk-server.h | 19 +
80
tests/qemu-iotests/015 | 5 +-
67
contrib/libvhost-user/libvhost-user.h | 21 +
81
tests/qemu-iotests/019 | 6 +-
68
include/qemu/vhost-user-server.h | 65 ++
82
tests/qemu-iotests/020 | 6 +-
69
tests/qtest/libqos/libqtest.h | 17 +
83
tests/qemu-iotests/024 | 10 +-
70
tests/qtest/libqos/vhost-user-blk.h | 48 ++
84
tests/qemu-iotests/026 | 5 +-
71
util/block-helpers.h | 19 +
85
tests/qemu-iotests/028 | 2 +-
72
block/export/export.c | 37 +-
86
tests/qemu-iotests/029 | 7 +-
73
block/export/vhost-user-blk-server.c | 431 +++++++++++
87
tests/qemu-iotests/031 | 9 +-
74
block/io.c | 132 ++--
88
tests/qemu-iotests/031.out | 36 +++----
75
block/nvme.c | 27 +
89
tests/qemu-iotests/036 | 15 +--
76
block/qcow2.c | 16 +-
90
tests/qemu-iotests/036.out | 66 ++----------
77
contrib/libvhost-user/libvhost-user-glib.c | 2 +-
91
tests/qemu-iotests/039 | 27 ++---
78
contrib/libvhost-user/libvhost-user.c | 15 +-
92
tests/qemu-iotests/039.out | 22 ++--
79
hw/core/qdev-properties-system.c | 31 +-
93
tests/qemu-iotests/041 | 44 ++++++++
80
nbd/server.c | 2 -
94
tests/qemu-iotests/041.out | 4 +-
81
qemu-nbd.c | 21 +-
95
tests/qemu-iotests/043 | 4 +-
82
softmmu/vl.c | 4 +
96
tests/qemu-iotests/046 | 2 +
83
stubs/blk-exp-close-all.c | 7 +
97
tests/qemu-iotests/048 | 4 +-
84
tests/qtest/libqos/vhost-user-blk.c | 129 ++++
98
tests/qemu-iotests/050 | 8 +-
85
tests/qtest/libqtest.c | 36 +-
99
tests/qemu-iotests/051 | 7 +-
86
tests/qtest/vhost-user-blk-test.c | 822 +++++++++++++++++++++
100
tests/qemu-iotests/053 | 4 +-
87
tests/vhost-user-bridge.c | 2 +
101
tests/qemu-iotests/058 | 7 +-
88
tools/virtiofsd/fuse_virtio.c | 4 +-
102
tests/qemu-iotests/059 | 20 ++--
89
util/block-helpers.c | 46 ++
103
tests/qemu-iotests/060 | 14 +--
90
util/vhost-user-server.c | 446 +++++++++++
104
tests/qemu-iotests/060.out | 20 ++--
91
block/export/meson.build | 3 +-
105
tests/qemu-iotests/061 | 63 ++++++------
92
contrib/libvhost-user/meson.build | 1 +
106
tests/qemu-iotests/061.out | 72 ++++++-------
93
meson.build | 22 +-
107
tests/qemu-iotests/062 | 5 +-
94
nbd/meson.build | 2 +
108
tests/qemu-iotests/063 | 18 ++--
95
storage-daemon/meson.build | 3 +-
109
tests/qemu-iotests/063.out | 3 +-
96
stubs/meson.build | 1 +
110
tests/qemu-iotests/066 | 7 +-
97
tests/qemu-iotests/274 | 20 +
111
tests/qemu-iotests/067 | 6 +-
98
tests/qemu-iotests/274.out | 68 ++
112
tests/qemu-iotests/068 | 6 +-
99
tests/qtest/libqos/meson.build | 1 +
113
tests/qemu-iotests/069 | 2 +-
100
tests/qtest/meson.build | 4 +-
114
tests/qemu-iotests/071 | 7 +-
101
util/meson.build | 4 +
115
tests/qemu-iotests/073 | 4 +
102
40 files changed, 2476 insertions(+), 124 deletions(-)
116
tests/qemu-iotests/074 | 4 +-
103
create mode 100644 block/export/vhost-user-blk-server.h
117
tests/qemu-iotests/079 | 3 +-
104
create mode 100644 include/qemu/vhost-user-server.h
118
tests/qemu-iotests/080 | 7 +-
105
create mode 100644 tests/qtest/libqos/vhost-user-blk.h
119
tests/qemu-iotests/081 | 6 +-
106
create mode 100644 util/block-helpers.h
120
tests/qemu-iotests/085 | 18 ++--
107
create mode 100644 block/export/vhost-user-blk-server.c
121
tests/qemu-iotests/085.out | 8 +-
108
create mode 100644 stubs/blk-exp-close-all.c
122
tests/qemu-iotests/088 | 2 +-
109
create mode 100644 tests/qtest/libqos/vhost-user-blk.c
123
tests/qemu-iotests/090 | 2 +
110
create mode 100644 tests/qtest/vhost-user-blk-test.c
124
tests/qemu-iotests/091 | 2 +-
111
create mode 100644 util/block-helpers.c
125
tests/qemu-iotests/091.out | 2 -
112
create mode 100644 util/vhost-user-server.c
126
tests/qemu-iotests/092 | 2 +-
127
tests/qemu-iotests/094 | 4 +-
128
tests/qemu-iotests/095 | 5 +-
129
tests/qemu-iotests/098 | 6 +-
130
tests/qemu-iotests/099 | 10 +-
131
tests/qemu-iotests/103 | 5 +-
132
tests/qemu-iotests/106 | 2 +-
133
tests/qemu-iotests/108 | 10 +-
134
tests/qemu-iotests/109 | 4 +-
135
tests/qemu-iotests/110 | 11 +-
136
tests/qemu-iotests/110.out | 4 +-
137
tests/qemu-iotests/111 | 3 +-
138
tests/qemu-iotests/112 | 37 +++----
139
tests/qemu-iotests/114 | 2 +
140
tests/qemu-iotests/115 | 3 +-
141
tests/qemu-iotests/121 | 9 +-
142
tests/qemu-iotests/122 | 6 +-
143
tests/qemu-iotests/123 | 4 +-
144
tests/qemu-iotests/125 | 2 +-
145
tests/qemu-iotests/137 | 17 +++-
146
tests/qemu-iotests/137.out | 6 +-
147
tests/qemu-iotests/138 | 8 +-
148
tests/qemu-iotests/141 | 4 +-
149
tests/qemu-iotests/142 | 2 +-
150
tests/qemu-iotests/144 | 4 +-
151
tests/qemu-iotests/153 | 12 +--
152
tests/qemu-iotests/156 | 10 +-
153
tests/qemu-iotests/159 | 2 +-
154
tests/qemu-iotests/160 | 3 +-
155
tests/qemu-iotests/161 | 4 +-
156
tests/qemu-iotests/170 | 2 +-
157
tests/qemu-iotests/172 | 6 +-
158
tests/qemu-iotests/173 | 3 +-
159
tests/qemu-iotests/174 | 2 +-
160
tests/qemu-iotests/175 | 2 +-
161
tests/qemu-iotests/176 | 7 +-
162
tests/qemu-iotests/178 | 6 +-
163
tests/qemu-iotests/182 | 2 +-
164
tests/qemu-iotests/183 | 2 +-
165
tests/qemu-iotests/185 | 4 +-
166
tests/qemu-iotests/187 | 6 +-
167
tests/qemu-iotests/190 | 4 +-
168
tests/qemu-iotests/191 | 11 +-
169
tests/qemu-iotests/195 | 2 +-
170
tests/qemu-iotests/197 | 6 +-
171
tests/qemu-iotests/198 | 6 +-
172
tests/qemu-iotests/198.out | 4 +-
173
tests/qemu-iotests/200 | 7 +-
174
tests/qemu-iotests/201 | 6 +-
175
tests/qemu-iotests/214 | 46 ++++++++-
176
tests/qemu-iotests/214.out | 14 +++
177
tests/qemu-iotests/215 | 6 +-
178
tests/qemu-iotests/217 | 3 +-
179
tests/qemu-iotests/220 | 5 +-
180
tests/qemu-iotests/225 | 2 +-
181
tests/qemu-iotests/229 | 3 +-
182
tests/qemu-iotests/232 | 4 +-
183
tests/qemu-iotests/235 | 2 +-
184
tests/qemu-iotests/243 | 10 +-
185
tests/qemu-iotests/244 | 15 +--
186
tests/qemu-iotests/247 | 4 +-
187
tests/qemu-iotests/249 | 4 +-
188
tests/qemu-iotests/250 | 5 +-
189
tests/qemu-iotests/252 | 2 +-
190
tests/qemu-iotests/261 | 5 +-
191
tests/qemu-iotests/265 | 2 +-
192
tests/qemu-iotests/267 | 17 ++--
193
tests/qemu-iotests/273 | 3 +
194
tests/qemu-iotests/check | 6 +-
195
tests/qemu-iotests/common.filter | 47 ++++++++-
196
tests/qemu-iotests/common.rc | 63 ++++++++++--
197
tests/qemu-iotests/iotests.py | 18 ++--
198
tests/qemu-iotests/qcow2.py | 23 ++++-
199
131 files changed, 1139 insertions(+), 552 deletions(-)
200
create mode 100644 block/filter-compress.c
201
113
202
--
114
--
203
2.24.1
115
2.26.2
204
116
205
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
2
3
Commit 6f6e1698a6 desugarized "-machine accel=" to a list
3
Keep statistics of some hardware errors, and number of
4
of "-accel" options. Since now "-machine accel" and "-accel"
4
aligned/unaligned I/O accesses.
5
became incompatible, update the iotests to the new format.
6
5
7
Error reported here:
6
QMP example booting a full RHEL 8.3 aarch64 guest:
8
https://gitlab.com/qemu-project/qemu/-/jobs/385801004#L3400
9
7
10
Reported-by: GitLab CI
8
{ "execute": "query-blockstats" }
11
Fixes: 6f6e1698a6 (vl: configure accelerators from -accel options)
9
{
10
"return": [
11
{
12
"device": "",
13
"node-name": "drive0",
14
"stats": {
15
"flush_total_time_ns": 6026948,
16
"wr_highest_offset": 3383991230464,
17
"wr_total_time_ns": 807450995,
18
"failed_wr_operations": 0,
19
"failed_rd_operations": 0,
20
"wr_merged": 3,
21
"wr_bytes": 50133504,
22
"failed_unmap_operations": 0,
23
"failed_flush_operations": 0,
24
"account_invalid": false,
25
"rd_total_time_ns": 1846979900,
26
"flush_operations": 130,
27
"wr_operations": 659,
28
"rd_merged": 1192,
29
"rd_bytes": 218244096,
30
"account_failed": false,
31
"idle_time_ns": 2678641497,
32
"rd_operations": 7406,
33
},
34
"driver-specific": {
35
"driver": "nvme",
36
"completion-errors": 0,
37
"unaligned-accesses": 2959,
38
"aligned-accesses": 4477
39
},
40
"qdev": "/machine/peripheral-anon/device[0]/virtio-backend"
41
}
42
]
43
}
44
45
Suggested-by: Stefan Hajnoczi <stefanha@gmail.com>
12
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
46
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
13
Message-id: 20200106130951.29873-1-philmd@redhat.com
47
Acked-by: Markus Armbruster <armbru@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
48
Message-id: 20201001162939.1567915-1-philmd@redhat.com
49
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
50
---
16
tests/qemu-iotests/235 | 2 +-
51
qapi/block-core.json | 24 +++++++++++++++++++++++-
17
tests/qemu-iotests/check | 6 +++---
52
block/nvme.c | 27 +++++++++++++++++++++++++++
18
2 files changed, 4 insertions(+), 4 deletions(-)
53
2 files changed, 50 insertions(+), 1 deletion(-)
19
54
20
diff --git a/tests/qemu-iotests/235 b/tests/qemu-iotests/235
55
diff --git a/qapi/block-core.json b/qapi/block-core.json
21
index XXXXXXX..XXXXXXX 100755
56
index XXXXXXX..XXXXXXX 100644
22
--- a/tests/qemu-iotests/235
57
--- a/qapi/block-core.json
23
+++ b/tests/qemu-iotests/235
58
+++ b/qapi/block-core.json
24
@@ -XXX,XX +XXX,XX @@ qemu_img_create('-f', iotests.imgfmt, '-o', 'preallocation=metadata', disk,
59
@@ -XXX,XX +XXX,XX @@
25
str(size))
60
'discard-nb-failed': 'uint64',
26
61
'discard-bytes-ok': 'uint64' } }
27
vm = QEMUMachine(iotests.qemu_prog)
62
28
-vm.add_args('-machine', 'accel=kvm:tcg')
63
+##
29
+vm.add_args('-accel', 'kvm', '-accel', 'tcg')
64
+# @BlockStatsSpecificNvme:
30
if iotests.qemu_default_machine == 's390-ccw-virtio':
65
+#
31
vm.add_args('-no-shutdown')
66
+# NVMe driver statistics
32
vm.add_args('-drive', 'id=src,file=' + disk)
67
+#
33
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
68
+# @completion-errors: The number of completion errors.
34
index XXXXXXX..XXXXXXX 100755
69
+#
35
--- a/tests/qemu-iotests/check
70
+# @aligned-accesses: The number of aligned accesses performed by
36
+++ b/tests/qemu-iotests/check
71
+# the driver.
37
@@ -XXX,XX +XXX,XX @@ export QEMU_PROG="$(type -p "$QEMU_PROG")"
72
+#
38
73
+# @unaligned-accesses: The number of unaligned accesses performed by
39
case "$QEMU_PROG" in
74
+# the driver.
40
*qemu-system-arm|*qemu-system-aarch64)
75
+#
41
- export QEMU_OPTIONS="-nodefaults -display none -machine virt,accel=qtest"
76
+# Since: 5.2
42
+ export QEMU_OPTIONS="-nodefaults -display none -machine virt -accel qtest"
77
+##
43
;;
78
+{ 'struct': 'BlockStatsSpecificNvme',
44
*qemu-system-tricore)
79
+ 'data': {
45
- export QEMU_OPTIONS="-nodefaults -display none -machine tricore_testboard,accel=qtest"
80
+ 'completion-errors': 'uint64',
46
+ export QEMU_OPTIONS="-nodefaults -display none -machine tricore_testboard -accel qtest"
81
+ 'aligned-accesses': 'uint64',
47
;;
82
+ 'unaligned-accesses': 'uint64' } }
48
*)
83
+
49
- export QEMU_OPTIONS="-nodefaults -display none -machine accel=qtest"
84
##
50
+ export QEMU_OPTIONS="-nodefaults -display none -accel qtest"
85
# @BlockStatsSpecific:
51
;;
86
#
52
esac
87
@@ -XXX,XX +XXX,XX @@
53
88
'discriminator': 'driver',
89
'data': {
90
'file': 'BlockStatsSpecificFile',
91
- 'host_device': 'BlockStatsSpecificFile' } }
92
+ 'host_device': 'BlockStatsSpecificFile',
93
+ 'nvme': 'BlockStatsSpecificNvme' } }
94
95
##
96
# @BlockStats:
97
diff --git a/block/nvme.c b/block/nvme.c
98
index XXXXXXX..XXXXXXX 100644
99
--- a/block/nvme.c
100
+++ b/block/nvme.c
101
@@ -XXX,XX +XXX,XX @@ struct BDRVNVMeState {
102
103
/* PCI address (required for nvme_refresh_filename()) */
104
char *device;
105
+
106
+ struct {
107
+ uint64_t completion_errors;
108
+ uint64_t aligned_accesses;
109
+ uint64_t unaligned_accesses;
110
+ } stats;
111
};
112
113
#define NVME_BLOCK_OPT_DEVICE "device"
114
@@ -XXX,XX +XXX,XX @@ static bool nvme_process_completion(NVMeQueuePair *q)
115
break;
116
}
117
ret = nvme_translate_error(c);
118
+ if (ret) {
119
+ s->stats.completion_errors++;
120
+ }
121
q->cq.head = (q->cq.head + 1) % NVME_QUEUE_SIZE;
122
if (!q->cq.head) {
123
q->cq_phase = !q->cq_phase;
124
@@ -XXX,XX +XXX,XX @@ static int nvme_co_prw(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
125
assert(QEMU_IS_ALIGNED(bytes, s->page_size));
126
assert(bytes <= s->max_transfer);
127
if (nvme_qiov_aligned(bs, qiov)) {
128
+ s->stats.aligned_accesses++;
129
return nvme_co_prw_aligned(bs, offset, bytes, qiov, is_write, flags);
130
}
131
+ s->stats.unaligned_accesses++;
132
trace_nvme_prw_buffered(s, offset, bytes, qiov->niov, is_write);
133
buf = qemu_try_memalign(s->page_size, bytes);
134
135
@@ -XXX,XX +XXX,XX @@ static void nvme_unregister_buf(BlockDriverState *bs, void *host)
136
qemu_vfio_dma_unmap(s->vfio, host);
137
}
138
139
+static BlockStatsSpecific *nvme_get_specific_stats(BlockDriverState *bs)
140
+{
141
+ BlockStatsSpecific *stats = g_new(BlockStatsSpecific, 1);
142
+ BDRVNVMeState *s = bs->opaque;
143
+
144
+ stats->driver = BLOCKDEV_DRIVER_NVME;
145
+ stats->u.nvme = (BlockStatsSpecificNvme) {
146
+ .completion_errors = s->stats.completion_errors,
147
+ .aligned_accesses = s->stats.aligned_accesses,
148
+ .unaligned_accesses = s->stats.unaligned_accesses,
149
+ };
150
+
151
+ return stats;
152
+}
153
+
154
static const char *const nvme_strong_runtime_opts[] = {
155
NVME_BLOCK_OPT_DEVICE,
156
NVME_BLOCK_OPT_NAMESPACE,
157
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nvme = {
158
.bdrv_refresh_filename = nvme_refresh_filename,
159
.bdrv_refresh_limits = nvme_refresh_limits,
160
.strong_runtime_opts = nvme_strong_runtime_opts,
161
+ .bdrv_get_specific_stats = nvme_get_specific_stats,
162
163
.bdrv_detach_aio_context = nvme_detach_aio_context,
164
.bdrv_attach_aio_context = nvme_attach_aio_context,
54
--
165
--
55
2.24.1
166
2.26.2
56
167
57
diff view generated by jsdifflib
1
When dropping backup-top, we need to drain the node before freeing the
1
From: Coiby Xu <coiby.xu@gmail.com>
2
BlockCopyState. Otherwise, requests may still be in flight and then the
3
assertion in shres_destroy() will fail.
4
2
5
(This becomes visible in intermittent failure of 056.)
3
Allow vu_message_read to be replaced by one which will make use of the
4
QIOChannel functions. Thus reading vhost-user message won't stall the
5
guest. For slave channel, we still use the default vu_message_read.
6
6
7
Cc: qemu-stable@nongnu.org
7
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Coiby Xu <coiby.xu@gmail.com>
9
Message-id: 20191219182638.104621-1-mreitz@redhat.com
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 20200918080912.321299-2-coiby.xu@gmail.com
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
---
12
block/backup-top.c | 4 ++--
13
contrib/libvhost-user/libvhost-user.h | 21 +++++++++++++++++++++
13
1 file changed, 2 insertions(+), 2 deletions(-)
14
contrib/libvhost-user/libvhost-user-glib.c | 2 +-
15
contrib/libvhost-user/libvhost-user.c | 14 +++++++-------
16
tests/vhost-user-bridge.c | 2 ++
17
tools/virtiofsd/fuse_virtio.c | 4 ++--
18
5 files changed, 33 insertions(+), 10 deletions(-)
14
19
15
diff --git a/block/backup-top.c b/block/backup-top.c
20
diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h
16
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
17
--- a/block/backup-top.c
22
--- a/contrib/libvhost-user/libvhost-user.h
18
+++ b/block/backup-top.c
23
+++ b/contrib/libvhost-user/libvhost-user.h
19
@@ -XXX,XX +XXX,XX @@ void bdrv_backup_top_drop(BlockDriverState *bs)
24
@@ -XXX,XX +XXX,XX @@
20
BDRVBackupTopState *s = bs->opaque;
25
*/
21
AioContext *aio_context = bdrv_get_aio_context(bs);
26
#define VHOST_USER_MAX_RAM_SLOTS 32
22
27
23
- block_copy_state_free(s->bcs);
28
+#define VHOST_USER_HDR_SIZE offsetof(VhostUserMsg, payload.u64)
29
+
30
typedef enum VhostSetConfigType {
31
VHOST_SET_CONFIG_TYPE_MASTER = 0,
32
VHOST_SET_CONFIG_TYPE_MIGRATION = 1,
33
@@ -XXX,XX +XXX,XX @@ typedef uint64_t (*vu_get_features_cb) (VuDev *dev);
34
typedef void (*vu_set_features_cb) (VuDev *dev, uint64_t features);
35
typedef int (*vu_process_msg_cb) (VuDev *dev, VhostUserMsg *vmsg,
36
int *do_reply);
37
+typedef bool (*vu_read_msg_cb) (VuDev *dev, int sock, VhostUserMsg *vmsg);
38
typedef void (*vu_queue_set_started_cb) (VuDev *dev, int qidx, bool started);
39
typedef bool (*vu_queue_is_processed_in_order_cb) (VuDev *dev, int qidx);
40
typedef int (*vu_get_config_cb) (VuDev *dev, uint8_t *config, uint32_t len);
41
@@ -XXX,XX +XXX,XX @@ struct VuDev {
42
bool broken;
43
uint16_t max_queues;
44
45
+ /* @read_msg: custom method to read vhost-user message
46
+ *
47
+ * Read data from vhost_user socket fd and fill up
48
+ * the passed VhostUserMsg *vmsg struct.
49
+ *
50
+ * If reading fails, it should close the received set of file
51
+ * descriptors as socket message's auxiliary data.
52
+ *
53
+ * For the details, please refer to vu_message_read in libvhost-user.c
54
+ * which will be used by default if not custom method is provided when
55
+ * calling vu_init
56
+ *
57
+ * Returns: true if vhost-user message successfully received,
58
+ * otherwise return false.
59
+ *
60
+ */
61
+ vu_read_msg_cb read_msg;
62
/* @set_watch: add or update the given fd to the watch set,
63
* call cb when condition is met */
64
vu_set_watch_cb set_watch;
65
@@ -XXX,XX +XXX,XX @@ bool vu_init(VuDev *dev,
66
uint16_t max_queues,
67
int socket,
68
vu_panic_cb panic,
69
+ vu_read_msg_cb read_msg,
70
vu_set_watch_cb set_watch,
71
vu_remove_watch_cb remove_watch,
72
const VuDevIface *iface);
73
diff --git a/contrib/libvhost-user/libvhost-user-glib.c b/contrib/libvhost-user/libvhost-user-glib.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/contrib/libvhost-user/libvhost-user-glib.c
76
+++ b/contrib/libvhost-user/libvhost-user-glib.c
77
@@ -XXX,XX +XXX,XX @@ vug_init(VugDev *dev, uint16_t max_queues, int socket,
78
g_assert(dev);
79
g_assert(iface);
80
81
- if (!vu_init(&dev->parent, max_queues, socket, panic, set_watch,
82
+ if (!vu_init(&dev->parent, max_queues, socket, panic, NULL, set_watch,
83
remove_watch, iface)) {
84
return false;
85
}
86
diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/contrib/libvhost-user/libvhost-user.c
89
+++ b/contrib/libvhost-user/libvhost-user.c
90
@@ -XXX,XX +XXX,XX @@
91
/* The version of inflight buffer */
92
#define INFLIGHT_VERSION 1
93
94
-#define VHOST_USER_HDR_SIZE offsetof(VhostUserMsg, payload.u64)
24
-
95
-
25
aio_context_acquire(aio_context);
96
/* The version of the protocol we support */
26
97
#define VHOST_USER_VERSION 1
27
bdrv_drained_begin(bs);
98
#define LIBVHOST_USER_DEBUG 0
28
99
@@ -XXX,XX +XXX,XX @@ have_userfault(void)
29
+ block_copy_state_free(s->bcs);
100
}
30
+
101
31
s->active = false;
102
static bool
32
bdrv_child_refresh_perms(bs, bs->backing, &error_abort);
103
-vu_message_read(VuDev *dev, int conn_fd, VhostUserMsg *vmsg)
33
bdrv_replace_node(bs, backing_bs(bs), &error_abort);
104
+vu_message_read_default(VuDev *dev, int conn_fd, VhostUserMsg *vmsg)
105
{
106
char control[CMSG_SPACE(VHOST_MEMORY_BASELINE_NREGIONS * sizeof(int))] = {};
107
struct iovec iov = {
108
@@ -XXX,XX +XXX,XX @@ vu_process_message_reply(VuDev *dev, const VhostUserMsg *vmsg)
109
goto out;
110
}
111
112
- if (!vu_message_read(dev, dev->slave_fd, &msg_reply)) {
113
+ if (!vu_message_read_default(dev, dev->slave_fd, &msg_reply)) {
114
goto out;
115
}
116
117
@@ -XXX,XX +XXX,XX @@ vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg)
118
/* Wait for QEMU to confirm that it's registered the handler for the
119
* faults.
120
*/
121
- if (!vu_message_read(dev, dev->sock, vmsg) ||
122
+ if (!dev->read_msg(dev, dev->sock, vmsg) ||
123
vmsg->size != sizeof(vmsg->payload.u64) ||
124
vmsg->payload.u64 != 0) {
125
vu_panic(dev, "failed to receive valid ack for postcopy set-mem-table");
126
@@ -XXX,XX +XXX,XX @@ vu_dispatch(VuDev *dev)
127
int reply_requested;
128
bool need_reply, success = false;
129
130
- if (!vu_message_read(dev, dev->sock, &vmsg)) {
131
+ if (!dev->read_msg(dev, dev->sock, &vmsg)) {
132
goto end;
133
}
134
135
@@ -XXX,XX +XXX,XX @@ vu_init(VuDev *dev,
136
uint16_t max_queues,
137
int socket,
138
vu_panic_cb panic,
139
+ vu_read_msg_cb read_msg,
140
vu_set_watch_cb set_watch,
141
vu_remove_watch_cb remove_watch,
142
const VuDevIface *iface)
143
@@ -XXX,XX +XXX,XX @@ vu_init(VuDev *dev,
144
145
dev->sock = socket;
146
dev->panic = panic;
147
+ dev->read_msg = read_msg ? read_msg : vu_message_read_default;
148
dev->set_watch = set_watch;
149
dev->remove_watch = remove_watch;
150
dev->iface = iface;
151
@@ -XXX,XX +XXX,XX @@ static void _vu_queue_notify(VuDev *dev, VuVirtq *vq, bool sync)
152
153
vu_message_write(dev, dev->slave_fd, &vmsg);
154
if (ack) {
155
- vu_message_read(dev, dev->slave_fd, &vmsg);
156
+ vu_message_read_default(dev, dev->slave_fd, &vmsg);
157
}
158
return;
159
}
160
diff --git a/tests/vhost-user-bridge.c b/tests/vhost-user-bridge.c
161
index XXXXXXX..XXXXXXX 100644
162
--- a/tests/vhost-user-bridge.c
163
+++ b/tests/vhost-user-bridge.c
164
@@ -XXX,XX +XXX,XX @@ vubr_accept_cb(int sock, void *ctx)
165
VHOST_USER_BRIDGE_MAX_QUEUES,
166
conn_fd,
167
vubr_panic,
168
+ NULL,
169
vubr_set_watch,
170
vubr_remove_watch,
171
&vuiface)) {
172
@@ -XXX,XX +XXX,XX @@ vubr_new(const char *path, bool client)
173
VHOST_USER_BRIDGE_MAX_QUEUES,
174
dev->sock,
175
vubr_panic,
176
+ NULL,
177
vubr_set_watch,
178
vubr_remove_watch,
179
&vuiface)) {
180
diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
181
index XXXXXXX..XXXXXXX 100644
182
--- a/tools/virtiofsd/fuse_virtio.c
183
+++ b/tools/virtiofsd/fuse_virtio.c
184
@@ -XXX,XX +XXX,XX @@ int virtio_session_mount(struct fuse_session *se)
185
se->vu_socketfd = data_sock;
186
se->virtio_dev->se = se;
187
pthread_rwlock_init(&se->virtio_dev->vu_dispatch_rwlock, NULL);
188
- vu_init(&se->virtio_dev->dev, 2, se->vu_socketfd, fv_panic, fv_set_watch,
189
- fv_remove_watch, &fv_iface);
190
+ vu_init(&se->virtio_dev->dev, 2, se->vu_socketfd, fv_panic, NULL,
191
+ fv_set_watch, fv_remove_watch, &fv_iface);
192
193
return 0;
194
}
34
--
195
--
35
2.24.1
196
2.26.2
36
197
37
diff view generated by jsdifflib
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
1
From: Coiby Xu <coiby.xu@gmail.com>
2
2
3
Add the case to the iotest #214 that checks possibility of writing
3
When the client is running in gdb and quit command is run in gdb,
4
compressed data of more than one cluster size. The test case involves
4
QEMU will still dispatch the event which will cause segment fault in
5
the compress filter driver showing a sample usage of that.
5
the callback function.
6
6
7
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
7
Signed-off-by: Coiby Xu <coiby.xu@gmail.com>
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
10
Message-id: 1575288906-551879-4-git-send-email-andrey.shinkevich@virtuozzo.com
10
Message-id: 20200918080912.321299-3-coiby.xu@gmail.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
12
---
13
tests/qemu-iotests/214 | 43 ++++++++++++++++++++++++++++++++++++++
13
contrib/libvhost-user/libvhost-user.c | 1 +
14
tests/qemu-iotests/214.out | 14 +++++++++++++
14
1 file changed, 1 insertion(+)
15
2 files changed, 57 insertions(+)
16
15
17
diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214
16
diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c
18
index XXXXXXX..XXXXXXX 100755
19
--- a/tests/qemu-iotests/214
20
+++ b/tests/qemu-iotests/214
21
@@ -XXX,XX +XXX,XX @@ _check_test_img -r all
22
$QEMU_IO -c "read -P 0x11 0 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
23
$QEMU_IO -c "read -P 0x22 4M 4M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
24
25
+echo
26
+echo "=== Write compressed data of multiple clusters ==="
27
+echo
28
+cluster_size=0x10000
29
+_make_test_img 2M -o cluster_size=$cluster_size
30
+
31
+echo "Write uncompressed data:"
32
+let data_size="8 * $cluster_size"
33
+$QEMU_IO -c "write -P 0xaa 0 $data_size" "$TEST_IMG" \
34
+ 2>&1 | _filter_qemu_io | _filter_testdir
35
+sizeA=$($QEMU_IMG info --output=json "$TEST_IMG" |
36
+ sed -n '/"actual-size":/ s/[^0-9]//gp')
37
+
38
+_make_test_img 2M -o cluster_size=$cluster_size
39
+echo "Write compressed data:"
40
+let data_size="3 * $cluster_size + $cluster_size / 2"
41
+# Set compress on. That will align the written data
42
+# by the cluster size and will write them compressed.
43
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT \
44
+$QEMU_IO -c "write -P 0xbb 0 $data_size" --image-opts \
45
+ "driver=compress,file.driver=$IMGFMT,file.file.driver=file,file.file.filename=$TEST_IMG" \
46
+ 2>&1 | _filter_qemu_io | _filter_testdir
47
+
48
+let offset="4 * $cluster_size + $cluster_size / 4"
49
+QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT \
50
+$QEMU_IO -c "write -P 0xcc $offset $data_size" "json:{\
51
+ 'driver': 'compress',
52
+ 'file': {'driver': '$IMGFMT',
53
+ 'file': {'driver': 'file',
54
+ 'filename': '$TEST_IMG'}}}" | \
55
+ _filter_qemu_io | _filter_testdir
56
+
57
+sizeB=$($QEMU_IMG info --output=json "$TEST_IMG" |
58
+ sed -n '/"actual-size":/ s/[^0-9]//gp')
59
+
60
+if [ $sizeA -le $sizeB ]
61
+then
62
+ echo "Compression ERROR"
63
+fi
64
+
65
+$QEMU_IMG check --output=json "$TEST_IMG" |
66
+ sed -n 's/,$//; /"compressed-clusters":/ s/^ *//p'
67
+
68
# success, all done
69
echo '*** done'
70
rm -f $seq.full
71
diff --git a/tests/qemu-iotests/214.out b/tests/qemu-iotests/214.out
72
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
73
--- a/tests/qemu-iotests/214.out
18
--- a/contrib/libvhost-user/libvhost-user.c
74
+++ b/tests/qemu-iotests/214.out
19
+++ b/contrib/libvhost-user/libvhost-user.c
75
@@ -XXX,XX +XXX,XX @@ read 4194304/4194304 bytes at offset 0
20
@@ -XXX,XX +XXX,XX @@ vu_deinit(VuDev *dev)
76
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
21
}
77
read 4194304/4194304 bytes at offset 4194304
22
78
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
23
if (vq->kick_fd != -1) {
79
+
24
+ dev->remove_watch(dev, vq->kick_fd);
80
+=== Write compressed data of multiple clusters ===
25
close(vq->kick_fd);
81
+
26
vq->kick_fd = -1;
82
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2097152
27
}
83
+Write uncompressed data:
84
+wrote 524288/524288 bytes at offset 0
85
+512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
86
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2097152
87
+Write compressed data:
88
+wrote 229376/229376 bytes at offset 0
89
+224 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
90
+wrote 229376/229376 bytes at offset 278528
91
+224 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
92
+"compressed-clusters": 8
93
*** done
94
--
28
--
95
2.24.1
29
2.26.2
96
30
97
diff view generated by jsdifflib
1
Signed-off-by: Max Reitz <mreitz@redhat.com>
1
From: Coiby Xu <coiby.xu@gmail.com>
2
Message-id: 20191107163708.833192-22-mreitz@redhat.com
2
3
[mreitz: Also disable 273]
3
Sharing QEMU devices via vhost-user protocol.
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
5
Only one vhost-user client can connect to the server one time.
6
7
Suggested-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Coiby Xu <coiby.xu@gmail.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
12
Message-id: 20200918080912.321299-4-coiby.xu@gmail.com
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
---
14
---
6
tests/qemu-iotests/007 | 5 +++--
15
util/vhost-user-server.h | 65 ++++++
7
tests/qemu-iotests/014 | 2 ++
16
util/vhost-user-server.c | 428 +++++++++++++++++++++++++++++++++++++++
8
tests/qemu-iotests/015 | 5 +++--
17
util/meson.build | 1 +
9
tests/qemu-iotests/026 | 5 ++++-
18
3 files changed, 494 insertions(+)
10
tests/qemu-iotests/029 | 5 +++--
19
create mode 100644 util/vhost-user-server.h
11
tests/qemu-iotests/031 | 6 +++---
20
create mode 100644 util/vhost-user-server.c
12
tests/qemu-iotests/036 | 5 +++--
13
tests/qemu-iotests/039 | 3 +++
14
tests/qemu-iotests/046 | 2 ++
15
tests/qemu-iotests/048 | 2 ++
16
tests/qemu-iotests/051 | 5 +++--
17
tests/qemu-iotests/058 | 5 +++--
18
tests/qemu-iotests/060 | 6 ++++--
19
tests/qemu-iotests/061 | 6 ++++--
20
tests/qemu-iotests/062 | 2 +-
21
tests/qemu-iotests/066 | 4 +++-
22
tests/qemu-iotests/067 | 6 ++++--
23
tests/qemu-iotests/068 | 5 +++--
24
tests/qemu-iotests/071 | 3 +++
25
tests/qemu-iotests/073 | 4 ++++
26
tests/qemu-iotests/074 | 2 ++
27
tests/qemu-iotests/080 | 5 +++--
28
tests/qemu-iotests/090 | 2 ++
29
tests/qemu-iotests/098 | 6 ++++--
30
tests/qemu-iotests/099 | 3 ++-
31
tests/qemu-iotests/103 | 5 +++--
32
tests/qemu-iotests/108 | 6 ++++--
33
tests/qemu-iotests/112 | 5 +++--
34
tests/qemu-iotests/114 | 2 ++
35
tests/qemu-iotests/121 | 3 +++
36
tests/qemu-iotests/138 | 3 +++
37
tests/qemu-iotests/156 | 2 ++
38
tests/qemu-iotests/176 | 7 +++++--
39
tests/qemu-iotests/191 | 2 ++
40
tests/qemu-iotests/201 | 6 +++---
41
tests/qemu-iotests/214 | 3 ++-
42
tests/qemu-iotests/217 | 3 ++-
43
tests/qemu-iotests/220 | 5 +++--
44
tests/qemu-iotests/243 | 6 ++++--
45
tests/qemu-iotests/244 | 5 +++--
46
tests/qemu-iotests/250 | 2 ++
47
tests/qemu-iotests/261 | 3 ++-
48
tests/qemu-iotests/267 | 5 +++--
49
tests/qemu-iotests/273 | 3 +++
50
44 files changed, 127 insertions(+), 53 deletions(-)
51
21
52
diff --git a/tests/qemu-iotests/007 b/tests/qemu-iotests/007
22
diff --git a/util/vhost-user-server.h b/util/vhost-user-server.h
53
index XXXXXXX..XXXXXXX 100755
23
new file mode 100644
54
--- a/tests/qemu-iotests/007
24
index XXXXXXX..XXXXXXX
55
+++ b/tests/qemu-iotests/007
25
--- /dev/null
56
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
26
+++ b/util/vhost-user-server.h
57
_supported_fmt qcow2
27
@@ -XXX,XX +XXX,XX @@
58
_supported_proto generic
28
+/*
59
# refcount_bits must be at least 4 so we can create ten internal snapshots
29
+ * Sharing QEMU devices via vhost-user protocol
60
-# (1 bit supports none, 2 bits support two, 4 bits support 14)
30
+ *
61
-_unsupported_imgopts 'refcount_bits=\(1\|2\)[^0-9]'
31
+ * Copyright (c) Coiby Xu <coiby.xu@gmail.com>.
62
+# (1 bit supports none, 2 bits support two, 4 bits support 14);
32
+ * Copyright (c) 2020 Red Hat, Inc.
63
+# snapshot are generally impossible with external data files
33
+ *
64
+_unsupported_imgopts 'refcount_bits=\(1\|2\)[^0-9]' data_file
34
+ * This work is licensed under the terms of the GNU GPL, version 2 or
65
35
+ * later. See the COPYING file in the top-level directory.
66
echo
36
+ */
67
echo "creating image"
37
+
68
diff --git a/tests/qemu-iotests/014 b/tests/qemu-iotests/014
38
+#ifndef VHOST_USER_SERVER_H
69
index XXXXXXX..XXXXXXX 100755
39
+#define VHOST_USER_SERVER_H
70
--- a/tests/qemu-iotests/014
40
+
71
+++ b/tests/qemu-iotests/014
41
+#include "contrib/libvhost-user/libvhost-user.h"
72
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
42
+#include "io/channel-socket.h"
73
_supported_fmt qcow2
43
+#include "io/channel-file.h"
74
_supported_proto file
44
+#include "io/net-listener.h"
75
_supported_os Linux
45
+#include "qemu/error-report.h"
76
+# Compression and snapshots do not work with external data files
46
+#include "qapi/error.h"
77
+_unsupported_imgopts data_file
47
+#include "standard-headers/linux/virtio_blk.h"
78
48
+
79
TEST_OFFSETS="0 4294967296"
49
+typedef struct VuFdWatch {
80
TEST_OPS="writev read write readv"
50
+ VuDev *vu_dev;
81
diff --git a/tests/qemu-iotests/015 b/tests/qemu-iotests/015
51
+ int fd; /*kick fd*/
82
index XXXXXXX..XXXXXXX 100755
52
+ void *pvt;
83
--- a/tests/qemu-iotests/015
53
+ vu_watch_cb cb;
84
+++ b/tests/qemu-iotests/015
54
+ bool processing;
85
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
55
+ QTAILQ_ENTRY(VuFdWatch) next;
86
# actually any format that supports snapshots
56
+} VuFdWatch;
87
_supported_fmt qcow2
57
+
88
_supported_proto generic
58
+typedef struct VuServer VuServer;
89
-# Internal snapshots are (currently) impossible with refcount_bits=1
59
+typedef void DevicePanicNotifierFn(VuServer *server);
90
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
60
+
91
+# Internal snapshots are (currently) impossible with refcount_bits=1,
61
+struct VuServer {
92
+# and generally impossible with external data files
62
+ QIONetListener *listener;
93
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
63
+ AioContext *ctx;
94
64
+ DevicePanicNotifierFn *device_panic_notifier;
95
echo
65
+ int max_queues;
96
echo "creating image"
66
+ const VuDevIface *vu_iface;
97
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
67
+ VuDev vu_dev;
98
index XXXXXXX..XXXXXXX 100755
68
+ QIOChannel *ioc; /* The I/O channel with the client */
99
--- a/tests/qemu-iotests/026
69
+ QIOChannelSocket *sioc; /* The underlying data channel with the client */
100
+++ b/tests/qemu-iotests/026
70
+ /* IOChannel for fd provided via VHOST_USER_SET_SLAVE_REQ_FD */
101
@@ -XXX,XX +XXX,XX @@ _supported_cache_modes writethrough none
71
+ QIOChannel *ioc_slave;
102
# 32 and 64 bits do not work either, however, due to different leaked cluster
72
+ QIOChannelSocket *sioc_slave;
103
# count on error.
73
+ Coroutine *co_trip; /* coroutine for processing VhostUserMsg */
104
# Thus, the only remaining option is refcount_bits=16.
74
+ QTAILQ_HEAD(, VuFdWatch) vu_fd_watches;
105
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
75
+ /* restart coroutine co_trip if AIOContext is changed */
106
+#
76
+ bool aio_context_changed;
107
+# As for data_file, none of the refcount tests can work for it.
77
+ bool processing_msg;
108
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' \
78
+};
109
+ data_file
79
+
110
80
+bool vhost_user_server_start(VuServer *server,
111
echo "Errors while writing 128 kB"
81
+ SocketAddress *unix_socket,
112
echo
82
+ AioContext *ctx,
113
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
83
+ uint16_t max_queues,
114
index XXXXXXX..XXXXXXX 100755
84
+ DevicePanicNotifierFn *device_panic_notifier,
115
--- a/tests/qemu-iotests/029
85
+ const VuDevIface *vu_iface,
116
+++ b/tests/qemu-iotests/029
86
+ Error **errp);
117
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
87
+
118
_supported_fmt qcow2
88
+void vhost_user_server_stop(VuServer *server);
119
_supported_proto generic
89
+
120
_unsupported_proto vxhs
90
+void vhost_user_server_set_aio_context(VuServer *server, AioContext *ctx);
121
-# Internal snapshots are (currently) impossible with refcount_bits=1
91
+
122
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
92
+#endif /* VHOST_USER_SERVER_H */
123
+# Internal snapshots are (currently) impossible with refcount_bits=1,
93
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
124
+# and generally impossible with external data files
94
new file mode 100644
125
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
95
index XXXXXXX..XXXXXXX
126
96
--- /dev/null
127
offset_size=24
97
+++ b/util/vhost-user-server.c
128
offset_l1_size=36
98
@@ -XXX,XX +XXX,XX @@
129
diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
99
+/*
130
index XXXXXXX..XXXXXXX 100755
100
+ * Sharing QEMU devices via vhost-user protocol
131
--- a/tests/qemu-iotests/031
101
+ *
132
+++ b/tests/qemu-iotests/031
102
+ * Copyright (c) Coiby Xu <coiby.xu@gmail.com>.
133
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
103
+ * Copyright (c) 2020 Red Hat, Inc.
134
# This tests qcow2-specific low-level functionality
104
+ *
135
_supported_fmt qcow2
105
+ * This work is licensed under the terms of the GNU GPL, version 2 or
136
_supported_proto file
106
+ * later. See the COPYING file in the top-level directory.
137
-# We want to test compat=0.10, which does not support refcount widths
107
+ */
138
-# other than 16
108
+#include "qemu/osdep.h"
139
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
109
+#include "qemu/main-loop.h"
140
+# We want to test compat=0.10, which does not support external data
110
+#include "vhost-user-server.h"
141
+# files or refcount widths other than 16
111
+
142
+_unsupported_imgopts data_file 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
112
+static void vmsg_close_fds(VhostUserMsg *vmsg)
143
113
+{
144
CLUSTER_SIZE=65536
114
+ int i;
145
115
+ for (i = 0; i < vmsg->fd_num; i++) {
146
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
116
+ close(vmsg->fds[i]);
147
index XXXXXXX..XXXXXXX 100755
117
+ }
148
--- a/tests/qemu-iotests/036
118
+}
149
+++ b/tests/qemu-iotests/036
119
+
150
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
120
+static void vmsg_unblock_fds(VhostUserMsg *vmsg)
151
# This tests qcow2-specific low-level functionality
121
+{
152
_supported_fmt qcow2
122
+ int i;
153
_supported_proto file
123
+ for (i = 0; i < vmsg->fd_num; i++) {
154
-# Only qcow2v3 and later supports feature bits
124
+ qemu_set_nonblock(vmsg->fds[i]);
155
-_unsupported_imgopts 'compat=0.10'
125
+ }
156
+# Only qcow2v3 and later supports feature bits;
126
+}
157
+# qcow2.py does not support external data files
127
+
158
+_unsupported_imgopts 'compat=0.10' data_file
128
+static void vu_accept(QIONetListener *listener, QIOChannelSocket *sioc,
159
129
+ gpointer opaque);
160
echo
130
+
161
echo === Image with unknown incompatible feature bit ===
131
+static void close_client(VuServer *server)
162
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
132
+{
163
index XXXXXXX..XXXXXXX 100755
133
+ /*
164
--- a/tests/qemu-iotests/039
134
+ * Before closing the client
165
+++ b/tests/qemu-iotests/039
135
+ *
166
@@ -XXX,XX +XXX,XX @@ _supported_proto file
136
+ * 1. Let vu_client_trip stop processing new vhost-user msg
167
_supported_os Linux
137
+ *
168
_default_cache_mode writethrough
138
+ * 2. remove kick_handler
169
_supported_cache_modes writethrough
139
+ *
170
+# Some of these test cases expect no external data file so that all
140
+ * 3. wait for the kick handler to be finished
171
+# clusters are part of the qcow2 image and refcounted
141
+ *
172
+_unsupported_imgopts data_file
142
+ * 4. wait for the current vhost-user msg to be finished processing
173
143
+ */
174
size=128M
144
+
175
145
+ QIOChannelSocket *sioc = server->sioc;
176
diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046
146
+ /* When this is set vu_client_trip will stop new processing vhost-user message */
177
index XXXXXXX..XXXXXXX 100755
147
+ server->sioc = NULL;
178
--- a/tests/qemu-iotests/046
148
+
179
+++ b/tests/qemu-iotests/046
149
+ VuFdWatch *vu_fd_watch, *next;
180
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
150
+ QTAILQ_FOREACH_SAFE(vu_fd_watch, &server->vu_fd_watches, next, next) {
181
151
+ aio_set_fd_handler(server->ioc->ctx, vu_fd_watch->fd, true, NULL,
182
_supported_fmt qcow2
152
+ NULL, NULL, NULL);
183
_supported_proto file
153
+ }
184
+# data_file does not support compressed clusters
154
+
185
+_unsupported_imgopts data_file
155
+ while (!QTAILQ_EMPTY(&server->vu_fd_watches)) {
186
156
+ QTAILQ_FOREACH_SAFE(vu_fd_watch, &server->vu_fd_watches, next, next) {
187
CLUSTER_SIZE=64k
157
+ if (!vu_fd_watch->processing) {
188
size=128M
158
+ QTAILQ_REMOVE(&server->vu_fd_watches, vu_fd_watch, next);
189
diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048
159
+ g_free(vu_fd_watch);
190
index XXXXXXX..XXXXXXX 100755
160
+ }
191
--- a/tests/qemu-iotests/048
161
+ }
192
+++ b/tests/qemu-iotests/048
162
+ }
193
@@ -XXX,XX +XXX,XX @@ _compare()
163
+
194
_supported_fmt raw qcow2 qed luks
164
+ while (server->processing_msg) {
195
_supported_proto file
165
+ if (server->ioc->read_coroutine) {
196
_supported_os Linux
166
+ server->ioc->read_coroutine = NULL;
197
+# Using 'cp' is incompatible with external data files
167
+ qio_channel_set_aio_fd_handler(server->ioc, server->ioc->ctx, NULL,
198
+_unsupported_imgopts data_file
168
+ NULL, server->ioc);
199
169
+ server->processing_msg = false;
200
# Remove once all tests are fixed to use TEST_IMG_FILE
170
+ }
201
# correctly and common.rc sets it unconditionally
171
+ }
202
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
172
+
203
index XXXXXXX..XXXXXXX 100755
173
+ vu_deinit(&server->vu_dev);
204
--- a/tests/qemu-iotests/051
174
+ object_unref(OBJECT(sioc));
205
+++ b/tests/qemu-iotests/051
175
+ object_unref(OBJECT(server->ioc));
206
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
176
+}
207
_supported_fmt qcow2
177
+
208
_supported_proto file
178
+static void panic_cb(VuDev *vu_dev, const char *buf)
209
# A compat=0.10 image is created in this test which does not support anything
179
+{
210
-# other than refcount_bits=16
180
+ VuServer *server = container_of(vu_dev, VuServer, vu_dev);
211
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
181
+
212
+# other than refcount_bits=16;
182
+ /* avoid while loop in close_client */
213
+# it also will not support an external data file
183
+ server->processing_msg = false;
214
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
184
+
215
_require_drivers nbd
185
+ if (buf) {
216
186
+ error_report("vu_panic: %s", buf);
217
do_run_qemu()
187
+ }
218
diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058
188
+
219
index XXXXXXX..XXXXXXX 100755
189
+ if (server->sioc) {
220
--- a/tests/qemu-iotests/058
190
+ close_client(server);
221
+++ b/tests/qemu-iotests/058
191
+ }
222
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow2
192
+
223
_supported_proto file
193
+ if (server->device_panic_notifier) {
224
_supported_os Linux
194
+ server->device_panic_notifier(server);
225
_require_command QEMU_NBD
195
+ }
226
-# Internal snapshots are (currently) impossible with refcount_bits=1
196
+
227
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
197
+ /*
228
+# Internal snapshots are (currently) impossible with refcount_bits=1,
198
+ * Set the callback function for network listener so another
229
+# and generally impossible with external data files
199
+ * vhost-user client can connect to this server
230
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
200
+ */
231
201
+ qio_net_listener_set_client_func(server->listener,
232
nbd_snapshot_img="nbd:unix:$nbd_unix_socket"
202
+ vu_accept,
233
203
+ server,
234
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
204
+ NULL);
235
index XXXXXXX..XXXXXXX 100755
205
+}
236
--- a/tests/qemu-iotests/060
206
+
237
+++ b/tests/qemu-iotests/060
207
+static bool coroutine_fn
238
@@ -XXX,XX +XXX,XX @@ _filter_io_error()
208
+vu_message_read(VuDev *vu_dev, int conn_fd, VhostUserMsg *vmsg)
239
_supported_fmt qcow2
209
+{
240
_supported_proto file
210
+ struct iovec iov = {
241
_supported_os Linux
211
+ .iov_base = (char *)vmsg,
242
-# These tests only work for compat=1.1 images with refcount_bits=16
212
+ .iov_len = VHOST_USER_HDR_SIZE,
243
-_unsupported_imgopts 'compat=0.10' 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
213
+ };
244
+# These tests only work for compat=1.1 images without an external
214
+ int rc, read_bytes = 0;
245
+# data file with refcount_bits=16
215
+ Error *local_err = NULL;
246
+_unsupported_imgopts 'compat=0.10' data_file \
216
+ /*
247
+ 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
217
+ * Store fds/nfds returned from qio_channel_readv_full into
248
218
+ * temporary variables.
249
# The repair process will create a large file - so check for availability first
219
+ *
250
_require_large_file 64G
220
+ * VhostUserMsg is a packed structure, gcc will complain about passing
251
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
221
+ * pointer to a packed structure member if we pass &VhostUserMsg.fd_num
252
index XXXXXXX..XXXXXXX 100755
222
+ * and &VhostUserMsg.fds directly when calling qio_channel_readv_full,
253
--- a/tests/qemu-iotests/061
223
+ * thus two temporary variables nfds and fds are used here.
254
+++ b/tests/qemu-iotests/061
224
+ */
255
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow2
225
+ size_t nfds = 0, nfds_t = 0;
256
_supported_proto file
226
+ const size_t max_fds = G_N_ELEMENTS(vmsg->fds);
257
_supported_os Linux
227
+ int *fds_t = NULL;
258
# Conversion between different compat versions can only really work
228
+ VuServer *server = container_of(vu_dev, VuServer, vu_dev);
259
-# with refcount_bits=16
229
+ QIOChannel *ioc = server->ioc;
260
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
230
+
261
+# with refcount_bits=16;
231
+ if (!ioc) {
262
+# we have explicit tests for data_file here, but the whole test does
232
+ error_report_err(local_err);
263
+# not work with it
233
+ goto fail;
264
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
234
+ }
265
235
+
266
echo
236
+ assert(qemu_in_coroutine());
267
echo "=== Testing version downgrade with zero expansion ==="
237
+ do {
268
diff --git a/tests/qemu-iotests/062 b/tests/qemu-iotests/062
238
+ /*
269
index XXXXXXX..XXXXXXX 100755
239
+ * qio_channel_readv_full may have short reads, keeping calling it
270
--- a/tests/qemu-iotests/062
240
+ * until getting VHOST_USER_HDR_SIZE or 0 bytes in total
271
+++ b/tests/qemu-iotests/062
241
+ */
272
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
242
+ rc = qio_channel_readv_full(ioc, &iov, 1, &fds_t, &nfds_t, &local_err);
273
_supported_fmt qcow2
243
+ if (rc < 0) {
274
_supported_proto generic
244
+ if (rc == QIO_CHANNEL_ERR_BLOCK) {
275
# We need zero clusters and snapshots
245
+ qio_channel_yield(ioc, G_IO_IN);
276
-_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]'
246
+ continue;
277
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file
247
+ } else {
278
248
+ error_report_err(local_err);
279
IMG_SIZE=64M
249
+ return false;
280
250
+ }
281
diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066
251
+ }
282
index XXXXXXX..XXXXXXX 100755
252
+ read_bytes += rc;
283
--- a/tests/qemu-iotests/066
253
+ if (nfds_t > 0) {
284
+++ b/tests/qemu-iotests/066
254
+ if (nfds + nfds_t > max_fds) {
285
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
255
+ error_report("A maximum of %zu fds are allowed, "
286
_supported_fmt qcow2
256
+ "however got %lu fds now",
287
_supported_proto generic
257
+ max_fds, nfds + nfds_t);
288
# We need zero clusters and snapshots
258
+ goto fail;
289
-_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]'
259
+ }
290
+# (TODO: Consider splitting the snapshot part into a separate test
260
+ memcpy(vmsg->fds + nfds, fds_t,
291
+# file, so this one runs with refcount_bits=1 and data_file)
261
+ nfds_t *sizeof(vmsg->fds[0]));
292
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file
262
+ nfds += nfds_t;
293
263
+ g_free(fds_t);
294
# Intentionally create an unaligned image
264
+ }
295
IMG_SIZE=$((64 * 1024 * 1024 + 512))
265
+ if (read_bytes == VHOST_USER_HDR_SIZE || rc == 0) {
296
diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067
266
+ break;
297
index XXXXXXX..XXXXXXX 100755
267
+ }
298
--- a/tests/qemu-iotests/067
268
+ iov.iov_base = (char *)vmsg + read_bytes;
299
+++ b/tests/qemu-iotests/067
269
+ iov.iov_len = VHOST_USER_HDR_SIZE - read_bytes;
300
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
270
+ } while (true);
301
271
+
302
_supported_fmt qcow2
272
+ vmsg->fd_num = nfds;
303
_supported_proto file
273
+ /* qio_channel_readv_full will make socket fds blocking, unblock them */
304
-# Because anything other than 16 would change the output of query-block
274
+ vmsg_unblock_fds(vmsg);
305
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
275
+ if (vmsg->size > sizeof(vmsg->payload)) {
306
+# Because anything other than 16 would change the output of query-block,
276
+ error_report("Error: too big message request: %d, "
307
+# and external data files would change the output of
277
+ "size: vmsg->size: %u, "
308
+# query-named-block-nodes
278
+ "while sizeof(vmsg->payload) = %zu",
309
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
279
+ vmsg->request, vmsg->size, sizeof(vmsg->payload));
310
280
+ goto fail;
311
do_run_qemu()
281
+ }
312
{
282
+
313
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
283
+ struct iovec iov_payload = {
314
index XXXXXXX..XXXXXXX 100755
284
+ .iov_base = (char *)&vmsg->payload,
315
--- a/tests/qemu-iotests/068
285
+ .iov_len = vmsg->size,
316
+++ b/tests/qemu-iotests/068
286
+ };
317
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
287
+ if (vmsg->size) {
318
# This tests qcow2-specific low-level functionality
288
+ rc = qio_channel_readv_all_eof(ioc, &iov_payload, 1, &local_err);
319
_supported_fmt qcow2
289
+ if (rc == -1) {
320
_supported_proto generic
290
+ error_report_err(local_err);
321
-# Internal snapshots are (currently) impossible with refcount_bits=1
291
+ goto fail;
322
-_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]'
292
+ }
323
+# Internal snapshots are (currently) impossible with refcount_bits=1,
293
+ }
324
+# and generally impossible with external data files
294
+
325
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file
295
+ return true;
326
296
+
327
IMG_SIZE=128K
297
+fail:
328
298
+ vmsg_close_fds(vmsg);
329
diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
299
+
330
index XXXXXXX..XXXXXXX 100755
300
+ return false;
331
--- a/tests/qemu-iotests/071
301
+}
332
+++ b/tests/qemu-iotests/071
302
+
333
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
303
+
334
_supported_fmt qcow2
304
+static void vu_client_start(VuServer *server);
335
_supported_proto file
305
+static coroutine_fn void vu_client_trip(void *opaque)
336
_require_drivers blkdebug blkverify
306
+{
337
+# blkdebug can only inject errors on bs->file, not on the data_file,
307
+ VuServer *server = opaque;
338
+# so thie test does not work with external data files
308
+
339
+_unsupported_imgopts data_file
309
+ while (!server->aio_context_changed && server->sioc) {
340
310
+ server->processing_msg = true;
341
do_run_qemu()
311
+ vu_dispatch(&server->vu_dev);
342
{
312
+ server->processing_msg = false;
343
diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073
313
+ }
344
index XXXXXXX..XXXXXXX 100755
314
+
345
--- a/tests/qemu-iotests/073
315
+ if (server->aio_context_changed && server->sioc) {
346
+++ b/tests/qemu-iotests/073
316
+ server->aio_context_changed = false;
347
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
317
+ vu_client_start(server);
348
_supported_fmt qcow2
318
+ }
349
_supported_proto generic
319
+}
350
_unsupported_proto vxhs
320
+
351
+# External data files do not support compressed clusters
321
+static void vu_client_start(VuServer *server)
352
+# (TODO: Consider writing a version for external data files that does
322
+{
353
+# not test compressed clusters)
323
+ server->co_trip = qemu_coroutine_create(vu_client_trip, server);
354
+_unsupported_imgopts data_file
324
+ aio_co_enter(server->ctx, server->co_trip);
355
325
+}
356
CLUSTER_SIZE=64k
326
+
357
size=128M
327
+/*
358
diff --git a/tests/qemu-iotests/074 b/tests/qemu-iotests/074
328
+ * a wrapper for vu_kick_cb
359
index XXXXXXX..XXXXXXX 100755
329
+ *
360
--- a/tests/qemu-iotests/074
330
+ * since aio_dispatch can only pass one user data pointer to the
361
+++ b/tests/qemu-iotests/074
331
+ * callback function, pack VuDev and pvt into a struct. Then unpack it
362
@@ -XXX,XX +XXX,XX @@ _compare()
332
+ * and pass them to vu_kick_cb
363
_supported_fmt qcow2
333
+ */
364
_supported_proto file
334
+static void kick_handler(void *opaque)
365
_supported_os Linux
335
+{
366
+# blkdebug can only inject errors on bs->file
336
+ VuFdWatch *vu_fd_watch = opaque;
367
+_unsupported_imgopts data_file
337
+ vu_fd_watch->processing = true;
368
338
+ vu_fd_watch->cb(vu_fd_watch->vu_dev, 0, vu_fd_watch->pvt);
369
# Setup test basic parameters
339
+ vu_fd_watch->processing = false;
370
TEST_IMG2=$TEST_IMG.2
340
+}
371
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
341
+
372
index XXXXXXX..XXXXXXX 100755
342
+
373
--- a/tests/qemu-iotests/080
343
+static VuFdWatch *find_vu_fd_watch(VuServer *server, int fd)
374
+++ b/tests/qemu-iotests/080
344
+{
375
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
345
+
376
_supported_fmt qcow2
346
+ VuFdWatch *vu_fd_watch, *next;
377
_supported_proto file
347
+ QTAILQ_FOREACH_SAFE(vu_fd_watch, &server->vu_fd_watches, next, next) {
378
_supported_os Linux
348
+ if (vu_fd_watch->fd == fd) {
379
-# - Internal snapshots are (currently) impossible with refcount_bits=1
349
+ return vu_fd_watch;
380
+# - Internal snapshots are (currently) impossible with refcount_bits=1,
350
+ }
381
+# and generally impossible with external data files
351
+ }
382
# - This is generally a test for compat=1.1 images
352
+ return NULL;
383
-_unsupported_imgopts 'refcount_bits=1[^0-9]' 'compat=0.10'
353
+}
384
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file 'compat=0.10'
354
+
385
355
+static void
386
header_size=104
356
+set_watch(VuDev *vu_dev, int fd, int vu_evt,
387
357
+ vu_watch_cb cb, void *pvt)
388
diff --git a/tests/qemu-iotests/090 b/tests/qemu-iotests/090
358
+{
389
index XXXXXXX..XXXXXXX 100755
359
+
390
--- a/tests/qemu-iotests/090
360
+ VuServer *server = container_of(vu_dev, VuServer, vu_dev);
391
+++ b/tests/qemu-iotests/090
361
+ g_assert(vu_dev);
392
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
362
+ g_assert(fd >= 0);
393
363
+ g_assert(cb);
394
_supported_fmt qcow2
364
+
395
_supported_proto file nfs
365
+ VuFdWatch *vu_fd_watch = find_vu_fd_watch(server, fd);
396
+# External data files do not support compressed clusters
366
+
397
+_unsupported_imgopts data_file
367
+ if (!vu_fd_watch) {
398
368
+ VuFdWatch *vu_fd_watch = g_new0(VuFdWatch, 1);
399
IMG_SIZE=128K
369
+
400
370
+ QTAILQ_INSERT_TAIL(&server->vu_fd_watches, vu_fd_watch, next);
401
diff --git a/tests/qemu-iotests/098 b/tests/qemu-iotests/098
371
+
402
index XXXXXXX..XXXXXXX 100755
372
+ vu_fd_watch->fd = fd;
403
--- a/tests/qemu-iotests/098
373
+ vu_fd_watch->cb = cb;
404
+++ b/tests/qemu-iotests/098
374
+ qemu_set_nonblock(fd);
405
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
375
+ aio_set_fd_handler(server->ioc->ctx, fd, true, kick_handler,
406
376
+ NULL, NULL, vu_fd_watch);
407
_supported_fmt qcow2
377
+ vu_fd_watch->vu_dev = vu_dev;
408
_supported_proto file
378
+ vu_fd_watch->pvt = pvt;
409
-# The code path we want to test here only works for compat=1.1 images
379
+ }
410
-_unsupported_imgopts 'compat=0.10'
380
+}
411
+# The code path we want to test here only works for compat=1.1 images;
381
+
412
+# blkdebug can only inject errors on bs->file, so external data files
382
+
413
+# do not work with this test
383
+static void remove_watch(VuDev *vu_dev, int fd)
414
+_unsupported_imgopts 'compat=0.10' data_file
384
+{
415
385
+ VuServer *server;
416
for event in l1_update empty_image_prepare reftable_update refblock_alloc; do
386
+ g_assert(vu_dev);
417
387
+ g_assert(fd >= 0);
418
diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099
388
+
419
index XXXXXXX..XXXXXXX 100755
389
+ server = container_of(vu_dev, VuServer, vu_dev);
420
--- a/tests/qemu-iotests/099
390
+
421
+++ b/tests/qemu-iotests/099
391
+ VuFdWatch *vu_fd_watch = find_vu_fd_watch(server, fd);
422
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow qcow2 qed vdi vhdx vmdk vpc
392
+
423
_supported_proto file
393
+ if (!vu_fd_watch) {
424
_supported_os Linux
394
+ return;
425
_require_drivers blkdebug blkverify
395
+ }
426
+# data_file would change the json:{} filenames
396
+ aio_set_fd_handler(server->ioc->ctx, fd, true, NULL, NULL, NULL, NULL);
427
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
397
+
428
- "subformat=twoGbMaxExtentSparse"
398
+ QTAILQ_REMOVE(&server->vu_fd_watches, vu_fd_watch, next);
429
+ "subformat=twoGbMaxExtentSparse" data_file
399
+ g_free(vu_fd_watch);
430
400
+}
431
do_run_qemu()
401
+
432
{
402
+
433
diff --git a/tests/qemu-iotests/103 b/tests/qemu-iotests/103
403
+static void vu_accept(QIONetListener *listener, QIOChannelSocket *sioc,
434
index XXXXXXX..XXXXXXX 100755
404
+ gpointer opaque)
435
--- a/tests/qemu-iotests/103
405
+{
436
+++ b/tests/qemu-iotests/103
406
+ VuServer *server = opaque;
437
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
407
+
438
408
+ if (server->sioc) {
439
_supported_fmt qcow2
409
+ warn_report("Only one vhost-user client is allowed to "
440
_supported_proto file nfs
410
+ "connect the server one time");
441
-# Internal snapshots are (currently) impossible with refcount_bits=1
411
+ return;
442
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
412
+ }
443
+# Internal snapshots are (currently) impossible with refcount_bits=1,
413
+
444
+# and generally impossible with external data files
414
+ if (!vu_init(&server->vu_dev, server->max_queues, sioc->fd, panic_cb,
445
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
415
+ vu_message_read, set_watch, remove_watch, server->vu_iface)) {
446
416
+ error_report("Failed to initialize libvhost-user");
447
IMG_SIZE=64K
417
+ return;
448
418
+ }
449
diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108
419
+
450
index XXXXXXX..XXXXXXX 100755
420
+ /*
451
--- a/tests/qemu-iotests/108
421
+ * Unset the callback function for network listener to make another
452
+++ b/tests/qemu-iotests/108
422
+ * vhost-user client keeping waiting until this client disconnects
453
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
423
+ */
454
_supported_fmt qcow2
424
+ qio_net_listener_set_client_func(server->listener,
455
_supported_proto file
425
+ NULL,
456
_supported_os Linux
426
+ NULL,
457
-# This test directly modifies a refblock so it relies on refcount_bits being 16
427
+ NULL);
458
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
428
+ server->sioc = sioc;
459
+# This test directly modifies a refblock so it relies on refcount_bits being 16;
429
+ /*
460
+# and the low-level modification it performs are not tuned for external data
430
+ * Increase the object reference, so sioc will not freed by
461
+# files
431
+ * qio_net_listener_channel_func which will call object_unref(OBJECT(sioc))
462
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
432
+ */
463
433
+ object_ref(OBJECT(server->sioc));
464
echo
434
+ qio_channel_set_name(QIO_CHANNEL(sioc), "vhost-user client");
465
echo '=== Repairing an image without any refcount table ==='
435
+ server->ioc = QIO_CHANNEL(sioc);
466
diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
436
+ object_ref(OBJECT(server->ioc));
467
index XXXXXXX..XXXXXXX 100755
437
+ qio_channel_attach_aio_context(server->ioc, server->ctx);
468
--- a/tests/qemu-iotests/112
438
+ qio_channel_set_blocking(QIO_CHANNEL(server->sioc), false, NULL);
469
+++ b/tests/qemu-iotests/112
439
+ vu_client_start(server);
470
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
440
+}
471
_supported_fmt qcow2
441
+
472
_supported_proto file
442
+
473
# This test will set refcount_bits on its own which would conflict with the
443
+void vhost_user_server_stop(VuServer *server)
474
-# manual setting; compat will be overridden as well
444
+{
475
-_unsupported_imgopts refcount_bits 'compat=0.10'
445
+ if (server->sioc) {
476
+# manual setting; compat will be overridden as well;
446
+ close_client(server);
477
+# and external data files do not work well with our refcount testing
447
+ }
478
+_unsupported_imgopts refcount_bits 'compat=0.10' data_file
448
+
479
449
+ if (server->listener) {
480
print_refcount_bits()
450
+ qio_net_listener_disconnect(server->listener);
481
{
451
+ object_unref(OBJECT(server->listener));
482
diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114
452
+ }
483
index XXXXXXX..XXXXXXX 100755
453
+
484
--- a/tests/qemu-iotests/114
454
+}
485
+++ b/tests/qemu-iotests/114
455
+
486
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
456
+void vhost_user_server_set_aio_context(VuServer *server, AioContext *ctx)
487
_supported_fmt qcow2
457
+{
488
_supported_proto generic
458
+ VuFdWatch *vu_fd_watch, *next;
489
_unsupported_proto vxhs
459
+ void *opaque = NULL;
490
+# qcow2.py does not work too well with external data files
460
+ IOHandler *io_read = NULL;
491
+_unsupported_imgopts data_file
461
+ bool attach;
492
462
+
493
463
+ server->ctx = ctx ? ctx : qemu_get_aio_context();
494
TEST_IMG="$TEST_IMG.base" _make_test_img 64M
464
+
495
diff --git a/tests/qemu-iotests/121 b/tests/qemu-iotests/121
465
+ if (!server->sioc) {
496
index XXXXXXX..XXXXXXX 100755
466
+ /* not yet serving any client*/
497
--- a/tests/qemu-iotests/121
467
+ return;
498
+++ b/tests/qemu-iotests/121
468
+ }
499
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
469
+
500
_supported_fmt qcow2
470
+ if (ctx) {
501
_supported_proto file
471
+ qio_channel_attach_aio_context(server->ioc, ctx);
502
_supported_os Linux
472
+ server->aio_context_changed = true;
503
+# Refcount structures are used much differently with external data
473
+ io_read = kick_handler;
504
+# files
474
+ attach = true;
505
+_unsupported_imgopts data_file
475
+ } else {
506
476
+ qio_channel_detach_aio_context(server->ioc);
507
echo
477
+ /* server->ioc->ctx keeps the old AioConext */
508
echo '=== New refcount structures may not conflict with existing structures ==='
478
+ ctx = server->ioc->ctx;
509
diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138
479
+ attach = false;
510
index XXXXXXX..XXXXXXX 100755
480
+ }
511
--- a/tests/qemu-iotests/138
481
+
512
+++ b/tests/qemu-iotests/138
482
+ QTAILQ_FOREACH_SAFE(vu_fd_watch, &server->vu_fd_watches, next, next) {
513
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
483
+ if (vu_fd_watch->cb) {
514
_supported_fmt qcow2
484
+ opaque = attach ? vu_fd_watch : NULL;
515
_supported_proto file
485
+ aio_set_fd_handler(ctx, vu_fd_watch->fd, true,
516
_supported_os Linux
486
+ io_read, NULL, NULL,
517
+# With an external data file, data clusters are not refcounted
487
+ opaque);
518
+# (and so qemu-img check does not check their refcount)
488
+ }
519
+_unsupported_imgopts data_file
489
+ }
520
490
+}
521
echo
491
+
522
echo '=== Check on an image with a multiple of 2^32 clusters ==='
492
+
523
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
493
+bool vhost_user_server_start(VuServer *server,
524
index XXXXXXX..XXXXXXX 100755
494
+ SocketAddress *socket_addr,
525
--- a/tests/qemu-iotests/156
495
+ AioContext *ctx,
526
+++ b/tests/qemu-iotests/156
496
+ uint16_t max_queues,
527
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
497
+ DevicePanicNotifierFn *device_panic_notifier,
528
_supported_fmt qcow2 qed
498
+ const VuDevIface *vu_iface,
529
_supported_proto generic
499
+ Error **errp)
530
_unsupported_proto vxhs
500
+{
531
+# Copying files around with cp does not work with external data files
501
+ QIONetListener *listener = qio_net_listener_new();
532
+_unsupported_imgopts data_file
502
+ if (qio_net_listener_open_sync(listener, socket_addr, 1,
533
503
+ errp) < 0) {
534
# Create source disk
504
+ object_unref(OBJECT(listener));
535
TEST_IMG="$TEST_IMG.backing" _make_test_img 1M
505
+ return false;
536
diff --git a/tests/qemu-iotests/176 b/tests/qemu-iotests/176
506
+ }
537
index XXXXXXX..XXXXXXX 100755
507
+
538
--- a/tests/qemu-iotests/176
508
+ /* zero out unspecified fileds */
539
+++ b/tests/qemu-iotests/176
509
+ *server = (VuServer) {
540
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
510
+ .listener = listener,
541
_supported_fmt qcow2
511
+ .vu_iface = vu_iface,
542
_supported_proto file
512
+ .max_queues = max_queues,
543
_supported_os Linux
513
+ .ctx = ctx,
544
-# Persistent dirty bitmaps require compat=1.1
514
+ .device_panic_notifier = device_panic_notifier,
545
-_unsupported_imgopts 'compat=0.10'
515
+ };
546
+# Persistent dirty bitmaps require compat=1.1;
516
+
547
+# Internal snapshots forbid using an external data file
517
+ qio_net_listener_set_name(server->listener, "vhost-user-backend-listener");
548
+# (they work with refcount_bits=1 here, though, because there actually
518
+
549
+# is no data when creating the snapshot)
519
+ qio_net_listener_set_client_func(server->listener,
550
+_unsupported_imgopts 'compat=0.10' data_file
520
+ vu_accept,
551
521
+ server,
552
run_qemu()
522
+ NULL);
553
{
523
+
554
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
524
+ QTAILQ_INIT(&server->vu_fd_watches);
555
index XXXXXXX..XXXXXXX 100755
525
+ return true;
556
--- a/tests/qemu-iotests/191
526
+}
557
+++ b/tests/qemu-iotests/191
527
diff --git a/util/meson.build b/util/meson.build
558
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
528
index XXXXXXX..XXXXXXX 100644
559
529
--- a/util/meson.build
560
_supported_fmt qcow2
530
+++ b/util/meson.build
561
_supported_proto file
531
@@ -XXX,XX +XXX,XX @@ if have_block
562
+# An external data file would change the query-named-block-nodes output
532
util_ss.add(files('main-loop.c'))
563
+_unsupported_imgopts data_file
533
util_ss.add(files('nvdimm-utils.c'))
564
534
util_ss.add(files('qemu-coroutine.c', 'qemu-coroutine-lock.c', 'qemu-coroutine-io.c'))
565
size=64M
535
+ util_ss.add(when: 'CONFIG_LINUX', if_true: files('vhost-user-server.c'))
566
536
util_ss.add(files('qemu-coroutine-sleep.c'))
567
diff --git a/tests/qemu-iotests/201 b/tests/qemu-iotests/201
537
util_ss.add(files('qemu-co-shared-resource.c'))
568
index XXXXXXX..XXXXXXX 100755
538
util_ss.add(files('thread-pool.c', 'qemu-timer.c'))
569
--- a/tests/qemu-iotests/201
570
+++ b/tests/qemu-iotests/201
571
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow2
572
_supported_proto generic
573
_supported_os Linux
574
575
-# Internal snapshots are (currently) impossible with refcount_bits=1
576
-# This was taken from test 080
577
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
578
+# Internal snapshots are (currently) impossible with refcount_bits=1,
579
+# and generally impossible with external data files
580
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
581
582
size=64M
583
_make_test_img $size
584
diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214
585
index XXXXXXX..XXXXXXX 100755
586
--- a/tests/qemu-iotests/214
587
+++ b/tests/qemu-iotests/214
588
@@ -XXX,XX +XXX,XX @@ _supported_proto file
589
590
# Repairing the corrupted image requires qemu-img check to store a
591
# refcount up to 3, which requires at least two refcount bits.
592
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
593
+# External data files do not support compressed clusters.
594
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
595
596
597
echo
598
diff --git a/tests/qemu-iotests/217 b/tests/qemu-iotests/217
599
index XXXXXXX..XXXXXXX 100755
600
--- a/tests/qemu-iotests/217
601
+++ b/tests/qemu-iotests/217
602
@@ -XXX,XX +XXX,XX @@ _supported_proto file
603
604
# This test needs clusters with at least a refcount of 2 so that
605
# OFLAG_COPIED is not set. refcount_bits=1 is therefore unsupported.
606
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
607
+# (As are external data files.)
608
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
609
610
echo
611
echo '=== Simulating an I/O error during snapshot deletion ==='
612
diff --git a/tests/qemu-iotests/220 b/tests/qemu-iotests/220
613
index XXXXXXX..XXXXXXX 100755
614
--- a/tests/qemu-iotests/220
615
+++ b/tests/qemu-iotests/220
616
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
617
_supported_fmt qcow2
618
_supported_proto file
619
_supported_os Linux
620
-# To use a different refcount width but 16 bits we need compat=1.1
621
-_unsupported_imgopts 'compat=0.10'
622
+# To use a different refcount width but 16 bits we need compat=1.1,
623
+# and external data files do not support compressed clusters.
624
+_unsupported_imgopts 'compat=0.10' data_file
625
626
echo "== Creating huge file =="
627
628
diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243
629
index XXXXXXX..XXXXXXX 100755
630
--- a/tests/qemu-iotests/243
631
+++ b/tests/qemu-iotests/243
632
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
633
_supported_fmt qcow2
634
_supported_proto file
635
_supported_os Linux
636
-# External data files do not work with compat=0.10
637
-_unsupported_imgopts 'compat=0.10'
638
+# External data files do not work with compat=0.10, and because there
639
+# is an explicit case for external data files here, we cannot allow
640
+# the user to specify whether to use one
641
+_unsupported_imgopts 'compat=0.10' data_file
642
643
for mode in off metadata falloc full; do
644
645
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
646
index XXXXXXX..XXXXXXX 100755
647
--- a/tests/qemu-iotests/244
648
+++ b/tests/qemu-iotests/244
649
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
650
_supported_fmt qcow2
651
_supported_proto file
652
_supported_os Linux
653
-# External data files do not work with compat=0.10
654
-_unsupported_imgopts 'compat=0.10'
655
+# External data files do not work with compat=0.10, and because we use
656
+# our own external data file, we cannot let the user specify one
657
+_unsupported_imgopts 'compat=0.10' data_file
658
659
echo
660
echo "=== Create and open image with external data file ==="
661
diff --git a/tests/qemu-iotests/250 b/tests/qemu-iotests/250
662
index XXXXXXX..XXXXXXX 100755
663
--- a/tests/qemu-iotests/250
664
+++ b/tests/qemu-iotests/250
665
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
666
_supported_fmt qcow2
667
_supported_proto file
668
_supported_os Linux
669
+# This test does not make much sense with external data files
670
+_unsupported_imgopts data_file
671
672
# This test checks that qcow2_process_discards does not truncate a discard
673
# request > 2G.
674
diff --git a/tests/qemu-iotests/261 b/tests/qemu-iotests/261
675
index XXXXXXX..XXXXXXX 100755
676
--- a/tests/qemu-iotests/261
677
+++ b/tests/qemu-iotests/261
678
@@ -XXX,XX +XXX,XX @@ _supported_os Linux
679
# (1) We create a v2 image that supports nothing but refcount_bits=16
680
# (2) We do some refcount management on our own which expects
681
# refcount_bits=16
682
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
683
+# As for data files, they do not support snapshots at all.
684
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
685
686
# Parameters:
687
# $1: image filename
688
diff --git a/tests/qemu-iotests/267 b/tests/qemu-iotests/267
689
index XXXXXXX..XXXXXXX 100755
690
--- a/tests/qemu-iotests/267
691
+++ b/tests/qemu-iotests/267
692
@@ -XXX,XX +XXX,XX @@ _supported_proto file
693
_supported_os Linux
694
_require_drivers copy-on-read
695
696
-# Internal snapshots are (currently) impossible with refcount_bits=1
697
-_unsupported_imgopts 'refcount_bits=1[^0-9]'
698
+# Internal snapshots are (currently) impossible with refcount_bits=1,
699
+# and generally impossible with external data files
700
+_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
701
702
do_run_qemu()
703
{
704
diff --git a/tests/qemu-iotests/273 b/tests/qemu-iotests/273
705
index XXXXXXX..XXXXXXX 100755
706
--- a/tests/qemu-iotests/273
707
+++ b/tests/qemu-iotests/273
708
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
709
_supported_fmt qcow2
710
_supported_proto file
711
_supported_os Linux
712
+# External data files would add nodes to the block graph, so it would
713
+# not match the reference output
714
+_unsupported_imgopts data_file
715
716
do_run_qemu()
717
{
718
--
539
--
719
2.24.1
540
2.26.2
720
541
721
diff view generated by jsdifflib
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
1
From: Coiby Xu <coiby.xu@gmail.com>
2
2
3
QEMU currently supports writing compressed data of the size equal to
3
Move the constants from hw/core/qdev-properties.c to
4
one cluster. This patch allows writing QCOW2 compressed data that
4
util/block-helpers.h so that knowledge of the min/max values is
5
exceed one cluster. Now, we split buffered data into separate clusters
6
and write them compressed using the block/aio_task API.
7
5
8
Suggested-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Coiby Xu <coiby.xu@gmail.com>
10
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Acked-by: Eduardo Habkost <ehabkost@redhat.com>
13
Message-id: 1575288906-551879-3-git-send-email-andrey.shinkevich@virtuozzo.com
11
Message-id: 20200918080912.321299-5-coiby.xu@gmail.com
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
13
---
16
block/qcow2.c | 102 +++++++++++++++++++++++++++++++++++++-------------
14
util/block-helpers.h | 19 +++++++++++++
17
1 file changed, 75 insertions(+), 27 deletions(-)
15
hw/core/qdev-properties-system.c | 31 ++++-----------------
16
util/block-helpers.c | 46 ++++++++++++++++++++++++++++++++
17
util/meson.build | 1 +
18
4 files changed, 71 insertions(+), 26 deletions(-)
19
create mode 100644 util/block-helpers.h
20
create mode 100644 util/block-helpers.c
18
21
19
diff --git a/block/qcow2.c b/block/qcow2.c
22
diff --git a/util/block-helpers.h b/util/block-helpers.h
23
new file mode 100644
24
index XXXXXXX..XXXXXXX
25
--- /dev/null
26
+++ b/util/block-helpers.h
27
@@ -XXX,XX +XXX,XX @@
28
+#ifndef BLOCK_HELPERS_H
29
+#define BLOCK_HELPERS_H
30
+
31
+#include "qemu/units.h"
32
+
33
+/* lower limit is sector size */
34
+#define MIN_BLOCK_SIZE INT64_C(512)
35
+#define MIN_BLOCK_SIZE_STR "512 B"
36
+/*
37
+ * upper limit is arbitrary, 2 MiB looks sufficient for all sensible uses, and
38
+ * matches qcow2 cluster size limit
39
+ */
40
+#define MAX_BLOCK_SIZE (2 * MiB)
41
+#define MAX_BLOCK_SIZE_STR "2 MiB"
42
+
43
+void check_block_size(const char *id, const char *name, int64_t value,
44
+ Error **errp);
45
+
46
+#endif /* BLOCK_HELPERS_H */
47
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
20
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
21
--- a/block/qcow2.c
49
--- a/hw/core/qdev-properties-system.c
22
+++ b/block/qcow2.c
50
+++ b/hw/core/qdev-properties-system.c
23
@@ -XXX,XX +XXX,XX @@ fail:
51
@@ -XXX,XX +XXX,XX @@
24
return ret;
52
#include "sysemu/blockdev.h"
25
}
53
#include "net/net.h"
26
54
#include "hw/pci/pci.h"
27
-/* XXX: put compressed sectors first, then all the cluster aligned
55
+#include "util/block-helpers.h"
28
- tables to avoid losing bytes in alignment */
56
29
static coroutine_fn int
57
static bool check_prop_still_unset(DeviceState *dev, const char *name,
30
-qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
58
const void *old_val, const char *new_val,
31
+qcow2_co_pwritev_compressed_task(BlockDriverState *bs,
59
@@ -XXX,XX +XXX,XX @@ const PropertyInfo qdev_prop_losttickpolicy = {
32
uint64_t offset, uint64_t bytes,
60
33
QEMUIOVector *qiov, size_t qiov_offset)
61
/* --- blocksize --- */
62
63
-/* lower limit is sector size */
64
-#define MIN_BLOCK_SIZE 512
65
-#define MIN_BLOCK_SIZE_STR "512 B"
66
-/*
67
- * upper limit is arbitrary, 2 MiB looks sufficient for all sensible uses, and
68
- * matches qcow2 cluster size limit
69
- */
70
-#define MAX_BLOCK_SIZE (2 * MiB)
71
-#define MAX_BLOCK_SIZE_STR "2 MiB"
72
-
73
static void set_blocksize(Object *obj, Visitor *v, const char *name,
74
void *opaque, Error **errp)
34
{
75
{
35
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
76
@@ -XXX,XX +XXX,XX @@ static void set_blocksize(Object *obj, Visitor *v, const char *name,
36
uint8_t *buf, *out_buf;
77
Property *prop = opaque;
37
uint64_t cluster_offset;
78
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
38
79
uint64_t value;
39
- if (has_data_file(bs)) {
80
+ Error *local_err = NULL;
40
- return -ENOTSUP;
81
82
if (dev->realized) {
83
qdev_prop_set_after_realize(dev, name, errp);
84
@@ -XXX,XX +XXX,XX @@ static void set_blocksize(Object *obj, Visitor *v, const char *name,
85
if (!visit_type_size(v, name, &value, errp)) {
86
return;
87
}
88
- /* value of 0 means "unset" */
89
- if (value && (value < MIN_BLOCK_SIZE || value > MAX_BLOCK_SIZE)) {
90
- error_setg(errp,
91
- "Property %s.%s doesn't take value %" PRIu64
92
- " (minimum: " MIN_BLOCK_SIZE_STR
93
- ", maximum: " MAX_BLOCK_SIZE_STR ")",
94
- dev->id ? : "", name, value);
95
+ check_block_size(dev->id ? : "", name, value, &local_err);
96
+ if (local_err) {
97
+ error_propagate(errp, local_err);
98
return;
99
}
100
-
101
- /* We rely on power-of-2 blocksizes for bitmasks */
102
- if ((value & (value - 1)) != 0) {
103
- error_setg(errp,
104
- "Property %s.%s doesn't take value '%" PRId64 "', "
105
- "it's not a power of 2", dev->id ?: "", name, (int64_t)value);
106
- return;
41
- }
107
- }
42
-
108
-
43
- if (bytes == 0) {
109
*ptr = value;
44
- /* align end of file to a sector boundary to ease reading with
45
- sector based I/Os */
46
- int64_t len = bdrv_getlength(bs->file->bs);
47
- if (len < 0) {
48
- return len;
49
- }
50
- return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
51
- }
52
-
53
- if (offset_into_cluster(s, offset)) {
54
- return -EINVAL;
55
- }
56
+ assert(bytes == s->cluster_size || (bytes < s->cluster_size &&
57
+ (offset + bytes == bs->total_sectors << BDRV_SECTOR_BITS)));
58
59
buf = qemu_blockalign(bs, s->cluster_size);
60
- if (bytes != s->cluster_size) {
61
- if (bytes > s->cluster_size ||
62
- offset + bytes != bs->total_sectors << BDRV_SECTOR_BITS)
63
- {
64
- qemu_vfree(buf);
65
- return -EINVAL;
66
- }
67
+ if (bytes < s->cluster_size) {
68
/* Zero-pad last write if image size is not cluster aligned */
69
memset(buf + bytes, 0, s->cluster_size - bytes);
70
}
71
@@ -XXX,XX +XXX,XX @@ fail:
72
return ret;
73
}
110
}
74
111
75
+static coroutine_fn int qcow2_co_pwritev_compressed_task_entry(AioTask *task)
112
diff --git a/util/block-helpers.c b/util/block-helpers.c
113
new file mode 100644
114
index XXXXXXX..XXXXXXX
115
--- /dev/null
116
+++ b/util/block-helpers.c
117
@@ -XXX,XX +XXX,XX @@
118
+/*
119
+ * Block utility functions
120
+ *
121
+ * Copyright IBM, Corp. 2011
122
+ * Copyright (c) 2020 Coiby Xu <coiby.xu@gmail.com>
123
+ *
124
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
125
+ * See the COPYING file in the top-level directory.
126
+ */
127
+
128
+#include "qemu/osdep.h"
129
+#include "qapi/error.h"
130
+#include "qapi/qmp/qerror.h"
131
+#include "block-helpers.h"
132
+
133
+/**
134
+ * check_block_size:
135
+ * @id: The unique ID of the object
136
+ * @name: The name of the property being validated
137
+ * @value: The block size in bytes
138
+ * @errp: A pointer to an area to store an error
139
+ *
140
+ * This function checks that the block size meets the following conditions:
141
+ * 1. At least MIN_BLOCK_SIZE
142
+ * 2. No larger than MAX_BLOCK_SIZE
143
+ * 3. A power of 2
144
+ */
145
+void check_block_size(const char *id, const char *name, int64_t value,
146
+ Error **errp)
76
+{
147
+{
77
+ Qcow2AioTask *t = container_of(task, Qcow2AioTask, task);
148
+ /* value of 0 means "unset" */
78
+
149
+ if (value && (value < MIN_BLOCK_SIZE || value > MAX_BLOCK_SIZE)) {
79
+ assert(!t->cluster_type && !t->l2meta);
150
+ error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
80
+
151
+ id, name, value, MIN_BLOCK_SIZE, MAX_BLOCK_SIZE);
81
+ return qcow2_co_pwritev_compressed_task(t->bs, t->offset, t->bytes, t->qiov,
152
+ return;
82
+ t->qiov_offset);
83
+}
84
+
85
+/*
86
+ * XXX: put compressed sectors first, then all the cluster aligned
87
+ * tables to avoid losing bytes in alignment
88
+ */
89
+static coroutine_fn int
90
+qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
91
+ uint64_t offset, uint64_t bytes,
92
+ QEMUIOVector *qiov, size_t qiov_offset)
93
+{
94
+ BDRVQcow2State *s = bs->opaque;
95
+ AioTaskPool *aio = NULL;
96
+ int ret = 0;
97
+
98
+ if (has_data_file(bs)) {
99
+ return -ENOTSUP;
100
+ }
153
+ }
101
+
154
+
102
+ if (bytes == 0) {
155
+ /* We rely on power-of-2 blocksizes for bitmasks */
103
+ /*
156
+ if ((value & (value - 1)) != 0) {
104
+ * align end of file to a sector boundary to ease reading with
157
+ error_setg(errp,
105
+ * sector based I/Os
158
+ "Property %s.%s doesn't take value '%" PRId64
106
+ */
159
+ "', it's not a power of 2",
107
+ int64_t len = bdrv_getlength(bs->file->bs);
160
+ id, name, value);
108
+ if (len < 0) {
161
+ return;
109
+ return len;
110
+ }
111
+ return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
112
+ }
162
+ }
113
+
114
+ if (offset_into_cluster(s, offset)) {
115
+ return -EINVAL;
116
+ }
117
+
118
+ while (bytes && aio_task_pool_status(aio) == 0) {
119
+ uint64_t chunk_size = MIN(bytes, s->cluster_size);
120
+
121
+ if (!aio && chunk_size != bytes) {
122
+ aio = aio_task_pool_new(QCOW2_MAX_WORKERS);
123
+ }
124
+
125
+ ret = qcow2_add_task(bs, aio, qcow2_co_pwritev_compressed_task_entry,
126
+ 0, 0, offset, chunk_size, qiov, qiov_offset, NULL);
127
+ if (ret < 0) {
128
+ break;
129
+ }
130
+ qiov_offset += chunk_size;
131
+ offset += chunk_size;
132
+ bytes -= chunk_size;
133
+ }
134
+
135
+ if (aio) {
136
+ aio_task_pool_wait_all(aio);
137
+ if (ret == 0) {
138
+ ret = aio_task_pool_status(aio);
139
+ }
140
+ g_free(aio);
141
+ }
142
+
143
+ return ret;
144
+}
163
+}
145
+
164
diff --git a/util/meson.build b/util/meson.build
146
static int coroutine_fn
165
index XXXXXXX..XXXXXXX 100644
147
qcow2_co_preadv_compressed(BlockDriverState *bs,
166
--- a/util/meson.build
148
uint64_t file_cluster_offset,
167
+++ b/util/meson.build
168
@@ -XXX,XX +XXX,XX @@ if have_block
169
util_ss.add(files('nvdimm-utils.c'))
170
util_ss.add(files('qemu-coroutine.c', 'qemu-coroutine-lock.c', 'qemu-coroutine-io.c'))
171
util_ss.add(when: 'CONFIG_LINUX', if_true: files('vhost-user-server.c'))
172
+ util_ss.add(files('block-helpers.c'))
173
util_ss.add(files('qemu-coroutine-sleep.c'))
174
util_ss.add(files('qemu-co-shared-resource.c'))
175
util_ss.add(files('thread-pool.c', 'qemu-timer.c'))
149
--
176
--
150
2.24.1
177
2.26.2
151
178
152
diff view generated by jsdifflib
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
1
From: Coiby Xu <coiby.xu@gmail.com>
2
2
3
Allow writing all the data compressed through the filter driver.
3
By making use of libvhost-user, block device drive can be shared to
4
The written data will be aligned by the cluster size.
4
the connected vhost-user client. Only one client can connect to the
5
Based on the QEMU current implementation, that data can be written to
5
server one time.
6
unallocated clusters only. May be used for a backup job.
7
6
8
Suggested-by: Max Reitz <mreitz@redhat.com>
7
Since vhost-user-server needs a block drive to be created first, delay
9
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
8
the creation of this object.
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
11
Message-id: 1575288906-551879-2-git-send-email-andrey.shinkevich@virtuozzo.com
10
Suggested-by: Kevin Wolf <kwolf@redhat.com>
12
[mreitz: Replace NULL bdrv_get_format_name() by "(no format)"]
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
Signed-off-by: Coiby Xu <coiby.xu@gmail.com>
13
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
15
Message-id: 20200918080912.321299-6-coiby.xu@gmail.com
16
[Shorten "vhost_user_blk_server" string to "vhost_user_blk" to avoid the
17
following compiler warning:
18
../block/export/vhost-user-blk-server.c:178:50: error: ‘%s’ directive output truncated writing 21 bytes into a region of size 20 [-Werror=format-truncation=]
19
--Stefan]
20
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
---
21
---
15
block/Makefile.objs | 1 +
22
block/export/vhost-user-blk-server.h | 36 ++
16
block/filter-compress.c | 168 ++++++++++++++++++++++++++++++++++++++++
23
block/export/vhost-user-blk-server.c | 661 +++++++++++++++++++++++++++
17
qapi/block-core.json | 10 ++-
24
softmmu/vl.c | 4 +
18
3 files changed, 175 insertions(+), 4 deletions(-)
25
block/meson.build | 1 +
19
create mode 100644 block/filter-compress.c
26
4 files changed, 702 insertions(+)
27
create mode 100644 block/export/vhost-user-blk-server.h
28
create mode 100644 block/export/vhost-user-blk-server.c
20
29
21
diff --git a/block/Makefile.objs b/block/Makefile.objs
30
diff --git a/block/export/vhost-user-blk-server.h b/block/export/vhost-user-blk-server.h
22
index XXXXXXX..XXXXXXX 100644
23
--- a/block/Makefile.objs
24
+++ b/block/Makefile.objs
25
@@ -XXX,XX +XXX,XX @@ block-obj-y += crypto.o
26
27
block-obj-y += aio_task.o
28
block-obj-y += backup-top.o
29
+block-obj-y += filter-compress.o
30
31
common-obj-y += stream.o
32
33
diff --git a/block/filter-compress.c b/block/filter-compress.c
34
new file mode 100644
31
new file mode 100644
35
index XXXXXXX..XXXXXXX
32
index XXXXXXX..XXXXXXX
36
--- /dev/null
33
--- /dev/null
37
+++ b/block/filter-compress.c
34
+++ b/block/export/vhost-user-blk-server.h
38
@@ -XXX,XX +XXX,XX @@
35
@@ -XXX,XX +XXX,XX @@
39
+/*
36
+/*
40
+ * Compress filter block driver
37
+ * Sharing QEMU block devices via vhost-user protocal
41
+ *
38
+ *
42
+ * Copyright (c) 2019 Virtuozzo International GmbH
39
+ * Copyright (c) Coiby Xu <coiby.xu@gmail.com>.
40
+ * Copyright (c) 2020 Red Hat, Inc.
43
+ *
41
+ *
44
+ * Author:
42
+ * This work is licensed under the terms of the GNU GPL, version 2 or
45
+ * Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
43
+ * later. See the COPYING file in the top-level directory.
46
+ * (based on block/copy-on-read.c by Max Reitz)
44
+ */
45
+
46
+#ifndef VHOST_USER_BLK_SERVER_H
47
+#define VHOST_USER_BLK_SERVER_H
48
+#include "util/vhost-user-server.h"
49
+
50
+typedef struct VuBlockDev VuBlockDev;
51
+#define TYPE_VHOST_USER_BLK_SERVER "vhost-user-blk-server"
52
+#define VHOST_USER_BLK_SERVER(obj) \
53
+ OBJECT_CHECK(VuBlockDev, obj, TYPE_VHOST_USER_BLK_SERVER)
54
+
55
+/* vhost user block device */
56
+struct VuBlockDev {
57
+ Object parent_obj;
58
+ char *node_name;
59
+ SocketAddress *addr;
60
+ AioContext *ctx;
61
+ VuServer vu_server;
62
+ bool running;
63
+ uint32_t blk_size;
64
+ BlockBackend *backend;
65
+ QIOChannelSocket *sioc;
66
+ QTAILQ_ENTRY(VuBlockDev) next;
67
+ struct virtio_blk_config blkcfg;
68
+ bool writable;
69
+};
70
+
71
+#endif /* VHOST_USER_BLK_SERVER_H */
72
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
73
new file mode 100644
74
index XXXXXXX..XXXXXXX
75
--- /dev/null
76
+++ b/block/export/vhost-user-blk-server.c
77
@@ -XXX,XX +XXX,XX @@
78
+/*
79
+ * Sharing QEMU block devices via vhost-user protocal
47
+ *
80
+ *
48
+ * This program is free software; you can redistribute it and/or
81
+ * Parts of the code based on nbd/server.c.
49
+ * modify it under the terms of the GNU General Public License as
50
+ * published by the Free Software Foundation; either version 2 or
51
+ * (at your option) any later version of the License.
52
+ *
82
+ *
53
+ * This program is distributed in the hope that it will be useful,
83
+ * Copyright (c) Coiby Xu <coiby.xu@gmail.com>.
54
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
84
+ * Copyright (c) 2020 Red Hat, Inc.
55
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
56
+ * GNU General Public License for more details.
57
+ *
85
+ *
58
+ * You should have received a copy of the GNU General Public License
86
+ * This work is licensed under the terms of the GNU GPL, version 2 or
59
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
87
+ * later. See the COPYING file in the top-level directory.
60
+ */
88
+ */
61
+
62
+#include "qemu/osdep.h"
89
+#include "qemu/osdep.h"
63
+#include "block/block_int.h"
90
+#include "block/block.h"
64
+#include "qemu/module.h"
91
+#include "vhost-user-blk-server.h"
65
+#include "qapi/error.h"
92
+#include "qapi/error.h"
66
+
93
+#include "qom/object_interfaces.h"
67
+
94
+#include "sysemu/block-backend.h"
68
+static int compress_open(BlockDriverState *bs, QDict *options, int flags,
95
+#include "util/block-helpers.h"
69
+ Error **errp)
96
+
70
+{
97
+enum {
71
+ bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, false,
98
+ VHOST_USER_BLK_MAX_QUEUES = 1,
72
+ errp);
99
+};
73
+ if (!bs->file) {
100
+struct virtio_blk_inhdr {
101
+ unsigned char status;
102
+};
103
+
104
+typedef struct VuBlockReq {
105
+ VuVirtqElement *elem;
106
+ int64_t sector_num;
107
+ size_t size;
108
+ struct virtio_blk_inhdr *in;
109
+ struct virtio_blk_outhdr out;
110
+ VuServer *server;
111
+ struct VuVirtq *vq;
112
+} VuBlockReq;
113
+
114
+static void vu_block_req_complete(VuBlockReq *req)
115
+{
116
+ VuDev *vu_dev = &req->server->vu_dev;
117
+
118
+ /* IO size with 1 extra status byte */
119
+ vu_queue_push(vu_dev, req->vq, req->elem, req->size + 1);
120
+ vu_queue_notify(vu_dev, req->vq);
121
+
122
+ if (req->elem) {
123
+ free(req->elem);
124
+ }
125
+
126
+ g_free(req);
127
+}
128
+
129
+static VuBlockDev *get_vu_block_device_by_server(VuServer *server)
130
+{
131
+ return container_of(server, VuBlockDev, vu_server);
132
+}
133
+
134
+static int coroutine_fn
135
+vu_block_discard_write_zeroes(VuBlockReq *req, struct iovec *iov,
136
+ uint32_t iovcnt, uint32_t type)
137
+{
138
+ struct virtio_blk_discard_write_zeroes desc;
139
+ ssize_t size = iov_to_buf(iov, iovcnt, 0, &desc, sizeof(desc));
140
+ if (unlikely(size != sizeof(desc))) {
141
+ error_report("Invalid size %ld, expect %ld", size, sizeof(desc));
74
+ return -EINVAL;
142
+ return -EINVAL;
75
+ }
143
+ }
76
+
144
+
77
+ if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) {
145
+ VuBlockDev *vdev_blk = get_vu_block_device_by_server(req->server);
78
+ error_setg(errp,
146
+ uint64_t range[2] = { le64_to_cpu(desc.sector) << 9,
79
+ "Compression is not supported for underlying format: %s",
147
+ le32_to_cpu(desc.num_sectors) << 9 };
80
+ bdrv_get_format_name(bs->file->bs) ?: "(no format)");
148
+ if (type == VIRTIO_BLK_T_DISCARD) {
81
+
149
+ if (blk_co_pdiscard(vdev_blk->backend, range[0], range[1]) == 0) {
82
+ return -ENOTSUP;
150
+ return 0;
83
+ }
151
+ }
84
+
152
+ } else if (type == VIRTIO_BLK_T_WRITE_ZEROES) {
85
+ bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
153
+ if (blk_co_pwrite_zeroes(vdev_blk->backend,
86
+ (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
154
+ range[0], range[1], 0) == 0) {
87
+
155
+ return 0;
88
+ bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
156
+ }
89
+ ((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
157
+ }
90
+ bs->file->bs->supported_zero_flags);
158
+
159
+ return -EINVAL;
160
+}
161
+
162
+static void coroutine_fn vu_block_flush(VuBlockReq *req)
163
+{
164
+ VuBlockDev *vdev_blk = get_vu_block_device_by_server(req->server);
165
+ BlockBackend *backend = vdev_blk->backend;
166
+ blk_co_flush(backend);
167
+}
168
+
169
+struct req_data {
170
+ VuServer *server;
171
+ VuVirtq *vq;
172
+ VuVirtqElement *elem;
173
+};
174
+
175
+static void coroutine_fn vu_block_virtio_process_req(void *opaque)
176
+{
177
+ struct req_data *data = opaque;
178
+ VuServer *server = data->server;
179
+ VuVirtq *vq = data->vq;
180
+ VuVirtqElement *elem = data->elem;
181
+ uint32_t type;
182
+ VuBlockReq *req;
183
+
184
+ VuBlockDev *vdev_blk = get_vu_block_device_by_server(server);
185
+ BlockBackend *backend = vdev_blk->backend;
186
+
187
+ struct iovec *in_iov = elem->in_sg;
188
+ struct iovec *out_iov = elem->out_sg;
189
+ unsigned in_num = elem->in_num;
190
+ unsigned out_num = elem->out_num;
191
+ /* refer to hw/block/virtio_blk.c */
192
+ if (elem->out_num < 1 || elem->in_num < 1) {
193
+ error_report("virtio-blk request missing headers");
194
+ free(elem);
195
+ return;
196
+ }
197
+
198
+ req = g_new0(VuBlockReq, 1);
199
+ req->server = server;
200
+ req->vq = vq;
201
+ req->elem = elem;
202
+
203
+ if (unlikely(iov_to_buf(out_iov, out_num, 0, &req->out,
204
+ sizeof(req->out)) != sizeof(req->out))) {
205
+ error_report("virtio-blk request outhdr too short");
206
+ goto err;
207
+ }
208
+
209
+ iov_discard_front(&out_iov, &out_num, sizeof(req->out));
210
+
211
+ if (in_iov[in_num - 1].iov_len < sizeof(struct virtio_blk_inhdr)) {
212
+ error_report("virtio-blk request inhdr too short");
213
+ goto err;
214
+ }
215
+
216
+ /* We always touch the last byte, so just see how big in_iov is. */
217
+ req->in = (void *)in_iov[in_num - 1].iov_base
218
+ + in_iov[in_num - 1].iov_len
219
+ - sizeof(struct virtio_blk_inhdr);
220
+ iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr));
221
+
222
+ type = le32_to_cpu(req->out.type);
223
+ switch (type & ~VIRTIO_BLK_T_BARRIER) {
224
+ case VIRTIO_BLK_T_IN:
225
+ case VIRTIO_BLK_T_OUT: {
226
+ ssize_t ret = 0;
227
+ bool is_write = type & VIRTIO_BLK_T_OUT;
228
+ req->sector_num = le64_to_cpu(req->out.sector);
229
+
230
+ int64_t offset = req->sector_num * vdev_blk->blk_size;
231
+ QEMUIOVector qiov;
232
+ if (is_write) {
233
+ qemu_iovec_init_external(&qiov, out_iov, out_num);
234
+ ret = blk_co_pwritev(backend, offset, qiov.size,
235
+ &qiov, 0);
236
+ } else {
237
+ qemu_iovec_init_external(&qiov, in_iov, in_num);
238
+ ret = blk_co_preadv(backend, offset, qiov.size,
239
+ &qiov, 0);
240
+ }
241
+ if (ret >= 0) {
242
+ req->in->status = VIRTIO_BLK_S_OK;
243
+ } else {
244
+ req->in->status = VIRTIO_BLK_S_IOERR;
245
+ }
246
+ break;
247
+ }
248
+ case VIRTIO_BLK_T_FLUSH:
249
+ vu_block_flush(req);
250
+ req->in->status = VIRTIO_BLK_S_OK;
251
+ break;
252
+ case VIRTIO_BLK_T_GET_ID: {
253
+ size_t size = MIN(iov_size(&elem->in_sg[0], in_num),
254
+ VIRTIO_BLK_ID_BYTES);
255
+ snprintf(elem->in_sg[0].iov_base, size, "%s", "vhost_user_blk");
256
+ req->in->status = VIRTIO_BLK_S_OK;
257
+ req->size = elem->in_sg[0].iov_len;
258
+ break;
259
+ }
260
+ case VIRTIO_BLK_T_DISCARD:
261
+ case VIRTIO_BLK_T_WRITE_ZEROES: {
262
+ int rc;
263
+ rc = vu_block_discard_write_zeroes(req, &elem->out_sg[1],
264
+ out_num, type);
265
+ if (rc == 0) {
266
+ req->in->status = VIRTIO_BLK_S_OK;
267
+ } else {
268
+ req->in->status = VIRTIO_BLK_S_IOERR;
269
+ }
270
+ break;
271
+ }
272
+ default:
273
+ req->in->status = VIRTIO_BLK_S_UNSUPP;
274
+ break;
275
+ }
276
+
277
+ vu_block_req_complete(req);
278
+ return;
279
+
280
+err:
281
+ free(elem);
282
+ g_free(req);
283
+ return;
284
+}
285
+
286
+static void vu_block_process_vq(VuDev *vu_dev, int idx)
287
+{
288
+ VuServer *server;
289
+ VuVirtq *vq;
290
+ struct req_data *req_data;
291
+
292
+ server = container_of(vu_dev, VuServer, vu_dev);
293
+ assert(server);
294
+
295
+ vq = vu_get_queue(vu_dev, idx);
296
+ assert(vq);
297
+ VuVirtqElement *elem;
298
+ while (1) {
299
+ elem = vu_queue_pop(vu_dev, vq, sizeof(VuVirtqElement) +
300
+ sizeof(VuBlockReq));
301
+ if (elem) {
302
+ req_data = g_new0(struct req_data, 1);
303
+ req_data->server = server;
304
+ req_data->vq = vq;
305
+ req_data->elem = elem;
306
+ Coroutine *co = qemu_coroutine_create(vu_block_virtio_process_req,
307
+ req_data);
308
+ aio_co_enter(server->ioc->ctx, co);
309
+ } else {
310
+ break;
311
+ }
312
+ }
313
+}
314
+
315
+static void vu_block_queue_set_started(VuDev *vu_dev, int idx, bool started)
316
+{
317
+ VuVirtq *vq;
318
+
319
+ assert(vu_dev);
320
+
321
+ vq = vu_get_queue(vu_dev, idx);
322
+ vu_set_queue_handler(vu_dev, vq, started ? vu_block_process_vq : NULL);
323
+}
324
+
325
+static uint64_t vu_block_get_features(VuDev *dev)
326
+{
327
+ uint64_t features;
328
+ VuServer *server = container_of(dev, VuServer, vu_dev);
329
+ VuBlockDev *vdev_blk = get_vu_block_device_by_server(server);
330
+ features = 1ull << VIRTIO_BLK_F_SIZE_MAX |
331
+ 1ull << VIRTIO_BLK_F_SEG_MAX |
332
+ 1ull << VIRTIO_BLK_F_TOPOLOGY |
333
+ 1ull << VIRTIO_BLK_F_BLK_SIZE |
334
+ 1ull << VIRTIO_BLK_F_FLUSH |
335
+ 1ull << VIRTIO_BLK_F_DISCARD |
336
+ 1ull << VIRTIO_BLK_F_WRITE_ZEROES |
337
+ 1ull << VIRTIO_BLK_F_CONFIG_WCE |
338
+ 1ull << VIRTIO_F_VERSION_1 |
339
+ 1ull << VIRTIO_RING_F_INDIRECT_DESC |
340
+ 1ull << VIRTIO_RING_F_EVENT_IDX |
341
+ 1ull << VHOST_USER_F_PROTOCOL_FEATURES;
342
+
343
+ if (!vdev_blk->writable) {
344
+ features |= 1ull << VIRTIO_BLK_F_RO;
345
+ }
346
+
347
+ return features;
348
+}
349
+
350
+static uint64_t vu_block_get_protocol_features(VuDev *dev)
351
+{
352
+ return 1ull << VHOST_USER_PROTOCOL_F_CONFIG |
353
+ 1ull << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD;
354
+}
355
+
356
+static int
357
+vu_block_get_config(VuDev *vu_dev, uint8_t *config, uint32_t len)
358
+{
359
+ VuServer *server = container_of(vu_dev, VuServer, vu_dev);
360
+ VuBlockDev *vdev_blk = get_vu_block_device_by_server(server);
361
+ memcpy(config, &vdev_blk->blkcfg, len);
91
+
362
+
92
+ return 0;
363
+ return 0;
93
+}
364
+}
94
+
365
+
95
+
366
+static int
96
+static int64_t compress_getlength(BlockDriverState *bs)
367
+vu_block_set_config(VuDev *vu_dev, const uint8_t *data,
97
+{
368
+ uint32_t offset, uint32_t size, uint32_t flags)
98
+ return bdrv_getlength(bs->file->bs);
369
+{
99
+}
370
+ VuServer *server = container_of(vu_dev, VuServer, vu_dev);
100
+
371
+ VuBlockDev *vdev_blk = get_vu_block_device_by_server(server);
101
+
372
+ uint8_t wce;
102
+static int coroutine_fn compress_co_preadv_part(BlockDriverState *bs,
373
+
103
+ uint64_t offset, uint64_t bytes,
374
+ /* don't support live migration */
104
+ QEMUIOVector *qiov,
375
+ if (flags != VHOST_SET_CONFIG_TYPE_MASTER) {
105
+ size_t qiov_offset,
376
+ return -EINVAL;
106
+ int flags)
377
+ }
107
+{
378
+
108
+ return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset,
379
+ if (offset != offsetof(struct virtio_blk_config, wce) ||
109
+ flags);
380
+ size != 1) {
110
+}
381
+ return -EINVAL;
111
+
382
+ }
112
+
383
+
113
+static int coroutine_fn compress_co_pwritev_part(BlockDriverState *bs,
384
+ wce = *data;
114
+ uint64_t offset,
385
+ vdev_blk->blkcfg.wce = wce;
115
+ uint64_t bytes,
386
+ blk_set_enable_write_cache(vdev_blk->backend, wce);
116
+ QEMUIOVector *qiov,
387
+ return 0;
117
+ size_t qiov_offset, int flags)
388
+}
118
+{
389
+
119
+ return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
390
+/*
120
+ flags | BDRV_REQ_WRITE_COMPRESSED);
391
+ * When the client disconnects, it sends a VHOST_USER_NONE request
121
+}
392
+ * and vu_process_message will simple call exit which cause the VM
122
+
393
+ * to exit abruptly.
123
+
394
+ * To avoid this issue, process VHOST_USER_NONE request ahead
124
+static int coroutine_fn compress_co_pwrite_zeroes(BlockDriverState *bs,
395
+ * of vu_process_message.
125
+ int64_t offset, int bytes,
396
+ *
126
+ BdrvRequestFlags flags)
397
+ */
127
+{
398
+static int vu_block_process_msg(VuDev *dev, VhostUserMsg *vmsg, int *do_reply)
128
+ return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
399
+{
129
+}
400
+ if (vmsg->request == VHOST_USER_NONE) {
130
+
401
+ dev->panic(dev, "disconnect");
131
+
402
+ return true;
132
+static int coroutine_fn compress_co_pdiscard(BlockDriverState *bs,
403
+ }
133
+ int64_t offset, int bytes)
404
+ return false;
134
+{
405
+}
135
+ return bdrv_co_pdiscard(bs->file, offset, bytes);
406
+
136
+}
407
+static const VuDevIface vu_block_iface = {
137
+
408
+ .get_features = vu_block_get_features,
138
+
409
+ .queue_set_started = vu_block_queue_set_started,
139
+static void compress_refresh_limits(BlockDriverState *bs, Error **errp)
410
+ .get_protocol_features = vu_block_get_protocol_features,
140
+{
411
+ .get_config = vu_block_get_config,
141
+ BlockDriverInfo bdi;
412
+ .set_config = vu_block_set_config,
413
+ .process_msg = vu_block_process_msg,
414
+};
415
+
416
+static void blk_aio_attached(AioContext *ctx, void *opaque)
417
+{
418
+ VuBlockDev *vub_dev = opaque;
419
+ aio_context_acquire(ctx);
420
+ vhost_user_server_set_aio_context(&vub_dev->vu_server, ctx);
421
+ aio_context_release(ctx);
422
+}
423
+
424
+static void blk_aio_detach(void *opaque)
425
+{
426
+ VuBlockDev *vub_dev = opaque;
427
+ AioContext *ctx = vub_dev->vu_server.ctx;
428
+ aio_context_acquire(ctx);
429
+ vhost_user_server_set_aio_context(&vub_dev->vu_server, NULL);
430
+ aio_context_release(ctx);
431
+}
432
+
433
+static void
434
+vu_block_initialize_config(BlockDriverState *bs,
435
+ struct virtio_blk_config *config, uint32_t blk_size)
436
+{
437
+ config->capacity = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
438
+ config->blk_size = blk_size;
439
+ config->size_max = 0;
440
+ config->seg_max = 128 - 2;
441
+ config->min_io_size = 1;
442
+ config->opt_io_size = 1;
443
+ config->num_queues = VHOST_USER_BLK_MAX_QUEUES;
444
+ config->max_discard_sectors = 32768;
445
+ config->max_discard_seg = 1;
446
+ config->discard_sector_alignment = config->blk_size >> 9;
447
+ config->max_write_zeroes_sectors = 32768;
448
+ config->max_write_zeroes_seg = 1;
449
+}
450
+
451
+static VuBlockDev *vu_block_init(VuBlockDev *vu_block_device, Error **errp)
452
+{
453
+
454
+ BlockBackend *blk;
455
+ Error *local_error = NULL;
456
+ const char *node_name = vu_block_device->node_name;
457
+ bool writable = vu_block_device->writable;
458
+ uint64_t perm = BLK_PERM_CONSISTENT_READ;
142
+ int ret;
459
+ int ret;
143
+
460
+
144
+ if (!bs->file) {
461
+ AioContext *ctx;
462
+
463
+ BlockDriverState *bs = bdrv_lookup_bs(node_name, node_name, &local_error);
464
+
465
+ if (!bs) {
466
+ error_propagate(errp, local_error);
467
+ return NULL;
468
+ }
469
+
470
+ if (bdrv_is_read_only(bs)) {
471
+ writable = false;
472
+ }
473
+
474
+ if (writable) {
475
+ perm |= BLK_PERM_WRITE;
476
+ }
477
+
478
+ ctx = bdrv_get_aio_context(bs);
479
+ aio_context_acquire(ctx);
480
+ bdrv_invalidate_cache(bs, NULL);
481
+ aio_context_release(ctx);
482
+
483
+ /*
484
+ * Don't allow resize while the vhost user server is running,
485
+ * otherwise we don't care what happens with the node.
486
+ */
487
+ blk = blk_new(bdrv_get_aio_context(bs), perm,
488
+ BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
489
+ BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD);
490
+ ret = blk_insert_bs(blk, bs, errp);
491
+
492
+ if (ret < 0) {
493
+ goto fail;
494
+ }
495
+
496
+ blk_set_enable_write_cache(blk, false);
497
+
498
+ blk_set_allow_aio_context_change(blk, true);
499
+
500
+ vu_block_device->blkcfg.wce = 0;
501
+ vu_block_device->backend = blk;
502
+ if (!vu_block_device->blk_size) {
503
+ vu_block_device->blk_size = BDRV_SECTOR_SIZE;
504
+ }
505
+ vu_block_device->blkcfg.blk_size = vu_block_device->blk_size;
506
+ blk_set_guest_block_size(blk, vu_block_device->blk_size);
507
+ vu_block_initialize_config(bs, &vu_block_device->blkcfg,
508
+ vu_block_device->blk_size);
509
+ return vu_block_device;
510
+
511
+fail:
512
+ blk_unref(blk);
513
+ return NULL;
514
+}
515
+
516
+static void vu_block_deinit(VuBlockDev *vu_block_device)
517
+{
518
+ if (vu_block_device->backend) {
519
+ blk_remove_aio_context_notifier(vu_block_device->backend, blk_aio_attached,
520
+ blk_aio_detach, vu_block_device);
521
+ }
522
+
523
+ blk_unref(vu_block_device->backend);
524
+}
525
+
526
+static void vhost_user_blk_server_stop(VuBlockDev *vu_block_device)
527
+{
528
+ vhost_user_server_stop(&vu_block_device->vu_server);
529
+ vu_block_deinit(vu_block_device);
530
+}
531
+
532
+static void vhost_user_blk_server_start(VuBlockDev *vu_block_device,
533
+ Error **errp)
534
+{
535
+ AioContext *ctx;
536
+ SocketAddress *addr = vu_block_device->addr;
537
+
538
+ if (!vu_block_init(vu_block_device, errp)) {
145
+ return;
539
+ return;
146
+ }
540
+ }
147
+
541
+
148
+ ret = bdrv_get_info(bs->file->bs, &bdi);
542
+ ctx = bdrv_get_aio_context(blk_bs(vu_block_device->backend));
149
+ if (ret < 0 || bdi.cluster_size == 0) {
543
+
544
+ if (!vhost_user_server_start(&vu_block_device->vu_server, addr, ctx,
545
+ VHOST_USER_BLK_MAX_QUEUES,
546
+ NULL, &vu_block_iface,
547
+ errp)) {
548
+ goto error;
549
+ }
550
+
551
+ blk_add_aio_context_notifier(vu_block_device->backend, blk_aio_attached,
552
+ blk_aio_detach, vu_block_device);
553
+ vu_block_device->running = true;
554
+ return;
555
+
556
+ error:
557
+ vu_block_deinit(vu_block_device);
558
+}
559
+
560
+static bool vu_prop_modifiable(VuBlockDev *vus, Error **errp)
561
+{
562
+ if (vus->running) {
563
+ error_setg(errp, "The property can't be modified "
564
+ "while the server is running");
565
+ return false;
566
+ }
567
+ return true;
568
+}
569
+
570
+static void vu_set_node_name(Object *obj, const char *value, Error **errp)
571
+{
572
+ VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
573
+
574
+ if (!vu_prop_modifiable(vus, errp)) {
150
+ return;
575
+ return;
151
+ }
576
+ }
152
+
577
+
153
+ bs->bl.request_alignment = bdi.cluster_size;
578
+ if (vus->node_name) {
154
+}
579
+ g_free(vus->node_name);
155
+
580
+ }
156
+
581
+
157
+static void compress_eject(BlockDriverState *bs, bool eject_flag)
582
+ vus->node_name = g_strdup(value);
158
+{
583
+}
159
+ bdrv_eject(bs->file->bs, eject_flag);
584
+
160
+}
585
+static char *vu_get_node_name(Object *obj, Error **errp)
161
+
586
+{
162
+
587
+ VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
163
+static void compress_lock_medium(BlockDriverState *bs, bool locked)
588
+ return g_strdup(vus->node_name);
164
+{
589
+}
165
+ bdrv_lock_medium(bs->file->bs, locked);
590
+
166
+}
591
+static void free_socket_addr(SocketAddress *addr)
167
+
592
+{
168
+
593
+ g_free(addr->u.q_unix.path);
169
+static bool compress_recurse_is_first_non_filter(BlockDriverState *bs,
594
+ g_free(addr);
170
+ BlockDriverState *candidate)
595
+}
171
+{
596
+
172
+ return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
597
+static void vu_set_unix_socket(Object *obj, const char *value,
173
+}
598
+ Error **errp)
174
+
599
+{
175
+
600
+ VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
176
+static BlockDriver bdrv_compress = {
601
+
177
+ .format_name = "compress",
602
+ if (!vu_prop_modifiable(vus, errp)) {
178
+
603
+ return;
179
+ .bdrv_open = compress_open,
604
+ }
180
+ .bdrv_child_perm = bdrv_filter_default_perms,
605
+
181
+
606
+ if (vus->addr) {
182
+ .bdrv_getlength = compress_getlength,
607
+ free_socket_addr(vus->addr);
183
+
608
+ }
184
+ .bdrv_co_preadv_part = compress_co_preadv_part,
609
+
185
+ .bdrv_co_pwritev_part = compress_co_pwritev_part,
610
+ SocketAddress *addr = g_new0(SocketAddress, 1);
186
+ .bdrv_co_pwrite_zeroes = compress_co_pwrite_zeroes,
611
+ addr->type = SOCKET_ADDRESS_TYPE_UNIX;
187
+ .bdrv_co_pdiscard = compress_co_pdiscard,
612
+ addr->u.q_unix.path = g_strdup(value);
188
+ .bdrv_refresh_limits = compress_refresh_limits,
613
+ vus->addr = addr;
189
+
614
+}
190
+ .bdrv_eject = compress_eject,
615
+
191
+ .bdrv_lock_medium = compress_lock_medium,
616
+static char *vu_get_unix_socket(Object *obj, Error **errp)
192
+
617
+{
193
+ .bdrv_co_block_status = bdrv_co_block_status_from_file,
618
+ VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
194
+
619
+ return g_strdup(vus->addr->u.q_unix.path);
195
+ .bdrv_recurse_is_first_non_filter = compress_recurse_is_first_non_filter,
620
+}
196
+
621
+
197
+ .has_variable_length = true,
622
+static bool vu_get_block_writable(Object *obj, Error **errp)
198
+ .is_filter = true,
623
+{
624
+ VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
625
+ return vus->writable;
626
+}
627
+
628
+static void vu_set_block_writable(Object *obj, bool value, Error **errp)
629
+{
630
+ VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
631
+
632
+ if (!vu_prop_modifiable(vus, errp)) {
633
+ return;
634
+ }
635
+
636
+ vus->writable = value;
637
+}
638
+
639
+static void vu_get_blk_size(Object *obj, Visitor *v, const char *name,
640
+ void *opaque, Error **errp)
641
+{
642
+ VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
643
+ uint32_t value = vus->blk_size;
644
+
645
+ visit_type_uint32(v, name, &value, errp);
646
+}
647
+
648
+static void vu_set_blk_size(Object *obj, Visitor *v, const char *name,
649
+ void *opaque, Error **errp)
650
+{
651
+ VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
652
+
653
+ Error *local_err = NULL;
654
+ uint32_t value;
655
+
656
+ if (!vu_prop_modifiable(vus, errp)) {
657
+ return;
658
+ }
659
+
660
+ visit_type_uint32(v, name, &value, &local_err);
661
+ if (local_err) {
662
+ goto out;
663
+ }
664
+
665
+ check_block_size(object_get_typename(obj), name, value, &local_err);
666
+ if (local_err) {
667
+ goto out;
668
+ }
669
+
670
+ vus->blk_size = value;
671
+
672
+out:
673
+ error_propagate(errp, local_err);
674
+}
675
+
676
+static void vhost_user_blk_server_instance_finalize(Object *obj)
677
+{
678
+ VuBlockDev *vub = VHOST_USER_BLK_SERVER(obj);
679
+
680
+ vhost_user_blk_server_stop(vub);
681
+
682
+ /*
683
+ * Unlike object_property_add_str, object_class_property_add_str
684
+ * doesn't have a release method. Thus manual memory freeing is
685
+ * needed.
686
+ */
687
+ free_socket_addr(vub->addr);
688
+ g_free(vub->node_name);
689
+}
690
+
691
+static void vhost_user_blk_server_complete(UserCreatable *obj, Error **errp)
692
+{
693
+ VuBlockDev *vub = VHOST_USER_BLK_SERVER(obj);
694
+
695
+ vhost_user_blk_server_start(vub, errp);
696
+}
697
+
698
+static void vhost_user_blk_server_class_init(ObjectClass *klass,
699
+ void *class_data)
700
+{
701
+ UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
702
+ ucc->complete = vhost_user_blk_server_complete;
703
+
704
+ object_class_property_add_bool(klass, "writable",
705
+ vu_get_block_writable,
706
+ vu_set_block_writable);
707
+
708
+ object_class_property_add_str(klass, "node-name",
709
+ vu_get_node_name,
710
+ vu_set_node_name);
711
+
712
+ object_class_property_add_str(klass, "unix-socket",
713
+ vu_get_unix_socket,
714
+ vu_set_unix_socket);
715
+
716
+ object_class_property_add(klass, "logical-block-size", "uint32",
717
+ vu_get_blk_size, vu_set_blk_size,
718
+ NULL, NULL);
719
+}
720
+
721
+static const TypeInfo vhost_user_blk_server_info = {
722
+ .name = TYPE_VHOST_USER_BLK_SERVER,
723
+ .parent = TYPE_OBJECT,
724
+ .instance_size = sizeof(VuBlockDev),
725
+ .instance_finalize = vhost_user_blk_server_instance_finalize,
726
+ .class_init = vhost_user_blk_server_class_init,
727
+ .interfaces = (InterfaceInfo[]) {
728
+ {TYPE_USER_CREATABLE},
729
+ {}
730
+ },
199
+};
731
+};
200
+
732
+
201
+static void bdrv_compress_init(void)
733
+static void vhost_user_blk_server_register_types(void)
202
+{
734
+{
203
+ bdrv_register(&bdrv_compress);
735
+ type_register_static(&vhost_user_blk_server_info);
204
+}
736
+}
205
+
737
+
206
+block_init(bdrv_compress_init);
738
+type_init(vhost_user_blk_server_register_types)
207
diff --git a/qapi/block-core.json b/qapi/block-core.json
739
diff --git a/softmmu/vl.c b/softmmu/vl.c
208
index XXXXXXX..XXXXXXX 100644
740
index XXXXXXX..XXXXXXX 100644
209
--- a/qapi/block-core.json
741
--- a/softmmu/vl.c
210
+++ b/qapi/block-core.json
742
+++ b/softmmu/vl.c
211
@@ -XXX,XX +XXX,XX @@
743
@@ -XXX,XX +XXX,XX @@ static bool object_create_initial(const char *type, QemuOpts *opts)
212
# @copy-on-read: Since 3.0
744
}
213
# @blklogwrites: Since 3.0
745
#endif
214
# @blkreplay: Since 4.2
746
215
+# @compress: Since 5.0
747
+ /* Reason: vhost-user-blk-server property "node-name" */
216
#
748
+ if (g_str_equal(type, "vhost-user-blk-server")) {
217
# Since: 2.9
749
+ return false;
218
##
750
+ }
219
{ 'enum': 'BlockdevDriver',
751
/*
220
'data': [ 'blkdebug', 'blklogwrites', 'blkreplay', 'blkverify', 'bochs',
752
* Reason: filter-* property "netdev" etc.
221
- 'cloop', 'copy-on-read', 'dmg', 'file', 'ftp', 'ftps', 'gluster',
753
*/
222
- 'host_cdrom', 'host_device', 'http', 'https', 'iscsi', 'luks',
754
diff --git a/block/meson.build b/block/meson.build
223
- 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels', 'qcow',
755
index XXXXXXX..XXXXXXX 100644
224
- 'qcow2', 'qed', 'quorum', 'raw', 'rbd',
756
--- a/block/meson.build
225
+ 'cloop', 'compress', 'copy-on-read', 'dmg', 'file', 'ftp', 'ftps',
757
+++ b/block/meson.build
226
+ 'gluster', 'host_cdrom', 'host_device', 'http', 'https', 'iscsi',
758
@@ -XXX,XX +XXX,XX @@ block_ss.add(when: 'CONFIG_WIN32', if_true: files('file-win32.c', 'win32-aio.c')
227
+ 'luks', 'nbd', 'nfs', 'null-aio', 'null-co', 'nvme', 'parallels',
759
block_ss.add(when: 'CONFIG_POSIX', if_true: [files('file-posix.c'), coref, iokit])
228
+ 'qcow', 'qcow2', 'qed', 'quorum', 'raw', 'rbd',
760
block_ss.add(when: 'CONFIG_LIBISCSI', if_true: files('iscsi-opts.c'))
229
{ 'name': 'replication', 'if': 'defined(CONFIG_REPLICATION)' },
761
block_ss.add(when: 'CONFIG_LINUX', if_true: files('nvme.c'))
230
'sheepdog',
762
+block_ss.add(when: 'CONFIG_LINUX', if_true: files('export/vhost-user-blk-server.c', '../contrib/libvhost-user/libvhost-user.c'))
231
'ssh', 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
763
block_ss.add(when: 'CONFIG_REPLICATION', if_true: files('replication.c'))
232
@@ -XXX,XX +XXX,XX @@
764
block_ss.add(when: 'CONFIG_SHEEPDOG', if_true: files('sheepdog.c'))
233
'blkreplay': 'BlockdevOptionsBlkreplay',
765
block_ss.add(when: ['CONFIG_LINUX_AIO', libaio], if_true: files('linux-aio.c'))
234
'bochs': 'BlockdevOptionsGenericFormat',
235
'cloop': 'BlockdevOptionsGenericFormat',
236
+ 'compress': 'BlockdevOptionsGenericFormat',
237
'copy-on-read':'BlockdevOptionsGenericFormat',
238
'dmg': 'BlockdevOptionsGenericFormat',
239
'file': 'BlockdevOptionsFile',
240
--
766
--
241
2.24.1
767
2.26.2
242
768
243
diff view generated by jsdifflib
1
Signed-off-by: Max Reitz <mreitz@redhat.com>
1
From: Coiby Xu <coiby.xu@gmail.com>
2
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
2
3
Message-id: 20191107163708.833192-5-mreitz@redhat.com
3
This test case has the same tests as tests/virtio-blk-test.c except for
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
tests have block_resize. Since vhost-user server can only server one
5
client one time, two instances of vhost-user-blk-server are started by
6
qemu-storage-daemon for the hotplug test.
7
8
In order to not block scripts/tap-driver.pl, vhost-user-blk-server will
9
send "quit" command to qemu-storage-daemon's QMP monitor. So a function
10
is added to libqtest.c to establish socket connection with socket
11
server.
12
13
Suggested-by: Thomas Huth <thuth@redhat.com>
14
Signed-off-by: Coiby Xu <coiby.xu@gmail.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
16
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
17
Message-id: 20200918080912.321299-7-coiby.xu@gmail.com
18
[Update meson.build to only test when CONFIG_TOOLS has built
19
qemu-storage-daemon. This prevents CI failures with --disable-tools.
20
--Stefan]
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
---
22
---
6
tests/qemu-iotests/common.filter | 24 ++++++++++++++++++++++++
23
tests/qtest/libqos/libqtest.h | 17 +
7
1 file changed, 24 insertions(+)
24
tests/qtest/libqos/vhost-user-blk.h | 48 ++
25
tests/qtest/libqos/vhost-user-blk.c | 129 +++++
26
tests/qtest/libqtest.c | 36 +-
27
tests/qtest/vhost-user-blk-test.c | 751 ++++++++++++++++++++++++++++
28
tests/qtest/libqos/meson.build | 1 +
29
tests/qtest/meson.build | 4 +-
30
7 files changed, 983 insertions(+), 3 deletions(-)
31
create mode 100644 tests/qtest/libqos/vhost-user-blk.h
32
create mode 100644 tests/qtest/libqos/vhost-user-blk.c
33
create mode 100644 tests/qtest/vhost-user-blk-test.c
8
34
9
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
35
diff --git a/tests/qtest/libqos/libqtest.h b/tests/qtest/libqos/libqtest.h
10
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
11
--- a/tests/qemu-iotests/common.filter
37
--- a/tests/qtest/libqos/libqtest.h
12
+++ b/tests/qemu-iotests/common.filter
38
+++ b/tests/qtest/libqos/libqtest.h
13
@@ -XXX,XX +XXX,XX @@ _filter_qmp_empty_return()
39
@@ -XXX,XX +XXX,XX @@ void qtest_qmp_send(QTestState *s, const char *fmt, ...)
14
grep -v '{"return": {}}'
40
void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...)
41
GCC_FMT_ATTR(2, 3);
42
43
+/**
44
+ * qtest_socket_client:
45
+ * @server_socket_path: the socket server's path
46
+ *
47
+ * Connect to a socket server.
48
+ */
49
+int qtest_socket_client(char *server_socket_path);
50
+
51
+/**
52
+ * qtest_create_state_with_qmp_fd:
53
+ * @fd: socket fd
54
+ *
55
+ * Wrap socket fd in QTestState to make use of qtest_qmp*
56
+ * functions
57
+ */
58
+QTestState *qtest_create_state_with_qmp_fd(int fd);
59
+
60
/**
61
* qtest_vqmp_fds:
62
* @s: #QTestState instance to operate on.
63
diff --git a/tests/qtest/libqos/vhost-user-blk.h b/tests/qtest/libqos/vhost-user-blk.h
64
new file mode 100644
65
index XXXXXXX..XXXXXXX
66
--- /dev/null
67
+++ b/tests/qtest/libqos/vhost-user-blk.h
68
@@ -XXX,XX +XXX,XX @@
69
+/*
70
+ * libqos driver framework
71
+ *
72
+ * Based on tests/qtest/libqos/virtio-blk.c
73
+ *
74
+ * Copyright (c) 2020 Coiby Xu <coiby.xu@gmail.com>
75
+ *
76
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
77
+ *
78
+ * This library is free software; you can redistribute it and/or
79
+ * modify it under the terms of the GNU Lesser General Public
80
+ * License version 2 as published by the Free Software Foundation.
81
+ *
82
+ * This library is distributed in the hope that it will be useful,
83
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
84
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
85
+ * Lesser General Public License for more details.
86
+ *
87
+ * You should have received a copy of the GNU Lesser General Public
88
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
89
+ */
90
+
91
+#ifndef TESTS_LIBQOS_VHOST_USER_BLK_H
92
+#define TESTS_LIBQOS_VHOST_USER_BLK_H
93
+
94
+#include "qgraph.h"
95
+#include "virtio.h"
96
+#include "virtio-pci.h"
97
+
98
+typedef struct QVhostUserBlk QVhostUserBlk;
99
+typedef struct QVhostUserBlkPCI QVhostUserBlkPCI;
100
+typedef struct QVhostUserBlkDevice QVhostUserBlkDevice;
101
+
102
+struct QVhostUserBlk {
103
+ QVirtioDevice *vdev;
104
+};
105
+
106
+struct QVhostUserBlkPCI {
107
+ QVirtioPCIDevice pci_vdev;
108
+ QVhostUserBlk blk;
109
+};
110
+
111
+struct QVhostUserBlkDevice {
112
+ QOSGraphObject obj;
113
+ QVhostUserBlk blk;
114
+};
115
+
116
+#endif
117
diff --git a/tests/qtest/libqos/vhost-user-blk.c b/tests/qtest/libqos/vhost-user-blk.c
118
new file mode 100644
119
index XXXXXXX..XXXXXXX
120
--- /dev/null
121
+++ b/tests/qtest/libqos/vhost-user-blk.c
122
@@ -XXX,XX +XXX,XX @@
123
+/*
124
+ * libqos driver framework
125
+ *
126
+ * Based on tests/qtest/libqos/virtio-blk.c
127
+ *
128
+ * Copyright (c) 2020 Coiby Xu <coiby.xu@gmail.com>
129
+ *
130
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito <e.emanuelegiuseppe@gmail.com>
131
+ *
132
+ * This library is free software; you can redistribute it and/or
133
+ * modify it under the terms of the GNU Lesser General Public
134
+ * License version 2.1 as published by the Free Software Foundation.
135
+ *
136
+ * This library is distributed in the hope that it will be useful,
137
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
138
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
139
+ * Lesser General Public License for more details.
140
+ *
141
+ * You should have received a copy of the GNU Lesser General Public
142
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
143
+ */
144
+
145
+#include "qemu/osdep.h"
146
+#include "libqtest.h"
147
+#include "qemu/module.h"
148
+#include "standard-headers/linux/virtio_blk.h"
149
+#include "vhost-user-blk.h"
150
+
151
+#define PCI_SLOT 0x04
152
+#define PCI_FN 0x00
153
+
154
+/* virtio-blk-device */
155
+static void *qvhost_user_blk_get_driver(QVhostUserBlk *v_blk,
156
+ const char *interface)
157
+{
158
+ if (!g_strcmp0(interface, "vhost-user-blk")) {
159
+ return v_blk;
160
+ }
161
+ if (!g_strcmp0(interface, "virtio")) {
162
+ return v_blk->vdev;
163
+ }
164
+
165
+ fprintf(stderr, "%s not present in vhost-user-blk-device\n", interface);
166
+ g_assert_not_reached();
167
+}
168
+
169
+static void *qvhost_user_blk_device_get_driver(void *object,
170
+ const char *interface)
171
+{
172
+ QVhostUserBlkDevice *v_blk = object;
173
+ return qvhost_user_blk_get_driver(&v_blk->blk, interface);
174
+}
175
+
176
+static void *vhost_user_blk_device_create(void *virtio_dev,
177
+ QGuestAllocator *t_alloc,
178
+ void *addr)
179
+{
180
+ QVhostUserBlkDevice *vhost_user_blk = g_new0(QVhostUserBlkDevice, 1);
181
+ QVhostUserBlk *interface = &vhost_user_blk->blk;
182
+
183
+ interface->vdev = virtio_dev;
184
+
185
+ vhost_user_blk->obj.get_driver = qvhost_user_blk_device_get_driver;
186
+
187
+ return &vhost_user_blk->obj;
188
+}
189
+
190
+/* virtio-blk-pci */
191
+static void *qvhost_user_blk_pci_get_driver(void *object, const char *interface)
192
+{
193
+ QVhostUserBlkPCI *v_blk = object;
194
+ if (!g_strcmp0(interface, "pci-device")) {
195
+ return v_blk->pci_vdev.pdev;
196
+ }
197
+ return qvhost_user_blk_get_driver(&v_blk->blk, interface);
198
+}
199
+
200
+static void *vhost_user_blk_pci_create(void *pci_bus, QGuestAllocator *t_alloc,
201
+ void *addr)
202
+{
203
+ QVhostUserBlkPCI *vhost_user_blk = g_new0(QVhostUserBlkPCI, 1);
204
+ QVhostUserBlk *interface = &vhost_user_blk->blk;
205
+ QOSGraphObject *obj = &vhost_user_blk->pci_vdev.obj;
206
+
207
+ virtio_pci_init(&vhost_user_blk->pci_vdev, pci_bus, addr);
208
+ interface->vdev = &vhost_user_blk->pci_vdev.vdev;
209
+
210
+ g_assert_cmphex(interface->vdev->device_type, ==, VIRTIO_ID_BLOCK);
211
+
212
+ obj->get_driver = qvhost_user_blk_pci_get_driver;
213
+
214
+ return obj;
215
+}
216
+
217
+static void vhost_user_blk_register_nodes(void)
218
+{
219
+ /*
220
+ * FIXME: every test using these two nodes needs to setup a
221
+ * -drive,id=drive0 otherwise QEMU is not going to start.
222
+ * Therefore, we do not include "produces" edge for virtio
223
+ * and pci-device yet.
224
+ */
225
+
226
+ char *arg = g_strdup_printf("id=drv0,chardev=char1,addr=%x.%x",
227
+ PCI_SLOT, PCI_FN);
228
+
229
+ QPCIAddress addr = {
230
+ .devfn = QPCI_DEVFN(PCI_SLOT, PCI_FN),
231
+ };
232
+
233
+ QOSGraphEdgeOptions opts = { };
234
+
235
+ /* virtio-blk-device */
236
+ /** opts.extra_device_opts = "drive=drive0"; */
237
+ qos_node_create_driver("vhost-user-blk-device", vhost_user_blk_device_create);
238
+ qos_node_consumes("vhost-user-blk-device", "virtio-bus", &opts);
239
+ qos_node_produces("vhost-user-blk-device", "vhost-user-blk");
240
+
241
+ /* virtio-blk-pci */
242
+ opts.extra_device_opts = arg;
243
+ add_qpci_address(&opts, &addr);
244
+ qos_node_create_driver("vhost-user-blk-pci", vhost_user_blk_pci_create);
245
+ qos_node_consumes("vhost-user-blk-pci", "pci-bus", &opts);
246
+ qos_node_produces("vhost-user-blk-pci", "vhost-user-blk");
247
+
248
+ g_free(arg);
249
+}
250
+
251
+libqos_init(vhost_user_blk_register_nodes);
252
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
253
index XXXXXXX..XXXXXXX 100644
254
--- a/tests/qtest/libqtest.c
255
+++ b/tests/qtest/libqtest.c
256
@@ -XXX,XX +XXX,XX @@
257
* Copyright IBM, Corp. 2012
258
* Copyright Red Hat, Inc. 2012
259
* Copyright SUSE LINUX Products GmbH 2013
260
+ * Copyright Copyright (c) Coiby Xu
261
*
262
* Authors:
263
* Anthony Liguori <aliguori@us.ibm.com>
264
* Paolo Bonzini <pbonzini@redhat.com>
265
* Andreas Färber <afaerber@suse.de>
266
+ * Coiby Xu <coiby.xu@gmail.com>
267
*
268
* This work is licensed under the terms of the GNU GPL, version 2 or later.
269
* See the COPYING file in the top-level directory.
270
@@ -XXX,XX +XXX,XX @@ typedef struct QTestClientTransportOps {
271
QTestRecvFn recv_line; /* for receiving qtest command responses */
272
} QTestTransportOps;
273
274
-struct QTestState
275
-{
276
+struct QTestState {
277
int fd;
278
int qmp_fd;
279
pid_t qemu_pid; /* our child QEMU process */
280
@@ -XXX,XX +XXX,XX @@ QDict *qtest_qmp_receive(QTestState *s)
281
return qmp_fd_receive(s->qmp_fd);
15
}
282
}
16
283
17
+_filter_json_filename()
284
+QTestState *qtest_create_state_with_qmp_fd(int fd)
18
+{
285
+{
19
+ $PYTHON -c 'import sys
286
+ QTestState *qmp_test_state = g_new0(QTestState, 1);
20
+result, *fnames = sys.stdin.read().split("json:{")
287
+ qmp_test_state->qmp_fd = fd;
21
+depth = 0
288
+ return qmp_test_state;
22
+for fname in fnames:
289
+}
23
+ depth += 1 # For the opening brace in the split separator
290
+
24
+ for chr_i, chr in enumerate(fname):
291
+int qtest_socket_client(char *server_socket_path)
25
+ if chr == "{":
292
+{
26
+ depth += 1
293
+ struct sockaddr_un serv_addr;
27
+ elif chr == "}":
294
+ int sock;
28
+ depth -= 1
295
+ int ret;
29
+ if depth == 0:
296
+ int retries = 0;
30
+ break
297
+ sock = socket(PF_UNIX, SOCK_STREAM, 0);
31
+
298
+ g_assert_cmpint(sock, !=, -1);
32
+ # json:{} filenames may be nested; filter out everything from
299
+ serv_addr.sun_family = AF_UNIX;
33
+ # inside the outermost one
300
+ snprintf(serv_addr.sun_path, sizeof(serv_addr.sun_path), "%s",
34
+ if depth == 0:
301
+ server_socket_path);
35
+ chr_i += 1 # First character past the filename
302
+
36
+ result += "json:{ /* filtered */ }" + fname[chr_i:]
303
+ for (retries = 0; retries < 3; retries++) {
37
+
304
+ ret = connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
38
+sys.stdout.write(result)'
305
+ if (ret == 0) {
39
+}
306
+ break;
40
+
307
+ }
41
# make sure this script returns success
308
+ g_usleep(G_USEC_PER_SEC);
42
true
309
+ }
310
+
311
+ g_assert_cmpint(ret, ==, 0);
312
+ return sock;
313
+}
314
+
315
/**
316
* Allow users to send a message without waiting for the reply,
317
* in the case that they choose to discard all replies up until
318
diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk-test.c
319
new file mode 100644
320
index XXXXXXX..XXXXXXX
321
--- /dev/null
322
+++ b/tests/qtest/vhost-user-blk-test.c
323
@@ -XXX,XX +XXX,XX @@
324
+/*
325
+ * QTest testcase for Vhost-user Block Device
326
+ *
327
+ * Based on tests/qtest//virtio-blk-test.c
328
+
329
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
330
+ * Copyright (c) 2014 Marc Marí
331
+ * Copyright (c) 2020 Coiby Xu
332
+ *
333
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
334
+ * See the COPYING file in the top-level directory.
335
+ */
336
+
337
+#include "qemu/osdep.h"
338
+#include "libqtest-single.h"
339
+#include "qemu/bswap.h"
340
+#include "qemu/module.h"
341
+#include "standard-headers/linux/virtio_blk.h"
342
+#include "standard-headers/linux/virtio_pci.h"
343
+#include "libqos/qgraph.h"
344
+#include "libqos/vhost-user-blk.h"
345
+#include "libqos/libqos-pc.h"
346
+
347
+#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
348
+#define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
349
+#define PCI_SLOT_HP 0x06
350
+
351
+typedef struct QVirtioBlkReq {
352
+ uint32_t type;
353
+ uint32_t ioprio;
354
+ uint64_t sector;
355
+ char *data;
356
+ uint8_t status;
357
+} QVirtioBlkReq;
358
+
359
+#ifdef HOST_WORDS_BIGENDIAN
360
+static const bool host_is_big_endian = true;
361
+#else
362
+static const bool host_is_big_endian; /* false */
363
+#endif
364
+
365
+static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
366
+{
367
+ if (qvirtio_is_big_endian(d) != host_is_big_endian) {
368
+ req->type = bswap32(req->type);
369
+ req->ioprio = bswap32(req->ioprio);
370
+ req->sector = bswap64(req->sector);
371
+ }
372
+}
373
+
374
+static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
375
+ struct virtio_blk_discard_write_zeroes *dwz_hdr)
376
+{
377
+ if (qvirtio_is_big_endian(d) != host_is_big_endian) {
378
+ dwz_hdr->sector = bswap64(dwz_hdr->sector);
379
+ dwz_hdr->num_sectors = bswap32(dwz_hdr->num_sectors);
380
+ dwz_hdr->flags = bswap32(dwz_hdr->flags);
381
+ }
382
+}
383
+
384
+static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
385
+ QVirtioBlkReq *req, uint64_t data_size)
386
+{
387
+ uint64_t addr;
388
+ uint8_t status = 0xFF;
389
+ QTestState *qts = global_qtest;
390
+
391
+ switch (req->type) {
392
+ case VIRTIO_BLK_T_IN:
393
+ case VIRTIO_BLK_T_OUT:
394
+ g_assert_cmpuint(data_size % 512, ==, 0);
395
+ break;
396
+ case VIRTIO_BLK_T_DISCARD:
397
+ case VIRTIO_BLK_T_WRITE_ZEROES:
398
+ g_assert_cmpuint(data_size %
399
+ sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
400
+ break;
401
+ default:
402
+ g_assert_cmpuint(data_size, ==, 0);
403
+ }
404
+
405
+ addr = guest_alloc(alloc, sizeof(*req) + data_size);
406
+
407
+ virtio_blk_fix_request(d, req);
408
+
409
+ qtest_memwrite(qts, addr, req, 16);
410
+ qtest_memwrite(qts, addr + 16, req->data, data_size);
411
+ qtest_memwrite(qts, addr + 16 + data_size, &status, sizeof(status));
412
+
413
+ return addr;
414
+}
415
+
416
+/* Returns the request virtqueue so the caller can perform further tests */
417
+static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
418
+{
419
+ QVirtioBlkReq req;
420
+ uint64_t req_addr;
421
+ uint64_t capacity;
422
+ uint64_t features;
423
+ uint32_t free_head;
424
+ uint8_t status;
425
+ char *data;
426
+ QTestState *qts = global_qtest;
427
+ QVirtQueue *vq;
428
+
429
+ features = qvirtio_get_features(dev);
430
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
431
+ (1u << VIRTIO_RING_F_INDIRECT_DESC) |
432
+ (1u << VIRTIO_RING_F_EVENT_IDX) |
433
+ (1u << VIRTIO_BLK_F_SCSI));
434
+ qvirtio_set_features(dev, features);
435
+
436
+ capacity = qvirtio_config_readq(dev, 0);
437
+ g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
438
+
439
+ vq = qvirtqueue_setup(dev, alloc, 0);
440
+
441
+ qvirtio_set_driver_ok(dev);
442
+
443
+ /* Write and read with 3 descriptor layout */
444
+ /* Write request */
445
+ req.type = VIRTIO_BLK_T_OUT;
446
+ req.ioprio = 1;
447
+ req.sector = 0;
448
+ req.data = g_malloc0(512);
449
+ strcpy(req.data, "TEST");
450
+
451
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
452
+
453
+ g_free(req.data);
454
+
455
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
456
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
457
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
458
+
459
+ qvirtqueue_kick(qts, dev, vq, free_head);
460
+
461
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
462
+ QVIRTIO_BLK_TIMEOUT_US);
463
+ status = readb(req_addr + 528);
464
+ g_assert_cmpint(status, ==, 0);
465
+
466
+ guest_free(alloc, req_addr);
467
+
468
+ /* Read request */
469
+ req.type = VIRTIO_BLK_T_IN;
470
+ req.ioprio = 1;
471
+ req.sector = 0;
472
+ req.data = g_malloc0(512);
473
+
474
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
475
+
476
+ g_free(req.data);
477
+
478
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
479
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
480
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
481
+
482
+ qvirtqueue_kick(qts, dev, vq, free_head);
483
+
484
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
485
+ QVIRTIO_BLK_TIMEOUT_US);
486
+ status = readb(req_addr + 528);
487
+ g_assert_cmpint(status, ==, 0);
488
+
489
+ data = g_malloc0(512);
490
+ qtest_memread(qts, req_addr + 16, data, 512);
491
+ g_assert_cmpstr(data, ==, "TEST");
492
+ g_free(data);
493
+
494
+ guest_free(alloc, req_addr);
495
+
496
+ if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
497
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
498
+ void *expected;
499
+
500
+ /*
501
+ * WRITE_ZEROES request on the same sector of previous test where
502
+ * we wrote "TEST".
503
+ */
504
+ req.type = VIRTIO_BLK_T_WRITE_ZEROES;
505
+ req.data = (char *) &dwz_hdr;
506
+ dwz_hdr.sector = 0;
507
+ dwz_hdr.num_sectors = 1;
508
+ dwz_hdr.flags = 0;
509
+
510
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
511
+
512
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
513
+
514
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
515
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
516
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
517
+ false);
518
+
519
+ qvirtqueue_kick(qts, dev, vq, free_head);
520
+
521
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
522
+ QVIRTIO_BLK_TIMEOUT_US);
523
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
524
+ g_assert_cmpint(status, ==, 0);
525
+
526
+ guest_free(alloc, req_addr);
527
+
528
+ /* Read request to check if the sector contains all zeroes */
529
+ req.type = VIRTIO_BLK_T_IN;
530
+ req.ioprio = 1;
531
+ req.sector = 0;
532
+ req.data = g_malloc0(512);
533
+
534
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
535
+
536
+ g_free(req.data);
537
+
538
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
539
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
540
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
541
+
542
+ qvirtqueue_kick(qts, dev, vq, free_head);
543
+
544
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
545
+ QVIRTIO_BLK_TIMEOUT_US);
546
+ status = readb(req_addr + 528);
547
+ g_assert_cmpint(status, ==, 0);
548
+
549
+ data = g_malloc(512);
550
+ expected = g_malloc0(512);
551
+ qtest_memread(qts, req_addr + 16, data, 512);
552
+ g_assert_cmpmem(data, 512, expected, 512);
553
+ g_free(expected);
554
+ g_free(data);
555
+
556
+ guest_free(alloc, req_addr);
557
+ }
558
+
559
+ if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
560
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
561
+
562
+ req.type = VIRTIO_BLK_T_DISCARD;
563
+ req.data = (char *) &dwz_hdr;
564
+ dwz_hdr.sector = 0;
565
+ dwz_hdr.num_sectors = 1;
566
+ dwz_hdr.flags = 0;
567
+
568
+ virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
569
+
570
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
571
+
572
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
573
+ qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
574
+ qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr),
575
+ 1, true, false);
576
+
577
+ qvirtqueue_kick(qts, dev, vq, free_head);
578
+
579
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
580
+ QVIRTIO_BLK_TIMEOUT_US);
581
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
582
+ g_assert_cmpint(status, ==, 0);
583
+
584
+ guest_free(alloc, req_addr);
585
+ }
586
+
587
+ if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
588
+ /* Write and read with 2 descriptor layout */
589
+ /* Write request */
590
+ req.type = VIRTIO_BLK_T_OUT;
591
+ req.ioprio = 1;
592
+ req.sector = 1;
593
+ req.data = g_malloc0(512);
594
+ strcpy(req.data, "TEST");
595
+
596
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
597
+
598
+ g_free(req.data);
599
+
600
+ free_head = qvirtqueue_add(qts, vq, req_addr, 528, false, true);
601
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
602
+ qvirtqueue_kick(qts, dev, vq, free_head);
603
+
604
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
605
+ QVIRTIO_BLK_TIMEOUT_US);
606
+ status = readb(req_addr + 528);
607
+ g_assert_cmpint(status, ==, 0);
608
+
609
+ guest_free(alloc, req_addr);
610
+
611
+ /* Read request */
612
+ req.type = VIRTIO_BLK_T_IN;
613
+ req.ioprio = 1;
614
+ req.sector = 1;
615
+ req.data = g_malloc0(512);
616
+
617
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
618
+
619
+ g_free(req.data);
620
+
621
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
622
+ qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
623
+
624
+ qvirtqueue_kick(qts, dev, vq, free_head);
625
+
626
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
627
+ QVIRTIO_BLK_TIMEOUT_US);
628
+ status = readb(req_addr + 528);
629
+ g_assert_cmpint(status, ==, 0);
630
+
631
+ data = g_malloc0(512);
632
+ qtest_memread(qts, req_addr + 16, data, 512);
633
+ g_assert_cmpstr(data, ==, "TEST");
634
+ g_free(data);
635
+
636
+ guest_free(alloc, req_addr);
637
+ }
638
+
639
+ return vq;
640
+}
641
+
642
+static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
643
+{
644
+ QVhostUserBlk *blk_if = obj;
645
+ QVirtQueue *vq;
646
+
647
+ vq = test_basic(blk_if->vdev, t_alloc);
648
+ qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
649
+
650
+}
651
+
652
+static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
653
+{
654
+ QVirtQueue *vq;
655
+ QVhostUserBlk *blk_if = obj;
656
+ QVirtioDevice *dev = blk_if->vdev;
657
+ QVirtioBlkReq req;
658
+ QVRingIndirectDesc *indirect;
659
+ uint64_t req_addr;
660
+ uint64_t capacity;
661
+ uint64_t features;
662
+ uint32_t free_head;
663
+ uint8_t status;
664
+ char *data;
665
+ QTestState *qts = global_qtest;
666
+
667
+ features = qvirtio_get_features(dev);
668
+ g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
669
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
670
+ (1u << VIRTIO_RING_F_EVENT_IDX) |
671
+ (1u << VIRTIO_BLK_F_SCSI));
672
+ qvirtio_set_features(dev, features);
673
+
674
+ capacity = qvirtio_config_readq(dev, 0);
675
+ g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
676
+
677
+ vq = qvirtqueue_setup(dev, t_alloc, 0);
678
+ qvirtio_set_driver_ok(dev);
679
+
680
+ /* Write request */
681
+ req.type = VIRTIO_BLK_T_OUT;
682
+ req.ioprio = 1;
683
+ req.sector = 0;
684
+ req.data = g_malloc0(512);
685
+ strcpy(req.data, "TEST");
686
+
687
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
688
+
689
+ g_free(req.data);
690
+
691
+ indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
692
+ qvring_indirect_desc_add(dev, qts, indirect, req_addr, 528, false);
693
+ qvring_indirect_desc_add(dev, qts, indirect, req_addr + 528, 1, true);
694
+ free_head = qvirtqueue_add_indirect(qts, vq, indirect);
695
+ qvirtqueue_kick(qts, dev, vq, free_head);
696
+
697
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
698
+ QVIRTIO_BLK_TIMEOUT_US);
699
+ status = readb(req_addr + 528);
700
+ g_assert_cmpint(status, ==, 0);
701
+
702
+ g_free(indirect);
703
+ guest_free(t_alloc, req_addr);
704
+
705
+ /* Read request */
706
+ req.type = VIRTIO_BLK_T_IN;
707
+ req.ioprio = 1;
708
+ req.sector = 0;
709
+ req.data = g_malloc0(512);
710
+ strcpy(req.data, "TEST");
711
+
712
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
713
+
714
+ g_free(req.data);
715
+
716
+ indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
717
+ qvring_indirect_desc_add(dev, qts, indirect, req_addr, 16, false);
718
+ qvring_indirect_desc_add(dev, qts, indirect, req_addr + 16, 513, true);
719
+ free_head = qvirtqueue_add_indirect(qts, vq, indirect);
720
+ qvirtqueue_kick(qts, dev, vq, free_head);
721
+
722
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
723
+ QVIRTIO_BLK_TIMEOUT_US);
724
+ status = readb(req_addr + 528);
725
+ g_assert_cmpint(status, ==, 0);
726
+
727
+ data = g_malloc0(512);
728
+ qtest_memread(qts, req_addr + 16, data, 512);
729
+ g_assert_cmpstr(data, ==, "TEST");
730
+ g_free(data);
731
+
732
+ g_free(indirect);
733
+ guest_free(t_alloc, req_addr);
734
+ qvirtqueue_cleanup(dev->bus, vq, t_alloc);
735
+}
736
+
737
+static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
738
+{
739
+ QVirtQueue *vq;
740
+ QVhostUserBlkPCI *blk = obj;
741
+ QVirtioPCIDevice *pdev = &blk->pci_vdev;
742
+ QVirtioDevice *dev = &pdev->vdev;
743
+ QVirtioBlkReq req;
744
+ uint64_t req_addr;
745
+ uint64_t capacity;
746
+ uint64_t features;
747
+ uint32_t free_head;
748
+ uint32_t write_head;
749
+ uint32_t desc_idx;
750
+ uint8_t status;
751
+ char *data;
752
+ QOSGraphObject *blk_object = obj;
753
+ QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
754
+ QTestState *qts = global_qtest;
755
+
756
+ if (qpci_check_buggy_msi(pci_dev)) {
757
+ return;
758
+ }
759
+
760
+ qpci_msix_enable(pdev->pdev);
761
+ qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
762
+
763
+ features = qvirtio_get_features(dev);
764
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
765
+ (1u << VIRTIO_RING_F_INDIRECT_DESC) |
766
+ (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
767
+ (1u << VIRTIO_BLK_F_SCSI));
768
+ qvirtio_set_features(dev, features);
769
+
770
+ capacity = qvirtio_config_readq(dev, 0);
771
+ g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
772
+
773
+ vq = qvirtqueue_setup(dev, t_alloc, 0);
774
+ qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
775
+
776
+ qvirtio_set_driver_ok(dev);
777
+
778
+ /* Write request */
779
+ req.type = VIRTIO_BLK_T_OUT;
780
+ req.ioprio = 1;
781
+ req.sector = 0;
782
+ req.data = g_malloc0(512);
783
+ strcpy(req.data, "TEST");
784
+
785
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
786
+
787
+ g_free(req.data);
788
+
789
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
790
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
791
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
792
+ qvirtqueue_kick(qts, dev, vq, free_head);
793
+
794
+ qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
795
+ QVIRTIO_BLK_TIMEOUT_US);
796
+
797
+ /* Write request */
798
+ req.type = VIRTIO_BLK_T_OUT;
799
+ req.ioprio = 1;
800
+ req.sector = 1;
801
+ req.data = g_malloc0(512);
802
+ strcpy(req.data, "TEST");
803
+
804
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
805
+
806
+ g_free(req.data);
807
+
808
+ /* Notify after processing the third request */
809
+ qvirtqueue_set_used_event(qts, vq, 2);
810
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
811
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
812
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
813
+ qvirtqueue_kick(qts, dev, vq, free_head);
814
+ write_head = free_head;
815
+
816
+ /* No notification expected */
817
+ status = qvirtio_wait_status_byte_no_isr(qts, dev,
818
+ vq, req_addr + 528,
819
+ QVIRTIO_BLK_TIMEOUT_US);
820
+ g_assert_cmpint(status, ==, 0);
821
+
822
+ guest_free(t_alloc, req_addr);
823
+
824
+ /* Read request */
825
+ req.type = VIRTIO_BLK_T_IN;
826
+ req.ioprio = 1;
827
+ req.sector = 1;
828
+ req.data = g_malloc0(512);
829
+
830
+ req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
831
+
832
+ g_free(req.data);
833
+
834
+ free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
835
+ qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
836
+ qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
837
+
838
+ qvirtqueue_kick(qts, dev, vq, free_head);
839
+
840
+ /* We get just one notification for both requests */
841
+ qvirtio_wait_used_elem(qts, dev, vq, write_head, NULL,
842
+ QVIRTIO_BLK_TIMEOUT_US);
843
+ g_assert(qvirtqueue_get_buf(qts, vq, &desc_idx, NULL));
844
+ g_assert_cmpint(desc_idx, ==, free_head);
845
+
846
+ status = readb(req_addr + 528);
847
+ g_assert_cmpint(status, ==, 0);
848
+
849
+ data = g_malloc0(512);
850
+ qtest_memread(qts, req_addr + 16, data, 512);
851
+ g_assert_cmpstr(data, ==, "TEST");
852
+ g_free(data);
853
+
854
+ guest_free(t_alloc, req_addr);
855
+
856
+ /* End test */
857
+ qpci_msix_disable(pdev->pdev);
858
+
859
+ qvirtqueue_cleanup(dev->bus, vq, t_alloc);
860
+}
861
+
862
+static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
863
+{
864
+ QVirtioPCIDevice *dev1 = obj;
865
+ QVirtioPCIDevice *dev;
866
+ QTestState *qts = dev1->pdev->bus->qts;
867
+
868
+ /* plug secondary disk */
869
+ qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
870
+ "{'addr': %s, 'chardev': 'char2'}",
871
+ stringify(PCI_SLOT_HP) ".0");
872
+
873
+ dev = virtio_pci_new(dev1->pdev->bus,
874
+ &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
875
+ });
876
+ g_assert_nonnull(dev);
877
+ g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
878
+ qvirtio_pci_device_disable(dev);
879
+ qos_object_destroy((QOSGraphObject *)dev);
880
+
881
+ /* unplug secondary disk */
882
+ qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
883
+}
884
+
885
+/*
886
+ * Check that setting the vring addr on a non-existent virtqueue does
887
+ * not crash.
888
+ */
889
+static void test_nonexistent_virtqueue(void *obj, void *data,
890
+ QGuestAllocator *t_alloc)
891
+{
892
+ QVhostUserBlkPCI *blk = obj;
893
+ QVirtioPCIDevice *pdev = &blk->pci_vdev;
894
+ QPCIBar bar0;
895
+ QPCIDevice *dev;
896
+
897
+ dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
898
+ g_assert(dev != NULL);
899
+ qpci_device_enable(dev);
900
+
901
+ bar0 = qpci_iomap(dev, 0, NULL);
902
+
903
+ qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
904
+ qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
905
+
906
+ g_free(dev);
907
+}
908
+
909
+static const char *qtest_qemu_storage_daemon_binary(void)
910
+{
911
+ const char *qemu_storage_daemon_bin;
912
+
913
+ qemu_storage_daemon_bin = getenv("QTEST_QEMU_STORAGE_DAEMON_BINARY");
914
+ if (!qemu_storage_daemon_bin) {
915
+ fprintf(stderr, "Environment variable "
916
+ "QTEST_QEMU_STORAGE_DAEMON_BINARY required\n");
917
+ exit(0);
918
+ }
919
+
920
+ return qemu_storage_daemon_bin;
921
+}
922
+
923
+static void drive_destroy(void *path)
924
+{
925
+ unlink(path);
926
+ g_free(path);
927
+ qos_invalidate_command_line();
928
+}
929
+
930
+static char *drive_create(void)
931
+{
932
+ int fd, ret;
933
+ /** vhost-user-blk won't recognize drive located in /tmp */
934
+ char *t_path = g_strdup("qtest.XXXXXX");
935
+
936
+ /** Create a temporary raw image */
937
+ fd = mkstemp(t_path);
938
+ g_assert_cmpint(fd, >=, 0);
939
+ ret = ftruncate(fd, TEST_IMAGE_SIZE);
940
+ g_assert_cmpint(ret, ==, 0);
941
+ close(fd);
942
+
943
+ g_test_queue_destroy(drive_destroy, t_path);
944
+ return t_path;
945
+}
946
+
947
+static char sock_path_tempate[] = "/tmp/qtest.vhost_user_blk.XXXXXX";
948
+static char qmp_sock_path_tempate[] = "/tmp/qtest.vhost_user_blk.qmp.XXXXXX";
949
+
950
+static void quit_storage_daemon(void *qmp_test_state)
951
+{
952
+ const char quit_str[] = "{ 'execute': 'quit' }";
953
+
954
+ /* Before quiting storate-daemon, quit qemu to avoid dubious messages */
955
+ qobject_unref(qtest_qmp(global_qtest, quit_str));
956
+
957
+ /*
958
+ * Give storage-daemon enough time to wake up&terminate
959
+ * vu_client_trip coroutine so the Coroutine object could
960
+ * be cleaned up. Otherwise LeakSanitizer would complain
961
+ * about memory leaks.
962
+ */
963
+ g_usleep(1000);
964
+
965
+ qobject_unref(qtest_qmp((QTestState *)qmp_test_state, quit_str));
966
+ g_free(qmp_test_state);
967
+}
968
+
969
+static char *start_vhost_user_blk(GString *cmd_line, int vus_instances)
970
+{
971
+ const char *vhost_user_blk_bin = qtest_qemu_storage_daemon_binary();
972
+ int fd, qmp_fd, i;
973
+ QTestState *qmp_test_state;
974
+ gchar *img_path;
975
+ char *sock_path = NULL;
976
+ char *qmp_sock_path = g_strdup(qmp_sock_path_tempate);
977
+ GString *storage_daemon_command = g_string_new(NULL);
978
+
979
+ qmp_fd = mkstemp(qmp_sock_path);
980
+ g_assert_cmpint(qmp_fd, >=, 0);
981
+ g_test_queue_destroy(drive_destroy, qmp_sock_path);
982
+
983
+ g_string_append_printf(storage_daemon_command,
984
+ "exec %s "
985
+ "--chardev socket,id=qmp,path=%s,server,nowait --monitor chardev=qmp ",
986
+ vhost_user_blk_bin, qmp_sock_path);
987
+
988
+ g_string_append_printf(cmd_line,
989
+ " -object memory-backend-memfd,id=mem,size=128M,share=on -numa node,memdev=mem ");
990
+
991
+ for (i = 0; i < vus_instances; i++) {
992
+ sock_path = g_strdup(sock_path_tempate);
993
+ fd = mkstemp(sock_path);
994
+ g_assert_cmpint(fd, >=, 0);
995
+ g_test_queue_destroy(drive_destroy, sock_path);
996
+ /* create image file */
997
+ img_path = drive_create();
998
+ g_string_append_printf(storage_daemon_command,
999
+ "--blockdev driver=file,node-name=disk%d,filename=%s "
1000
+ "--object vhost-user-blk-server,id=disk%d,unix-socket=%s,"
1001
+ "node-name=disk%i,writable=on ",
1002
+ i, img_path, i, sock_path, i);
1003
+
1004
+ g_string_append_printf(cmd_line, "-chardev socket,id=char%d,path=%s ",
1005
+ i + 1, sock_path);
1006
+ }
1007
+
1008
+ g_test_message("starting vhost-user backend: %s",
1009
+ storage_daemon_command->str);
1010
+ pid_t pid = fork();
1011
+ if (pid == 0) {
1012
+ execlp("/bin/sh", "sh", "-c", storage_daemon_command->str, NULL);
1013
+ exit(1);
1014
+ }
1015
+ g_string_free(storage_daemon_command, true);
1016
+
1017
+ qmp_test_state = qtest_create_state_with_qmp_fd(
1018
+ qtest_socket_client(qmp_sock_path));
1019
+ /*
1020
+ * Ask qemu-storage-daemon to quit so it
1021
+ * will not block scripts/tap-driver.pl.
1022
+ */
1023
+ g_test_queue_destroy(quit_storage_daemon, qmp_test_state);
1024
+
1025
+ qobject_unref(qtest_qmp(qmp_test_state, "{'execute': 'qmp_capabilities'}"));
1026
+ return sock_path;
1027
+}
1028
+
1029
+static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg)
1030
+{
1031
+ start_vhost_user_blk(cmd_line, 1);
1032
+ return arg;
1033
+}
1034
+
1035
+/*
1036
+ * Setup for hotplug.
1037
+ *
1038
+ * Since vhost-user server only serves one vhost-user client one time,
1039
+ * another exprot
1040
+ *
1041
+ */
1042
+static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *arg)
1043
+{
1044
+ /* "-chardev socket,id=char2" is used for pci_hotplug*/
1045
+ start_vhost_user_blk(cmd_line, 2);
1046
+ return arg;
1047
+}
1048
+
1049
+static void register_vhost_user_blk_test(void)
1050
+{
1051
+ QOSGraphTestOptions opts = {
1052
+ .before = vhost_user_blk_test_setup,
1053
+ };
1054
+
1055
+ /*
1056
+ * tests for vhost-user-blk and vhost-user-blk-pci
1057
+ * The tests are borrowed from tests/virtio-blk-test.c. But some tests
1058
+ * regarding block_resize don't work for vhost-user-blk.
1059
+ * vhost-user-blk device doesn't have -drive, so tests containing
1060
+ * block_resize are also abandoned,
1061
+ * - config
1062
+ * - resize
1063
+ */
1064
+ qos_add_test("basic", "vhost-user-blk", basic, &opts);
1065
+ qos_add_test("indirect", "vhost-user-blk", indirect, &opts);
1066
+ qos_add_test("idx", "vhost-user-blk-pci", idx, &opts);
1067
+ qos_add_test("nxvirtq", "vhost-user-blk-pci",
1068
+ test_nonexistent_virtqueue, &opts);
1069
+
1070
+ opts.before = vhost_user_blk_hotplug_test_setup;
1071
+ qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts);
1072
+}
1073
+
1074
+libqos_init(register_vhost_user_blk_test);
1075
diff --git a/tests/qtest/libqos/meson.build b/tests/qtest/libqos/meson.build
1076
index XXXXXXX..XXXXXXX 100644
1077
--- a/tests/qtest/libqos/meson.build
1078
+++ b/tests/qtest/libqos/meson.build
1079
@@ -XXX,XX +XXX,XX @@ libqos_srcs = files('../libqtest.c',
1080
'virtio-9p.c',
1081
'virtio-balloon.c',
1082
'virtio-blk.c',
1083
+ 'vhost-user-blk.c',
1084
'virtio-mmio.c',
1085
'virtio-net.c',
1086
'virtio-pci.c',
1087
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
1088
index XXXXXXX..XXXXXXX 100644
1089
--- a/tests/qtest/meson.build
1090
+++ b/tests/qtest/meson.build
1091
@@ -XXX,XX +XXX,XX @@ qos_test_ss.add(
1092
)
1093
qos_test_ss.add(when: 'CONFIG_VIRTFS', if_true: files('virtio-9p-test.c'))
1094
qos_test_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user-test.c'))
1095
+qos_test_ss.add(when: ['CONFIG_LINUX', 'CONFIG_TOOLS'], if_true: files('vhost-user-blk-test.c'))
1096
1097
extra_qtest_deps = {
1098
'bios-tables-test': [io],
1099
@@ -XXX,XX +XXX,XX @@ foreach dir : target_dirs
1100
endif
1101
qtest_env.set('G_TEST_DBUS_DAEMON', meson.source_root() / 'tests/dbus-vmstate-daemon.sh')
1102
qtest_env.set('QTEST_QEMU_BINARY', './qemu-system-' + target_base)
1103
-
1104
+ qtest_env.set('QTEST_QEMU_STORAGE_DAEMON_BINARY', './storage-daemon/qemu-storage-daemon')
1105
+
1106
foreach test : qtests
1107
# Executables are shared across targets, declare them only the first time we
1108
# encounter them
43
--
1109
--
44
2.24.1
1110
2.26.2
45
1111
46
diff view generated by jsdifflib
1
We do not care about the json:{} filenames here, so we can just filter
1
From: Coiby Xu <coiby.xu@gmail.com>
2
them out and thus make the test work both with and without external data
3
files.
4
2
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
Suggested-by: Stefano Garzarella <sgarzare@redhat.com>
6
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
4
Signed-off-by: Coiby Xu <coiby.xu@gmail.com>
7
Message-id: 20191107163708.833192-21-mreitz@redhat.com
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
7
Message-id: 20200918080912.321299-8-coiby.xu@gmail.com
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
9
---
10
tests/qemu-iotests/198 | 6 ++++--
10
MAINTAINERS | 8 ++++++++
11
tests/qemu-iotests/198.out | 4 ++--
11
1 file changed, 8 insertions(+)
12
2 files changed, 6 insertions(+), 4 deletions(-)
13
12
14
diff --git a/tests/qemu-iotests/198 b/tests/qemu-iotests/198
13
diff --git a/MAINTAINERS b/MAINTAINERS
15
index XXXXXXX..XXXXXXX 100755
16
--- a/tests/qemu-iotests/198
17
+++ b/tests/qemu-iotests/198
18
@@ -XXX,XX +XXX,XX @@ echo
19
echo "== checking image base =="
20
$QEMU_IMG info --image-opts $IMGSPECBASE | _filter_img_info --format-specific \
21
| sed -e "/^disk size:/ D" -e '/refcount bits:/ D' -e '/compat:/ D' \
22
- -e '/lazy refcounts:/ D' -e '/corrupt:/ D'
23
+ -e '/lazy refcounts:/ D' -e '/corrupt:/ D' -e '/^\s*data file/ D' \
24
+ | _filter_json_filename
25
26
echo
27
echo "== checking image layer =="
28
$QEMU_IMG info --image-opts $IMGSPECLAYER | _filter_img_info --format-specific \
29
| sed -e "/^disk size:/ D" -e '/refcount bits:/ D' -e '/compat:/ D' \
30
- -e '/lazy refcounts:/ D' -e '/corrupt:/ D'
31
+ -e '/lazy refcounts:/ D' -e '/corrupt:/ D' -e '/^\s*data file/ D' \
32
+ | _filter_json_filename
33
34
35
# success, all done
36
diff --git a/tests/qemu-iotests/198.out b/tests/qemu-iotests/198.out
37
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
38
--- a/tests/qemu-iotests/198.out
15
--- a/MAINTAINERS
39
+++ b/tests/qemu-iotests/198.out
16
+++ b/MAINTAINERS
40
@@ -XXX,XX +XXX,XX @@ read 16777216/16777216 bytes at offset 0
17
@@ -XXX,XX +XXX,XX @@ L: qemu-block@nongnu.org
41
16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
18
S: Supported
42
19
F: tests/image-fuzzer/
43
== checking image base ==
20
44
-image: json:{"encrypt.key-secret": "sec0", "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.base"}}
21
+Vhost-user block device backend server
45
+image: json:{ /* filtered */ }
22
+M: Coiby Xu <Coiby.Xu@gmail.com>
46
file format: IMGFMT
23
+S: Maintained
47
virtual size: 16 MiB (16777216 bytes)
24
+F: block/export/vhost-user-blk-server.c
48
Format specific information:
25
+F: util/vhost-user-server.c
49
@@ -XXX,XX +XXX,XX @@ Format specific information:
26
+F: tests/qtest/vhost-user-blk-test.c
50
master key iters: 1024
27
+F: tests/qtest/libqos/vhost-user-blk.c
51
28
+
52
== checking image layer ==
29
Replication
53
-image: json:{"encrypt.key-secret": "sec1", "driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}}
30
M: Wen Congyang <wencongyang2@huawei.com>
54
+image: json:{ /* filtered */ }
31
M: Xie Changlong <xiechanglong.d@gmail.com>
55
file format: IMGFMT
56
virtual size: 16 MiB (16777216 bytes)
57
backing file: TEST_DIR/t.IMGFMT.base
58
--
32
--
59
2.24.1
33
2.26.2
60
34
61
diff view generated by jsdifflib
1
It did not matter before, but now that _make_test_img understands -o, we
1
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2
should use it properly here.
2
Message-id: 20200924151549.913737-3-stefanha@redhat.com
3
3
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
6
Message-id: 20191107163708.833192-11-mreitz@redhat.com
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
4
---
9
tests/qemu-iotests/051 | 2 +-
5
util/vhost-user-server.c | 2 +-
10
1 file changed, 1 insertion(+), 1 deletion(-)
6
1 file changed, 1 insertion(+), 1 deletion(-)
11
7
12
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
8
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
13
index XXXXXXX..XXXXXXX 100755
9
index XXXXXXX..XXXXXXX 100644
14
--- a/tests/qemu-iotests/051
10
--- a/util/vhost-user-server.c
15
+++ b/tests/qemu-iotests/051
11
+++ b/util/vhost-user-server.c
16
@@ -XXX,XX +XXX,XX @@ echo
12
@@ -XXX,XX +XXX,XX @@ bool vhost_user_server_start(VuServer *server,
17
echo === With version 2 images enabling lazy refcounts must fail ===
13
return false;
18
echo
14
}
19
15
20
-_make_test_img -ocompat=0.10 $size
16
- /* zero out unspecified fileds */
21
+_make_test_img -o compat=0.10 $size
17
+ /* zero out unspecified fields */
22
18
*server = (VuServer) {
23
run_qemu -drive file="$TEST_IMG",format=qcow2,lazy-refcounts=on
19
.listener = listener,
24
run_qemu -drive file="$TEST_IMG",format=qcow2,lazy-refcounts=off
20
.vu_iface = vu_iface,
25
--
21
--
26
2.24.1
22
2.26.2
27
23
28
diff view generated by jsdifflib
1
Use _make_test_img whenever possible. This way, we will not ignore
1
We already have access to the value with the correct type (ioc and sioc
2
user-specified image options.
2
are the same QIOChannel).
3
3
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
5
Message-id: 20200924151549.913737-4-stefanha@redhat.com
6
Message-id: 20191107163708.833192-15-mreitz@redhat.com
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
7
---
9
tests/qemu-iotests/094 | 2 +-
8
util/vhost-user-server.c | 2 +-
10
tests/qemu-iotests/111 | 3 +--
9
1 file changed, 1 insertion(+), 1 deletion(-)
11
tests/qemu-iotests/123 | 2 +-
12
tests/qemu-iotests/153 | 2 +-
13
tests/qemu-iotests/200 | 4 ++--
14
5 files changed, 6 insertions(+), 7 deletions(-)
15
10
16
diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094
11
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
17
index XXXXXXX..XXXXXXX 100755
12
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/qemu-iotests/094
13
--- a/util/vhost-user-server.c
19
+++ b/tests/qemu-iotests/094
14
+++ b/util/vhost-user-server.c
20
@@ -XXX,XX +XXX,XX @@ _supported_proto nbd
15
@@ -XXX,XX +XXX,XX @@ static void vu_accept(QIONetListener *listener, QIOChannelSocket *sioc,
21
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
16
server->ioc = QIO_CHANNEL(sioc);
22
17
object_ref(OBJECT(server->ioc));
23
_make_test_img 64M
18
qio_channel_attach_aio_context(server->ioc, server->ctx);
24
-$QEMU_IMG create -f $IMGFMT "$TEST_DIR/source.$IMGFMT" 64M | _filter_img_create
19
- qio_channel_set_blocking(QIO_CHANNEL(server->sioc), false, NULL);
25
+TEST_IMG_FILE="$TEST_DIR/source.$IMGFMT" IMGPROTO=file _make_test_img 64M
20
+ qio_channel_set_blocking(server->ioc, false, NULL);
26
21
vu_client_start(server);
27
_launch_qemu -drive if=none,id=src,file="$TEST_DIR/source.$IMGFMT",format=raw \
22
}
28
-nodefaults
29
diff --git a/tests/qemu-iotests/111 b/tests/qemu-iotests/111
30
index XXXXXXX..XXXXXXX 100755
31
--- a/tests/qemu-iotests/111
32
+++ b/tests/qemu-iotests/111
33
@@ -XXX,XX +XXX,XX @@ _supported_fmt qed qcow qcow2 vmdk
34
_supported_proto file
35
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
36
37
-$QEMU_IMG create -f $IMGFMT -b "$TEST_IMG.inexistent" "$TEST_IMG" 2>&1 \
38
- | _filter_testdir | _filter_imgfmt
39
+_make_test_img -b "$TEST_IMG.inexistent"
40
41
# success, all done
42
echo '*** done'
43
diff --git a/tests/qemu-iotests/123 b/tests/qemu-iotests/123
44
index XXXXXXX..XXXXXXX 100755
45
--- a/tests/qemu-iotests/123
46
+++ b/tests/qemu-iotests/123
47
@@ -XXX,XX +XXX,XX @@ _supported_os Linux
48
SRC_IMG="$TEST_DIR/source.$IMGFMT"
49
50
_make_test_img 1M
51
-$QEMU_IMG create -f $IMGFMT "$SRC_IMG" 1M | _filter_img_create
52
+TEST_IMG_FILE=$SRC_IMG IMGPROTO=file _make_test_img 1M
53
54
$QEMU_IO -c 'write -P 42 0 1M' "$SRC_IMG" | _filter_qemu_io
55
56
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
57
index XXXXXXX..XXXXXXX 100755
58
--- a/tests/qemu-iotests/153
59
+++ b/tests/qemu-iotests/153
60
@@ -XXX,XX +XXX,XX @@ for opts1 in "" "read-only=on" "read-only=on,force-share=on"; do
61
62
echo
63
echo "== Creating test image =="
64
- $QEMU_IMG create -f $IMGFMT "${TEST_IMG}" -b ${TEST_IMG}.base | _filter_img_create
65
+ _make_test_img -b "${TEST_IMG}.base"
66
67
echo
68
echo "== Launching QEMU, opts: '$opts1' =="
69
diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200
70
index XXXXXXX..XXXXXXX 100755
71
--- a/tests/qemu-iotests/200
72
+++ b/tests/qemu-iotests/200
73
@@ -XXX,XX +XXX,XX @@ _supported_proto file
74
BACKING_IMG="${TEST_DIR}/backing.img"
75
TEST_IMG="${TEST_DIR}/test.img"
76
77
-${QEMU_IMG} create -f $IMGFMT "${BACKING_IMG}" 512M | _filter_img_create
78
-${QEMU_IMG} create -f $IMGFMT -F $IMGFMT "${TEST_IMG}" -b "${BACKING_IMG}" 512M | _filter_img_create
79
+TEST_IMG="$BACKING_IMG" _make_test_img 512M
80
+_make_test_img -F $IMGFMT -b "$BACKING_IMG" 512M
81
82
${QEMU_IO} -c "write -P 0xa5 512 300M" "${BACKING_IMG}" | _filter_qemu_io
83
23
84
--
24
--
85
2.24.1
25
2.26.2
86
26
87
diff view generated by jsdifflib
1
From: PanNengyuan <pannengyuan@huawei.com>
1
Explicitly deleting watches is not necessary since libvhost-user calls
2
remove_watch() during vu_deinit(). Add an assertion to check this
3
though.
2
4
3
This avoid a memory leak when qom-set is called to set throttle_group
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
limits, here is an easy way to reproduce:
6
Message-id: 20200924151549.913737-5-stefanha@redhat.com
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
---
9
util/vhost-user-server.c | 19 ++++---------------
10
1 file changed, 4 insertions(+), 15 deletions(-)
5
11
6
1. run qemu-iotests as follow and check the result with asan:
12
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
7
./check -qcow2 184
8
9
Following is the asan output backtrack:
10
Direct leak of 912 byte(s) in 3 object(s) allocated from:
11
#0 0xffff8d7ab3c3 in __interceptor_calloc (/lib64/libasan.so.4+0xd33c3)
12
#1 0xffff8d4c31cb in g_malloc0 (/lib64/libglib-2.0.so.0+0x571cb)
13
#2 0x190c857 in qobject_input_start_struct /mnt/sdc/qemu-master/qemu-4.2.0-rc0/qapi/qobject-input-visitor.c:295
14
#3 0x19070df in visit_start_struct /mnt/sdc/qemu-master/qemu-4.2.0-rc0/qapi/qapi-visit-core.c:49
15
#4 0x1948b87 in visit_type_ThrottleLimits qapi/qapi-visit-block-core.c:3759
16
#5 0x17e4aa3 in throttle_group_set_limits /mnt/sdc/qemu-master/qemu-4.2.0-rc0/block/throttle-groups.c:900
17
#6 0x1650eff in object_property_set /mnt/sdc/qemu-master/qemu-4.2.0-rc0/qom/object.c:1272
18
#7 0x1658517 in object_property_set_qobject /mnt/sdc/qemu-master/qemu-4.2.0-rc0/qom/qom-qobject.c:26
19
#8 0x15880bb in qmp_qom_set /mnt/sdc/qemu-master/qemu-4.2.0-rc0/qom/qom-qmp-cmds.c:74
20
#9 0x157e3e3 in qmp_marshal_qom_set qapi/qapi-commands-qom.c:154
21
22
Reported-by: Euler Robot <euler.robot@huawei.com>
23
Signed-off-by: PanNengyuan <pannengyuan@huawei.com>
24
Message-id: 1574835614-42028-1-git-send-email-pannengyuan@huawei.com
25
Signed-off-by: Max Reitz <mreitz@redhat.com>
26
---
27
block/throttle-groups.c | 4 ++--
28
1 file changed, 2 insertions(+), 2 deletions(-)
29
30
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
31
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
32
--- a/block/throttle-groups.c
14
--- a/util/vhost-user-server.c
33
+++ b/block/throttle-groups.c
15
+++ b/util/vhost-user-server.c
34
@@ -XXX,XX +XXX,XX @@ static void throttle_group_set_limits(Object *obj, Visitor *v,
16
@@ -XXX,XX +XXX,XX @@ static void close_client(VuServer *server)
35
{
17
/* When this is set vu_client_trip will stop new processing vhost-user message */
36
ThrottleGroup *tg = THROTTLE_GROUP(obj);
18
server->sioc = NULL;
37
ThrottleConfig cfg;
19
38
- ThrottleLimits arg = { 0 };
20
- VuFdWatch *vu_fd_watch, *next;
39
- ThrottleLimits *argp = &arg;
21
- QTAILQ_FOREACH_SAFE(vu_fd_watch, &server->vu_fd_watches, next, next) {
40
+ ThrottleLimits *argp;
22
- aio_set_fd_handler(server->ioc->ctx, vu_fd_watch->fd, true, NULL,
41
Error *local_err = NULL;
23
- NULL, NULL, NULL);
42
24
- }
43
visit_type_ThrottleLimits(v, name, &argp, &local_err);
25
-
44
@@ -XXX,XX +XXX,XX @@ static void throttle_group_set_limits(Object *obj, Visitor *v,
26
- while (!QTAILQ_EMPTY(&server->vu_fd_watches)) {
45
unlock:
27
- QTAILQ_FOREACH_SAFE(vu_fd_watch, &server->vu_fd_watches, next, next) {
46
qemu_mutex_unlock(&tg->lock);
28
- if (!vu_fd_watch->processing) {
47
ret:
29
- QTAILQ_REMOVE(&server->vu_fd_watches, vu_fd_watch, next);
48
+ qapi_free_ThrottleLimits(argp);
30
- g_free(vu_fd_watch);
49
error_propagate(errp, local_err);
31
- }
50
return;
32
- }
33
- }
34
-
35
while (server->processing_msg) {
36
if (server->ioc->read_coroutine) {
37
server->ioc->read_coroutine = NULL;
38
@@ -XXX,XX +XXX,XX @@ static void close_client(VuServer *server)
39
}
40
41
vu_deinit(&server->vu_dev);
42
+
43
+ /* vu_deinit() should have called remove_watch() */
44
+ assert(QTAILQ_EMPTY(&server->vu_fd_watches));
45
+
46
object_unref(OBJECT(sioc));
47
object_unref(OBJECT(server->ioc));
51
}
48
}
52
--
49
--
53
2.24.1
50
2.26.2
54
51
55
diff view generated by jsdifflib
1
This will allow us to add more options than just -b.
1
Only one struct is needed per request. Drop req_data and the separate
2
VuBlockReq instance. Instead let vu_queue_pop() allocate everything at
3
once.
2
4
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
This fixes the req_data memory leak in vu_block_virtio_process_req().
4
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
6
5
Message-id: 20191107163708.833192-9-mreitz@redhat.com
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Message-id: 20200924151549.913737-6-stefanha@redhat.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
---
10
---
8
tests/qemu-iotests/common.rc | 28 ++++++++++++++++++++--------
11
block/export/vhost-user-blk-server.c | 68 +++++++++-------------------
9
1 file changed, 20 insertions(+), 8 deletions(-)
12
1 file changed, 21 insertions(+), 47 deletions(-)
10
13
11
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
14
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/tests/qemu-iotests/common.rc
16
--- a/block/export/vhost-user-blk-server.c
14
+++ b/tests/qemu-iotests/common.rc
17
+++ b/block/export/vhost-user-blk-server.c
15
@@ -XXX,XX +XXX,XX @@ _make_test_img()
18
@@ -XXX,XX +XXX,XX @@ struct virtio_blk_inhdr {
16
# extra qemu-img options can be added by tests
19
};
17
# at least one argument (the image size) needs to be added
20
18
local extra_img_options=""
21
typedef struct VuBlockReq {
19
- local image_size=$*
22
- VuVirtqElement *elem;
20
local optstr=""
23
+ VuVirtqElement elem;
21
local img_name=""
24
int64_t sector_num;
22
local use_backing=0
25
size_t size;
23
local backing_file=""
26
struct virtio_blk_inhdr *in;
24
local object_options=""
27
@@ -XXX,XX +XXX,XX @@ static void vu_block_req_complete(VuBlockReq *req)
25
+ local misc_params=()
28
VuDev *vu_dev = &req->server->vu_dev;
26
29
27
if [ -n "$TEST_IMG_FILE" ]; then
30
/* IO size with 1 extra status byte */
28
img_name=$TEST_IMG_FILE
31
- vu_queue_push(vu_dev, req->vq, req->elem, req->size + 1);
29
@@ -XXX,XX +XXX,XX @@ _make_test_img()
32
+ vu_queue_push(vu_dev, req->vq, &req->elem, req->size + 1);
30
optstr=$(_optstr_add "$optstr" "key-secret=keysec0")
33
vu_queue_notify(vu_dev, req->vq);
31
fi
34
32
35
- if (req->elem) {
33
- if [ "$1" = "-b" ]; then
36
- free(req->elem);
34
- use_backing=1
37
- }
35
- backing_file=$2
38
-
36
- image_size=$3
39
- g_free(req);
37
- fi
40
+ free(req);
38
+ for param; do
41
}
39
+ if [ "$use_backing" = "1" -a -z "$backing_file" ]; then
42
40
+ backing_file=$param
43
static VuBlockDev *get_vu_block_device_by_server(VuServer *server)
41
+ continue
44
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_block_flush(VuBlockReq *req)
42
+ fi
45
blk_co_flush(backend);
46
}
47
48
-struct req_data {
49
- VuServer *server;
50
- VuVirtq *vq;
51
- VuVirtqElement *elem;
52
-};
53
-
54
static void coroutine_fn vu_block_virtio_process_req(void *opaque)
55
{
56
- struct req_data *data = opaque;
57
- VuServer *server = data->server;
58
- VuVirtq *vq = data->vq;
59
- VuVirtqElement *elem = data->elem;
60
+ VuBlockReq *req = opaque;
61
+ VuServer *server = req->server;
62
+ VuVirtqElement *elem = &req->elem;
63
uint32_t type;
64
- VuBlockReq *req;
65
66
VuBlockDev *vdev_blk = get_vu_block_device_by_server(server);
67
BlockBackend *backend = vdev_blk->backend;
68
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_block_virtio_process_req(void *opaque)
69
struct iovec *out_iov = elem->out_sg;
70
unsigned in_num = elem->in_num;
71
unsigned out_num = elem->out_num;
43
+
72
+
44
+ case "$param" in
73
/* refer to hw/block/virtio_blk.c */
45
+ -b)
74
if (elem->out_num < 1 || elem->in_num < 1) {
46
+ use_backing=1
75
error_report("virtio-blk request missing headers");
47
+ ;;
76
- free(elem);
77
- return;
78
+ goto err;
79
}
80
81
- req = g_new0(VuBlockReq, 1);
82
- req->server = server;
83
- req->vq = vq;
84
- req->elem = elem;
85
-
86
if (unlikely(iov_to_buf(out_iov, out_num, 0, &req->out,
87
sizeof(req->out)) != sizeof(req->out))) {
88
error_report("virtio-blk request outhdr too short");
89
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_block_virtio_process_req(void *opaque)
90
91
err:
92
free(elem);
93
- g_free(req);
94
- return;
95
}
96
97
static void vu_block_process_vq(VuDev *vu_dev, int idx)
98
{
99
- VuServer *server;
100
- VuVirtq *vq;
101
- struct req_data *req_data;
102
+ VuServer *server = container_of(vu_dev, VuServer, vu_dev);
103
+ VuVirtq *vq = vu_get_queue(vu_dev, idx);
104
105
- server = container_of(vu_dev, VuServer, vu_dev);
106
- assert(server);
107
-
108
- vq = vu_get_queue(vu_dev, idx);
109
- assert(vq);
110
- VuVirtqElement *elem;
111
while (1) {
112
- elem = vu_queue_pop(vu_dev, vq, sizeof(VuVirtqElement) +
113
- sizeof(VuBlockReq));
114
- if (elem) {
115
- req_data = g_new0(struct req_data, 1);
116
- req_data->server = server;
117
- req_data->vq = vq;
118
- req_data->elem = elem;
119
- Coroutine *co = qemu_coroutine_create(vu_block_virtio_process_req,
120
- req_data);
121
- aio_co_enter(server->ioc->ctx, co);
122
- } else {
123
+ VuBlockReq *req;
48
+
124
+
49
+ *)
125
+ req = vu_queue_pop(vu_dev, vq, sizeof(VuBlockReq));
50
+ misc_params=("${misc_params[@]}" "$param")
126
+ if (!req) {
51
+ ;;
127
break;
52
+ esac
128
}
53
+ done
54
+
129
+
55
if [ \( "$IMGFMT" = "qcow2" -o "$IMGFMT" = "qed" \) -a -n "$CLUSTER_SIZE" ]; then
130
+ req->server = server;
56
optstr=$(_optstr_add "$optstr" "cluster_size=$CLUSTER_SIZE")
131
+ req->vq = vq;
57
fi
132
+
58
@@ -XXX,XX +XXX,XX @@ _make_test_img()
133
+ Coroutine *co =
59
# XXX(hch): have global image options?
134
+ qemu_coroutine_create(vu_block_virtio_process_req, req);
60
(
135
+ qemu_coroutine_enter(co);
61
if [ $use_backing = 1 ]; then
136
}
62
- $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options -b "$backing_file" "$img_name" $image_size 2>&1
137
}
63
+ $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options -b "$backing_file" "$img_name" "${misc_params[@]}" 2>&1
64
else
65
- $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options "$img_name" $image_size 2>&1
66
+ $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options "$img_name" "${misc_params[@]}" 2>&1
67
fi
68
) | _filter_img_create
69
138
70
--
139
--
71
2.24.1
140
2.26.2
72
141
73
diff view generated by jsdifflib
1
When using an external data file, there are no refcounts for data
1
The device panic notifier callback is not used. Drop it.
2
clusters. We thus have to adjust the corruption test in this patch to
3
not be based around a data cluster allocation, but the L2 table
4
allocation (L2 tables are still refcounted with external data files).
5
2
6
Furthermore, we should not print qcow2.py's list of incompatible
3
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
features because it differs depending on whether there is an external
4
Message-id: 20200924151549.913737-7-stefanha@redhat.com
8
data file or not.
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
---
7
util/vhost-user-server.h | 3 ---
8
block/export/vhost-user-blk-server.c | 3 +--
9
util/vhost-user-server.c | 6 ------
10
3 files changed, 1 insertion(+), 11 deletions(-)
9
11
10
With those two changes, the test will work both with and without
12
diff --git a/util/vhost-user-server.h b/util/vhost-user-server.h
11
external data files (once that options works with the iotests at all).
13
index XXXXXXX..XXXXXXX 100644
14
--- a/util/vhost-user-server.h
15
+++ b/util/vhost-user-server.h
16
@@ -XXX,XX +XXX,XX @@ typedef struct VuFdWatch {
17
} VuFdWatch;
18
19
typedef struct VuServer VuServer;
20
-typedef void DevicePanicNotifierFn(VuServer *server);
21
22
struct VuServer {
23
QIONetListener *listener;
24
AioContext *ctx;
25
- DevicePanicNotifierFn *device_panic_notifier;
26
int max_queues;
27
const VuDevIface *vu_iface;
28
VuDev vu_dev;
29
@@ -XXX,XX +XXX,XX @@ bool vhost_user_server_start(VuServer *server,
30
SocketAddress *unix_socket,
31
AioContext *ctx,
32
uint16_t max_queues,
33
- DevicePanicNotifierFn *device_panic_notifier,
34
const VuDevIface *vu_iface,
35
Error **errp);
36
37
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
38
index XXXXXXX..XXXXXXX 100644
39
--- a/block/export/vhost-user-blk-server.c
40
+++ b/block/export/vhost-user-blk-server.c
41
@@ -XXX,XX +XXX,XX @@ static void vhost_user_blk_server_start(VuBlockDev *vu_block_device,
42
ctx = bdrv_get_aio_context(blk_bs(vu_block_device->backend));
43
44
if (!vhost_user_server_start(&vu_block_device->vu_server, addr, ctx,
45
- VHOST_USER_BLK_MAX_QUEUES,
46
- NULL, &vu_block_iface,
47
+ VHOST_USER_BLK_MAX_QUEUES, &vu_block_iface,
48
errp)) {
49
goto error;
50
}
51
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
52
index XXXXXXX..XXXXXXX 100644
53
--- a/util/vhost-user-server.c
54
+++ b/util/vhost-user-server.c
55
@@ -XXX,XX +XXX,XX @@ static void panic_cb(VuDev *vu_dev, const char *buf)
56
close_client(server);
57
}
58
59
- if (server->device_panic_notifier) {
60
- server->device_panic_notifier(server);
61
- }
62
-
63
/*
64
* Set the callback function for network listener so another
65
* vhost-user client can connect to this server
66
@@ -XXX,XX +XXX,XX @@ bool vhost_user_server_start(VuServer *server,
67
SocketAddress *socket_addr,
68
AioContext *ctx,
69
uint16_t max_queues,
70
- DevicePanicNotifierFn *device_panic_notifier,
71
const VuDevIface *vu_iface,
72
Error **errp)
73
{
74
@@ -XXX,XX +XXX,XX @@ bool vhost_user_server_start(VuServer *server,
75
.vu_iface = vu_iface,
76
.max_queues = max_queues,
77
.ctx = ctx,
78
- .device_panic_notifier = device_panic_notifier,
79
};
80
81
qio_net_listener_set_name(server->listener, "vhost-user-backend-listener");
82
--
83
2.26.2
12
84
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
15
Message-id: 20191107163708.833192-20-mreitz@redhat.com
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
tests/qemu-iotests/137 | 15 +++++++++++----
19
tests/qemu-iotests/137.out | 6 ++----
20
2 files changed, 13 insertions(+), 8 deletions(-)
21
22
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
23
index XXXXXXX..XXXXXXX 100755
24
--- a/tests/qemu-iotests/137
25
+++ b/tests/qemu-iotests/137
26
@@ -XXX,XX +XXX,XX @@ $QEMU_IO \
27
"$TEST_IMG" 2>&1 | _filter_qemu_io
28
29
# The dirty bit must not be set
30
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
31
+# (Filter the external data file bit)
32
+if $PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features \
33
+ | grep -q '\<0\>'
34
+then
35
+ echo 'ERROR: Dirty bit set'
36
+else
37
+ echo 'OK: Dirty bit not set'
38
+fi
39
40
# Similarly we can test whether corruption detection has been enabled:
41
-# Create L1/L2, overwrite first entry in refcount block, allocate something.
42
+# Create L1, overwrite refcounts, force allocation of L2 by writing
43
+# data.
44
# Disabling the checks should fail, so the corruption must be detected.
45
_make_test_img 64M
46
-$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
47
-poke_file "$TEST_IMG" "$((0x20000))" "\x00\x00"
48
+poke_file "$TEST_IMG" "$((0x20000))" "\x00\x00\x00\x00\x00\x00\x00\x00"
49
$QEMU_IO \
50
-c "reopen -o overlap-check=none,lazy-refcounts=42" \
51
-c "write 64k 64k" \
52
diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out
53
index XXXXXXX..XXXXXXX 100644
54
--- a/tests/qemu-iotests/137.out
55
+++ b/tests/qemu-iotests/137.out
56
@@ -XXX,XX +XXX,XX @@ qemu-io: Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are
57
wrote 512/512 bytes at offset 0
58
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
59
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
60
-incompatible_features []
61
+OK: Dirty bit not set
62
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
63
-wrote 65536/65536 bytes at offset 0
64
-64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
65
qemu-io: Parameter 'lazy-refcounts' expects 'on' or 'off'
66
-qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with qcow2_header); further corruption events will be suppressed
67
+qcow2: Marking image as corrupt: Preventing invalid allocation of L2 table at offset 0; further corruption events will be suppressed
68
write failed: Input/output error
69
*** done
70
--
71
2.24.1
72
73
diff view generated by jsdifflib
1
The only difference is that the json:{} filename of the image looks
1
fds[] is leaked when qio_channel_readv_full() fails.
2
different. We actually do not care about that filename in this test, we
3
are only interested in (1) that there is a json:{} filename, and (2)
4
whether the backing filename can be constructed.
5
2
6
So just filter out the json:{} data, thus making this test pass both
3
Use vmsg->fds[] instead of keeping a local fds[] array. Then we can
7
with and without data_file.
4
reuse goto fail to clean up fds. vmsg->fd_num must be zeroed before the
5
loop to make this safe.
8
6
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
8
Message-id: 20200924151549.913737-8-stefanha@redhat.com
11
Message-id: 20191107163708.833192-19-mreitz@redhat.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
10
---
14
tests/qemu-iotests/110 | 7 +++++--
11
util/vhost-user-server.c | 50 ++++++++++++++++++----------------------
15
tests/qemu-iotests/110.out | 4 ++--
12
1 file changed, 23 insertions(+), 27 deletions(-)
16
2 files changed, 7 insertions(+), 4 deletions(-)
17
13
18
diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110
14
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
19
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
20
--- a/tests/qemu-iotests/110
16
--- a/util/vhost-user-server.c
21
+++ b/tests/qemu-iotests/110
17
+++ b/util/vhost-user-server.c
22
@@ -XXX,XX +XXX,XX @@ echo
18
@@ -XXX,XX +XXX,XX @@ vu_message_read(VuDev *vu_dev, int conn_fd, VhostUserMsg *vmsg)
23
# Across blkdebug without a config file, you cannot reconstruct filenames, so
19
};
24
# qemu is incapable of knowing the directory of the top image from the filename
20
int rc, read_bytes = 0;
25
# alone. However, using bdrv_dirname(), it should still work.
21
Error *local_err = NULL;
26
+# (Filter out the json:{} filename so this test works with external data files)
22
- /*
27
TEST_IMG="json:{
23
- * Store fds/nfds returned from qio_channel_readv_full into
28
'driver': '$IMGFMT',
24
- * temporary variables.
29
'file': {
25
- *
30
@@ -XXX,XX +XXX,XX @@ TEST_IMG="json:{
26
- * VhostUserMsg is a packed structure, gcc will complain about passing
27
- * pointer to a packed structure member if we pass &VhostUserMsg.fd_num
28
- * and &VhostUserMsg.fds directly when calling qio_channel_readv_full,
29
- * thus two temporary variables nfds and fds are used here.
30
- */
31
- size_t nfds = 0, nfds_t = 0;
32
const size_t max_fds = G_N_ELEMENTS(vmsg->fds);
33
- int *fds_t = NULL;
34
VuServer *server = container_of(vu_dev, VuServer, vu_dev);
35
QIOChannel *ioc = server->ioc;
36
37
+ vmsg->fd_num = 0;
38
if (!ioc) {
39
error_report_err(local_err);
40
goto fail;
41
@@ -XXX,XX +XXX,XX @@ vu_message_read(VuDev *vu_dev, int conn_fd, VhostUserMsg *vmsg)
42
43
assert(qemu_in_coroutine());
44
do {
45
+ size_t nfds = 0;
46
+ int *fds = NULL;
47
+
48
/*
49
* qio_channel_readv_full may have short reads, keeping calling it
50
* until getting VHOST_USER_HDR_SIZE or 0 bytes in total
51
*/
52
- rc = qio_channel_readv_full(ioc, &iov, 1, &fds_t, &nfds_t, &local_err);
53
+ rc = qio_channel_readv_full(ioc, &iov, 1, &fds, &nfds, &local_err);
54
if (rc < 0) {
55
if (rc == QIO_CHANNEL_ERR_BLOCK) {
56
+ assert(local_err == NULL);
57
qio_channel_yield(ioc, G_IO_IN);
58
continue;
59
} else {
60
error_report_err(local_err);
61
- return false;
62
+ goto fail;
31
}
63
}
32
]
64
}
33
}
65
- read_bytes += rc;
34
-}" _img_info | _filter_img_info | grep -v 'backing file format'
66
- if (nfds_t > 0) {
35
+}" _img_info | _filter_img_info | grep -v 'backing file format' \
67
- if (nfds + nfds_t > max_fds) {
36
+ | _filter_json_filename
68
+
37
69
+ if (nfds > 0) {
38
echo
70
+ if (vmsg->fd_num + nfds > max_fds) {
39
echo '=== Backing name is always relative to the backed image ==='
71
error_report("A maximum of %zu fds are allowed, "
40
@@ -XXX,XX +XXX,XX @@ TEST_IMG="json:{
72
"however got %lu fds now",
73
- max_fds, nfds + nfds_t);
74
+ max_fds, vmsg->fd_num + nfds);
75
+ g_free(fds);
76
goto fail;
41
}
77
}
42
]
78
- memcpy(vmsg->fds + nfds, fds_t,
43
}
79
- nfds_t *sizeof(vmsg->fds[0]));
44
-}" _img_info | _filter_img_info | grep -v 'backing file format'
80
- nfds += nfds_t;
45
+}" _img_info | _filter_img_info | grep -v 'backing file format' \
81
- g_free(fds_t);
46
+ | _filter_json_filename
82
+ memcpy(vmsg->fds + vmsg->fd_num, fds, nfds * sizeof(vmsg->fds[0]));
47
83
+ vmsg->fd_num += nfds;
48
84
+ g_free(fds);
49
# success, all done
85
}
50
diff --git a/tests/qemu-iotests/110.out b/tests/qemu-iotests/110.out
86
- if (read_bytes == VHOST_USER_HDR_SIZE || rc == 0) {
51
index XXXXXXX..XXXXXXX 100644
87
- break;
52
--- a/tests/qemu-iotests/110.out
88
+
53
+++ b/tests/qemu-iotests/110.out
89
+ if (rc == 0) { /* socket closed */
54
@@ -XXX,XX +XXX,XX @@ backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base)
90
+ goto fail;
55
91
}
56
=== Non-reconstructable filename ===
92
- iov.iov_base = (char *)vmsg + read_bytes;
57
93
- iov.iov_len = VHOST_USER_HDR_SIZE - read_bytes;
58
-image: json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}}
94
- } while (true);
59
+image: json:{ /* filtered */ }
95
60
file format: IMGFMT
96
- vmsg->fd_num = nfds;
61
virtual size: 64 MiB (67108864 bytes)
97
+ iov.iov_base += rc;
62
backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base)
98
+ iov.iov_len -= rc;
63
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.b
99
+ read_bytes += rc;
64
100
+ } while (read_bytes != VHOST_USER_HDR_SIZE);
65
=== Nodes without a common directory ===
101
+
66
102
/* qio_channel_readv_full will make socket fds blocking, unblock them */
67
-image: json:{"driver": "IMGFMT", "file": {"children": [{"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, {"driver": "file", "filename": "TEST_DIR/t.IMGFMT.copy"}], "driver": "quorum", "vote-threshold": 1}}
103
vmsg_unblock_fds(vmsg);
68
+image: json:{ /* filtered */ }
104
if (vmsg->size > sizeof(vmsg->payload)) {
69
file format: IMGFMT
70
virtual size: 64 MiB (67108864 bytes)
71
backing file: t.IMGFMT.base (cannot determine actual path)
72
--
105
--
73
2.24.1
106
2.26.2
74
107
75
diff view generated by jsdifflib
1
The image end offset as reported by qemu-img check is different when
1
Unexpected EOF is an error that must be reported.
2
using an external data file; we do not care about its value here, so we
3
can just filter it. Incidentally, common.rc already has _check_test_img
4
for us which does exactly that.
5
2
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
4
Message-id: 20200924151549.913737-9-stefanha@redhat.com
8
Message-id: 20191107163708.833192-18-mreitz@redhat.com
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
6
---
11
tests/qemu-iotests/091 | 2 +-
7
util/vhost-user-server.c | 6 ++++--
12
tests/qemu-iotests/091.out | 2 --
8
1 file changed, 4 insertions(+), 2 deletions(-)
13
2 files changed, 1 insertion(+), 3 deletions(-)
14
9
15
diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091
10
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
16
index XXXXXXX..XXXXXXX 100755
17
--- a/tests/qemu-iotests/091
18
+++ b/tests/qemu-iotests/091
19
@@ -XXX,XX +XXX,XX @@ echo "Check image pattern"
20
${QEMU_IO} -c "read -P 0x22 0 4M" "${TEST_IMG}" | _filter_testdir | _filter_qemu_io
21
22
echo "Running 'qemu-img check -r all \$TEST_IMG'"
23
-"${QEMU_IMG}" check -r all "${TEST_IMG}" 2>&1 | _filter_testdir | _filter_qemu
24
+_check_test_img -r all
25
26
echo "*** done"
27
rm -f $seq.full
28
diff --git a/tests/qemu-iotests/091.out b/tests/qemu-iotests/091.out
29
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
30
--- a/tests/qemu-iotests/091.out
12
--- a/util/vhost-user-server.c
31
+++ b/tests/qemu-iotests/091.out
13
+++ b/util/vhost-user-server.c
32
@@ -XXX,XX +XXX,XX @@ read 4194304/4194304 bytes at offset 0
14
@@ -XXX,XX +XXX,XX @@ vu_message_read(VuDev *vu_dev, int conn_fd, VhostUserMsg *vmsg)
33
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
15
};
34
Running 'qemu-img check -r all $TEST_IMG'
16
if (vmsg->size) {
35
No errors were found on the image.
17
rc = qio_channel_readv_all_eof(ioc, &iov_payload, 1, &local_err);
36
-80/16384 = 0.49% allocated, 0.00% fragmented, 0.00% compressed clusters
18
- if (rc == -1) {
37
-Image end offset: 5570560
19
- error_report_err(local_err);
38
*** done
20
+ if (rc != 1) {
21
+ if (local_err) {
22
+ error_report_err(local_err);
23
+ }
24
goto fail;
25
}
26
}
39
--
27
--
40
2.24.1
28
2.26.2
41
29
42
diff view generated by jsdifflib
1
The problem with allowing the data_file option is that you want to use a
1
The vu_client_trip() coroutine is leaked during AioContext switching. It
2
different data file per image used in the test. Therefore, we need to
2
is also unsafe to destroy the vu_dev in panic_cb() since its callers
3
allow patterns like -o data_file='$TEST_IMG.data_file'.
3
still access it in some cases.
4
4
5
Then, we need to filter it out from qemu-img map, qemu-img create, and
5
Rework the lifecycle to solve these safety issues.
6
remove the data file in _rm_test_img.
7
6
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
8
Message-id: 20200924151549.913737-10-stefanha@redhat.com
10
Message-id: 20191107163708.833192-23-mreitz@redhat.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
10
---
13
tests/qemu-iotests/common.filter | 23 +++++++++++++++++++++--
11
util/vhost-user-server.h | 29 ++--
14
tests/qemu-iotests/common.rc | 22 +++++++++++++++++++++-
12
block/export/vhost-user-blk-server.c | 9 +-
15
2 files changed, 42 insertions(+), 3 deletions(-)
13
util/vhost-user-server.c | 245 +++++++++++++++------------
14
3 files changed, 155 insertions(+), 128 deletions(-)
16
15
17
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
16
diff --git a/util/vhost-user-server.h b/util/vhost-user-server.h
18
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/common.filter
18
--- a/util/vhost-user-server.h
20
+++ b/tests/qemu-iotests/common.filter
19
+++ b/util/vhost-user-server.h
21
@@ -XXX,XX +XXX,XX @@ _filter_actual_image_size()
20
@@ -XXX,XX +XXX,XX @@
22
# replace driver-specific options in the "Formatting..." line
21
#include "qapi/error.h"
23
_filter_img_create()
22
#include "standard-headers/linux/virtio_blk.h"
24
{
23
25
- $SED -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
24
+/* A kick fd that we monitor on behalf of libvhost-user */
26
+ data_file_filter=()
25
typedef struct VuFdWatch {
27
+ if data_file=$(_get_data_file "$TEST_IMG"); then
26
VuDev *vu_dev;
28
+ data_file_filter=(-e "s# data_file=$data_file##")
27
int fd; /*kick fd*/
29
+ fi
28
void *pvt;
30
+
29
vu_watch_cb cb;
31
+ $SED "${data_file_filter[@]}" \
30
- bool processing;
32
+ -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
31
QTAILQ_ENTRY(VuFdWatch) next;
33
-e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
32
} VuFdWatch;
34
-e "s#$TEST_DIR#TEST_DIR#g" \
33
35
-e "s#$SOCK_DIR#SOCK_DIR#g" \
34
-typedef struct VuServer VuServer;
36
@@ -XXX,XX +XXX,XX @@ _filter_img_info()
35
-
37
# human and json output
36
-struct VuServer {
38
_filter_qemu_img_map()
37
+/**
39
{
38
+ * VuServer:
40
+ # Assuming the data_file value in $IMGOPTS contains a '$TEST_IMG',
39
+ * A vhost-user server instance with user-defined VuDevIface callbacks.
41
+ # create a filter that replaces the data file name by $TEST_IMG.
40
+ * Vhost-user device backends can be implemented using VuServer. VuDevIface
42
+ # Example:
41
+ * callbacks and virtqueue kicks run in the given AioContext.
43
+ # In $IMGOPTS: 'data_file=$TEST_IMG.data_file'
42
+ */
44
+ # Then data_file_pattern == '\(.*\).data_file'
43
+typedef struct {
45
+ # And data_file_filter == -e 's#\(.*\).data_file#\1#
44
QIONetListener *listener;
46
+ data_file_filter=()
45
+ QEMUBH *restart_listener_bh;
47
+ if data_file_pattern=$(_get_data_file '\\(.*\\)'); then
46
AioContext *ctx;
48
+ data_file_filter=(-e "s#$data_file_pattern#\\1#")
47
int max_queues;
49
+ fi
48
const VuDevIface *vu_iface;
50
+
49
+
51
$SED -e 's/\([0-9a-fx]* *[0-9a-fx]* *\)[0-9a-fx]* */\1/g' \
50
+ /* Protected by ctx lock */
52
-e 's/"offset": [0-9]\+/"offset": OFFSET/g' \
51
VuDev vu_dev;
53
- -e 's/Mapped to *//' | _filter_testdir | _filter_imgfmt
52
QIOChannel *ioc; /* The I/O channel with the client */
54
+ -e 's/Mapped to *//' \
53
QIOChannelSocket *sioc; /* The underlying data channel with the client */
55
+ "${data_file_filter[@]}" \
54
- /* IOChannel for fd provided via VHOST_USER_SET_SLAVE_REQ_FD */
56
+ | _filter_testdir | _filter_imgfmt
55
- QIOChannel *ioc_slave;
57
}
56
- QIOChannelSocket *sioc_slave;
58
57
- Coroutine *co_trip; /* coroutine for processing VhostUserMsg */
59
_filter_nbd()
58
QTAILQ_HEAD(, VuFdWatch) vu_fd_watches;
60
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
59
- /* restart coroutine co_trip if AIOContext is changed */
60
- bool aio_context_changed;
61
- bool processing_msg;
62
-};
63
+
64
+ Coroutine *co_trip; /* coroutine for processing VhostUserMsg */
65
+} VuServer;
66
67
bool vhost_user_server_start(VuServer *server,
68
SocketAddress *unix_socket,
69
@@ -XXX,XX +XXX,XX @@ bool vhost_user_server_start(VuServer *server,
70
71
void vhost_user_server_stop(VuServer *server);
72
73
-void vhost_user_server_set_aio_context(VuServer *server, AioContext *ctx);
74
+void vhost_user_server_attach_aio_context(VuServer *server, AioContext *ctx);
75
+void vhost_user_server_detach_aio_context(VuServer *server);
76
77
#endif /* VHOST_USER_SERVER_H */
78
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
61
index XXXXXXX..XXXXXXX 100644
79
index XXXXXXX..XXXXXXX 100644
62
--- a/tests/qemu-iotests/common.rc
80
--- a/block/export/vhost-user-blk-server.c
63
+++ b/tests/qemu-iotests/common.rc
81
+++ b/block/export/vhost-user-blk-server.c
64
@@ -XXX,XX +XXX,XX @@ _stop_nbd_server()
82
@@ -XXX,XX +XXX,XX @@ static const VuDevIface vu_block_iface = {
65
fi
83
static void blk_aio_attached(AioContext *ctx, void *opaque)
66
}
84
{
67
85
VuBlockDev *vub_dev = opaque;
68
+# Gets the data_file value from IMGOPTS and replaces the '$TEST_IMG'
86
- aio_context_acquire(ctx);
69
+# pattern by '$1'
87
- vhost_user_server_set_aio_context(&vub_dev->vu_server, ctx);
70
+# Caution: The replacement is done with sed, so $1 must be escaped
88
- aio_context_release(ctx);
71
+# properly. (The delimiter is '#'.)
89
+ vhost_user_server_attach_aio_context(&vub_dev->vu_server, ctx);
72
+_get_data_file()
90
}
91
92
static void blk_aio_detach(void *opaque)
93
{
94
VuBlockDev *vub_dev = opaque;
95
- AioContext *ctx = vub_dev->vu_server.ctx;
96
- aio_context_acquire(ctx);
97
- vhost_user_server_set_aio_context(&vub_dev->vu_server, NULL);
98
- aio_context_release(ctx);
99
+ vhost_user_server_detach_aio_context(&vub_dev->vu_server);
100
}
101
102
static void
103
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
104
index XXXXXXX..XXXXXXX 100644
105
--- a/util/vhost-user-server.c
106
+++ b/util/vhost-user-server.c
107
@@ -XXX,XX +XXX,XX @@
108
*/
109
#include "qemu/osdep.h"
110
#include "qemu/main-loop.h"
111
+#include "block/aio-wait.h"
112
#include "vhost-user-server.h"
113
114
+/*
115
+ * Theory of operation:
116
+ *
117
+ * VuServer is started and stopped by vhost_user_server_start() and
118
+ * vhost_user_server_stop() from the main loop thread. Starting the server
119
+ * opens a vhost-user UNIX domain socket and listens for incoming connections.
120
+ * Only one connection is allowed at a time.
121
+ *
122
+ * The connection is handled by the vu_client_trip() coroutine in the
123
+ * VuServer->ctx AioContext. The coroutine consists of a vu_dispatch() loop
124
+ * where libvhost-user calls vu_message_read() to receive the next vhost-user
125
+ * protocol messages over the UNIX domain socket.
126
+ *
127
+ * When virtqueues are set up libvhost-user calls set_watch() to monitor kick
128
+ * fds. These fds are also handled in the VuServer->ctx AioContext.
129
+ *
130
+ * Both vu_client_trip() and kick fd monitoring can be stopped by shutting down
131
+ * the socket connection. Shutting down the socket connection causes
132
+ * vu_message_read() to fail since no more data can be received from the socket.
133
+ * After vu_dispatch() fails, vu_client_trip() calls vu_deinit() to stop
134
+ * libvhost-user before terminating the coroutine. vu_deinit() calls
135
+ * remove_watch() to stop monitoring kick fds and this stops virtqueue
136
+ * processing.
137
+ *
138
+ * When vu_client_trip() has finished cleaning up it schedules a BH in the main
139
+ * loop thread to accept the next client connection.
140
+ *
141
+ * When libvhost-user detects an error it calls panic_cb() and sets the
142
+ * dev->broken flag. Both vu_client_trip() and kick fd processing stop when
143
+ * the dev->broken flag is set.
144
+ *
145
+ * It is possible to switch AioContexts using
146
+ * vhost_user_server_detach_aio_context() and
147
+ * vhost_user_server_attach_aio_context(). They stop monitoring fds in the old
148
+ * AioContext and resume monitoring in the new AioContext. The vu_client_trip()
149
+ * coroutine remains in a yielded state during the switch. This is made
150
+ * possible by QIOChannel's support for spurious coroutine re-entry in
151
+ * qio_channel_yield(). The coroutine will restart I/O when re-entered from the
152
+ * new AioContext.
153
+ */
154
+
155
static void vmsg_close_fds(VhostUserMsg *vmsg)
156
{
157
int i;
158
@@ -XXX,XX +XXX,XX @@ static void vmsg_unblock_fds(VhostUserMsg *vmsg)
159
}
160
}
161
162
-static void vu_accept(QIONetListener *listener, QIOChannelSocket *sioc,
163
- gpointer opaque);
164
-
165
-static void close_client(VuServer *server)
166
-{
167
- /*
168
- * Before closing the client
169
- *
170
- * 1. Let vu_client_trip stop processing new vhost-user msg
171
- *
172
- * 2. remove kick_handler
173
- *
174
- * 3. wait for the kick handler to be finished
175
- *
176
- * 4. wait for the current vhost-user msg to be finished processing
177
- */
178
-
179
- QIOChannelSocket *sioc = server->sioc;
180
- /* When this is set vu_client_trip will stop new processing vhost-user message */
181
- server->sioc = NULL;
182
-
183
- while (server->processing_msg) {
184
- if (server->ioc->read_coroutine) {
185
- server->ioc->read_coroutine = NULL;
186
- qio_channel_set_aio_fd_handler(server->ioc, server->ioc->ctx, NULL,
187
- NULL, server->ioc);
188
- server->processing_msg = false;
189
- }
190
- }
191
-
192
- vu_deinit(&server->vu_dev);
193
-
194
- /* vu_deinit() should have called remove_watch() */
195
- assert(QTAILQ_EMPTY(&server->vu_fd_watches));
196
-
197
- object_unref(OBJECT(sioc));
198
- object_unref(OBJECT(server->ioc));
199
-}
200
-
201
static void panic_cb(VuDev *vu_dev, const char *buf)
202
{
203
- VuServer *server = container_of(vu_dev, VuServer, vu_dev);
204
-
205
- /* avoid while loop in close_client */
206
- server->processing_msg = false;
207
-
208
- if (buf) {
209
- error_report("vu_panic: %s", buf);
210
- }
211
-
212
- if (server->sioc) {
213
- close_client(server);
214
- }
215
-
216
- /*
217
- * Set the callback function for network listener so another
218
- * vhost-user client can connect to this server
219
- */
220
- qio_net_listener_set_client_func(server->listener,
221
- vu_accept,
222
- server,
223
- NULL);
224
+ error_report("vu_panic: %s", buf);
225
}
226
227
static bool coroutine_fn
228
@@ -XXX,XX +XXX,XX @@ fail:
229
return false;
230
}
231
232
-
233
-static void vu_client_start(VuServer *server);
234
static coroutine_fn void vu_client_trip(void *opaque)
235
{
236
VuServer *server = opaque;
237
+ VuDev *vu_dev = &server->vu_dev;
238
239
- while (!server->aio_context_changed && server->sioc) {
240
- server->processing_msg = true;
241
- vu_dispatch(&server->vu_dev);
242
- server->processing_msg = false;
243
+ while (!vu_dev->broken && vu_dispatch(vu_dev)) {
244
+ /* Keep running */
245
}
246
247
- if (server->aio_context_changed && server->sioc) {
248
- server->aio_context_changed = false;
249
- vu_client_start(server);
250
- }
251
-}
252
+ vu_deinit(vu_dev);
253
+
254
+ /* vu_deinit() should have called remove_watch() */
255
+ assert(QTAILQ_EMPTY(&server->vu_fd_watches));
256
+
257
+ object_unref(OBJECT(server->sioc));
258
+ server->sioc = NULL;
259
260
-static void vu_client_start(VuServer *server)
261
-{
262
- server->co_trip = qemu_coroutine_create(vu_client_trip, server);
263
- aio_co_enter(server->ctx, server->co_trip);
264
+ object_unref(OBJECT(server->ioc));
265
+ server->ioc = NULL;
266
+
267
+ server->co_trip = NULL;
268
+ if (server->restart_listener_bh) {
269
+ qemu_bh_schedule(server->restart_listener_bh);
270
+ }
271
+ aio_wait_kick();
272
}
273
274
/*
275
@@ -XXX,XX +XXX,XX @@ static void vu_client_start(VuServer *server)
276
static void kick_handler(void *opaque)
277
{
278
VuFdWatch *vu_fd_watch = opaque;
279
- vu_fd_watch->processing = true;
280
- vu_fd_watch->cb(vu_fd_watch->vu_dev, 0, vu_fd_watch->pvt);
281
- vu_fd_watch->processing = false;
282
+ VuDev *vu_dev = vu_fd_watch->vu_dev;
283
+
284
+ vu_fd_watch->cb(vu_dev, 0, vu_fd_watch->pvt);
285
+
286
+ /* Stop vu_client_trip() if an error occurred in vu_fd_watch->cb() */
287
+ if (vu_dev->broken) {
288
+ VuServer *server = container_of(vu_dev, VuServer, vu_dev);
289
+
290
+ qio_channel_shutdown(server->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
291
+ }
292
}
293
294
-
295
static VuFdWatch *find_vu_fd_watch(VuServer *server, int fd)
296
{
297
298
@@ -XXX,XX +XXX,XX @@ static void vu_accept(QIONetListener *listener, QIOChannelSocket *sioc,
299
qio_channel_set_name(QIO_CHANNEL(sioc), "vhost-user client");
300
server->ioc = QIO_CHANNEL(sioc);
301
object_ref(OBJECT(server->ioc));
302
- qio_channel_attach_aio_context(server->ioc, server->ctx);
303
+
304
+ /* TODO vu_message_write() spins if non-blocking! */
305
qio_channel_set_blocking(server->ioc, false, NULL);
306
- vu_client_start(server);
307
+
308
+ server->co_trip = qemu_coroutine_create(vu_client_trip, server);
309
+
310
+ aio_context_acquire(server->ctx);
311
+ vhost_user_server_attach_aio_context(server, server->ctx);
312
+ aio_context_release(server->ctx);
313
}
314
315
-
316
void vhost_user_server_stop(VuServer *server)
317
{
318
+ aio_context_acquire(server->ctx);
319
+
320
+ qemu_bh_delete(server->restart_listener_bh);
321
+ server->restart_listener_bh = NULL;
322
+
323
if (server->sioc) {
324
- close_client(server);
325
+ VuFdWatch *vu_fd_watch;
326
+
327
+ QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) {
328
+ aio_set_fd_handler(server->ctx, vu_fd_watch->fd, true,
329
+ NULL, NULL, NULL, vu_fd_watch);
330
+ }
331
+
332
+ qio_channel_shutdown(server->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
333
+
334
+ AIO_WAIT_WHILE(server->ctx, server->co_trip);
335
}
336
337
+ aio_context_release(server->ctx);
338
+
339
if (server->listener) {
340
qio_net_listener_disconnect(server->listener);
341
object_unref(OBJECT(server->listener));
342
}
343
+}
344
+
345
+/*
346
+ * Allow the next client to connect to the server. Called from a BH in the main
347
+ * loop.
348
+ */
349
+static void restart_listener_bh(void *opaque)
73
+{
350
+{
74
+ if ! echo "$IMGOPTS" | grep -q 'data_file='; then
351
+ VuServer *server = opaque;
75
+ return 1
352
76
+ fi
353
+ qio_net_listener_set_client_func(server->listener, vu_accept, server,
77
+
354
+ NULL);
78
+ echo "$IMGOPTS" | sed -e 's/.*data_file=\([^,]*\).*/\1/' \
355
}
79
+ | sed -e "s#\\\$TEST_IMG#$1#"
356
357
-void vhost_user_server_set_aio_context(VuServer *server, AioContext *ctx)
358
+/* Called with ctx acquired */
359
+void vhost_user_server_attach_aio_context(VuServer *server, AioContext *ctx)
360
{
361
- VuFdWatch *vu_fd_watch, *next;
362
- void *opaque = NULL;
363
- IOHandler *io_read = NULL;
364
- bool attach;
365
+ VuFdWatch *vu_fd_watch;
366
367
- server->ctx = ctx ? ctx : qemu_get_aio_context();
368
+ server->ctx = ctx;
369
370
if (!server->sioc) {
371
- /* not yet serving any client*/
372
return;
373
}
374
375
- if (ctx) {
376
- qio_channel_attach_aio_context(server->ioc, ctx);
377
- server->aio_context_changed = true;
378
- io_read = kick_handler;
379
- attach = true;
380
- } else {
381
+ qio_channel_attach_aio_context(server->ioc, ctx);
382
+
383
+ QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) {
384
+ aio_set_fd_handler(ctx, vu_fd_watch->fd, true, kick_handler, NULL,
385
+ NULL, vu_fd_watch);
386
+ }
387
+
388
+ aio_co_schedule(ctx, server->co_trip);
80
+}
389
+}
81
+
390
+
82
_make_test_img()
391
+/* Called with server->ctx acquired */
83
{
392
+void vhost_user_server_detach_aio_context(VuServer *server)
84
# extra qemu-img options can be added by tests
393
+{
85
@@ -XXX,XX +XXX,XX @@ _make_test_img()
394
+ if (server->sioc) {
86
fi
395
+ VuFdWatch *vu_fd_watch;
87
396
+
88
if [ -n "$IMGOPTS" ]; then
397
+ QTAILQ_FOREACH(vu_fd_watch, &server->vu_fd_watches, next) {
89
- optstr=$(_optstr_add "$optstr" "$IMGOPTS")
398
+ aio_set_fd_handler(server->ctx, vu_fd_watch->fd, true,
90
+ imgopts_expanded=$(echo "$IMGOPTS" | sed -e "s#\\\$TEST_IMG#$img_name#")
399
+ NULL, NULL, NULL, vu_fd_watch);
91
+ optstr=$(_optstr_add "$optstr" "$imgopts_expanded")
400
+ }
92
fi
401
+
93
if [ -n "$IMGKEYSECRET" ]; then
402
qio_channel_detach_aio_context(server->ioc);
94
object_options="--object secret,id=keysec0,data=$IMGKEYSECRET"
403
- /* server->ioc->ctx keeps the old AioConext */
95
@@ -XXX,XX +XXX,XX @@ _rm_test_img()
404
- ctx = server->ioc->ctx;
96
# Remove all the extents for vmdk
405
- attach = false;
97
"$QEMU_IMG" info "$img" 2>/dev/null | grep 'filename:' | cut -f 2 -d: \
406
}
98
| xargs -I {} rm -f "{}"
407
99
+ elif [ "$IMGFMT" = "qcow2" ]; then
408
- QTAILQ_FOREACH_SAFE(vu_fd_watch, &server->vu_fd_watches, next, next) {
100
+ # Remove external data file
409
- if (vu_fd_watch->cb) {
101
+ if data_file=$(_get_data_file "$img"); then
410
- opaque = attach ? vu_fd_watch : NULL;
102
+ rm -f "$data_file"
411
- aio_set_fd_handler(ctx, vu_fd_watch->fd, true,
103
+ fi
412
- io_read, NULL, NULL,
104
fi
413
- opaque);
105
rm -f "$img"
414
- }
106
}
415
- }
416
+ server->ctx = NULL;
417
}
418
419
-
420
bool vhost_user_server_start(VuServer *server,
421
SocketAddress *socket_addr,
422
AioContext *ctx,
423
@@ -XXX,XX +XXX,XX @@ bool vhost_user_server_start(VuServer *server,
424
const VuDevIface *vu_iface,
425
Error **errp)
426
{
427
+ QEMUBH *bh;
428
QIONetListener *listener = qio_net_listener_new();
429
if (qio_net_listener_open_sync(listener, socket_addr, 1,
430
errp) < 0) {
431
@@ -XXX,XX +XXX,XX @@ bool vhost_user_server_start(VuServer *server,
432
return false;
433
}
434
435
+ bh = qemu_bh_new(restart_listener_bh, server);
436
+
437
/* zero out unspecified fields */
438
*server = (VuServer) {
439
.listener = listener,
440
+ .restart_listener_bh = bh,
441
.vu_iface = vu_iface,
442
.max_queues = max_queues,
443
.ctx = ctx,
107
--
444
--
108
2.24.1
445
2.26.2
109
446
110
diff view generated by jsdifflib
1
This will not work with external data files, so try to get tests working
1
Propagate the flush return value since errors are possible.
2
without it as far as possible.
3
2
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
4
Message-id: 20200924151549.913737-11-stefanha@redhat.com
6
Message-id: 20191107163708.833192-17-mreitz@redhat.com
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
6
---
9
tests/qemu-iotests/063 | 12 ++++--------
7
block/export/vhost-user-blk-server.c | 11 +++++++----
10
tests/qemu-iotests/063.out | 3 ++-
8
1 file changed, 7 insertions(+), 4 deletions(-)
11
tests/qemu-iotests/085 | 9 +++------
12
tests/qemu-iotests/085.out | 8 ++++----
13
4 files changed, 13 insertions(+), 19 deletions(-)
14
9
15
diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063
10
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
16
index XXXXXXX..XXXXXXX 100755
17
--- a/tests/qemu-iotests/063
18
+++ b/tests/qemu-iotests/063
19
@@ -XXX,XX +XXX,XX @@ _unsupported_imgopts "subformat=monolithicFlat" \
20
_make_test_img 4M
21
22
echo "== Testing conversion with -n fails with no target file =="
23
-# check .orig file does not exist
24
-rm -f "$TEST_IMG.orig"
25
if $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG.orig" >/dev/null 2>&1; then
26
exit 1
27
fi
28
29
echo "== Testing conversion with -n succeeds with a target file =="
30
-rm -f "$TEST_IMG.orig"
31
-cp "$TEST_IMG" "$TEST_IMG.orig"
32
+_rm_test_img "$TEST_IMG.orig"
33
+TEST_IMG="$TEST_IMG.orig" _make_test_img 4M
34
if ! $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG.orig" ; then
35
exit 1
36
fi
37
@@ -XXX,XX +XXX,XX @@ fi
38
_check_test_img
39
40
echo "== Testing conversion to a smaller file fails =="
41
-rm -f "$TEST_IMG.orig"
42
-mv "$TEST_IMG" "$TEST_IMG.orig"
43
-_make_test_img 2M
44
-if $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG.orig" "$TEST_IMG" >/dev/null 2>&1; then
45
+TEST_IMG="$TEST_IMG.target" _make_test_img 2M
46
+if $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG.target" >/dev/null 2>&1; then
47
exit 1
48
fi
49
50
diff --git a/tests/qemu-iotests/063.out b/tests/qemu-iotests/063.out
51
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
52
--- a/tests/qemu-iotests/063.out
12
--- a/block/export/vhost-user-blk-server.c
53
+++ b/tests/qemu-iotests/063.out
13
+++ b/block/export/vhost-user-blk-server.c
54
@@ -XXX,XX +XXX,XX @@ QA output created by 063
14
@@ -XXX,XX +XXX,XX @@ vu_block_discard_write_zeroes(VuBlockReq *req, struct iovec *iov,
55
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4194304
15
return -EINVAL;
56
== Testing conversion with -n fails with no target file ==
16
}
57
== Testing conversion with -n succeeds with a target file ==
17
58
+Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=4194304
18
-static void coroutine_fn vu_block_flush(VuBlockReq *req)
59
== Testing conversion to raw is the same after conversion with -n ==
19
+static int coroutine_fn vu_block_flush(VuBlockReq *req)
60
== Testing conversion back to original format ==
61
No errors were found on the image.
62
== Testing conversion to a smaller file fails ==
63
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2097152
64
+Formatting 'TEST_DIR/t.IMGFMT.target', fmt=IMGFMT size=2097152
65
== Regression testing for copy offloading bug ==
66
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
67
Formatting 'TEST_DIR/t.IMGFMT.target', fmt=IMGFMT size=1048576
68
diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085
69
index XXXXXXX..XXXXXXX 100755
70
--- a/tests/qemu-iotests/085
71
+++ b/tests/qemu-iotests/085
72
@@ -XXX,XX +XXX,XX @@ add_snapshot_image()
73
{
20
{
74
base_image="${TEST_DIR}/$((${1}-1))-${snapshot_virt0}"
21
VuBlockDev *vdev_blk = get_vu_block_device_by_server(req->server);
75
snapshot_file="${TEST_DIR}/${1}-${snapshot_virt0}"
22
BlockBackend *backend = vdev_blk->backend;
76
- _make_test_img -u -b "${base_image}" "$size"
23
- blk_co_flush(backend);
77
- mv "${TEST_IMG}" "${snapshot_file}"
24
+ return blk_co_flush(backend);
78
+ TEST_IMG=$snapshot_file _make_test_img -u -b "${base_image}" "$size"
79
do_blockdev_add "$1" "'backing': null, " "${snapshot_file}"
80
}
25
}
81
26
82
@@ -XXX,XX +XXX,XX @@ blockdev_snapshot()
27
static void coroutine_fn vu_block_virtio_process_req(void *opaque)
83
28
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_block_virtio_process_req(void *opaque)
84
size=128M
29
break;
85
30
}
86
-_make_test_img $size
31
case VIRTIO_BLK_T_FLUSH:
87
-mv "${TEST_IMG}" "${TEST_IMG}.1"
32
- vu_block_flush(req);
88
-_make_test_img $size
33
- req->in->status = VIRTIO_BLK_S_OK;
89
-mv "${TEST_IMG}" "${TEST_IMG}.2"
34
+ if (vu_block_flush(req) == 0) {
90
+TEST_IMG="$TEST_IMG.1" _make_test_img $size
35
+ req->in->status = VIRTIO_BLK_S_OK;
91
+TEST_IMG="$TEST_IMG.2" _make_test_img $size
36
+ } else {
92
37
+ req->in->status = VIRTIO_BLK_S_IOERR;
93
echo
38
+ }
94
echo === Running QEMU ===
39
break;
95
diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out
40
case VIRTIO_BLK_T_GET_ID: {
96
index XXXXXXX..XXXXXXX 100644
41
size_t size = MIN(iov_size(&elem->in_sg[0], in_num),
97
--- a/tests/qemu-iotests/085.out
98
+++ b/tests/qemu-iotests/085.out
99
@@ -XXX,XX +XXX,XX @@
100
QA output created by 085
101
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
102
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
103
+Formatting 'TEST_DIR/t.IMGFMT.1', fmt=IMGFMT size=134217728
104
+Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=134217728
105
106
=== Running QEMU ===
107
108
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_fil
109
110
=== Create a couple of snapshots using blockdev-snapshot ===
111
112
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/10-snapshot-v0.IMGFMT
113
+Formatting 'TEST_DIR/11-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/10-snapshot-v0.IMGFMT
114
{ 'execute': 'blockdev-add', 'arguments': { 'driver': 'IMGFMT', 'node-name': 'snap_11', 'backing': null, 'file': { 'driver': 'file', 'filename': 'TEST_DIR/11-snapshot-v0.IMGFMT', 'node-name': 'file_11' } } }
115
{"return": {}}
116
{ 'execute': 'blockdev-snapshot', 'arguments': { 'node': 'virtio0', 'overlay':'snap_11' } }
117
{"return": {}}
118
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/11-snapshot-v0.IMGFMT
119
+Formatting 'TEST_DIR/12-snapshot-v0.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/11-snapshot-v0.IMGFMT
120
{ 'execute': 'blockdev-add', 'arguments': { 'driver': 'IMGFMT', 'node-name': 'snap_12', 'backing': null, 'file': { 'driver': 'file', 'filename': 'TEST_DIR/12-snapshot-v0.IMGFMT', 'node-name': 'file_12' } } }
121
{"return": {}}
122
{ 'execute': 'blockdev-snapshot', 'arguments': { 'node': 'virtio0', 'overlay':'snap_12' } }
123
--
42
--
124
2.24.1
43
2.26.2
125
44
126
diff view generated by jsdifflib
1
We can save some LoC in xdbg_graph_add_edge() by using
1
Use the new QAPI block exports API instead of defining our own QOM
2
bdrv_qapi_perm_to_blk_perm().
2
objects.
3
3
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
This is a large change because the lifecycle of VuBlockDev needs to
5
Message-id: 20191108123455.39445-3-mreitz@redhat.com
5
follow BlockExportDriver. QOM properties are replaced by QAPI options
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
objects.
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
8
VuBlockDev is renamed VuBlkExport and contains a BlockExport field.
9
Several fields can be dropped since BlockExport already has equivalents.
10
11
The file names and meson build integration will be adjusted in a future
12
patch. libvhost-user should probably be built as a static library that
13
is linked into QEMU instead of as a .c file that results in duplicate
14
compilation.
15
16
The new command-line syntax is:
17
18
$ qemu-storage-daemon \
19
--blockdev file,node-name=drive0,filename=test.img \
20
--export vhost-user-blk,node-name=drive0,id=export0,unix-socket=/tmp/vhost-user-blk.sock
21
22
Note that unix-socket is optional because we may wish to accept chardevs
23
too in the future.
24
25
Markus noted that supported address families are not explicit in the
26
QAPI schema. It is unlikely that support for more address families will
27
be added since file descriptor passing is required and few address
28
families support it. If a new address family needs to be added, then the
29
QAPI 'features' syntax can be used to advertize them.
30
31
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
32
Acked-by: Markus Armbruster <armbru@redhat.com>
33
Message-id: 20200924151549.913737-12-stefanha@redhat.com
34
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
---
35
---
9
block.c | 29 ++++++++---------------------
36
qapi/block-export.json | 21 +-
10
1 file changed, 8 insertions(+), 21 deletions(-)
37
block/export/vhost-user-blk-server.h | 23 +-
11
38
block/export/export.c | 6 +
12
diff --git a/block.c b/block.c
39
block/export/vhost-user-blk-server.c | 452 +++++++--------------------
40
tests/qtest/vhost-user-blk-test.c | 2 +-
41
util/vhost-user-server.c | 10 +-
42
block/export/meson.build | 1 +
43
block/meson.build | 1 -
44
8 files changed, 157 insertions(+), 359 deletions(-)
45
46
diff --git a/qapi/block-export.json b/qapi/block-export.json
13
index XXXXXXX..XXXXXXX 100644
47
index XXXXXXX..XXXXXXX 100644
14
--- a/block.c
48
--- a/qapi/block-export.json
15
+++ b/block.c
49
+++ b/qapi/block-export.json
16
@@ -XXX,XX +XXX,XX @@ static void xdbg_graph_add_node(XDbgBlockGraphConstructor *gr, void *node,
50
@@ -XXX,XX +XXX,XX @@
17
static void xdbg_graph_add_edge(XDbgBlockGraphConstructor *gr, void *parent,
51
'data': { '*name': 'str', '*description': 'str',
18
const BdrvChild *child)
52
'*bitmap': 'str' } }
19
{
53
20
- typedef struct {
54
+##
21
- unsigned int flag;
55
+# @BlockExportOptionsVhostUserBlk:
22
- BlockPermission num;
56
+#
23
- } PermissionMap;
57
+# A vhost-user-blk block export.
24
-
58
+#
25
- static const PermissionMap permissions[] = {
59
+# @addr: The vhost-user socket on which to listen. Both 'unix' and 'fd'
26
- { BLK_PERM_CONSISTENT_READ, BLOCK_PERMISSION_CONSISTENT_READ },
60
+# SocketAddress types are supported. Passed fds must be UNIX domain
27
- { BLK_PERM_WRITE, BLOCK_PERMISSION_WRITE },
61
+# sockets.
28
- { BLK_PERM_WRITE_UNCHANGED, BLOCK_PERMISSION_WRITE_UNCHANGED },
62
+# @logical-block-size: Logical block size in bytes. Defaults to 512 bytes.
29
- { BLK_PERM_RESIZE, BLOCK_PERMISSION_RESIZE },
63
+#
30
- { BLK_PERM_GRAPH_MOD, BLOCK_PERMISSION_GRAPH_MOD },
64
+# Since: 5.2
31
- { 0, 0 }
65
+##
32
- };
66
+{ 'struct': 'BlockExportOptionsVhostUserBlk',
33
- const PermissionMap *p;
67
+ 'data': { 'addr': 'SocketAddress', '*logical-block-size': 'size' } }
34
+ BlockPermission qapi_perm;
35
XDbgBlockGraphEdge *edge;
36
37
- QEMU_BUILD_BUG_ON(1UL << (ARRAY_SIZE(permissions) - 1) != BLK_PERM_ALL + 1);
38
-
39
edge = g_new0(XDbgBlockGraphEdge, 1);
40
41
edge->parent = xdbg_graph_node_num(gr, parent);
42
edge->child = xdbg_graph_node_num(gr, child->bs);
43
edge->name = g_strdup(child->name);
44
45
- for (p = permissions; p->flag; p++) {
46
- if (p->flag & child->perm) {
47
- QAPI_LIST_ADD(edge->perm, p->num);
48
+ for (qapi_perm = 0; qapi_perm < BLOCK_PERMISSION__MAX; qapi_perm++) {
49
+ uint64_t flag = bdrv_qapi_perm_to_blk_perm(qapi_perm);
50
+
68
+
51
+ if (flag & child->perm) {
69
##
52
+ QAPI_LIST_ADD(edge->perm, qapi_perm);
70
# @NbdServerAddOptions:
71
#
72
@@ -XXX,XX +XXX,XX @@
73
# An enumeration of block export types
74
#
75
# @nbd: NBD export
76
+# @vhost-user-blk: vhost-user-blk export (since 5.2)
77
#
78
# Since: 4.2
79
##
80
{ 'enum': 'BlockExportType',
81
- 'data': [ 'nbd' ] }
82
+ 'data': [ 'nbd', 'vhost-user-blk' ] }
83
84
##
85
# @BlockExportOptions:
86
@@ -XXX,XX +XXX,XX @@
87
'*writethrough': 'bool' },
88
'discriminator': 'type',
89
'data': {
90
- 'nbd': 'BlockExportOptionsNbd'
91
+ 'nbd': 'BlockExportOptionsNbd',
92
+ 'vhost-user-blk': 'BlockExportOptionsVhostUserBlk'
93
} }
94
95
##
96
diff --git a/block/export/vhost-user-blk-server.h b/block/export/vhost-user-blk-server.h
97
index XXXXXXX..XXXXXXX 100644
98
--- a/block/export/vhost-user-blk-server.h
99
+++ b/block/export/vhost-user-blk-server.h
100
@@ -XXX,XX +XXX,XX @@
101
102
#ifndef VHOST_USER_BLK_SERVER_H
103
#define VHOST_USER_BLK_SERVER_H
104
-#include "util/vhost-user-server.h"
105
106
-typedef struct VuBlockDev VuBlockDev;
107
-#define TYPE_VHOST_USER_BLK_SERVER "vhost-user-blk-server"
108
-#define VHOST_USER_BLK_SERVER(obj) \
109
- OBJECT_CHECK(VuBlockDev, obj, TYPE_VHOST_USER_BLK_SERVER)
110
+#include "block/export.h"
111
112
-/* vhost user block device */
113
-struct VuBlockDev {
114
- Object parent_obj;
115
- char *node_name;
116
- SocketAddress *addr;
117
- AioContext *ctx;
118
- VuServer vu_server;
119
- bool running;
120
- uint32_t blk_size;
121
- BlockBackend *backend;
122
- QIOChannelSocket *sioc;
123
- QTAILQ_ENTRY(VuBlockDev) next;
124
- struct virtio_blk_config blkcfg;
125
- bool writable;
126
-};
127
+/* For block/export/export.c */
128
+extern const BlockExportDriver blk_exp_vhost_user_blk;
129
130
#endif /* VHOST_USER_BLK_SERVER_H */
131
diff --git a/block/export/export.c b/block/export/export.c
132
index XXXXXXX..XXXXXXX 100644
133
--- a/block/export/export.c
134
+++ b/block/export/export.c
135
@@ -XXX,XX +XXX,XX @@
136
#include "sysemu/block-backend.h"
137
#include "block/export.h"
138
#include "block/nbd.h"
139
+#if CONFIG_LINUX
140
+#include "block/export/vhost-user-blk-server.h"
141
+#endif
142
#include "qapi/error.h"
143
#include "qapi/qapi-commands-block-export.h"
144
#include "qapi/qapi-events-block-export.h"
145
@@ -XXX,XX +XXX,XX @@
146
147
static const BlockExportDriver *blk_exp_drivers[] = {
148
&blk_exp_nbd,
149
+#if CONFIG_LINUX
150
+ &blk_exp_vhost_user_blk,
151
+#endif
152
};
153
154
/* Only accessed from the main thread */
155
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
156
index XXXXXXX..XXXXXXX 100644
157
--- a/block/export/vhost-user-blk-server.c
158
+++ b/block/export/vhost-user-blk-server.c
159
@@ -XXX,XX +XXX,XX @@
160
*/
161
#include "qemu/osdep.h"
162
#include "block/block.h"
163
+#include "contrib/libvhost-user/libvhost-user.h"
164
+#include "standard-headers/linux/virtio_blk.h"
165
+#include "util/vhost-user-server.h"
166
#include "vhost-user-blk-server.h"
167
#include "qapi/error.h"
168
#include "qom/object_interfaces.h"
169
@@ -XXX,XX +XXX,XX @@ struct virtio_blk_inhdr {
170
unsigned char status;
171
};
172
173
-typedef struct VuBlockReq {
174
+typedef struct VuBlkReq {
175
VuVirtqElement elem;
176
int64_t sector_num;
177
size_t size;
178
@@ -XXX,XX +XXX,XX @@ typedef struct VuBlockReq {
179
struct virtio_blk_outhdr out;
180
VuServer *server;
181
struct VuVirtq *vq;
182
-} VuBlockReq;
183
+} VuBlkReq;
184
185
-static void vu_block_req_complete(VuBlockReq *req)
186
+/* vhost user block device */
187
+typedef struct {
188
+ BlockExport export;
189
+ VuServer vu_server;
190
+ uint32_t blk_size;
191
+ QIOChannelSocket *sioc;
192
+ struct virtio_blk_config blkcfg;
193
+ bool writable;
194
+} VuBlkExport;
195
+
196
+static void vu_blk_req_complete(VuBlkReq *req)
197
{
198
VuDev *vu_dev = &req->server->vu_dev;
199
200
@@ -XXX,XX +XXX,XX @@ static void vu_block_req_complete(VuBlockReq *req)
201
free(req);
202
}
203
204
-static VuBlockDev *get_vu_block_device_by_server(VuServer *server)
205
-{
206
- return container_of(server, VuBlockDev, vu_server);
207
-}
208
-
209
static int coroutine_fn
210
-vu_block_discard_write_zeroes(VuBlockReq *req, struct iovec *iov,
211
- uint32_t iovcnt, uint32_t type)
212
+vu_blk_discard_write_zeroes(BlockBackend *blk, struct iovec *iov,
213
+ uint32_t iovcnt, uint32_t type)
214
{
215
struct virtio_blk_discard_write_zeroes desc;
216
ssize_t size = iov_to_buf(iov, iovcnt, 0, &desc, sizeof(desc));
217
@@ -XXX,XX +XXX,XX @@ vu_block_discard_write_zeroes(VuBlockReq *req, struct iovec *iov,
218
return -EINVAL;
219
}
220
221
- VuBlockDev *vdev_blk = get_vu_block_device_by_server(req->server);
222
uint64_t range[2] = { le64_to_cpu(desc.sector) << 9,
223
le32_to_cpu(desc.num_sectors) << 9 };
224
if (type == VIRTIO_BLK_T_DISCARD) {
225
- if (blk_co_pdiscard(vdev_blk->backend, range[0], range[1]) == 0) {
226
+ if (blk_co_pdiscard(blk, range[0], range[1]) == 0) {
227
return 0;
53
}
228
}
54
- if (p->flag & child->shared_perm) {
229
} else if (type == VIRTIO_BLK_T_WRITE_ZEROES) {
55
- QAPI_LIST_ADD(edge->shared_perm, p->num);
230
- if (blk_co_pwrite_zeroes(vdev_blk->backend,
56
+ if (flag & child->shared_perm) {
231
- range[0], range[1], 0) == 0) {
57
+ QAPI_LIST_ADD(edge->shared_perm, qapi_perm);
232
+ if (blk_co_pwrite_zeroes(blk, range[0], range[1], 0) == 0) {
233
return 0;
58
}
234
}
59
}
235
}
60
236
@@ -XXX,XX +XXX,XX @@ vu_block_discard_write_zeroes(VuBlockReq *req, struct iovec *iov,
237
return -EINVAL;
238
}
239
240
-static int coroutine_fn vu_block_flush(VuBlockReq *req)
241
+static void coroutine_fn vu_blk_virtio_process_req(void *opaque)
242
{
243
- VuBlockDev *vdev_blk = get_vu_block_device_by_server(req->server);
244
- BlockBackend *backend = vdev_blk->backend;
245
- return blk_co_flush(backend);
246
-}
247
-
248
-static void coroutine_fn vu_block_virtio_process_req(void *opaque)
249
-{
250
- VuBlockReq *req = opaque;
251
+ VuBlkReq *req = opaque;
252
VuServer *server = req->server;
253
VuVirtqElement *elem = &req->elem;
254
uint32_t type;
255
256
- VuBlockDev *vdev_blk = get_vu_block_device_by_server(server);
257
- BlockBackend *backend = vdev_blk->backend;
258
+ VuBlkExport *vexp = container_of(server, VuBlkExport, vu_server);
259
+ BlockBackend *blk = vexp->export.blk;
260
261
struct iovec *in_iov = elem->in_sg;
262
struct iovec *out_iov = elem->out_sg;
263
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_block_virtio_process_req(void *opaque)
264
bool is_write = type & VIRTIO_BLK_T_OUT;
265
req->sector_num = le64_to_cpu(req->out.sector);
266
267
- int64_t offset = req->sector_num * vdev_blk->blk_size;
268
+ if (is_write && !vexp->writable) {
269
+ req->in->status = VIRTIO_BLK_S_IOERR;
270
+ break;
271
+ }
272
+
273
+ int64_t offset = req->sector_num * vexp->blk_size;
274
QEMUIOVector qiov;
275
if (is_write) {
276
qemu_iovec_init_external(&qiov, out_iov, out_num);
277
- ret = blk_co_pwritev(backend, offset, qiov.size,
278
- &qiov, 0);
279
+ ret = blk_co_pwritev(blk, offset, qiov.size, &qiov, 0);
280
} else {
281
qemu_iovec_init_external(&qiov, in_iov, in_num);
282
- ret = blk_co_preadv(backend, offset, qiov.size,
283
- &qiov, 0);
284
+ ret = blk_co_preadv(blk, offset, qiov.size, &qiov, 0);
285
}
286
if (ret >= 0) {
287
req->in->status = VIRTIO_BLK_S_OK;
288
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_block_virtio_process_req(void *opaque)
289
break;
290
}
291
case VIRTIO_BLK_T_FLUSH:
292
- if (vu_block_flush(req) == 0) {
293
+ if (blk_co_flush(blk) == 0) {
294
req->in->status = VIRTIO_BLK_S_OK;
295
} else {
296
req->in->status = VIRTIO_BLK_S_IOERR;
297
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_block_virtio_process_req(void *opaque)
298
case VIRTIO_BLK_T_DISCARD:
299
case VIRTIO_BLK_T_WRITE_ZEROES: {
300
int rc;
301
- rc = vu_block_discard_write_zeroes(req, &elem->out_sg[1],
302
- out_num, type);
303
+
304
+ if (!vexp->writable) {
305
+ req->in->status = VIRTIO_BLK_S_IOERR;
306
+ break;
307
+ }
308
+
309
+ rc = vu_blk_discard_write_zeroes(blk, &elem->out_sg[1], out_num, type);
310
if (rc == 0) {
311
req->in->status = VIRTIO_BLK_S_OK;
312
} else {
313
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn vu_block_virtio_process_req(void *opaque)
314
break;
315
}
316
317
- vu_block_req_complete(req);
318
+ vu_blk_req_complete(req);
319
return;
320
321
err:
322
- free(elem);
323
+ free(req);
324
}
325
326
-static void vu_block_process_vq(VuDev *vu_dev, int idx)
327
+static void vu_blk_process_vq(VuDev *vu_dev, int idx)
328
{
329
VuServer *server = container_of(vu_dev, VuServer, vu_dev);
330
VuVirtq *vq = vu_get_queue(vu_dev, idx);
331
332
while (1) {
333
- VuBlockReq *req;
334
+ VuBlkReq *req;
335
336
- req = vu_queue_pop(vu_dev, vq, sizeof(VuBlockReq));
337
+ req = vu_queue_pop(vu_dev, vq, sizeof(VuBlkReq));
338
if (!req) {
339
break;
340
}
341
@@ -XXX,XX +XXX,XX @@ static void vu_block_process_vq(VuDev *vu_dev, int idx)
342
req->vq = vq;
343
344
Coroutine *co =
345
- qemu_coroutine_create(vu_block_virtio_process_req, req);
346
+ qemu_coroutine_create(vu_blk_virtio_process_req, req);
347
qemu_coroutine_enter(co);
348
}
349
}
350
351
-static void vu_block_queue_set_started(VuDev *vu_dev, int idx, bool started)
352
+static void vu_blk_queue_set_started(VuDev *vu_dev, int idx, bool started)
353
{
354
VuVirtq *vq;
355
356
assert(vu_dev);
357
358
vq = vu_get_queue(vu_dev, idx);
359
- vu_set_queue_handler(vu_dev, vq, started ? vu_block_process_vq : NULL);
360
+ vu_set_queue_handler(vu_dev, vq, started ? vu_blk_process_vq : NULL);
361
}
362
363
-static uint64_t vu_block_get_features(VuDev *dev)
364
+static uint64_t vu_blk_get_features(VuDev *dev)
365
{
366
uint64_t features;
367
VuServer *server = container_of(dev, VuServer, vu_dev);
368
- VuBlockDev *vdev_blk = get_vu_block_device_by_server(server);
369
+ VuBlkExport *vexp = container_of(server, VuBlkExport, vu_server);
370
features = 1ull << VIRTIO_BLK_F_SIZE_MAX |
371
1ull << VIRTIO_BLK_F_SEG_MAX |
372
1ull << VIRTIO_BLK_F_TOPOLOGY |
373
@@ -XXX,XX +XXX,XX @@ static uint64_t vu_block_get_features(VuDev *dev)
374
1ull << VIRTIO_RING_F_EVENT_IDX |
375
1ull << VHOST_USER_F_PROTOCOL_FEATURES;
376
377
- if (!vdev_blk->writable) {
378
+ if (!vexp->writable) {
379
features |= 1ull << VIRTIO_BLK_F_RO;
380
}
381
382
return features;
383
}
384
385
-static uint64_t vu_block_get_protocol_features(VuDev *dev)
386
+static uint64_t vu_blk_get_protocol_features(VuDev *dev)
387
{
388
return 1ull << VHOST_USER_PROTOCOL_F_CONFIG |
389
1ull << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD;
390
}
391
392
static int
393
-vu_block_get_config(VuDev *vu_dev, uint8_t *config, uint32_t len)
394
+vu_blk_get_config(VuDev *vu_dev, uint8_t *config, uint32_t len)
395
{
396
+ /* TODO blkcfg must be little-endian for VIRTIO 1.0 */
397
VuServer *server = container_of(vu_dev, VuServer, vu_dev);
398
- VuBlockDev *vdev_blk = get_vu_block_device_by_server(server);
399
- memcpy(config, &vdev_blk->blkcfg, len);
400
-
401
+ VuBlkExport *vexp = container_of(server, VuBlkExport, vu_server);
402
+ memcpy(config, &vexp->blkcfg, len);
403
return 0;
404
}
405
406
static int
407
-vu_block_set_config(VuDev *vu_dev, const uint8_t *data,
408
+vu_blk_set_config(VuDev *vu_dev, const uint8_t *data,
409
uint32_t offset, uint32_t size, uint32_t flags)
410
{
411
VuServer *server = container_of(vu_dev, VuServer, vu_dev);
412
- VuBlockDev *vdev_blk = get_vu_block_device_by_server(server);
413
+ VuBlkExport *vexp = container_of(server, VuBlkExport, vu_server);
414
uint8_t wce;
415
416
/* don't support live migration */
417
@@ -XXX,XX +XXX,XX @@ vu_block_set_config(VuDev *vu_dev, const uint8_t *data,
418
}
419
420
wce = *data;
421
- vdev_blk->blkcfg.wce = wce;
422
- blk_set_enable_write_cache(vdev_blk->backend, wce);
423
+ vexp->blkcfg.wce = wce;
424
+ blk_set_enable_write_cache(vexp->export.blk, wce);
425
return 0;
426
}
427
428
@@ -XXX,XX +XXX,XX @@ vu_block_set_config(VuDev *vu_dev, const uint8_t *data,
429
* of vu_process_message.
430
*
431
*/
432
-static int vu_block_process_msg(VuDev *dev, VhostUserMsg *vmsg, int *do_reply)
433
+static int vu_blk_process_msg(VuDev *dev, VhostUserMsg *vmsg, int *do_reply)
434
{
435
if (vmsg->request == VHOST_USER_NONE) {
436
dev->panic(dev, "disconnect");
437
@@ -XXX,XX +XXX,XX @@ static int vu_block_process_msg(VuDev *dev, VhostUserMsg *vmsg, int *do_reply)
438
return false;
439
}
440
441
-static const VuDevIface vu_block_iface = {
442
- .get_features = vu_block_get_features,
443
- .queue_set_started = vu_block_queue_set_started,
444
- .get_protocol_features = vu_block_get_protocol_features,
445
- .get_config = vu_block_get_config,
446
- .set_config = vu_block_set_config,
447
- .process_msg = vu_block_process_msg,
448
+static const VuDevIface vu_blk_iface = {
449
+ .get_features = vu_blk_get_features,
450
+ .queue_set_started = vu_blk_queue_set_started,
451
+ .get_protocol_features = vu_blk_get_protocol_features,
452
+ .get_config = vu_blk_get_config,
453
+ .set_config = vu_blk_set_config,
454
+ .process_msg = vu_blk_process_msg,
455
};
456
457
static void blk_aio_attached(AioContext *ctx, void *opaque)
458
{
459
- VuBlockDev *vub_dev = opaque;
460
- vhost_user_server_attach_aio_context(&vub_dev->vu_server, ctx);
461
+ VuBlkExport *vexp = opaque;
462
+ vhost_user_server_attach_aio_context(&vexp->vu_server, ctx);
463
}
464
465
static void blk_aio_detach(void *opaque)
466
{
467
- VuBlockDev *vub_dev = opaque;
468
- vhost_user_server_detach_aio_context(&vub_dev->vu_server);
469
+ VuBlkExport *vexp = opaque;
470
+ vhost_user_server_detach_aio_context(&vexp->vu_server);
471
}
472
473
static void
474
-vu_block_initialize_config(BlockDriverState *bs,
475
+vu_blk_initialize_config(BlockDriverState *bs,
476
struct virtio_blk_config *config, uint32_t blk_size)
477
{
478
config->capacity = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
479
@@ -XXX,XX +XXX,XX @@ vu_block_initialize_config(BlockDriverState *bs,
480
config->max_write_zeroes_seg = 1;
481
}
482
483
-static VuBlockDev *vu_block_init(VuBlockDev *vu_block_device, Error **errp)
484
+static void vu_blk_exp_request_shutdown(BlockExport *exp)
485
{
486
+ VuBlkExport *vexp = container_of(exp, VuBlkExport, export);
487
488
- BlockBackend *blk;
489
- Error *local_error = NULL;
490
- const char *node_name = vu_block_device->node_name;
491
- bool writable = vu_block_device->writable;
492
- uint64_t perm = BLK_PERM_CONSISTENT_READ;
493
- int ret;
494
-
495
- AioContext *ctx;
496
-
497
- BlockDriverState *bs = bdrv_lookup_bs(node_name, node_name, &local_error);
498
-
499
- if (!bs) {
500
- error_propagate(errp, local_error);
501
- return NULL;
502
- }
503
-
504
- if (bdrv_is_read_only(bs)) {
505
- writable = false;
506
- }
507
-
508
- if (writable) {
509
- perm |= BLK_PERM_WRITE;
510
- }
511
-
512
- ctx = bdrv_get_aio_context(bs);
513
- aio_context_acquire(ctx);
514
- bdrv_invalidate_cache(bs, NULL);
515
- aio_context_release(ctx);
516
-
517
- /*
518
- * Don't allow resize while the vhost user server is running,
519
- * otherwise we don't care what happens with the node.
520
- */
521
- blk = blk_new(bdrv_get_aio_context(bs), perm,
522
- BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
523
- BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD);
524
- ret = blk_insert_bs(blk, bs, errp);
525
-
526
- if (ret < 0) {
527
- goto fail;
528
- }
529
-
530
- blk_set_enable_write_cache(blk, false);
531
-
532
- blk_set_allow_aio_context_change(blk, true);
533
-
534
- vu_block_device->blkcfg.wce = 0;
535
- vu_block_device->backend = blk;
536
- if (!vu_block_device->blk_size) {
537
- vu_block_device->blk_size = BDRV_SECTOR_SIZE;
538
- }
539
- vu_block_device->blkcfg.blk_size = vu_block_device->blk_size;
540
- blk_set_guest_block_size(blk, vu_block_device->blk_size);
541
- vu_block_initialize_config(bs, &vu_block_device->blkcfg,
542
- vu_block_device->blk_size);
543
- return vu_block_device;
544
-
545
-fail:
546
- blk_unref(blk);
547
- return NULL;
548
-}
549
-
550
-static void vu_block_deinit(VuBlockDev *vu_block_device)
551
-{
552
- if (vu_block_device->backend) {
553
- blk_remove_aio_context_notifier(vu_block_device->backend, blk_aio_attached,
554
- blk_aio_detach, vu_block_device);
555
- }
556
-
557
- blk_unref(vu_block_device->backend);
558
-}
559
-
560
-static void vhost_user_blk_server_stop(VuBlockDev *vu_block_device)
561
-{
562
- vhost_user_server_stop(&vu_block_device->vu_server);
563
- vu_block_deinit(vu_block_device);
564
-}
565
-
566
-static void vhost_user_blk_server_start(VuBlockDev *vu_block_device,
567
- Error **errp)
568
-{
569
- AioContext *ctx;
570
- SocketAddress *addr = vu_block_device->addr;
571
-
572
- if (!vu_block_init(vu_block_device, errp)) {
573
- return;
574
- }
575
-
576
- ctx = bdrv_get_aio_context(blk_bs(vu_block_device->backend));
577
-
578
- if (!vhost_user_server_start(&vu_block_device->vu_server, addr, ctx,
579
- VHOST_USER_BLK_MAX_QUEUES, &vu_block_iface,
580
- errp)) {
581
- goto error;
582
- }
583
-
584
- blk_add_aio_context_notifier(vu_block_device->backend, blk_aio_attached,
585
- blk_aio_detach, vu_block_device);
586
- vu_block_device->running = true;
587
- return;
588
-
589
- error:
590
- vu_block_deinit(vu_block_device);
591
-}
592
-
593
-static bool vu_prop_modifiable(VuBlockDev *vus, Error **errp)
594
-{
595
- if (vus->running) {
596
- error_setg(errp, "The property can't be modified "
597
- "while the server is running");
598
- return false;
599
- }
600
- return true;
601
-}
602
-
603
-static void vu_set_node_name(Object *obj, const char *value, Error **errp)
604
-{
605
- VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
606
-
607
- if (!vu_prop_modifiable(vus, errp)) {
608
- return;
609
- }
610
-
611
- if (vus->node_name) {
612
- g_free(vus->node_name);
613
- }
614
-
615
- vus->node_name = g_strdup(value);
616
-}
617
-
618
-static char *vu_get_node_name(Object *obj, Error **errp)
619
-{
620
- VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
621
- return g_strdup(vus->node_name);
622
-}
623
-
624
-static void free_socket_addr(SocketAddress *addr)
625
-{
626
- g_free(addr->u.q_unix.path);
627
- g_free(addr);
628
-}
629
-
630
-static void vu_set_unix_socket(Object *obj, const char *value,
631
- Error **errp)
632
-{
633
- VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
634
-
635
- if (!vu_prop_modifiable(vus, errp)) {
636
- return;
637
- }
638
-
639
- if (vus->addr) {
640
- free_socket_addr(vus->addr);
641
- }
642
-
643
- SocketAddress *addr = g_new0(SocketAddress, 1);
644
- addr->type = SOCKET_ADDRESS_TYPE_UNIX;
645
- addr->u.q_unix.path = g_strdup(value);
646
- vus->addr = addr;
647
+ vhost_user_server_stop(&vexp->vu_server);
648
}
649
650
-static char *vu_get_unix_socket(Object *obj, Error **errp)
651
+static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
652
+ Error **errp)
653
{
654
- VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
655
- return g_strdup(vus->addr->u.q_unix.path);
656
-}
657
-
658
-static bool vu_get_block_writable(Object *obj, Error **errp)
659
-{
660
- VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
661
- return vus->writable;
662
-}
663
-
664
-static void vu_set_block_writable(Object *obj, bool value, Error **errp)
665
-{
666
- VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
667
-
668
- if (!vu_prop_modifiable(vus, errp)) {
669
- return;
670
- }
671
-
672
- vus->writable = value;
673
-}
674
-
675
-static void vu_get_blk_size(Object *obj, Visitor *v, const char *name,
676
- void *opaque, Error **errp)
677
-{
678
- VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
679
- uint32_t value = vus->blk_size;
680
-
681
- visit_type_uint32(v, name, &value, errp);
682
-}
683
-
684
-static void vu_set_blk_size(Object *obj, Visitor *v, const char *name,
685
- void *opaque, Error **errp)
686
-{
687
- VuBlockDev *vus = VHOST_USER_BLK_SERVER(obj);
688
-
689
+ VuBlkExport *vexp = container_of(exp, VuBlkExport, export);
690
+ BlockExportOptionsVhostUserBlk *vu_opts = &opts->u.vhost_user_blk;
691
Error *local_err = NULL;
692
- uint32_t value;
693
+ uint64_t logical_block_size;
694
695
- if (!vu_prop_modifiable(vus, errp)) {
696
- return;
697
- }
698
+ vexp->writable = opts->writable;
699
+ vexp->blkcfg.wce = 0;
700
701
- visit_type_uint32(v, name, &value, &local_err);
702
- if (local_err) {
703
- goto out;
704
+ if (vu_opts->has_logical_block_size) {
705
+ logical_block_size = vu_opts->logical_block_size;
706
+ } else {
707
+ logical_block_size = BDRV_SECTOR_SIZE;
708
}
709
-
710
- check_block_size(object_get_typename(obj), name, value, &local_err);
711
+ check_block_size(exp->id, "logical-block-size", logical_block_size,
712
+ &local_err);
713
if (local_err) {
714
- goto out;
715
+ error_propagate(errp, local_err);
716
+ return -EINVAL;
717
+ }
718
+ vexp->blk_size = logical_block_size;
719
+ blk_set_guest_block_size(exp->blk, logical_block_size);
720
+ vu_blk_initialize_config(blk_bs(exp->blk), &vexp->blkcfg,
721
+ logical_block_size);
722
+
723
+ blk_set_allow_aio_context_change(exp->blk, true);
724
+ blk_add_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
725
+ vexp);
726
+
727
+ if (!vhost_user_server_start(&vexp->vu_server, vu_opts->addr, exp->ctx,
728
+ VHOST_USER_BLK_MAX_QUEUES, &vu_blk_iface,
729
+ errp)) {
730
+ blk_remove_aio_context_notifier(exp->blk, blk_aio_attached,
731
+ blk_aio_detach, vexp);
732
+ return -EADDRNOTAVAIL;
733
}
734
735
- vus->blk_size = value;
736
-
737
-out:
738
- error_propagate(errp, local_err);
739
-}
740
-
741
-static void vhost_user_blk_server_instance_finalize(Object *obj)
742
-{
743
- VuBlockDev *vub = VHOST_USER_BLK_SERVER(obj);
744
-
745
- vhost_user_blk_server_stop(vub);
746
-
747
- /*
748
- * Unlike object_property_add_str, object_class_property_add_str
749
- * doesn't have a release method. Thus manual memory freeing is
750
- * needed.
751
- */
752
- free_socket_addr(vub->addr);
753
- g_free(vub->node_name);
754
-}
755
-
756
-static void vhost_user_blk_server_complete(UserCreatable *obj, Error **errp)
757
-{
758
- VuBlockDev *vub = VHOST_USER_BLK_SERVER(obj);
759
-
760
- vhost_user_blk_server_start(vub, errp);
761
+ return 0;
762
}
763
764
-static void vhost_user_blk_server_class_init(ObjectClass *klass,
765
- void *class_data)
766
+static void vu_blk_exp_delete(BlockExport *exp)
767
{
768
- UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
769
- ucc->complete = vhost_user_blk_server_complete;
770
-
771
- object_class_property_add_bool(klass, "writable",
772
- vu_get_block_writable,
773
- vu_set_block_writable);
774
-
775
- object_class_property_add_str(klass, "node-name",
776
- vu_get_node_name,
777
- vu_set_node_name);
778
-
779
- object_class_property_add_str(klass, "unix-socket",
780
- vu_get_unix_socket,
781
- vu_set_unix_socket);
782
+ VuBlkExport *vexp = container_of(exp, VuBlkExport, export);
783
784
- object_class_property_add(klass, "logical-block-size", "uint32",
785
- vu_get_blk_size, vu_set_blk_size,
786
- NULL, NULL);
787
+ blk_remove_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
788
+ vexp);
789
}
790
791
-static const TypeInfo vhost_user_blk_server_info = {
792
- .name = TYPE_VHOST_USER_BLK_SERVER,
793
- .parent = TYPE_OBJECT,
794
- .instance_size = sizeof(VuBlockDev),
795
- .instance_finalize = vhost_user_blk_server_instance_finalize,
796
- .class_init = vhost_user_blk_server_class_init,
797
- .interfaces = (InterfaceInfo[]) {
798
- {TYPE_USER_CREATABLE},
799
- {}
800
- },
801
+const BlockExportDriver blk_exp_vhost_user_blk = {
802
+ .type = BLOCK_EXPORT_TYPE_VHOST_USER_BLK,
803
+ .instance_size = sizeof(VuBlkExport),
804
+ .create = vu_blk_exp_create,
805
+ .delete = vu_blk_exp_delete,
806
+ .request_shutdown = vu_blk_exp_request_shutdown,
807
};
808
-
809
-static void vhost_user_blk_server_register_types(void)
810
-{
811
- type_register_static(&vhost_user_blk_server_info);
812
-}
813
-
814
-type_init(vhost_user_blk_server_register_types)
815
diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk-test.c
816
index XXXXXXX..XXXXXXX 100644
817
--- a/tests/qtest/vhost-user-blk-test.c
818
+++ b/tests/qtest/vhost-user-blk-test.c
819
@@ -XXX,XX +XXX,XX @@ static char *start_vhost_user_blk(GString *cmd_line, int vus_instances)
820
img_path = drive_create();
821
g_string_append_printf(storage_daemon_command,
822
"--blockdev driver=file,node-name=disk%d,filename=%s "
823
- "--object vhost-user-blk-server,id=disk%d,unix-socket=%s,"
824
+ "--export type=vhost-user-blk,id=disk%d,addr.type=unix,addr.path=%s,"
825
"node-name=disk%i,writable=on ",
826
i, img_path, i, sock_path, i);
827
828
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
829
index XXXXXXX..XXXXXXX 100644
830
--- a/util/vhost-user-server.c
831
+++ b/util/vhost-user-server.c
832
@@ -XXX,XX +XXX,XX @@ bool vhost_user_server_start(VuServer *server,
833
Error **errp)
834
{
835
QEMUBH *bh;
836
- QIONetListener *listener = qio_net_listener_new();
837
+ QIONetListener *listener;
838
+
839
+ if (socket_addr->type != SOCKET_ADDRESS_TYPE_UNIX &&
840
+ socket_addr->type != SOCKET_ADDRESS_TYPE_FD) {
841
+ error_setg(errp, "Only socket address types 'unix' and 'fd' are supported");
842
+ return false;
843
+ }
844
+
845
+ listener = qio_net_listener_new();
846
if (qio_net_listener_open_sync(listener, socket_addr, 1,
847
errp) < 0) {
848
object_unref(OBJECT(listener));
849
diff --git a/block/export/meson.build b/block/export/meson.build
850
index XXXXXXX..XXXXXXX 100644
851
--- a/block/export/meson.build
852
+++ b/block/export/meson.build
853
@@ -1 +1,2 @@
854
block_ss.add(files('export.c'))
855
+block_ss.add(when: 'CONFIG_LINUX', if_true: files('vhost-user-blk-server.c', '../../contrib/libvhost-user/libvhost-user.c'))
856
diff --git a/block/meson.build b/block/meson.build
857
index XXXXXXX..XXXXXXX 100644
858
--- a/block/meson.build
859
+++ b/block/meson.build
860
@@ -XXX,XX +XXX,XX @@ block_ss.add(when: 'CONFIG_WIN32', if_true: files('file-win32.c', 'win32-aio.c')
861
block_ss.add(when: 'CONFIG_POSIX', if_true: [files('file-posix.c'), coref, iokit])
862
block_ss.add(when: 'CONFIG_LIBISCSI', if_true: files('iscsi-opts.c'))
863
block_ss.add(when: 'CONFIG_LINUX', if_true: files('nvme.c'))
864
-block_ss.add(when: 'CONFIG_LINUX', if_true: files('export/vhost-user-blk-server.c', '../contrib/libvhost-user/libvhost-user.c'))
865
block_ss.add(when: 'CONFIG_REPLICATION', if_true: files('replication.c'))
866
block_ss.add(when: 'CONFIG_SHEEPDOG', if_true: files('sheepdog.c'))
867
block_ss.add(when: ['CONFIG_LINUX_AIO', libaio], if_true: files('linux-aio.c'))
61
--
868
--
62
2.24.1
869
2.26.2
63
870
64
diff view generated by jsdifflib
1
Just rm will not delete external data files. Use _rm_test_img every
1
Headers used by other subsystems are located in include/. Also add the
2
time we delete a test image.
2
vhost-user-server and vhost-user-blk-server headers to MAINTAINERS.
3
3
4
(In the process, clean up the indentation of every _cleanup() this patch
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
touches.)
5
Message-id: 20200924151549.913737-13-stefanha@redhat.com
6
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
---
8
MAINTAINERS | 4 +++-
9
{util => include/qemu}/vhost-user-server.h | 0
10
block/export/vhost-user-blk-server.c | 2 +-
11
util/vhost-user-server.c | 2 +-
12
4 files changed, 5 insertions(+), 3 deletions(-)
13
rename {util => include/qemu}/vhost-user-server.h (100%)
6
14
7
((Also, use quotes consistently. I am happy to see unquoted instances
15
diff --git a/MAINTAINERS b/MAINTAINERS
8
like "rm -rf $TEST_DIR/..." go.))
16
index XXXXXXX..XXXXXXX 100644
17
--- a/MAINTAINERS
18
+++ b/MAINTAINERS
19
@@ -XXX,XX +XXX,XX @@ Vhost-user block device backend server
20
M: Coiby Xu <Coiby.Xu@gmail.com>
21
S: Maintained
22
F: block/export/vhost-user-blk-server.c
23
-F: util/vhost-user-server.c
24
+F: block/export/vhost-user-blk-server.h
25
+F: include/qemu/vhost-user-server.h
26
F: tests/qtest/vhost-user-blk-test.c
27
F: tests/qtest/libqos/vhost-user-blk.c
28
+F: util/vhost-user-server.c
29
30
Replication
31
M: Wen Congyang <wencongyang2@huawei.com>
32
diff --git a/util/vhost-user-server.h b/include/qemu/vhost-user-server.h
33
similarity index 100%
34
rename from util/vhost-user-server.h
35
rename to include/qemu/vhost-user-server.h
36
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/block/export/vhost-user-blk-server.c
39
+++ b/block/export/vhost-user-blk-server.c
40
@@ -XXX,XX +XXX,XX @@
41
#include "block/block.h"
42
#include "contrib/libvhost-user/libvhost-user.h"
43
#include "standard-headers/linux/virtio_blk.h"
44
-#include "util/vhost-user-server.h"
45
+#include "qemu/vhost-user-server.h"
46
#include "vhost-user-blk-server.h"
47
#include "qapi/error.h"
48
#include "qom/object_interfaces.h"
49
diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/util/vhost-user-server.c
52
+++ b/util/vhost-user-server.c
53
@@ -XXX,XX +XXX,XX @@
54
*/
55
#include "qemu/osdep.h"
56
#include "qemu/main-loop.h"
57
+#include "qemu/vhost-user-server.h"
58
#include "block/aio-wait.h"
59
-#include "vhost-user-server.h"
60
61
/*
62
* Theory of operation:
63
--
64
2.26.2
9
65
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
12
Message-id: 20191107163708.833192-16-mreitz@redhat.com
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
tests/qemu-iotests/019 | 6 +++---
16
tests/qemu-iotests/020 | 6 +++---
17
tests/qemu-iotests/024 | 10 +++++-----
18
tests/qemu-iotests/028 | 2 +-
19
tests/qemu-iotests/029 | 2 +-
20
tests/qemu-iotests/043 | 4 +++-
21
tests/qemu-iotests/048 | 2 +-
22
tests/qemu-iotests/050 | 4 ++--
23
tests/qemu-iotests/053 | 4 ++--
24
tests/qemu-iotests/058 | 2 +-
25
tests/qemu-iotests/059 | 2 +-
26
tests/qemu-iotests/061 | 2 +-
27
tests/qemu-iotests/063 | 6 ++++--
28
tests/qemu-iotests/069 | 2 +-
29
tests/qemu-iotests/074 | 2 +-
30
tests/qemu-iotests/080 | 2 +-
31
tests/qemu-iotests/081 | 6 +++---
32
tests/qemu-iotests/085 | 9 ++++++---
33
tests/qemu-iotests/088 | 2 +-
34
tests/qemu-iotests/092 | 2 +-
35
tests/qemu-iotests/094 | 2 +-
36
tests/qemu-iotests/095 | 5 +++--
37
tests/qemu-iotests/099 | 7 ++++---
38
tests/qemu-iotests/109 | 4 ++--
39
tests/qemu-iotests/110 | 4 ++--
40
tests/qemu-iotests/122 | 6 ++++--
41
tests/qemu-iotests/123 | 2 +-
42
tests/qemu-iotests/141 | 4 +++-
43
tests/qemu-iotests/142 | 2 +-
44
tests/qemu-iotests/144 | 4 +++-
45
tests/qemu-iotests/153 | 10 +++-------
46
tests/qemu-iotests/156 | 8 ++++++--
47
tests/qemu-iotests/159 | 2 +-
48
tests/qemu-iotests/160 | 3 ++-
49
tests/qemu-iotests/161 | 4 ++--
50
tests/qemu-iotests/170 | 2 +-
51
tests/qemu-iotests/172 | 6 +++---
52
tests/qemu-iotests/173 | 3 ++-
53
tests/qemu-iotests/178 | 2 +-
54
tests/qemu-iotests/182 | 2 +-
55
tests/qemu-iotests/183 | 2 +-
56
tests/qemu-iotests/185 | 4 ++--
57
tests/qemu-iotests/187 | 6 +++---
58
tests/qemu-iotests/190 | 2 +-
59
tests/qemu-iotests/191 | 6 +++---
60
tests/qemu-iotests/195 | 2 +-
61
tests/qemu-iotests/197 | 2 +-
62
tests/qemu-iotests/200 | 3 ++-
63
tests/qemu-iotests/215 | 2 +-
64
tests/qemu-iotests/225 | 2 +-
65
tests/qemu-iotests/229 | 3 ++-
66
tests/qemu-iotests/232 | 4 +++-
67
tests/qemu-iotests/243 | 2 +-
68
tests/qemu-iotests/244 | 4 ++--
69
tests/qemu-iotests/247 | 4 +++-
70
tests/qemu-iotests/249 | 4 ++--
71
tests/qemu-iotests/252 | 2 +-
72
57 files changed, 118 insertions(+), 95 deletions(-)
73
74
diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019
75
index XXXXXXX..XXXXXXX 100755
76
--- a/tests/qemu-iotests/019
77
+++ b/tests/qemu-iotests/019
78
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
79
80
_cleanup()
81
{
82
-    _cleanup_test_img
83
- rm -f "$TEST_IMG.base"
84
- rm -f "$TEST_IMG.orig"
85
+ _cleanup_test_img
86
+ _rm_test_img "$TEST_IMG.base"
87
+ _rm_test_img "$TEST_IMG.orig"
88
}
89
trap "_cleanup; exit \$status" 0 1 2 3 15
90
91
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
92
index XXXXXXX..XXXXXXX 100755
93
--- a/tests/qemu-iotests/020
94
+++ b/tests/qemu-iotests/020
95
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
96
97
_cleanup()
98
{
99
-    _cleanup_test_img
100
- rm -f "$TEST_IMG.base"
101
- rm -f "$TEST_IMG.orig"
102
+ _cleanup_test_img
103
+ _rm_test_img "$TEST_IMG.base"
104
+ _rm_test_img "$TEST_IMG.orig"
105
}
106
trap "_cleanup; exit \$status" 0 1 2 3 15
107
108
diff --git a/tests/qemu-iotests/024 b/tests/qemu-iotests/024
109
index XXXXXXX..XXXXXXX 100755
110
--- a/tests/qemu-iotests/024
111
+++ b/tests/qemu-iotests/024
112
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
113
_cleanup()
114
{
115
_cleanup_test_img
116
- rm -f "$TEST_DIR/t.$IMGFMT.base_old"
117
- rm -f "$TEST_DIR/t.$IMGFMT.base_new"
118
+ _rm_test_img "$TEST_DIR/t.$IMGFMT.base_old"
119
+ _rm_test_img "$TEST_DIR/t.$IMGFMT.base_new"
120
121
- rm -f "$TEST_DIR/subdir/t.$IMGFMT"
122
- rm -f "$TEST_DIR/subdir/t.$IMGFMT.base_old"
123
- rm -f "$TEST_DIR/subdir/t.$IMGFMT.base_new"
124
+ _rm_test_img "$TEST_DIR/subdir/t.$IMGFMT"
125
+ _rm_test_img "$TEST_DIR/subdir/t.$IMGFMT.base_old"
126
+ _rm_test_img "$TEST_DIR/subdir/t.$IMGFMT.base_new"
127
rmdir "$TEST_DIR/subdir" 2> /dev/null
128
}
129
trap "_cleanup; exit \$status" 0 1 2 3 15
130
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
131
index XXXXXXX..XXXXXXX 100755
132
--- a/tests/qemu-iotests/028
133
+++ b/tests/qemu-iotests/028
134
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
135
_cleanup()
136
{
137
_cleanup_qemu
138
- rm -f "${TEST_IMG}.copy"
139
+ _rm_test_img "${TEST_IMG}.copy"
140
_cleanup_test_img
141
}
142
trap "_cleanup; exit \$status" 0 1 2 3 15
143
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
144
index XXXXXXX..XXXXXXX 100755
145
--- a/tests/qemu-iotests/029
146
+++ b/tests/qemu-iotests/029
147
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
148
149
_cleanup()
150
{
151
- rm -f $TEST_IMG.snap
152
+ _rm_test_img "$TEST_IMG.snap"
153
_cleanup_test_img
154
}
155
trap "_cleanup; exit \$status" 0 1 2 3 15
156
diff --git a/tests/qemu-iotests/043 b/tests/qemu-iotests/043
157
index XXXXXXX..XXXXXXX 100755
158
--- a/tests/qemu-iotests/043
159
+++ b/tests/qemu-iotests/043
160
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
161
_cleanup()
162
{
163
_cleanup_test_img
164
- rm -f "$TEST_IMG".[123].base
165
+ for img in "$TEST_IMG".[123].base; do
166
+ _rm_test_img "$img"
167
+ done
168
}
169
trap "_cleanup; exit \$status" 0 1 2 3 15
170
171
diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048
172
index XXXXXXX..XXXXXXX 100755
173
--- a/tests/qemu-iotests/048
174
+++ b/tests/qemu-iotests/048
175
@@ -XXX,XX +XXX,XX @@ _cleanup()
176
{
177
echo "Cleanup"
178
_cleanup_test_img
179
- rm "${TEST_IMG_FILE2}"
180
+ _rm_test_img "${TEST_IMG_FILE2}"
181
}
182
trap "_cleanup; exit \$status" 0 1 2 3 15
183
184
diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050
185
index XXXXXXX..XXXXXXX 100755
186
--- a/tests/qemu-iotests/050
187
+++ b/tests/qemu-iotests/050
188
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
189
_cleanup()
190
{
191
_cleanup_test_img
192
- rm -f "$TEST_IMG.old"
193
- rm -f "$TEST_IMG.new"
194
+ _rm_test_img "$TEST_IMG.old"
195
+ _rm_test_img "$TEST_IMG.new"
196
}
197
trap "_cleanup; exit \$status" 0 1 2 3 15
198
199
diff --git a/tests/qemu-iotests/053 b/tests/qemu-iotests/053
200
index XXXXXXX..XXXXXXX 100755
201
--- a/tests/qemu-iotests/053
202
+++ b/tests/qemu-iotests/053
203
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
204
205
_cleanup()
206
{
207
-    rm -f "$TEST_IMG.orig"
208
-    _cleanup_test_img
209
+ _rm_test_img "$TEST_IMG.orig"
210
+ _cleanup_test_img
211
}
212
trap "_cleanup; exit \$status" 0 1 2 3 15
213
214
diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058
215
index XXXXXXX..XXXXXXX 100755
216
--- a/tests/qemu-iotests/058
217
+++ b/tests/qemu-iotests/058
218
@@ -XXX,XX +XXX,XX @@ _cleanup()
219
{
220
nbd_server_stop
221
_cleanup_test_img
222
- rm -f "$converted_image"
223
+ _rm_test_img "$converted_image"
224
}
225
trap "_cleanup; exit \$status" 0 1 2 3 15
226
227
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
228
index XXXXXXX..XXXXXXX 100755
229
--- a/tests/qemu-iotests/059
230
+++ b/tests/qemu-iotests/059
231
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
232
_cleanup()
233
{
234
_cleanup_test_img
235
- rm -f "$TEST_IMG.qcow2"
236
+ IMGFMT=qcow2 _rm_test_img "$TEST_IMG.qcow2"
237
}
238
trap "_cleanup; exit \$status" 0 1 2 3 15
239
240
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
241
index XXXXXXX..XXXXXXX 100755
242
--- a/tests/qemu-iotests/061
243
+++ b/tests/qemu-iotests/061
244
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
245
_cleanup()
246
{
247
_cleanup_test_img
248
- rm -f $TEST_IMG.data
249
+ _rm_test_img "$TEST_IMG.data"
250
}
251
trap "_cleanup; exit \$status" 0 1 2 3 15
252
253
diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063
254
index XXXXXXX..XXXXXXX 100755
255
--- a/tests/qemu-iotests/063
256
+++ b/tests/qemu-iotests/063
257
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
258
259
_cleanup()
260
{
261
-    _cleanup_test_img
262
-    rm -f "$TEST_IMG.orig" "$TEST_IMG.raw1" "$TEST_IMG.raw2"
263
+ _cleanup_test_img
264
+ for img in "$TEST_IMG".{orig,raw1,raw2,target}; do
265
+ _rm_test_img "$img"
266
+ done
267
}
268
trap "_cleanup; exit \$status" 0 1 2 3 15
269
270
diff --git a/tests/qemu-iotests/069 b/tests/qemu-iotests/069
271
index XXXXXXX..XXXXXXX 100755
272
--- a/tests/qemu-iotests/069
273
+++ b/tests/qemu-iotests/069
274
@@ -XXX,XX +XXX,XX @@ echo "=== Creating an image with a backing file and deleting that file ==="
275
echo
276
TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
277
_make_test_img -b "$TEST_IMG.base" $IMG_SIZE
278
-rm -f "$TEST_IMG.base"
279
+_rm_test_img "$TEST_IMG.base"
280
# Just open the image and close it right again (this should print an error message)
281
$QEMU_IO -c quit "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
282
283
diff --git a/tests/qemu-iotests/074 b/tests/qemu-iotests/074
284
index XXXXXXX..XXXXXXX 100755
285
--- a/tests/qemu-iotests/074
286
+++ b/tests/qemu-iotests/074
287
@@ -XXX,XX +XXX,XX @@ _cleanup()
288
{
289
echo "Cleanup"
290
_cleanup_test_img
291
- rm "${TEST_IMG2}"
292
+ _rm_test_img "${TEST_IMG2}"
293
rm -f "$TEST_DIR/blkdebug.conf"
294
}
295
trap "_cleanup; exit \$status" 0 1 2 3 15
296
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
297
index XXXXXXX..XXXXXXX 100755
298
--- a/tests/qemu-iotests/080
299
+++ b/tests/qemu-iotests/080
300
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
301
302
_cleanup()
303
{
304
- rm -f $TEST_IMG.snap
305
+ _rm_test_img "$TEST_IMG.snap"
306
_cleanup_test_img
307
}
308
trap "_cleanup; exit \$status" 0 1 2 3 15
309
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
310
index XXXXXXX..XXXXXXX 100755
311
--- a/tests/qemu-iotests/081
312
+++ b/tests/qemu-iotests/081
313
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
314
315
_cleanup()
316
{
317
- rm -rf $TEST_DIR/1.raw
318
- rm -rf $TEST_DIR/2.raw
319
- rm -rf $TEST_DIR/3.raw
320
+ _rm_test_img "$TEST_DIR/1.raw"
321
+ _rm_test_img "$TEST_DIR/2.raw"
322
+ _rm_test_img "$TEST_DIR/3.raw"
323
}
324
trap "_cleanup; exit \$status" 0 1 2 3 15
325
326
diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085
327
index XXXXXXX..XXXXXXX 100755
328
--- a/tests/qemu-iotests/085
329
+++ b/tests/qemu-iotests/085
330
@@ -XXX,XX +XXX,XX @@ _cleanup()
331
_cleanup_qemu
332
for i in $(seq 1 ${SNAPSHOTS})
333
do
334
- rm -f "${TEST_DIR}/${i}-${snapshot_virt0}"
335
- rm -f "${TEST_DIR}/${i}-${snapshot_virt1}"
336
+ _rm_test_img "${TEST_DIR}/${i}-${snapshot_virt0}"
337
+ _rm_test_img "${TEST_DIR}/${i}-${snapshot_virt1}"
338
+ done
339
+ for img in "${TEST_IMG}".{1,2,base}
340
+ do
341
+ _rm_test_img "$img"
342
done
343
- rm -f "${TEST_IMG}" "${TEST_IMG}.1" "${TEST_IMG}.2" "${TEST_IMG}.base"
344
345
}
346
trap "_cleanup; exit \$status" 0 1 2 3 15
347
diff --git a/tests/qemu-iotests/088 b/tests/qemu-iotests/088
348
index XXXXXXX..XXXXXXX 100755
349
--- a/tests/qemu-iotests/088
350
+++ b/tests/qemu-iotests/088
351
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
352
353
_cleanup()
354
{
355
- rm -f $TEST_IMG.snap
356
+ _rm_test_img "$TEST_IMG.snap"
357
_cleanup_test_img
358
}
359
trap "_cleanup; exit \$status" 0 1 2 3 15
360
diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092
361
index XXXXXXX..XXXXXXX 100755
362
--- a/tests/qemu-iotests/092
363
+++ b/tests/qemu-iotests/092
364
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
365
366
_cleanup()
367
{
368
- rm -f $TEST_IMG.snap
369
+ _rm_test_img "$TEST_IMG.snap"
370
_cleanup_test_img
371
}
372
trap "_cleanup; exit \$status" 0 1 2 3 15
373
diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094
374
index XXXXXXX..XXXXXXX 100755
375
--- a/tests/qemu-iotests/094
376
+++ b/tests/qemu-iotests/094
377
@@ -XXX,XX +XXX,XX @@ _cleanup()
378
{
379
_cleanup_qemu
380
_cleanup_test_img
381
- rm -f "$TEST_DIR/source.$IMGFMT"
382
+ _rm_test_img "$TEST_DIR/source.$IMGFMT"
383
}
384
385
trap "_cleanup; exit \$status" 0 1 2 3 15
386
diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095
387
index XXXXXXX..XXXXXXX 100755
388
--- a/tests/qemu-iotests/095
389
+++ b/tests/qemu-iotests/095
390
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
391
_cleanup()
392
{
393
_cleanup_qemu
394
- rm -f "${TEST_IMG}.base" "${TEST_IMG}.snp1"
395
-    _cleanup_test_img
396
+ _rm_test_img "${TEST_IMG}.base"
397
+ _rm_test_img "${TEST_IMG}.snp1"
398
+ _cleanup_test_img
399
}
400
trap "_cleanup; exit \$status" 0 1 2 3 15
401
402
diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099
403
index XXXXXXX..XXXXXXX 100755
404
--- a/tests/qemu-iotests/099
405
+++ b/tests/qemu-iotests/099
406
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
407
408
_cleanup()
409
{
410
-    _cleanup_test_img
411
+ _cleanup_test_img
412
+ _rm_test_img "$TEST_IMG.compare"
413
+ rm -f "$TEST_DIR/blkdebug.conf"
414
+
415
}
416
trap "_cleanup; exit \$status" 0 1 2 3 15
417
418
@@ -XXX,XX +XXX,XX @@ echo
419
test_qemu "file.driver=blkdebug,file.image.filename=$TEST_IMG"
420
421
422
-rm -f "$TEST_IMG.compare" "$TEST_DIR/blkdebug.conf"
423
-
424
# success, all done
425
echo "*** done"
426
rm -f $seq.full
427
diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109
428
index XXXXXXX..XXXXXXX 100755
429
--- a/tests/qemu-iotests/109
430
+++ b/tests/qemu-iotests/109
431
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
432
_cleanup()
433
{
434
_cleanup_qemu
435
- rm -f $TEST_IMG.src
436
-    _cleanup_test_img
437
+ _rm_test_img "$TEST_IMG.src"
438
+ _cleanup_test_img
439
}
440
trap "_cleanup; exit \$status" 0 1 2 3 15
441
442
diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110
443
index XXXXXXX..XXXXXXX 100755
444
--- a/tests/qemu-iotests/110
445
+++ b/tests/qemu-iotests/110
446
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
447
448
_cleanup()
449
{
450
-    _cleanup_test_img
451
- rm -f "$TEST_IMG.copy"
452
+ _cleanup_test_img
453
+ _rm_test_img "$TEST_IMG.copy"
454
}
455
trap "_cleanup; exit \$status" 0 1 2 3 15
456
457
diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122
458
index XXXXXXX..XXXXXXX 100755
459
--- a/tests/qemu-iotests/122
460
+++ b/tests/qemu-iotests/122
461
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
462
463
_cleanup()
464
{
465
- rm -f "$TEST_IMG".[123]
466
-    _cleanup_test_img
467
+ for img in "$TEST_IMG".[123]; do
468
+ _rm_test_img "$img"
469
+ done
470
+ _cleanup_test_img
471
}
472
trap "_cleanup; exit \$status" 0 1 2 3 15
473
474
diff --git a/tests/qemu-iotests/123 b/tests/qemu-iotests/123
475
index XXXXXXX..XXXXXXX 100755
476
--- a/tests/qemu-iotests/123
477
+++ b/tests/qemu-iotests/123
478
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
479
_cleanup()
480
{
481
_cleanup_test_img
482
- rm -f "$SRC_IMG"
483
+ _rm_test_img "$SRC_IMG"
484
}
485
trap "_cleanup; exit \$status" 0 1 2 3 15
486
487
diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141
488
index XXXXXXX..XXXXXXX 100755
489
--- a/tests/qemu-iotests/141
490
+++ b/tests/qemu-iotests/141
491
@@ -XXX,XX +XXX,XX @@ _cleanup()
492
{
493
_cleanup_qemu
494
_cleanup_test_img
495
- rm -f "$TEST_DIR"/{b,m,o}.$IMGFMT
496
+ for img in "$TEST_DIR"/{b,m,o}.$IMGFMT; do
497
+ _rm_test_img "$img"
498
+ done
499
}
500
trap "_cleanup; exit \$status" 0 1 2 3 15
501
502
diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142
503
index XXXXXXX..XXXXXXX 100755
504
--- a/tests/qemu-iotests/142
505
+++ b/tests/qemu-iotests/142
506
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
507
_cleanup()
508
{
509
_cleanup_test_img
510
- rm -f $TEST_IMG.snap
511
+ _rm_test_img "$TEST_IMG.snap"
512
}
513
trap "_cleanup; exit \$status" 0 1 2 3 15
514
515
diff --git a/tests/qemu-iotests/144 b/tests/qemu-iotests/144
516
index XXXXXXX..XXXXXXX 100755
517
--- a/tests/qemu-iotests/144
518
+++ b/tests/qemu-iotests/144
519
@@ -XXX,XX +XXX,XX @@ TMP_SNAP2=${TEST_DIR}/tmp2.qcow2
520
_cleanup()
521
{
522
_cleanup_qemu
523
- rm -f "${TEST_IMG}" "${TMP_SNAP1}" "${TMP_SNAP2}"
524
+ for img in "${TEST_IMG}" "${TMP_SNAP1}" "${TMP_SNAP2}"; do
525
+ _rm_test_img "$img"
526
+ done
527
}
528
529
trap "_cleanup; exit \$status" 0 1 2 3 15
530
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
531
index XXXXXXX..XXXXXXX 100755
532
--- a/tests/qemu-iotests/153
533
+++ b/tests/qemu-iotests/153
534
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
535
_cleanup()
536
{
537
_cleanup_test_img
538
- rm -f "${TEST_IMG}.base"
539
- rm -f "${TEST_IMG}.overlay"
540
- rm -f "${TEST_IMG}.convert"
541
- rm -f "${TEST_IMG}.a"
542
- rm -f "${TEST_IMG}.b"
543
- rm -f "${TEST_IMG}.c"
544
- rm -f "${TEST_IMG}.lnk"
545
+ for img in "${TEST_IMG}".{base,overlay,convert,a,b,c,lnk}; do
546
+ _rm_test_img "$img"
547
+ done
548
}
549
trap "_cleanup; exit \$status" 0 1 2 3 15
550
551
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
552
index XXXXXXX..XXXXXXX 100755
553
--- a/tests/qemu-iotests/156
554
+++ b/tests/qemu-iotests/156
555
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
556
_cleanup()
557
{
558
_cleanup_qemu
559
- rm -f "$TEST_IMG"{,.target}{,.backing,.overlay}
560
+ for img in "$TEST_IMG"{,.target}{,.backing,.overlay}; do
561
+ _rm_test_img "$img"
562
+ done
563
}
564
trap "_cleanup; exit \$status" 0 1 2 3 15
565
566
@@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \
567
'"status": "null"'
568
569
# Remove the source images
570
-rm -f "$TEST_IMG{,.backing,.overlay}"
571
+for img in "$TEST_IMG{,.backing,.overlay}"; do
572
+ _rm_test_img "$img"
573
+done
574
575
echo
576
577
diff --git a/tests/qemu-iotests/159 b/tests/qemu-iotests/159
578
index XXXXXXX..XXXXXXX 100755
579
--- a/tests/qemu-iotests/159
580
+++ b/tests/qemu-iotests/159
581
@@ -XXX,XX +XXX,XX @@ status=1
582
_cleanup()
583
{
584
_cleanup_test_img
585
- rm -f "$TEST_IMG.out"
586
+ _rm_test_img "$TEST_IMG.out"
587
}
588
trap "_cleanup; exit \$status" 0 1 2 3 15
589
590
diff --git a/tests/qemu-iotests/160 b/tests/qemu-iotests/160
591
index XXXXXXX..XXXXXXX 100755
592
--- a/tests/qemu-iotests/160
593
+++ b/tests/qemu-iotests/160
594
@@ -XXX,XX +XXX,XX @@ status=1
595
_cleanup()
596
{
597
_cleanup_test_img
598
- rm -f "$TEST_IMG.out" "$TEST_IMG.out.dd"
599
+ _rm_test_img "$TEST_IMG.out"
600
+ _rm_test_img "$TEST_IMG.out.dd"
601
}
602
trap "_cleanup; exit \$status" 0 1 2 3 15
603
604
diff --git a/tests/qemu-iotests/161 b/tests/qemu-iotests/161
605
index XXXXXXX..XXXXXXX 100755
606
--- a/tests/qemu-iotests/161
607
+++ b/tests/qemu-iotests/161
608
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
609
_cleanup()
610
{
611
_cleanup_test_img
612
- rm -f "$TEST_IMG.base"
613
- rm -f "$TEST_IMG.int"
614
+ _rm_test_img "$TEST_IMG.base"
615
+ _rm_test_img "$TEST_IMG.int"
616
}
617
trap "_cleanup; exit \$status" 0 1 2 3 15
618
619
diff --git a/tests/qemu-iotests/170 b/tests/qemu-iotests/170
620
index XXXXXXX..XXXXXXX 100755
621
--- a/tests/qemu-iotests/170
622
+++ b/tests/qemu-iotests/170
623
@@ -XXX,XX +XXX,XX @@ status=1
624
_cleanup()
625
{
626
_cleanup_test_img
627
- rm -f "$TEST_IMG.out"
628
+ _rm_test_img "$TEST_IMG.out"
629
}
630
trap "_cleanup; exit \$status" 0 1 2 3 15
631
632
diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172
633
index XXXXXXX..XXXXXXX 100755
634
--- a/tests/qemu-iotests/172
635
+++ b/tests/qemu-iotests/172
636
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
637
638
_cleanup()
639
{
640
-    _cleanup_test_img
641
- rm -f "$TEST_IMG.2"
642
- rm -f "$TEST_IMG.3"
643
+ _cleanup_test_img
644
+ _rm_test_img "$TEST_IMG.2"
645
+ _rm_test_img "$TEST_IMG.3"
646
}
647
trap "_cleanup; exit \$status" 0 1 2 3 15
648
649
diff --git a/tests/qemu-iotests/173 b/tests/qemu-iotests/173
650
index XXXXXXX..XXXXXXX 100755
651
--- a/tests/qemu-iotests/173
652
+++ b/tests/qemu-iotests/173
653
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
654
_cleanup()
655
{
656
_cleanup_qemu
657
- rm -f "${QEMU_TEST_DIR}/image.base" "${QEMU_TEST_DIR}/image.snp1"
658
+ _rm_test_img "${TEST_DIR}/image.base"
659
+ _rm_test_img "${TEST_DIR}/image.snp1"
660
_cleanup_test_img
661
}
662
trap "_cleanup; exit \$status" 0 1 2 3 15
663
diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178
664
index XXXXXXX..XXXXXXX 100755
665
--- a/tests/qemu-iotests/178
666
+++ b/tests/qemu-iotests/178
667
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
668
_cleanup()
669
{
670
_cleanup_test_img
671
- rm -f "$TEST_IMG.converted"
672
+ _rm_test_img "$TEST_IMG.converted"
673
}
674
trap "_cleanup; exit \$status" 0 1 2 3 15
675
676
diff --git a/tests/qemu-iotests/182 b/tests/qemu-iotests/182
677
index XXXXXXX..XXXXXXX 100755
678
--- a/tests/qemu-iotests/182
679
+++ b/tests/qemu-iotests/182
680
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
681
_cleanup()
682
{
683
_cleanup_test_img
684
- rm -f "$TEST_IMG.overlay"
685
+ _rm_test_img "$TEST_IMG.overlay"
686
rm -f "$SOCK_DIR/nbd.socket"
687
}
688
trap "_cleanup; exit \$status" 0 1 2 3 15
689
diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183
690
index XXXXXXX..XXXXXXX 100755
691
--- a/tests/qemu-iotests/183
692
+++ b/tests/qemu-iotests/183
693
@@ -XXX,XX +XXX,XX @@ MIG_SOCKET="${SOCK_DIR}/migrate"
694
_cleanup()
695
{
696
rm -f "${MIG_SOCKET}"
697
- rm -f "${TEST_IMG}.dest"
698
+ _rm_test_img "${TEST_IMG}.dest"
699
_cleanup_test_img
700
_cleanup_qemu
701
}
702
diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185
703
index XXXXXXX..XXXXXXX 100755
704
--- a/tests/qemu-iotests/185
705
+++ b/tests/qemu-iotests/185
706
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
707
708
_cleanup()
709
{
710
- rm -f "${TEST_IMG}.mid"
711
- rm -f "${TEST_IMG}.copy"
712
+ _rm_test_img "${TEST_IMG}.mid"
713
+ _rm_test_img "${TEST_IMG}.copy"
714
_cleanup_test_img
715
_cleanup_qemu
716
}
717
diff --git a/tests/qemu-iotests/187 b/tests/qemu-iotests/187
718
index XXXXXXX..XXXXXXX 100755
719
--- a/tests/qemu-iotests/187
720
+++ b/tests/qemu-iotests/187
721
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
722
723
_cleanup()
724
{
725
-    _cleanup_test_img
726
- rm -f "$TEST_IMG.2"
727
- rm -f "$TEST_IMG.3"
728
+ _cleanup_test_img
729
+ _rm_test_img "$TEST_IMG.2"
730
+ _rm_test_img "$TEST_IMG.3"
731
}
732
trap "_cleanup; exit \$status" 0 1 2 3 15
733
734
diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190
735
index XXXXXXX..XXXXXXX 100755
736
--- a/tests/qemu-iotests/190
737
+++ b/tests/qemu-iotests/190
738
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
739
_cleanup()
740
{
741
_cleanup_test_img
742
- rm -f "$TEST_IMG.converted"
743
+ _rm_test_img "$TEST_IMG.converted"
744
}
745
trap "_cleanup; exit \$status" 0 1 2 3 15
746
747
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
748
index XXXXXXX..XXXXXXX 100755
749
--- a/tests/qemu-iotests/191
750
+++ b/tests/qemu-iotests/191
751
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
752
753
_cleanup()
754
{
755
- rm -f "${TEST_IMG}.mid"
756
- rm -f "${TEST_IMG}.ovl2"
757
- rm -f "${TEST_IMG}.ovl3"
758
+ _rm_test_img "${TEST_IMG}.mid"
759
+ _rm_test_img "${TEST_IMG}.ovl2"
760
+ _rm_test_img "${TEST_IMG}.ovl3"
761
_cleanup_test_img
762
_cleanup_qemu
763
}
764
diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195
765
index XXXXXXX..XXXXXXX 100755
766
--- a/tests/qemu-iotests/195
767
+++ b/tests/qemu-iotests/195
768
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
769
_cleanup()
770
{
771
_cleanup_test_img
772
- rm -f "$TEST_IMG.mid"
773
+ _rm_test_img "$TEST_IMG.mid"
774
}
775
trap "_cleanup; exit \$status" 0 1 2 3 15
776
777
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
778
index XXXXXXX..XXXXXXX 100755
779
--- a/tests/qemu-iotests/197
780
+++ b/tests/qemu-iotests/197
781
@@ -XXX,XX +XXX,XX @@ esac
782
_cleanup()
783
{
784
_cleanup_test_img
785
- rm -f "$TEST_WRAP"
786
+ _rm_test_img "$TEST_WRAP"
787
rm -f "$BLKDBG_CONF"
788
}
789
trap "_cleanup; exit \$status" 0 1 2 3 15
790
diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200
791
index XXXXXXX..XXXXXXX 100755
792
--- a/tests/qemu-iotests/200
793
+++ b/tests/qemu-iotests/200
794
@@ -XXX,XX +XXX,XX @@ status=1 # failure is the default!
795
_cleanup()
796
{
797
_cleanup_qemu
798
- rm -f "${TEST_IMG}" "${BACKING_IMG}"
799
+ _rm_test_img "${TEST_IMG}"
800
+ _rm_test_img "${BACKING_IMG}"
801
}
802
trap "_cleanup; exit \$status" 0 1 2 3 15
803
804
diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215
805
index XXXXXXX..XXXXXXX 100755
806
--- a/tests/qemu-iotests/215
807
+++ b/tests/qemu-iotests/215
808
@@ -XXX,XX +XXX,XX @@ esac
809
_cleanup()
810
{
811
_cleanup_test_img
812
- rm -f "$TEST_WRAP"
813
+ _rm_test_img "$TEST_WRAP"
814
rm -f "$BLKDBG_CONF"
815
}
816
trap "_cleanup; exit \$status" 0 1 2 3 15
817
diff --git a/tests/qemu-iotests/225 b/tests/qemu-iotests/225
818
index XXXXXXX..XXXXXXX 100755
819
--- a/tests/qemu-iotests/225
820
+++ b/tests/qemu-iotests/225
821
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
822
_cleanup()
823
{
824
_cleanup_test_img
825
- rm -f "$TEST_IMG.not_base"
826
+ _rm_test_img "$TEST_IMG.not_base"
827
}
828
trap "_cleanup; exit \$status" 0 1 2 3 15
829
830
diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229
831
index XXXXXXX..XXXXXXX 100755
832
--- a/tests/qemu-iotests/229
833
+++ b/tests/qemu-iotests/229
834
@@ -XXX,XX +XXX,XX @@ _cleanup()
835
{
836
_cleanup_qemu
837
_cleanup_test_img
838
- rm -f "$TEST_IMG" "$DEST_IMG"
839
+ _rm_test_img "$TEST_IMG"
840
+ _rm_test_img "$DEST_IMG"
841
}
842
trap "_cleanup; exit \$status" 0 1 2 3 15
843
844
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
845
index XXXXXXX..XXXXXXX 100755
846
--- a/tests/qemu-iotests/232
847
+++ b/tests/qemu-iotests/232
848
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
849
_cleanup()
850
{
851
_cleanup_test_img
852
- rm -f $TEST_IMG.[01234]
853
+ for img in "$TEST_IMG".[01234]; do
854
+ _rm_test_img "$img"
855
+ done
856
}
857
trap "_cleanup; exit \$status" 0 1 2 3 15
858
859
diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243
860
index XXXXXXX..XXXXXXX 100755
861
--- a/tests/qemu-iotests/243
862
+++ b/tests/qemu-iotests/243
863
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
864
_cleanup()
865
{
866
_cleanup_test_img
867
- rm -f $TEST_IMG.data
868
+ _rm_test_img "$TEST_IMG.data"
869
}
870
trap "_cleanup; exit \$status" 0 1 2 3 15
871
872
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
873
index XXXXXXX..XXXXXXX 100755
874
--- a/tests/qemu-iotests/244
875
+++ b/tests/qemu-iotests/244
876
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
877
_cleanup()
878
{
879
_cleanup_test_img
880
- rm -f $TEST_IMG.data
881
- rm -f $TEST_IMG.src
882
+ _rm_test_img "$TEST_IMG.data"
883
+ _rm_test_img "$TEST_IMG.src"
884
}
885
trap "_cleanup; exit \$status" 0 1 2 3 15
886
887
diff --git a/tests/qemu-iotests/247 b/tests/qemu-iotests/247
888
index XXXXXXX..XXXXXXX 100755
889
--- a/tests/qemu-iotests/247
890
+++ b/tests/qemu-iotests/247
891
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
892
_cleanup()
893
{
894
_cleanup_test_img
895
- rm -f $TEST_IMG.[01234]
896
+ for img in "$TEST_IMG".[01234]; do
897
+ _rm_test_img "$img"
898
+ done
899
}
900
trap "_cleanup; exit \$status" 0 1 2 3 15
901
902
diff --git a/tests/qemu-iotests/249 b/tests/qemu-iotests/249
903
index XXXXXXX..XXXXXXX 100755
904
--- a/tests/qemu-iotests/249
905
+++ b/tests/qemu-iotests/249
906
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
907
_cleanup()
908
{
909
_cleanup_test_img
910
- rm -f "$TEST_IMG.base"
911
- rm -f "$TEST_IMG.int"
912
+ _rm_test_img "$TEST_IMG.base"
913
+ _rm_test_img "$TEST_IMG.int"
914
}
915
trap "_cleanup; exit \$status" 0 1 2 3 15
916
917
diff --git a/tests/qemu-iotests/252 b/tests/qemu-iotests/252
918
index XXXXXXX..XXXXXXX 100755
919
--- a/tests/qemu-iotests/252
920
+++ b/tests/qemu-iotests/252
921
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
922
_cleanup()
923
{
924
_cleanup_test_img
925
- rm -f "$TEST_IMG.base_new"
926
+ _rm_test_img "$TEST_IMG.base_new"
927
}
928
trap "_cleanup; exit \$status" 0 1 2 3 15
929
930
--
931
2.24.1
932
933
diff view generated by jsdifflib
1
Blindly overriding IMGOPTS is suboptimal as this discards user-specified
1
Don't compile contrib/libvhost-user/libvhost-user.c again. Instead build
2
options. Whatever options the test needs should simply be appended.
2
the static library once and then reuse it throughout QEMU.
3
3
4
Some tests do this (with IMGOPTS=$(_optstr_add "$IMGOPTS" "...")), but
4
Also switch from CONFIG_LINUX to CONFIG_VHOST_USER, which is what the
5
that is cumbersome. It’s simpler to just give _make_test_img an -o
5
vhost-user tools (vhost-user-gpu, etc) do.
6
parameter with which tests can add options.
7
6
8
Some tests actually must override the user-specified options, though,
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
for example when creating an image in a different format than the test
8
Message-id: 20200924151549.913737-14-stefanha@redhat.com
10
$IMGFMT. For such cases, --no-opts allows clearing the current option
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
list.
10
---
11
block/export/export.c | 8 ++++----
12
block/export/meson.build | 2 +-
13
contrib/libvhost-user/meson.build | 1 +
14
meson.build | 6 +++++-
15
tests/qtest/meson.build | 2 +-
16
util/meson.build | 4 +++-
17
6 files changed, 15 insertions(+), 8 deletions(-)
12
18
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
diff --git a/block/export/export.c b/block/export/export.c
14
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
20
index XXXXXXX..XXXXXXX 100644
15
Message-id: 20191107163708.833192-10-mreitz@redhat.com
21
--- a/block/export/export.c
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
22
+++ b/block/export/export.c
17
---
23
@@ -XXX,XX +XXX,XX @@
18
tests/qemu-iotests/common.rc | 13 +++++++++++++
24
#include "sysemu/block-backend.h"
19
1 file changed, 13 insertions(+)
25
#include "block/export.h"
26
#include "block/nbd.h"
27
-#if CONFIG_LINUX
28
-#include "block/export/vhost-user-blk-server.h"
29
-#endif
30
#include "qapi/error.h"
31
#include "qapi/qapi-commands-block-export.h"
32
#include "qapi/qapi-events-block-export.h"
33
#include "qemu/id.h"
34
+#ifdef CONFIG_VHOST_USER
35
+#include "vhost-user-blk-server.h"
36
+#endif
37
38
static const BlockExportDriver *blk_exp_drivers[] = {
39
&blk_exp_nbd,
40
-#if CONFIG_LINUX
41
+#ifdef CONFIG_VHOST_USER
42
&blk_exp_vhost_user_blk,
43
#endif
44
};
45
diff --git a/block/export/meson.build b/block/export/meson.build
46
index XXXXXXX..XXXXXXX 100644
47
--- a/block/export/meson.build
48
+++ b/block/export/meson.build
49
@@ -XXX,XX +XXX,XX @@
50
block_ss.add(files('export.c'))
51
-block_ss.add(when: 'CONFIG_LINUX', if_true: files('vhost-user-blk-server.c', '../../contrib/libvhost-user/libvhost-user.c'))
52
+block_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user-blk-server.c'))
53
diff --git a/contrib/libvhost-user/meson.build b/contrib/libvhost-user/meson.build
54
index XXXXXXX..XXXXXXX 100644
55
--- a/contrib/libvhost-user/meson.build
56
+++ b/contrib/libvhost-user/meson.build
57
@@ -XXX,XX +XXX,XX @@
58
libvhost_user = static_library('vhost-user',
59
files('libvhost-user.c', 'libvhost-user-glib.c'),
60
build_by_default: false)
61
+vhost_user = declare_dependency(link_with: libvhost_user)
62
diff --git a/meson.build b/meson.build
63
index XXXXXXX..XXXXXXX 100644
64
--- a/meson.build
65
+++ b/meson.build
66
@@ -XXX,XX +XXX,XX @@ trace_events_subdirs += [
67
'util',
68
]
69
70
+vhost_user = not_found
71
+if 'CONFIG_VHOST_USER' in config_host
72
+ subdir('contrib/libvhost-user')
73
+endif
74
+
75
subdir('qapi')
76
subdir('qobject')
77
subdir('stubs')
78
@@ -XXX,XX +XXX,XX @@ if have_tools
79
install: true)
80
81
if 'CONFIG_VHOST_USER' in config_host
82
- subdir('contrib/libvhost-user')
83
subdir('contrib/vhost-user-blk')
84
subdir('contrib/vhost-user-gpu')
85
subdir('contrib/vhost-user-input')
86
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
87
index XXXXXXX..XXXXXXX 100644
88
--- a/tests/qtest/meson.build
89
+++ b/tests/qtest/meson.build
90
@@ -XXX,XX +XXX,XX @@ qos_test_ss.add(
91
)
92
qos_test_ss.add(when: 'CONFIG_VIRTFS', if_true: files('virtio-9p-test.c'))
93
qos_test_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user-test.c'))
94
-qos_test_ss.add(when: ['CONFIG_LINUX', 'CONFIG_TOOLS'], if_true: files('vhost-user-blk-test.c'))
95
+qos_test_ss.add(when: ['CONFIG_VHOST_USER', 'CONFIG_TOOLS'], if_true: files('vhost-user-blk-test.c'))
96
97
extra_qtest_deps = {
98
'bios-tables-test': [io],
99
diff --git a/util/meson.build b/util/meson.build
100
index XXXXXXX..XXXXXXX 100644
101
--- a/util/meson.build
102
+++ b/util/meson.build
103
@@ -XXX,XX +XXX,XX @@ if have_block
104
util_ss.add(files('main-loop.c'))
105
util_ss.add(files('nvdimm-utils.c'))
106
util_ss.add(files('qemu-coroutine.c', 'qemu-coroutine-lock.c', 'qemu-coroutine-io.c'))
107
- util_ss.add(when: 'CONFIG_LINUX', if_true: files('vhost-user-server.c'))
108
+ util_ss.add(when: 'CONFIG_VHOST_USER', if_true: [
109
+ files('vhost-user-server.c'), vhost_user
110
+ ])
111
util_ss.add(files('block-helpers.c'))
112
util_ss.add(files('qemu-coroutine-sleep.c'))
113
util_ss.add(files('qemu-co-shared-resource.c'))
114
--
115
2.26.2
20
116
21
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
22
index XXXXXXX..XXXXXXX 100644
23
--- a/tests/qemu-iotests/common.rc
24
+++ b/tests/qemu-iotests/common.rc
25
@@ -XXX,XX +XXX,XX @@ _make_test_img()
26
local use_backing=0
27
local backing_file=""
28
local object_options=""
29
+ local opts_param=false
30
local misc_params=()
31
32
if [ -n "$TEST_IMG_FILE" ]; then
33
@@ -XXX,XX +XXX,XX @@ _make_test_img()
34
if [ "$use_backing" = "1" -a -z "$backing_file" ]; then
35
backing_file=$param
36
continue
37
+ elif $opts_param; then
38
+ optstr=$(_optstr_add "$optstr" "$param")
39
+ opts_param=false
40
+ continue
41
fi
42
43
case "$param" in
44
@@ -XXX,XX +XXX,XX @@ _make_test_img()
45
use_backing=1
46
;;
47
48
+ -o)
49
+ opts_param=true
50
+ ;;
51
+
52
+ --no-opts)
53
+ optstr=""
54
+ ;;
55
+
56
*)
57
misc_params=("${misc_params[@]}" "$param")
58
;;
59
--
60
2.24.1
61
62
diff view generated by jsdifflib
1
IMGOPTS can never be empty for qcow2, because the check scripts adds
1
Introduce libblkdev.fa to avoid recompiling blockdev_ss twice.
2
compat=1.1 unless the user specified any compat option themselves.
3
Thus, this block does not do anything and can be dropped.
4
2
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
6
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
4
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
7
Message-id: 20191107163708.833192-8-mreitz@redhat.com
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Message-id: 20200929125516.186715-3-stefanha@redhat.com
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
8
---
10
tests/qemu-iotests/050 | 4 ----
9
meson.build | 12 ++++++++++--
11
1 file changed, 4 deletions(-)
10
storage-daemon/meson.build | 3 +--
11
2 files changed, 11 insertions(+), 4 deletions(-)
12
12
13
diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050
13
diff --git a/meson.build b/meson.build
14
index XXXXXXX..XXXXXXX 100755
14
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/050
15
--- a/meson.build
16
+++ b/tests/qemu-iotests/050
16
+++ b/meson.build
17
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
17
@@ -XXX,XX +XXX,XX @@ blockdev_ss.add(files(
18
_supported_fmt qcow2 qed
18
blockdev_ss.add(when: 'CONFIG_POSIX', if_true: files('os-posix.c'))
19
_supported_proto file
19
softmmu_ss.add(when: 'CONFIG_WIN32', if_true: [files('os-win32.c')])
20
20
21
-if test "$IMGFMT" = qcow2 && test $IMGOPTS = ""; then
21
-softmmu_ss.add_all(blockdev_ss)
22
- IMGOPTS=compat=1.1
22
softmmu_ss.add(files(
23
-fi
23
'bootdevice.c',
24
-
24
'dma-helpers.c',
25
echo
25
@@ -XXX,XX +XXX,XX @@ block = declare_dependency(link_whole: [libblock],
26
echo "== Creating images =="
26
link_args: '@block.syms',
27
dependencies: [crypto, io])
28
29
+blockdev_ss = blockdev_ss.apply(config_host, strict: false)
30
+libblockdev = static_library('blockdev', blockdev_ss.sources() + genh,
31
+ dependencies: blockdev_ss.dependencies(),
32
+ name_suffix: 'fa',
33
+ build_by_default: false)
34
+
35
+blockdev = declare_dependency(link_whole: [libblockdev],
36
+ dependencies: [block])
37
+
38
qmp_ss = qmp_ss.apply(config_host, strict: false)
39
libqmp = static_library('qmp', qmp_ss.sources() + genh,
40
dependencies: qmp_ss.dependencies(),
41
@@ -XXX,XX +XXX,XX @@ foreach m : block_mods + softmmu_mods
42
install_dir: config_host['qemu_moddir'])
43
endforeach
44
45
-softmmu_ss.add(authz, block, chardev, crypto, io, qmp)
46
+softmmu_ss.add(authz, blockdev, chardev, crypto, io, qmp)
47
common_ss.add(qom, qemuutil)
48
49
common_ss.add_all(when: 'CONFIG_SOFTMMU', if_true: [softmmu_ss])
50
diff --git a/storage-daemon/meson.build b/storage-daemon/meson.build
51
index XXXXXXX..XXXXXXX 100644
52
--- a/storage-daemon/meson.build
53
+++ b/storage-daemon/meson.build
54
@@ -XXX,XX +XXX,XX @@
55
qsd_ss = ss.source_set()
56
qsd_ss.add(files('qemu-storage-daemon.c'))
57
-qsd_ss.add(block, chardev, qmp, qom, qemuutil)
58
-qsd_ss.add_all(blockdev_ss)
59
+qsd_ss.add(blockdev, chardev, qmp, qom, qemuutil)
60
61
subdir('qapi')
27
62
28
--
63
--
29
2.24.1
64
2.26.2
30
65
31
diff view generated by jsdifflib
1
Tests should not overwrite all user-supplied image options, but only add
1
Block exports are used by softmmu, qemu-storage-daemon, and qemu-nbd.
2
to it (which will effectively overwrite conflicting values). Accomplish
2
They are not used by other programs and are not otherwise needed in
3
this by passing options to _make_test_img via -o instead of $IMGOPTS.
3
libblock.
4
4
5
For some tests, there is no functional change because they already only
5
Undo the recent move of blockdev-nbd.c from blockdev_ss into block_ss.
6
appended options to IMGOPTS. For these, this patch is just a
6
Since bdrv_close_all() (libblock) calls blk_exp_close_all()
7
simplification.
7
(libblockdev) a stub function is required..
8
8
9
For others, this is a change, so they now heed user-specified $IMGOPTS.
9
Make qemu-nbd.c use signal handling utility functions instead of
10
Some of those tests do not work with all image options, though, so we
10
duplicating the code. This helps because os-posix.c is in libblockdev
11
need to disable them accordingly.
11
and it depends on a qemu_system_killed() symbol that qemu-nbd.c lacks.
12
Once we use the signal handling utility functions we also end up
13
providing the necessary symbol.
12
14
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
16
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
15
Message-id: 20191107163708.833192-12-mreitz@redhat.com
17
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
Message-id: 20200929125516.186715-4-stefanha@redhat.com
19
[Fixed s/ndb/nbd/ typo in commit description as suggested by Eric Blake
20
--Stefan]
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
---
22
---
18
tests/qemu-iotests/031 | 9 ++++---
23
qemu-nbd.c | 21 +++++++++------------
19
tests/qemu-iotests/039 | 24 ++++++------------
24
stubs/blk-exp-close-all.c | 7 +++++++
20
tests/qemu-iotests/059 | 18 ++++++-------
25
block/export/meson.build | 4 ++--
21
tests/qemu-iotests/060 | 6 ++---
26
meson.build | 4 ++--
22
tests/qemu-iotests/061 | 57 ++++++++++++++++++++++--------------------
27
nbd/meson.build | 2 ++
23
tests/qemu-iotests/079 | 3 +--
28
stubs/meson.build | 1 +
24
tests/qemu-iotests/106 | 2 +-
29
6 files changed, 23 insertions(+), 16 deletions(-)
25
tests/qemu-iotests/108 | 2 +-
30
create mode 100644 stubs/blk-exp-close-all.c
26
tests/qemu-iotests/112 | 32 ++++++++++++------------
27
tests/qemu-iotests/115 | 3 +--
28
tests/qemu-iotests/121 | 6 ++---
29
tests/qemu-iotests/125 | 2 +-
30
tests/qemu-iotests/137 | 2 +-
31
tests/qemu-iotests/138 | 3 +--
32
tests/qemu-iotests/175 | 2 +-
33
tests/qemu-iotests/190 | 2 +-
34
tests/qemu-iotests/191 | 3 +--
35
tests/qemu-iotests/220 | 4 ++-
36
tests/qemu-iotests/243 | 6 +++--
37
tests/qemu-iotests/244 | 10 +++++---
38
tests/qemu-iotests/250 | 3 +--
39
tests/qemu-iotests/265 | 2 +-
40
22 files changed, 100 insertions(+), 101 deletions(-)
41
31
42
diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
32
diff --git a/qemu-nbd.c b/qemu-nbd.c
43
index XXXXXXX..XXXXXXX 100755
33
index XXXXXXX..XXXXXXX 100644
44
--- a/tests/qemu-iotests/031
34
--- a/qemu-nbd.c
45
+++ b/tests/qemu-iotests/031
35
+++ b/qemu-nbd.c
46
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
36
@@ -XXX,XX +XXX,XX @@
47
# This tests qcow2-specific low-level functionality
37
#include "qapi/error.h"
48
_supported_fmt qcow2
38
#include "qemu/cutils.h"
49
_supported_proto file
39
#include "sysemu/block-backend.h"
50
+# We want to test compat=0.10, which does not support refcount widths
40
+#include "sysemu/runstate.h" /* for qemu_system_killed() prototype */
51
+# other than 16
41
#include "block/block_int.h"
52
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
42
#include "block/nbd.h"
53
43
#include "qemu/main-loop.h"
54
CLUSTER_SIZE=65536
44
@@ -XXX,XX +XXX,XX @@ QEMU_COPYRIGHT "\n"
55
56
# qcow2.py output depends on the exact options used, so override the command
57
# line here as an exception
58
-for IMGOPTS in "compat=0.10" "compat=1.1"; do
59
+for compat in "compat=0.10" "compat=1.1"; do
60
61
echo
62
- echo ===== Testing with -o $IMGOPTS =====
63
+ echo ===== Testing with -o $compat =====
64
echo
65
echo === Create image with unknown header extension ===
66
echo
67
- _make_test_img 64M
68
+ _make_test_img -o $compat 64M
69
$PYTHON qcow2.py "$TEST_IMG" add-header-ext 0x12345678 "This is a test header extension"
70
$PYTHON qcow2.py "$TEST_IMG" dump-header
71
_check_test_img
72
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
73
index XXXXXXX..XXXXXXX 100755
74
--- a/tests/qemu-iotests/039
75
+++ b/tests/qemu-iotests/039
76
@@ -XXX,XX +XXX,XX @@ size=128M
77
echo
78
echo "== Checking that image is clean on shutdown =="
79
80
-IMGOPTS="compat=1.1,lazy_refcounts=on"
81
-_make_test_img $size
82
+_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
83
84
$QEMU_IO -c "write -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
85
86
@@ -XXX,XX +XXX,XX @@ _check_test_img
87
echo
88
echo "== Creating a dirty image file =="
89
90
-IMGOPTS="compat=1.1,lazy_refcounts=on"
91
-_make_test_img $size
92
+_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
93
94
_NO_VALGRIND \
95
$QEMU_IO -c "write -P 0x5a 0 512" \
96
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
97
echo
98
echo "== Opening a dirty image read/write should repair it =="
99
100
-IMGOPTS="compat=1.1,lazy_refcounts=on"
101
-_make_test_img $size
102
+_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
103
104
_NO_VALGRIND \
105
$QEMU_IO -c "write -P 0x5a 0 512" \
106
@@ -XXX,XX +XXX,XX @@ $PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
107
echo
108
echo "== Creating an image file with lazy_refcounts=off =="
109
110
-IMGOPTS="compat=1.1,lazy_refcounts=off"
111
-_make_test_img $size
112
+_make_test_img -o "compat=1.1,lazy_refcounts=off" $size
113
114
_NO_VALGRIND \
115
$QEMU_IO -c "write -P 0x5a 0 512" \
116
@@ -XXX,XX +XXX,XX @@ _check_test_img
117
echo
118
echo "== Committing to a backing file with lazy_refcounts=on =="
119
120
-IMGOPTS="compat=1.1,lazy_refcounts=on"
121
-TEST_IMG="$TEST_IMG".base _make_test_img $size
122
+TEST_IMG="$TEST_IMG".base _make_test_img -o "compat=1.1,lazy_refcounts=on" $size
123
124
-IMGOPTS="compat=1.1,lazy_refcounts=on,backing_file=$TEST_IMG.base"
125
-_make_test_img $size
126
+_make_test_img -o "compat=1.1,lazy_refcounts=on,backing_file=$TEST_IMG.base" $size
127
128
$QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io
129
$QEMU_IMG commit "$TEST_IMG"
130
@@ -XXX,XX +XXX,XX @@ TEST_IMG="$TEST_IMG".base _check_test_img
131
echo
132
echo "== Changing lazy_refcounts setting at runtime =="
133
134
-IMGOPTS="compat=1.1,lazy_refcounts=off"
135
-_make_test_img $size
136
+_make_test_img -o "compat=1.1,lazy_refcounts=off" $size
137
138
_NO_VALGRIND \
139
$QEMU_IO -c "reopen -o lazy-refcounts=on" \
140
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "reopen -o lazy-refcounts=on" \
141
$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
142
_check_test_img
143
144
-IMGOPTS="compat=1.1,lazy_refcounts=on"
145
-_make_test_img $size
146
+_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
147
148
_NO_VALGRIND \
149
$QEMU_IO -c "reopen -o lazy-refcounts=off" \
150
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
151
index XXXXXXX..XXXXXXX 100755
152
--- a/tests/qemu-iotests/059
153
+++ b/tests/qemu-iotests/059
154
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$grain_table_size_offset" "\x01\x00\x00\x00"
155
156
echo
157
echo "=== Testing monolithicFlat creation and opening ==="
158
-IMGOPTS="subformat=monolithicFlat" _make_test_img 2G
159
+_make_test_img -o "subformat=monolithicFlat" 2G
160
_img_info
161
_cleanup_test_img
162
163
echo
164
echo "=== Testing monolithicFlat with zeroed_grain ==="
165
-IMGOPTS="subformat=monolithicFlat,zeroed_grain=on" _make_test_img 2G
166
+_make_test_img -o "subformat=monolithicFlat,zeroed_grain=on" 2G
167
_cleanup_test_img
168
169
echo
170
echo "=== Testing big twoGbMaxExtentFlat ==="
171
-IMGOPTS="subformat=twoGbMaxExtentFlat" _make_test_img 1000G
172
+_make_test_img -o "subformat=twoGbMaxExtentFlat" 1000G
173
$QEMU_IMG info $TEST_IMG | _filter_testdir | sed -e 's/cid: [0-9]*/cid: XXXXXXXX/'
174
_cleanup_test_img
175
176
@@ -XXX,XX +XXX,XX @@ _img_info
177
178
echo
179
echo "=== Testing truncated sparse ==="
180
-IMGOPTS="subformat=monolithicSparse" _make_test_img 100G
181
+_make_test_img -o "subformat=monolithicSparse" 100G
182
truncate -s 10M $TEST_IMG
183
_img_info
184
185
echo
186
echo "=== Converting to streamOptimized from image with small cluster size==="
187
-TEST_IMG="$TEST_IMG.qcow2" IMGFMT=qcow2 IMGOPTS="cluster_size=4096" _make_test_img 1G
188
+TEST_IMG="$TEST_IMG.qcow2" IMGFMT=qcow2 _make_test_img -o "cluster_size=4096" 1G
189
$QEMU_IO -f qcow2 -c "write -P 0xa 0 512" "$TEST_IMG.qcow2" | _filter_qemu_io
190
$QEMU_IO -f qcow2 -c "write -P 0xb 10240 512" "$TEST_IMG.qcow2" | _filter_qemu_io
191
$QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2" "$TEST_IMG" 2>&1
192
@@ -XXX,XX +XXX,XX @@ echo "=== Testing monolithicFlat with internally generated JSON file name ==="
193
194
echo '--- blkdebug ---'
195
# Should work, because bdrv_dirname() works fine with blkdebug
196
-IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
197
+_make_test_img -o "subformat=monolithicFlat" 64M
198
$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" \
199
-c info \
200
2>&1 \
201
@@ -XXX,XX +XXX,XX @@ _cleanup_test_img
202
203
echo '--- quorum ---'
204
# Should not work, because bdrv_dirname() does not work with quorum
205
-IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
206
+_make_test_img -o "subformat=monolithicFlat" 64M
207
cp "$TEST_IMG" "$TEST_IMG.orig"
208
209
filename="json:{
210
@@ -XXX,XX +XXX,XX @@ _cleanup_test_img
211
212
echo
213
echo "=== Testing 4TB monolithicFlat creation and IO ==="
214
-IMGOPTS="subformat=monolithicFlat" _make_test_img 4T
215
+_make_test_img -o "subformat=monolithicFlat" 4T
216
_img_info
217
$QEMU_IO -c "write -P 0xa 900G 512" "$TEST_IMG" | _filter_qemu_io
218
$QEMU_IO -c "read -v 900G 1024" "$TEST_IMG" | _filter_qemu_io
219
@@ -XXX,XX +XXX,XX @@ _cleanup_test_img
220
echo
221
echo "=== Testing qemu-img map on extents ==="
222
for fmt in monolithicSparse twoGbMaxExtentSparse; do
223
- IMGOPTS="subformat=$fmt" _make_test_img 31G
224
+ _make_test_img -o "subformat=$fmt" 31G
225
$QEMU_IO -c "write 65024 1k" "$TEST_IMG" | _filter_qemu_io
226
$QEMU_IO -c "write 2147483136 1k" "$TEST_IMG" | _filter_qemu_io
227
$QEMU_IO -c "write 5G 1k" "$TEST_IMG" | _filter_qemu_io
228
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
229
index XXXXXXX..XXXXXXX 100755
230
--- a/tests/qemu-iotests/060
231
+++ b/tests/qemu-iotests/060
232
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'write 0k 64k' "$BACKING_IMG" | _filter_qemu_io
233
# compat=0.10 is required in order to make the following discard actually
234
# unallocate the sector rather than make it a zero sector - we want COW, after
235
# all.
236
-IMGOPTS='compat=0.10' _make_test_img -b "$BACKING_IMG" 1G
237
+_make_test_img -o 'compat=0.10' -b "$BACKING_IMG" 1G
238
# Write two clusters, the second one enforces creation of an L2 table after
239
# the first data cluster.
240
$QEMU_IO -c 'write 0k 64k' -c 'write 512M 64k' "$TEST_IMG" | _filter_qemu_io
241
@@ -XXX,XX +XXX,XX @@ echo
242
echo "=== Discarding a non-covered in-bounds refblock ==="
243
echo
244
245
-IMGOPTS='refcount_bits=1' _make_test_img 64M
246
+_make_test_img -o 'refcount_bits=1' 64M
247
248
# Pretend there's a refblock somewhere where there is no refblock to
249
# cover it (but the covering refblock has a valid index in the
250
@@ -XXX,XX +XXX,XX @@ echo
251
echo "=== Discarding a refblock covered by an unaligned refblock ==="
252
echo
253
254
-IMGOPTS='refcount_bits=1' _make_test_img 64M
255
+_make_test_img -o 'refcount_bits=1' 64M
256
257
# Same as above
258
poke_file "$TEST_IMG" "$(($rt_offset+8))" "\x00\x00\x00\x10\x00\x00\x00\x00"
259
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
260
index XXXXXXX..XXXXXXX 100755
261
--- a/tests/qemu-iotests/061
262
+++ b/tests/qemu-iotests/061
263
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
264
_supported_fmt qcow2
265
_supported_proto file
266
_supported_os Linux
267
+# Conversion between different compat versions can only really work
268
+# with refcount_bits=16
269
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
270
271
echo
272
echo "=== Testing version downgrade with zero expansion ==="
273
echo
274
-IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
275
+_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
276
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
277
$PYTHON qcow2.py "$TEST_IMG" dump-header
278
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
279
@@ -XXX,XX +XXX,XX @@ _check_test_img
280
echo
281
echo "=== Testing version downgrade with zero expansion and 4K cache entries ==="
282
echo
283
-IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
284
+_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
285
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
286
$QEMU_IO -c "write -z 32M 128k" "$TEST_IMG" | _filter_qemu_io
287
$QEMU_IO -c map "$TEST_IMG" | _filter_qemu_io
288
@@ -XXX,XX +XXX,XX @@ _check_test_img
289
echo
290
echo "=== Testing dirty version downgrade ==="
291
echo
292
-IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
293
+_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
294
_NO_VALGRIND \
295
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
296
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
297
@@ -XXX,XX +XXX,XX @@ _check_test_img
298
echo
299
echo "=== Testing version downgrade with unknown compat/autoclear flags ==="
300
echo
301
-IMGOPTS="compat=1.1" _make_test_img 64M
302
+_make_test_img -o "compat=1.1" 64M
303
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit compatible 42
304
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 42
305
$PYTHON qcow2.py "$TEST_IMG" dump-header
306
@@ -XXX,XX +XXX,XX @@ _check_test_img
307
echo
308
echo "=== Testing version upgrade and resize ==="
309
echo
310
-IMGOPTS="compat=0.10" _make_test_img 64M
311
+_make_test_img -o "compat=0.10" 64M
312
$QEMU_IO -c "write -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io
313
$PYTHON qcow2.py "$TEST_IMG" dump-header
314
$QEMU_IMG amend -o "compat=1.1,lazy_refcounts=on,size=128M" "$TEST_IMG"
315
@@ -XXX,XX +XXX,XX @@ _check_test_img
316
echo
317
echo "=== Testing dirty lazy_refcounts=off ==="
318
echo
319
-IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
320
+_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
321
_NO_VALGRIND \
322
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
323
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
324
@@ -XXX,XX +XXX,XX @@ _check_test_img
325
echo
326
echo "=== Testing backing file ==="
327
echo
328
-IMGOPTS="compat=1.1" _make_test_img 64M
329
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 64M
330
+_make_test_img -o "compat=1.1" 64M
331
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M
332
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io
333
$QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
334
$QEMU_IMG amend -o "backing_file=$TEST_IMG.base,backing_fmt=qcow2" "$TEST_IMG"
335
@@ -XXX,XX +XXX,XX @@ _check_test_img
336
echo
337
echo "=== Testing invalid configurations ==="
338
echo
339
-IMGOPTS="compat=0.10" _make_test_img 64M
340
+_make_test_img -o "compat=0.10" 64M
341
$QEMU_IMG amend -o "lazy_refcounts=on" "$TEST_IMG"
342
$QEMU_IMG amend -o "compat=1.1" "$TEST_IMG" # actually valid
343
$QEMU_IMG amend -o "compat=0.10,lazy_refcounts=on" "$TEST_IMG"
344
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG amend -o "preallocation=on" "$TEST_IMG"
345
echo
346
echo "=== Testing correct handling of unset value ==="
347
echo
348
-IMGOPTS="compat=1.1,cluster_size=1k" _make_test_img 64M
349
+_make_test_img -o "compat=1.1,cluster_size=1k" 64M
350
echo "Should work:"
351
$QEMU_IMG amend -o "lazy_refcounts=on" "$TEST_IMG"
352
echo "Should not work:" # Just to know which of these tests actually fails
353
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG amend -o "cluster_size=64k" "$TEST_IMG"
354
echo
355
echo "=== Testing zero expansion on inactive clusters ==="
356
echo
357
-IMGOPTS="compat=1.1" _make_test_img 64M
358
+_make_test_img -o "compat=1.1" 64M
359
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
360
$QEMU_IMG snapshot -c foo "$TEST_IMG"
361
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
362
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
363
echo
364
echo "=== Testing zero expansion on shared L2 table ==="
365
echo
366
-IMGOPTS="compat=1.1" _make_test_img 64M
367
+_make_test_img -o "compat=1.1" 64M
368
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
369
$QEMU_IMG snapshot -c foo "$TEST_IMG"
370
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
371
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
372
echo
373
echo "=== Testing zero expansion on backed image ==="
374
echo
375
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 64M
376
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M
377
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io
378
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 64M
379
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 64M
380
$QEMU_IO -c "read -P 0x2a 0 128k" -c "write -z 0 64k" "$TEST_IMG" | _filter_qemu_io
381
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
382
_check_test_img
383
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 0 64k" -c "read -P 0x2a 64k 64k" "$TEST_IMG" | _filter_qe
384
echo
385
echo "=== Testing zero expansion on backed inactive clusters ==="
386
echo
387
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 64M
388
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M
389
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io
390
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 64M
391
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 64M
392
$QEMU_IO -c "write -z 0 64k" "$TEST_IMG" | _filter_qemu_io
393
$QEMU_IMG snapshot -c foo "$TEST_IMG"
394
$QEMU_IO -c "write -P 0x42 0 128k" "$TEST_IMG" | _filter_qemu_io
395
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 0 64k" -c "read -P 0x2a 64k 64k" "$TEST_IMG" | _filter_qe
396
echo
397
echo "=== Testing zero expansion on backed image with shared L2 table ==="
398
echo
399
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 64M
400
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 64M
401
$QEMU_IO -c "write -P 0x2a 0 128k" "$TEST_IMG.base" | _filter_qemu_io
402
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 64M
403
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 64M
404
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
405
$QEMU_IMG snapshot -c foo "$TEST_IMG"
406
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
407
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
408
echo
409
echo "=== Testing preallocated zero expansion on full image ==="
410
echo
411
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG" _make_test_img 64M
412
+TEST_IMG="$TEST_IMG" _make_test_img -o "compat=1.1" 64M
413
$QEMU_IO -c "write -P 0x2a 0 64M" "$TEST_IMG" -c "write -z 0 64M" | _filter_qemu_io
414
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
415
_check_test_img
416
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0 0 64M" "$TEST_IMG" | _filter_qemu_io
417
echo
418
echo "=== Testing progress report without snapshot ==="
419
echo
420
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 4G
421
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 4G
422
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 4G
423
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 4G
424
$QEMU_IO -c "write -z 0 64k" \
425
-c "write -z 1G 64k" \
426
-c "write -z 2G 64k" \
427
@@ -XXX,XX +XXX,XX @@ _check_test_img
428
echo
429
echo "=== Testing progress report with snapshot ==="
430
echo
431
-IMGOPTS="compat=1.1" TEST_IMG="$TEST_IMG.base" _make_test_img 4G
432
-IMGOPTS="compat=1.1" _make_test_img -b "$TEST_IMG.base" 4G
433
+TEST_IMG="$TEST_IMG.base" _make_test_img -o "compat=1.1" 4G
434
+_make_test_img -o "compat=1.1" -b "$TEST_IMG.base" 4G
435
$QEMU_IO -c "write -z 0 64k" \
436
-c "write -z 1G 64k" \
437
-c "write -z 2G 64k" \
438
@@ -XXX,XX +XXX,XX @@ _check_test_img
439
echo
440
echo "=== Testing version downgrade with external data file ==="
441
echo
442
-IMGOPTS="compat=1.1,data_file=$TEST_IMG.data" _make_test_img 64M
443
+_make_test_img -o "compat=1.1,data_file=$TEST_IMG.data" 64M
444
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
445
_img_info --format-specific
446
_check_test_img
447
@@ -XXX,XX +XXX,XX @@ _check_test_img
448
echo
449
echo "=== Try changing the external data file ==="
450
echo
451
-IMGOPTS="compat=1.1" _make_test_img 64M
452
+_make_test_img -o "compat=1.1" 64M
453
$QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
454
455
echo
456
-IMGOPTS="compat=1.1,data_file=$TEST_IMG.data" _make_test_img 64M
457
+_make_test_img -o "compat=1.1,data_file=$TEST_IMG.data" 64M
458
$QEMU_IMG amend -o "data_file=foo" "$TEST_IMG"
459
_img_info --format-specific
460
TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts
461
@@ -XXX,XX +XXX,XX @@ TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info -
462
echo
463
echo "=== Clearing and setting data-file-raw ==="
464
echo
465
-IMGOPTS="compat=1.1,data_file=$TEST_IMG.data,data_file_raw=on" _make_test_img 64M
466
+_make_test_img -o "compat=1.1,data_file=$TEST_IMG.data,data_file_raw=on" 64M
467
$QEMU_IMG amend -o "data_file_raw=on" "$TEST_IMG"
468
_img_info --format-specific
469
_check_test_img
470
diff --git a/tests/qemu-iotests/079 b/tests/qemu-iotests/079
471
index XXXXXXX..XXXXXXX 100755
472
--- a/tests/qemu-iotests/079
473
+++ b/tests/qemu-iotests/079
474
@@ -XXX,XX +XXX,XX @@ echo
475
cluster_sizes="16384 32768 65536 131072 262144 524288 1048576 2097152 4194304"
476
477
for s in $cluster_sizes; do
478
- IMGOPTS=$(_optstr_add "$IMGOPTS" "preallocation=metadata,cluster_size=$s") \
479
- _make_test_img 4G
480
+ _make_test_img -o "preallocation=metadata,cluster_size=$s" 4G
481
done
482
483
# success, all done
484
diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106
485
index XXXXXXX..XXXXXXX 100755
486
--- a/tests/qemu-iotests/106
487
+++ b/tests/qemu-iotests/106
488
@@ -XXX,XX +XXX,XX @@ for create_mode in off falloc full; do
489
echo
490
echo "--- create_mode=$create_mode growth_mode=$growth_mode ---"
491
492
- IMGOPTS="preallocation=$create_mode" _make_test_img ${CREATION_SIZE}K
493
+ _make_test_img -o "preallocation=$create_mode" ${CREATION_SIZE}K
494
$QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K
495
496
expected_size=0
497
diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108
498
index XXXXXXX..XXXXXXX 100755
499
--- a/tests/qemu-iotests/108
500
+++ b/tests/qemu-iotests/108
501
@@ -XXX,XX +XXX,XX @@ echo
502
echo '=== Repairing unreferenced data cluster in new refblock area ==='
503
echo
504
505
-IMGOPTS='cluster_size=512' _make_test_img 64M
506
+_make_test_img -o 'cluster_size=512' 64M
507
# Allocate the first 128 kB in the image (first refblock)
508
$QEMU_IO -c 'write 0 0x1b200' "$TEST_IMG" | _filter_qemu_io
509
# should be 131072 == 0x20000
510
diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
511
index XXXXXXX..XXXXXXX 100755
512
--- a/tests/qemu-iotests/112
513
+++ b/tests/qemu-iotests/112
514
@@ -XXX,XX +XXX,XX @@ echo '=== refcount_bits limits ==='
515
echo
516
517
# Must be positive (non-zero)
518
-IMGOPTS="$IMGOPTS,refcount_bits=0" _make_test_img 64M
519
+_make_test_img -o "refcount_bits=0" 64M
520
# Must be positive (non-negative)
521
-IMGOPTS="$IMGOPTS,refcount_bits=-1" _make_test_img 64M
522
+_make_test_img -o "refcount_bits=-1" 64M
523
# May not exceed 64
524
-IMGOPTS="$IMGOPTS,refcount_bits=128" _make_test_img 64M
525
+_make_test_img -o "refcount_bits=128" 64M
526
# Must be a power of two
527
-IMGOPTS="$IMGOPTS,refcount_bits=42" _make_test_img 64M
528
+_make_test_img -o "refcount_bits=42" 64M
529
530
# 1 is the minimum
531
-IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
532
+_make_test_img -o "refcount_bits=1" 64M
533
print_refcount_bits
534
535
# 64 is the maximum
536
-IMGOPTS="$IMGOPTS,refcount_bits=64" _make_test_img 64M
537
+_make_test_img -o "refcount_bits=64" 64M
538
print_refcount_bits
539
540
# 16 is the default
541
@@ -XXX,XX +XXX,XX @@ echo '=== refcount_bits and compat=0.10 ==='
542
echo
543
544
# Should work
545
-IMGOPTS="$IMGOPTS,compat=0.10,refcount_bits=16" _make_test_img 64M
546
+_make_test_img -o "compat=0.10,refcount_bits=16" 64M
547
print_refcount_bits
548
549
# Should not work
550
-IMGOPTS="$IMGOPTS,compat=0.10,refcount_bits=1" _make_test_img 64M
551
-IMGOPTS="$IMGOPTS,compat=0.10,refcount_bits=64" _make_test_img 64M
552
+_make_test_img -o "compat=0.10,refcount_bits=1" 64M
553
+_make_test_img -o "compat=0.10,refcount_bits=64" 64M
554
555
556
echo
557
echo '=== Snapshot limit on refcount_bits=1 ==='
558
echo
559
560
-IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
561
+_make_test_img -o "refcount_bits=1" 64M
562
print_refcount_bits
563
564
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
565
@@ -XXX,XX +XXX,XX @@ echo
566
echo '=== Snapshot limit on refcount_bits=2 ==='
567
echo
568
569
-IMGOPTS="$IMGOPTS,refcount_bits=2" _make_test_img 64M
570
+_make_test_img -o "refcount_bits=2" 64M
571
print_refcount_bits
572
573
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
574
@@ -XXX,XX +XXX,XX @@ echo
575
echo '=== Compressed clusters with refcount_bits=1 ==='
576
echo
577
578
-IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
579
+_make_test_img -o "refcount_bits=1" 64M
580
print_refcount_bits
581
582
# Both should fit into a single host cluster; instead of failing to increase the
583
@@ -XXX,XX +XXX,XX @@ echo
584
echo '=== MSb set in 64 bit refcount ==='
585
echo
586
587
-IMGOPTS="$IMGOPTS,refcount_bits=64" _make_test_img 64M
588
+_make_test_img -o "refcount_bits=64" 64M
589
print_refcount_bits
590
591
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
592
@@ -XXX,XX +XXX,XX @@ echo
593
echo '=== Snapshot on maximum 64 bit refcount value ==='
594
echo
595
596
-IMGOPTS="$IMGOPTS,refcount_bits=64" _make_test_img 64M
597
+_make_test_img -o "refcount_bits=64" 64M
598
print_refcount_bits
599
600
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
601
@@ -XXX,XX +XXX,XX @@ echo
602
echo '=== Testing too many references for check ==='
603
echo
604
605
-IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
606
+_make_test_img -o "refcount_bits=1" 64M
607
print_refcount_bits
608
609
# This cluster should be created at 0x50000
610
@@ -XXX,XX +XXX,XX @@ echo
611
echo '=== Multiple walks necessary during amend ==='
612
echo
613
614
-IMGOPTS="$IMGOPTS,refcount_bits=1,cluster_size=512" _make_test_img 64k
615
+_make_test_img -o "refcount_bits=1,cluster_size=512" 64k
616
617
# Cluster 0 is the image header, clusters 1 to 4 are used by the L1 table, a
618
# single L2 table, the reftable and a single refblock. This creates 58 data
619
diff --git a/tests/qemu-iotests/115 b/tests/qemu-iotests/115
620
index XXXXXXX..XXXXXXX 100755
621
--- a/tests/qemu-iotests/115
622
+++ b/tests/qemu-iotests/115
623
@@ -XXX,XX +XXX,XX @@ echo
624
# least 256 MB. We can achieve that by using preallocation=metadata for an image
625
# which has a guest disk size of 256 MB.
626
627
-IMGOPTS="$IMGOPTS,refcount_bits=64,cluster_size=512,preallocation=metadata" \
628
- _make_test_img 256M
629
+_make_test_img -o "refcount_bits=64,cluster_size=512,preallocation=metadata" 256M
630
631
# We know for sure that the L1 and refcount tables do not overlap with any other
632
# structure because the metadata overlap checks would have caught that case.
633
diff --git a/tests/qemu-iotests/121 b/tests/qemu-iotests/121
634
index XXXXXXX..XXXXXXX 100755
635
--- a/tests/qemu-iotests/121
636
+++ b/tests/qemu-iotests/121
637
@@ -XXX,XX +XXX,XX @@ echo
638
# Preallocation speeds up the write operation, but preallocating everything will
639
# destroy the purpose of the write; so preallocate one KB less than what would
640
# cause a reftable growth...
641
-IMGOPTS='preallocation=metadata,cluster_size=1k' _make_test_img 64512K
642
+_make_test_img -o 'preallocation=metadata,cluster_size=1k' 64512K
643
# ...and make the image the desired size afterwards.
644
$QEMU_IMG resize "$TEST_IMG" 65M
645
646
@@ -XXX,XX +XXX,XX @@ echo
647
echo '--- Test 2 ---'
648
echo
649
650
-IMGOPTS='preallocation=metadata,cluster_size=1k' _make_test_img 64513K
651
+_make_test_img -o 'preallocation=metadata,cluster_size=1k' 64513K
652
# This results in an L1 table growth which in turn results in some clusters at
653
# the start of the image becoming free
654
$QEMU_IMG resize "$TEST_IMG" 65M
655
@@ -XXX,XX +XXX,XX @@ echo
656
echo '=== Allocating a new refcount block must not leave holes in the image ==='
657
echo
658
659
-IMGOPTS='cluster_size=512,refcount_bits=16' _make_test_img 1M
660
+_make_test_img -o 'cluster_size=512,refcount_bits=16' 1M
661
662
# This results in an image with 256 used clusters: the qcow2 header,
663
# the refcount table, one refcount block, the L1 table, four L2 tables
664
diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125
665
index XXXXXXX..XXXXXXX 100755
666
--- a/tests/qemu-iotests/125
667
+++ b/tests/qemu-iotests/125
668
@@ -XXX,XX +XXX,XX @@ for GROWTH_SIZE in 16 48 80; do
669
for growth_mode in off metadata falloc full; do
670
echo "--- cluster_size=$cluster_size growth_size=$GROWTH_SIZE create_mode=$create_mode growth_mode=$growth_mode ---"
671
672
- IMGOPTS="preallocation=$create_mode,cluster_size=$cluster_size" _make_test_img ${CREATION_SIZE}
673
+ _make_test_img -o "preallocation=$create_mode,cluster_size=$cluster_size" ${CREATION_SIZE}
674
$QEMU_IMG resize -f "$IMGFMT" --preallocation=$growth_mode "$TEST_IMG" +${GROWTH_SIZE}K
675
676
host_size_0=$(get_image_size_on_host)
677
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
678
index XXXXXXX..XXXXXXX 100755
679
--- a/tests/qemu-iotests/137
680
+++ b/tests/qemu-iotests/137
681
@@ -XXX,XX +XXX,XX @@ $QEMU_IO \
682
-c "reopen -o cache-clean-interval=-1" \
683
"$TEST_IMG" | _filter_qemu_io
684
685
-IMGOPTS="cluster_size=256k" _make_test_img 32P
686
+_make_test_img -o "cluster_size=256k" 32P
687
$QEMU_IO \
688
-c "reopen -o l2-cache-entry-size=512,l2-cache-size=1T" \
689
"$TEST_IMG" | _filter_qemu_io
690
diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138
691
index XXXXXXX..XXXXXXX 100755
692
--- a/tests/qemu-iotests/138
693
+++ b/tests/qemu-iotests/138
694
@@ -XXX,XX +XXX,XX @@ echo
695
echo '=== Check on an image with a multiple of 2^32 clusters ==='
696
echo
697
698
-IMGOPTS=$(_optstr_add "$IMGOPTS" "cluster_size=512") \
699
- _make_test_img 512
700
+_make_test_img -o "cluster_size=512" 512
701
702
# Allocate L2 table
703
$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
704
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
705
index XXXXXXX..XXXXXXX 100755
706
--- a/tests/qemu-iotests/175
707
+++ b/tests/qemu-iotests/175
708
@@ -XXX,XX +XXX,XX @@ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_block
709
for mode in off full falloc; do
710
echo
711
echo "== creating image with preallocation $mode =="
712
- IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt
713
+ _make_test_img -o preallocation=$mode $size | _filter_imgfmt
714
stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
715
done
716
717
diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190
718
index XXXXXXX..XXXXXXX 100755
719
--- a/tests/qemu-iotests/190
720
+++ b/tests/qemu-iotests/190
721
@@ -XXX,XX +XXX,XX @@ _supported_proto file
722
echo "== Huge file =="
723
echo
724
725
-IMGOPTS='cluster_size=2M' _make_test_img 2T
726
+_make_test_img -o 'cluster_size=2M' 2T
727
728
$QEMU_IMG measure -O raw -f qcow2 "$TEST_IMG"
729
$QEMU_IMG measure -O qcow2 -o cluster_size=64k -f qcow2 "$TEST_IMG"
730
diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191
731
index XXXXXXX..XXXXXXX 100755
732
--- a/tests/qemu-iotests/191
733
+++ b/tests/qemu-iotests/191
734
@@ -XXX,XX +XXX,XX @@ echo === Preparing and starting VM ===
735
echo
736
737
TEST_IMG="${TEST_IMG}.base" _make_test_img $size
738
-IMGOPTS=$(_optstr_add "$IMGOPTS" "backing_fmt=$IMGFMT") \
739
- TEST_IMG="${TEST_IMG}.mid" _make_test_img -b "${TEST_IMG}.base"
740
+TEST_IMG="${TEST_IMG}.mid" _make_test_img -o "backing_fmt=$IMGFMT" -b "${TEST_IMG}.base"
741
_make_test_img -b "${TEST_IMG}.mid"
742
TEST_IMG="${TEST_IMG}.ovl2" _make_test_img -b "${TEST_IMG}.mid"
743
744
diff --git a/tests/qemu-iotests/220 b/tests/qemu-iotests/220
745
index XXXXXXX..XXXXXXX 100755
746
--- a/tests/qemu-iotests/220
747
+++ b/tests/qemu-iotests/220
748
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
749
_supported_fmt qcow2
750
_supported_proto file
751
_supported_os Linux
752
+# To use a different refcount width but 16 bits we need compat=1.1
753
+_unsupported_imgopts 'compat=0.10'
754
755
echo "== Creating huge file =="
756
757
@@ -XXX,XX +XXX,XX @@ echo "== Creating huge file =="
758
# of a HUGE (but very sparse) file. tmpfs works, ext4 does not.
759
_require_large_file 513T
760
761
-IMGOPTS='cluster_size=2M,refcount_bits=1' _make_test_img 513T
762
+_make_test_img -o 'cluster_size=2M,refcount_bits=1' 513T
763
764
echo "== Populating refcounts =="
765
# We want an image with 256M refcounts * 2M clusters = 512T referenced.
766
diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243
767
index XXXXXXX..XXXXXXX 100755
768
--- a/tests/qemu-iotests/243
769
+++ b/tests/qemu-iotests/243
770
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
771
_supported_fmt qcow2
772
_supported_proto file
773
_supported_os Linux
774
+# External data files do not work with compat=0.10
775
+_unsupported_imgopts 'compat=0.10'
776
777
for mode in off metadata falloc full; do
778
779
@@ -XXX,XX +XXX,XX @@ for mode in off metadata falloc full; do
780
echo "=== preallocation=$mode ==="
781
echo
782
783
- IMGOPTS="preallocation=$mode" _make_test_img 64M
784
+ _make_test_img -o "preallocation=$mode" 64M
785
786
printf "File size: "
787
du -b $TEST_IMG | cut -f1
788
@@ -XXX,XX +XXX,XX @@ for mode in off metadata falloc full; do
789
echo "=== External data file: preallocation=$mode ==="
790
echo
791
792
- IMGOPTS="data_file=$TEST_IMG.data,preallocation=$mode" _make_test_img 64M
793
+ _make_test_img -o "data_file=$TEST_IMG.data,preallocation=$mode" 64M
794
795
echo -n "qcow2 file size: "
796
du -b $TEST_IMG | cut -f1
797
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
798
index XXXXXXX..XXXXXXX 100755
799
--- a/tests/qemu-iotests/244
800
+++ b/tests/qemu-iotests/244
801
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
802
_supported_fmt qcow2
803
_supported_proto file
804
_supported_os Linux
805
+# External data files do not work with compat=0.10
806
+_unsupported_imgopts 'compat=0.10'
807
808
echo
809
echo "=== Create and open image with external data file ==="
810
echo
811
812
echo "With data file name in the image:"
813
-IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M
814
+_make_test_img -o "data_file=$TEST_IMG.data" 64M
815
_check_test_img
816
817
$QEMU_IO -c "open $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir
818
@@ -XXX,XX +XXX,XX @@ echo
819
echo "=== Standalone image with external data file (efficient) ==="
820
echo
821
822
-IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M
823
+_make_test_img -o "data_file=$TEST_IMG.data" 64M
824
825
echo -n "qcow2 file size before I/O: "
826
du -b $TEST_IMG | cut -f1
827
@@ -XXX,XX +XXX,XX @@ echo
828
echo "=== Standalone image with external data file (valid raw) ==="
829
echo
830
831
-IMGOPTS="data_file=$TEST_IMG.data,data_file_raw=on" _make_test_img 64M
832
+_make_test_img -o "data_file=$TEST_IMG.data,data_file_raw=on" 64M
833
834
echo -n "qcow2 file size before I/O: "
835
du -b $TEST_IMG | cut -f1
836
@@ -XXX,XX +XXX,XX @@ echo
837
echo "=== bdrv_co_block_status test for file and offset=0 ==="
838
echo
839
840
-IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M
841
+_make_test_img -o "data_file=$TEST_IMG.data" 64M
842
843
$QEMU_IO -c 'write -P 0x11 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
844
$QEMU_IO -c 'read -P 0x11 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io
845
diff --git a/tests/qemu-iotests/250 b/tests/qemu-iotests/250
846
index XXXXXXX..XXXXXXX 100755
847
--- a/tests/qemu-iotests/250
848
+++ b/tests/qemu-iotests/250
849
@@ -XXX,XX +XXX,XX @@ disk_usage()
850
}
45
}
851
46
852
size=2100M
47
#if HAVE_NBD_DEVICE
853
-IMGOPTS="cluster_size=1M,preallocation=metadata"
48
-static void termsig_handler(int signum)
854
49
+/*
855
-_make_test_img $size
50
+ * The client thread uses SIGTERM to interrupt the server. A signal
856
+_make_test_img -o "cluster_size=1M,preallocation=metadata" $size
51
+ * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
857
$QEMU_IO -c 'discard 0 10M' -c 'discard 2090M 10M' \
52
+ */
858
-c 'write 2090M 10M' -c 'write 0 10M' "$TEST_IMG" | _filter_qemu_io
53
+void qemu_system_killed(int signum, pid_t pid)
859
54
{
860
diff --git a/tests/qemu-iotests/265 b/tests/qemu-iotests/265
55
qatomic_cmpxchg(&state, RUNNING, TERMINATE);
861
index XXXXXXX..XXXXXXX 100755
56
qemu_notify_event();
862
--- a/tests/qemu-iotests/265
57
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
863
+++ b/tests/qemu-iotests/265
58
const char *pid_file_name = NULL;
864
@@ -XXX,XX +XXX,XX @@ _supported_os Linux
59
BlockExportOptions *export_opts;
865
echo '--- Writing to the image ---'
60
866
61
+ os_setup_early_signal_handling();
867
# Reduce cluster size so we get more and quicker I/O
62
+
868
-IMGOPTS='cluster_size=4096' _make_test_img 1M
63
#if HAVE_NBD_DEVICE
869
+_make_test_img -o 'cluster_size=4096' 1M
64
- /* The client thread uses SIGTERM to interrupt the server. A signal
870
(for ((kb = 1024 - 4; kb >= 0; kb -= 4)); do \
65
- * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
871
echo "aio_write -P 42 $((kb + 1))k 2k"; \
66
- */
872
done) \
67
- struct sigaction sa_sigterm;
68
- memset(&sa_sigterm, 0, sizeof(sa_sigterm));
69
- sa_sigterm.sa_handler = termsig_handler;
70
- sigaction(SIGTERM, &sa_sigterm, NULL);
71
+ os_setup_signal_handling();
72
#endif /* HAVE_NBD_DEVICE */
73
74
-#ifdef CONFIG_POSIX
75
- signal(SIGPIPE, SIG_IGN);
76
-#endif
77
-
78
socket_init();
79
error_init(argv[0]);
80
module_call_init(MODULE_INIT_TRACE);
81
diff --git a/stubs/blk-exp-close-all.c b/stubs/blk-exp-close-all.c
82
new file mode 100644
83
index XXXXXXX..XXXXXXX
84
--- /dev/null
85
+++ b/stubs/blk-exp-close-all.c
86
@@ -XXX,XX +XXX,XX @@
87
+#include "qemu/osdep.h"
88
+#include "block/export.h"
89
+
90
+/* Only used in programs that support block exports (libblockdev.fa) */
91
+void blk_exp_close_all(void)
92
+{
93
+}
94
diff --git a/block/export/meson.build b/block/export/meson.build
95
index XXXXXXX..XXXXXXX 100644
96
--- a/block/export/meson.build
97
+++ b/block/export/meson.build
98
@@ -XXX,XX +XXX,XX @@
99
-block_ss.add(files('export.c'))
100
-block_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user-blk-server.c'))
101
+blockdev_ss.add(files('export.c'))
102
+blockdev_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user-blk-server.c'))
103
diff --git a/meson.build b/meson.build
104
index XXXXXXX..XXXXXXX 100644
105
--- a/meson.build
106
+++ b/meson.build
107
@@ -XXX,XX +XXX,XX @@ subdir('dump')
108
109
block_ss.add(files(
110
'block.c',
111
- 'blockdev-nbd.c',
112
'blockjob.c',
113
'job.c',
114
'qemu-io-cmds.c',
115
@@ -XXX,XX +XXX,XX @@ subdir('block')
116
117
blockdev_ss.add(files(
118
'blockdev.c',
119
+ 'blockdev-nbd.c',
120
'iothread.c',
121
'job-qmp.c',
122
))
123
@@ -XXX,XX +XXX,XX @@ if have_tools
124
qemu_io = executable('qemu-io', files('qemu-io.c'),
125
dependencies: [block, qemuutil], install: true)
126
qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'),
127
- dependencies: [block, qemuutil], install: true)
128
+ dependencies: [blockdev, qemuutil], install: true)
129
130
subdir('storage-daemon')
131
subdir('contrib/rdmacm-mux')
132
diff --git a/nbd/meson.build b/nbd/meson.build
133
index XXXXXXX..XXXXXXX 100644
134
--- a/nbd/meson.build
135
+++ b/nbd/meson.build
136
@@ -XXX,XX +XXX,XX @@
137
block_ss.add(files(
138
'client.c',
139
'common.c',
140
+))
141
+blockdev_ss.add(files(
142
'server.c',
143
))
144
diff --git a/stubs/meson.build b/stubs/meson.build
145
index XXXXXXX..XXXXXXX 100644
146
--- a/stubs/meson.build
147
+++ b/stubs/meson.build
148
@@ -XXX,XX +XXX,XX @@
149
stub_ss.add(files('arch_type.c'))
150
stub_ss.add(files('bdrv-next-monitor-owned.c'))
151
stub_ss.add(files('blk-commit-all.c'))
152
+stub_ss.add(files('blk-exp-close-all.c'))
153
stub_ss.add(files('blockdev-close-all-bdrv-states.c'))
154
stub_ss.add(files('change-state-handler.c'))
155
stub_ss.add(files('cmos.c'))
873
--
156
--
874
2.24.1
157
2.26.2
875
158
876
diff view generated by jsdifflib
1
Overwriting IMGOPTS means ignoring all user-supplied options, which is
1
Make it possible to specify the iothread where the export will run. By
2
not what we want. Replace the current IMGOPTS use by a new BACKING_FILE
2
default the block node can be moved to other AioContexts later and the
3
variable.
3
export will follow. The fixed-iothread option forces strict behavior
4
that prevents changing AioContext while the export is active. See the
5
QAPI docs for details.
4
6
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
8
Message-id: 20200929125516.186715-5-stefanha@redhat.com
7
Message-id: 20191107163708.833192-14-mreitz@redhat.com
9
[Fix stray '#' character in block-export.json and add missing "(since:
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
5.2)" as suggested by Eric Blake.
11
--Stefan]
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
13
---
10
tests/qemu-iotests/267 | 12 ++++++++----
14
qapi/block-export.json | 11 ++++++++++
11
1 file changed, 8 insertions(+), 4 deletions(-)
15
block/export/export.c | 31 +++++++++++++++++++++++++++-
16
block/export/vhost-user-blk-server.c | 5 ++++-
17
nbd/server.c | 2 --
18
4 files changed, 45 insertions(+), 4 deletions(-)
12
19
13
diff --git a/tests/qemu-iotests/267 b/tests/qemu-iotests/267
20
diff --git a/qapi/block-export.json b/qapi/block-export.json
14
index XXXXXXX..XXXXXXX 100755
21
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/267
22
--- a/qapi/block-export.json
16
+++ b/tests/qemu-iotests/267
23
+++ b/qapi/block-export.json
17
@@ -XXX,XX +XXX,XX @@ size=128M
24
@@ -XXX,XX +XXX,XX @@
18
25
# export before completion is signalled. (since: 5.2;
19
run_test()
26
# default: false)
27
#
28
+# @iothread: The name of the iothread object where the export will run. The
29
+# default is to use the thread currently associated with the
30
+# block node. (since: 5.2)
31
+#
32
+# @fixed-iothread: True prevents the block node from being moved to another
33
+# thread while the export is active. If true and @iothread is
34
+# given, export creation fails if the block node cannot be
35
+# moved to the iothread. The default is false. (since: 5.2)
36
+#
37
# Since: 4.2
38
##
39
{ 'union': 'BlockExportOptions',
40
'base': { 'type': 'BlockExportType',
41
'id': 'str',
42
+     '*fixed-iothread': 'bool',
43
+     '*iothread': 'str',
44
'node-name': 'str',
45
'*writable': 'bool',
46
'*writethrough': 'bool' },
47
diff --git a/block/export/export.c b/block/export/export.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/block/export/export.c
50
+++ b/block/export/export.c
51
@@ -XXX,XX +XXX,XX @@
52
53
#include "block/block.h"
54
#include "sysemu/block-backend.h"
55
+#include "sysemu/iothread.h"
56
#include "block/export.h"
57
#include "block/nbd.h"
58
#include "qapi/error.h"
59
@@ -XXX,XX +XXX,XX @@ static const BlockExportDriver *blk_exp_find_driver(BlockExportType type)
60
61
BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
20
{
62
{
21
- _make_test_img $size
63
+ bool fixed_iothread = export->has_fixed_iothread && export->fixed_iothread;
22
+ if [ -n "$BACKING_FILE" ]; then
64
const BlockExportDriver *drv;
23
+ _make_test_img -b "$BACKING_FILE" $size
65
BlockExport *exp = NULL;
24
+ else
66
BlockDriverState *bs;
25
+ _make_test_img $size
67
- BlockBackend *blk;
26
+ fi
68
+ BlockBackend *blk = NULL;
27
printf "savevm snap0\ninfo snapshots\nloadvm snap0\n" | run_qemu "$@" | _filter_date
69
AioContext *ctx;
70
uint64_t perm;
71
int ret;
72
@@ -XXX,XX +XXX,XX @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
73
ctx = bdrv_get_aio_context(bs);
74
aio_context_acquire(ctx);
75
76
+ if (export->has_iothread) {
77
+ IOThread *iothread;
78
+ AioContext *new_ctx;
79
+
80
+ iothread = iothread_by_id(export->iothread);
81
+ if (!iothread) {
82
+ error_setg(errp, "iothread \"%s\" not found", export->iothread);
83
+ goto fail;
84
+ }
85
+
86
+ new_ctx = iothread_get_aio_context(iothread);
87
+
88
+ ret = bdrv_try_set_aio_context(bs, new_ctx, errp);
89
+ if (ret == 0) {
90
+ aio_context_release(ctx);
91
+ aio_context_acquire(new_ctx);
92
+ ctx = new_ctx;
93
+ } else if (fixed_iothread) {
94
+ goto fail;
95
+ }
96
+ }
97
+
98
/*
99
* Block exports are used for non-shared storage migration. Make sure
100
* that BDRV_O_INACTIVE is cleared and the image is ready for write
101
@@ -XXX,XX +XXX,XX @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
102
}
103
104
blk = blk_new(ctx, perm, BLK_PERM_ALL);
105
+
106
+ if (!fixed_iothread) {
107
+ blk_set_allow_aio_context_change(blk, true);
108
+ }
109
+
110
ret = blk_insert_bs(blk, bs, errp);
111
if (ret < 0) {
112
goto fail;
113
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
114
index XXXXXXX..XXXXXXX 100644
115
--- a/block/export/vhost-user-blk-server.c
116
+++ b/block/export/vhost-user-blk-server.c
117
@@ -XXX,XX +XXX,XX @@ static const VuDevIface vu_blk_iface = {
118
static void blk_aio_attached(AioContext *ctx, void *opaque)
119
{
120
VuBlkExport *vexp = opaque;
121
+
122
+ vexp->export.ctx = ctx;
123
vhost_user_server_attach_aio_context(&vexp->vu_server, ctx);
28
}
124
}
29
125
30
@@ -XXX,XX +XXX,XX @@ echo
126
static void blk_aio_detach(void *opaque)
31
127
{
32
TEST_IMG="$TEST_IMG.base" _make_test_img $size
128
VuBlkExport *vexp = opaque;
33
129
+
34
-IMGOPTS="backing_file=$TEST_IMG.base" \
130
vhost_user_server_detach_aio_context(&vexp->vu_server);
35
+BACKING_FILE="$TEST_IMG.base" \
131
+ vexp->export.ctx = NULL;
36
run_test -blockdev driver=file,filename="$TEST_IMG.base",node-name=backing-file \
132
}
37
-blockdev driver=file,filename="$TEST_IMG",node-name=file \
133
38
-blockdev driver=$IMGFMT,file=file,backing=backing-file,node-name=fmt
134
static void
39
135
@@ -XXX,XX +XXX,XX @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
40
-IMGOPTS="backing_file=$TEST_IMG.base" \
136
vu_blk_initialize_config(blk_bs(exp->blk), &vexp->blkcfg,
41
+BACKING_FILE="$TEST_IMG.base" \
137
logical_block_size);
42
run_test -blockdev driver=file,filename="$TEST_IMG.base",node-name=backing-file \
138
43
-blockdev driver=$IMGFMT,file=backing-file,node-name=backing-fmt \
139
- blk_set_allow_aio_context_change(exp->blk, true);
44
-blockdev driver=file,filename="$TEST_IMG",node-name=file \
140
blk_add_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
45
@@ -XXX,XX +XXX,XX @@ echo
141
vexp);
46
echo "=== -blockdev with NBD server on the backing file ==="
142
47
echo
143
diff --git a/nbd/server.c b/nbd/server.c
48
144
index XXXXXXX..XXXXXXX 100644
49
-IMGOPTS="backing_file=$TEST_IMG.base" _make_test_img $size
145
--- a/nbd/server.c
50
+_make_test_img -b "$TEST_IMG.base" $size
146
+++ b/nbd/server.c
51
cat <<EOF |
147
@@ -XXX,XX +XXX,XX @@ static int nbd_export_create(BlockExport *blk_exp, BlockExportOptions *exp_args,
52
nbd_server_start unix:$SOCK_DIR/nbd
148
return ret;
53
nbd_server_add -w backing-fmt
149
}
150
151
- blk_set_allow_aio_context_change(blk, true);
152
-
153
QTAILQ_INIT(&exp->clients);
154
exp->name = g_strdup(arg->name);
155
exp->description = g_strdup(arg->description);
54
--
156
--
55
2.24.1
157
2.26.2
56
158
57
diff view generated by jsdifflib
1
Some tests require compat=1.1 and thus set IMGOPTS='compat=1.1'
1
Allow the number of queues to be configured using --export
2
globally. That is not how it should be done; instead, they should
2
vhost-user-blk,num-queues=N. This setting should match the QEMU --device
3
simply set _unsupported_imgopts to compat=0.10 (compat=1.1 is the
3
vhost-user-blk-pci,num-queues=N setting but QEMU vhost-user-blk.c lowers
4
default anyway).
4
its own value if the vhost-user-blk backend offers fewer queues than
5
QEMU.
5
6
6
This makes the tests heed user-specified $IMGOPTS. Some do not work
7
The vhost-user-blk-server.c code is already capable of multi-queue. All
7
with all image options, though, so we need to disable them accordingly.
8
virtqueue processing runs in the same AioContext. No new locking is
9
needed.
8
10
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Add the num-queues=N option and set the VIRTIO_BLK_F_MQ feature bit.
10
Reviewed-by: Maxim Levitsky <mlevitsky@redhat.com>
12
Note that the feature bit only announces the presence of the num_queues
11
Message-id: 20191107163708.833192-7-mreitz@redhat.com
13
configuration space field. It does not promise that there is more than 1
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
virtqueue, so we can set it unconditionally.
15
16
I tested multi-queue by running a random read fio test with numjobs=4 on
17
an -smp 4 guest. After the benchmark finished the guest /proc/interrupts
18
file showed activity on all 4 virtio-blk MSI-X. The /sys/block/vda/mq/
19
directory shows that Linux blk-mq has 4 queues configured.
20
21
An automated test is included in the next commit.
22
23
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
24
Acked-by: Markus Armbruster <armbru@redhat.com>
25
Message-id: 20201001144604.559733-2-stefanha@redhat.com
26
[Fixed accidental tab characters as suggested by Markus Armbruster
27
--Stefan]
28
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
29
---
14
tests/qemu-iotests/036 | 3 +--
30
qapi/block-export.json | 10 +++++++---
15
tests/qemu-iotests/060 | 4 ++--
31
block/export/vhost-user-blk-server.c | 24 ++++++++++++++++++------
16
tests/qemu-iotests/062 | 3 ++-
32
2 files changed, 25 insertions(+), 9 deletions(-)
17
tests/qemu-iotests/066 | 3 ++-
18
tests/qemu-iotests/068 | 3 ++-
19
tests/qemu-iotests/098 | 4 ++--
20
6 files changed, 11 insertions(+), 9 deletions(-)
21
33
22
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
34
diff --git a/qapi/block-export.json b/qapi/block-export.json
23
index XXXXXXX..XXXXXXX 100755
35
index XXXXXXX..XXXXXXX 100644
24
--- a/tests/qemu-iotests/036
36
--- a/qapi/block-export.json
25
+++ b/tests/qemu-iotests/036
37
+++ b/qapi/block-export.json
26
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
38
@@ -XXX,XX +XXX,XX @@
27
# This tests qcow2-specific low-level functionality
39
# SocketAddress types are supported. Passed fds must be UNIX domain
28
_supported_fmt qcow2
40
# sockets.
29
_supported_proto file
41
# @logical-block-size: Logical block size in bytes. Defaults to 512 bytes.
30
-
42
+# @num-queues: Number of request virtqueues. Must be greater than 0. Defaults
31
# Only qcow2v3 and later supports feature bits
43
+# to 1.
32
-IMGOPTS="compat=1.1"
44
#
33
+_unsupported_imgopts 'compat=0.10'
45
# Since: 5.2
34
46
##
35
echo
47
{ 'struct': 'BlockExportOptionsVhostUserBlk',
36
echo === Image with unknown incompatible feature bit ===
48
- 'data': { 'addr': 'SocketAddress', '*logical-block-size': 'size' } }
37
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
49
+ 'data': { 'addr': 'SocketAddress',
38
index XXXXXXX..XXXXXXX 100755
50
+     '*logical-block-size': 'size',
39
--- a/tests/qemu-iotests/060
51
+ '*num-queues': 'uint16'} }
40
+++ b/tests/qemu-iotests/060
52
41
@@ -XXX,XX +XXX,XX @@ _filter_io_error()
53
##
42
_supported_fmt qcow2
54
# @NbdServerAddOptions:
43
_supported_proto file
55
@@ -XXX,XX +XXX,XX @@
44
_supported_os Linux
56
{ 'union': 'BlockExportOptions',
45
+# These tests only work for compat=1.1 images with refcount_bits=16
57
'base': { 'type': 'BlockExportType',
46
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
58
'id': 'str',
47
59
-     '*fixed-iothread': 'bool',
48
# The repair process will create a large file - so check for availability first
60
-     '*iothread': 'str',
49
_require_large_file 64G
61
+ '*fixed-iothread': 'bool',
50
@@ -XXX,XX +XXX,XX @@ l1_offset=196608 # 0x30000 (XXX: just an assumption)
62
+ '*iothread': 'str',
51
l2_offset=262144 # 0x40000 (XXX: just an assumption)
63
'node-name': 'str',
52
l2_offset_after_snapshot=524288 # 0x80000 (XXX: just an assumption)
64
'*writable': 'bool',
53
65
'*writethrough': 'bool' },
54
-IMGOPTS="compat=1.1"
66
diff --git a/block/export/vhost-user-blk-server.c b/block/export/vhost-user-blk-server.c
55
-
67
index XXXXXXX..XXXXXXX 100644
56
OPEN_RW="open -o overlap-check=all $TEST_IMG"
68
--- a/block/export/vhost-user-blk-server.c
57
# Overlap checks are done before write operations only, therefore opening an
69
+++ b/block/export/vhost-user-blk-server.c
58
# image read-only makes the overlap-check option irrelevant
70
@@ -XXX,XX +XXX,XX @@
59
diff --git a/tests/qemu-iotests/062 b/tests/qemu-iotests/062
71
#include "util/block-helpers.h"
60
index XXXXXXX..XXXXXXX 100755
72
61
--- a/tests/qemu-iotests/062
73
enum {
62
+++ b/tests/qemu-iotests/062
74
- VHOST_USER_BLK_MAX_QUEUES = 1,
63
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
75
+ VHOST_USER_BLK_NUM_QUEUES_DEFAULT = 1,
64
# This tests qcow2-specific low-level functionality
76
};
65
_supported_fmt qcow2
77
struct virtio_blk_inhdr {
66
_supported_proto generic
78
unsigned char status;
67
+# We need zero clusters and snapshots
79
@@ -XXX,XX +XXX,XX @@ static uint64_t vu_blk_get_features(VuDev *dev)
68
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]'
80
1ull << VIRTIO_BLK_F_DISCARD |
69
81
1ull << VIRTIO_BLK_F_WRITE_ZEROES |
70
-IMGOPTS="compat=1.1"
82
1ull << VIRTIO_BLK_F_CONFIG_WCE |
71
IMG_SIZE=64M
83
+ 1ull << VIRTIO_BLK_F_MQ |
72
84
1ull << VIRTIO_F_VERSION_1 |
73
echo
85
1ull << VIRTIO_RING_F_INDIRECT_DESC |
74
diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066
86
1ull << VIRTIO_RING_F_EVENT_IDX |
75
index XXXXXXX..XXXXXXX 100755
87
@@ -XXX,XX +XXX,XX @@ static void blk_aio_detach(void *opaque)
76
--- a/tests/qemu-iotests/066
88
77
+++ b/tests/qemu-iotests/066
89
static void
78
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
90
vu_blk_initialize_config(BlockDriverState *bs,
79
# This tests qcow2-specific low-level functionality
91
- struct virtio_blk_config *config, uint32_t blk_size)
80
_supported_fmt qcow2
92
+ struct virtio_blk_config *config,
81
_supported_proto generic
93
+ uint32_t blk_size,
82
+# We need zero clusters and snapshots
94
+ uint16_t num_queues)
83
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]'
95
{
84
96
config->capacity = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
85
# Intentionally create an unaligned image
97
config->blk_size = blk_size;
86
-IMGOPTS="compat=1.1"
98
@@ -XXX,XX +XXX,XX @@ vu_blk_initialize_config(BlockDriverState *bs,
87
IMG_SIZE=$((64 * 1024 * 1024 + 512))
99
config->seg_max = 128 - 2;
88
100
config->min_io_size = 1;
89
echo
101
config->opt_io_size = 1;
90
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
102
- config->num_queues = VHOST_USER_BLK_MAX_QUEUES;
91
index XXXXXXX..XXXXXXX 100755
103
+ config->num_queues = num_queues;
92
--- a/tests/qemu-iotests/068
104
config->max_discard_sectors = 32768;
93
+++ b/tests/qemu-iotests/068
105
config->max_discard_seg = 1;
94
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
106
config->discard_sector_alignment = config->blk_size >> 9;
95
# This tests qcow2-specific low-level functionality
107
@@ -XXX,XX +XXX,XX @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
96
_supported_fmt qcow2
108
BlockExportOptionsVhostUserBlk *vu_opts = &opts->u.vhost_user_blk;
97
_supported_proto generic
109
Error *local_err = NULL;
98
+# Internal snapshots are (currently) impossible with refcount_bits=1
110
uint64_t logical_block_size;
99
+_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]'
111
+ uint16_t num_queues = VHOST_USER_BLK_NUM_QUEUES_DEFAULT;
100
112
101
-IMGOPTS="compat=1.1"
113
vexp->writable = opts->writable;
102
IMG_SIZE=128K
114
vexp->blkcfg.wce = 0;
103
115
@@ -XXX,XX +XXX,XX @@ static int vu_blk_exp_create(BlockExport *exp, BlockExportOptions *opts,
104
case "$QEMU_DEFAULT_MACHINE" in
116
}
105
diff --git a/tests/qemu-iotests/098 b/tests/qemu-iotests/098
117
vexp->blk_size = logical_block_size;
106
index XXXXXXX..XXXXXXX 100755
118
blk_set_guest_block_size(exp->blk, logical_block_size);
107
--- a/tests/qemu-iotests/098
119
+
108
+++ b/tests/qemu-iotests/098
120
+ if (vu_opts->has_num_queues) {
109
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
121
+ num_queues = vu_opts->num_queues;
110
122
+ }
111
_supported_fmt qcow2
123
+ if (num_queues == 0) {
112
_supported_proto file
124
+ error_setg(errp, "num-queues must be greater than 0");
113
-
125
+ return -EINVAL;
114
-IMGOPTS="compat=1.1"
126
+ }
115
+# The code path we want to test here only works for compat=1.1 images
127
+
116
+_unsupported_imgopts 'compat=0.10'
128
vu_blk_initialize_config(blk_bs(exp->blk), &vexp->blkcfg,
117
129
- logical_block_size);
118
for event in l1_update empty_image_prepare reftable_update refblock_alloc; do
130
+ logical_block_size, num_queues);
119
131
132
blk_add_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
133
vexp);
134
135
if (!vhost_user_server_start(&vexp->vu_server, vu_opts->addr, exp->ctx,
136
- VHOST_USER_BLK_MAX_QUEUES, &vu_blk_iface,
137
- errp)) {
138
+ num_queues, &vu_blk_iface, errp)) {
139
blk_remove_aio_context_notifier(exp->blk, blk_aio_attached,
140
blk_aio_detach, vexp);
141
return -EADDRNOTAVAIL;
120
--
142
--
121
2.24.1
143
2.26.2
122
144
123
diff view generated by jsdifflib
1
We need some way to correlate QAPI BlockPermission values with
1
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2
BLK_PERM_* flags. We could:
2
Message-id: 20201001144604.559733-3-stefanha@redhat.com
3
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
---
5
tests/qtest/vhost-user-blk-test.c | 81 +++++++++++++++++++++++++++++--
6
1 file changed, 76 insertions(+), 5 deletions(-)
3
7
4
(1) have the same order in the QAPI definition as the the BLK_PERM_*
8
diff --git a/tests/qtest/vhost-user-blk-test.c b/tests/qtest/vhost-user-blk-test.c
5
flags are in LSb-first order. However, then there is no guarantee
6
that they actually match (e.g. when someone modifies the QAPI schema
7
without thinking of the BLK_PERM_* definitions).
8
We could add static assertions, but these would break what’s good
9
about this solution, namely its simplicity.
10
11
(2) define the BLK_PERM_* flags based on the BlockPermission values.
12
But this way whenever someone were to modify the QAPI order
13
(perfectly sensible in theory), the BLK_PERM_* values would change.
14
Because these values are used for file locking, this might break
15
file locking between different qemu versions.
16
17
Therefore, go the slightly more cumbersome way: Add a function to
18
translate from the QAPI constants to the BLK_PERM_* flags.
19
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
Message-id: 20191108123455.39445-2-mreitz@redhat.com
22
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
23
Signed-off-by: Max Reitz <mreitz@redhat.com>
24
---
25
block.c | 18 ++++++++++++++++++
26
include/block/block.h | 1 +
27
2 files changed, 19 insertions(+)
28
29
diff --git a/block.c b/block.c
30
index XXXXXXX..XXXXXXX 100644
9
index XXXXXXX..XXXXXXX 100644
31
--- a/block.c
10
--- a/tests/qtest/vhost-user-blk-test.c
32
+++ b/block.c
11
+++ b/tests/qtest/vhost-user-blk-test.c
33
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
12
@@ -XXX,XX +XXX,XX @@ static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
34
*nshared = shared;
13
qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
35
}
14
}
36
15
37
+uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
16
+static void multiqueue(void *obj, void *data, QGuestAllocator *t_alloc)
38
+{
17
+{
39
+ static const uint64_t permissions[] = {
18
+ QVirtioPCIDevice *pdev1 = obj;
40
+ [BLOCK_PERMISSION_CONSISTENT_READ] = BLK_PERM_CONSISTENT_READ,
19
+ QVirtioDevice *dev1 = &pdev1->vdev;
41
+ [BLOCK_PERMISSION_WRITE] = BLK_PERM_WRITE,
20
+ QVirtioPCIDevice *pdev8;
42
+ [BLOCK_PERMISSION_WRITE_UNCHANGED] = BLK_PERM_WRITE_UNCHANGED,
21
+ QVirtioDevice *dev8;
43
+ [BLOCK_PERMISSION_RESIZE] = BLK_PERM_RESIZE,
22
+ QTestState *qts = pdev1->pdev->bus->qts;
44
+ [BLOCK_PERMISSION_GRAPH_MOD] = BLK_PERM_GRAPH_MOD,
23
+ uint64_t features;
45
+ };
24
+ uint16_t num_queues;
46
+
25
+
47
+ QEMU_BUILD_BUG_ON(ARRAY_SIZE(permissions) != BLOCK_PERMISSION__MAX);
26
+ /*
48
+ QEMU_BUILD_BUG_ON(1UL << ARRAY_SIZE(permissions) != BLK_PERM_ALL + 1);
27
+ * The primary device has 1 queue and VIRTIO_BLK_F_MQ is not enabled. The
28
+ * VIRTIO specification allows VIRTIO_BLK_F_MQ to be enabled when there is
29
+ * only 1 virtqueue, but --device vhost-user-blk-pci doesn't do this (which
30
+ * is also spec-compliant).
31
+ */
32
+ features = qvirtio_get_features(dev1);
33
+ g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ), ==, 0);
34
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
35
+ (1u << VIRTIO_RING_F_INDIRECT_DESC) |
36
+ (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
37
+ (1u << VIRTIO_BLK_F_SCSI));
38
+ qvirtio_set_features(dev1, features);
49
+
39
+
50
+ assert(qapi_perm < BLOCK_PERMISSION__MAX);
40
+ /* Hotplug a secondary device with 8 queues */
41
+ qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
42
+ "{'addr': %s, 'chardev': 'char2', 'num-queues': 8}",
43
+ stringify(PCI_SLOT_HP) ".0");
51
+
44
+
52
+ return permissions[qapi_perm];
45
+ pdev8 = virtio_pci_new(pdev1->pdev->bus,
46
+ &(QPCIAddress) {
47
+ .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
48
+ });
49
+ g_assert_nonnull(pdev8);
50
+ g_assert_cmpint(pdev8->vdev.device_type, ==, VIRTIO_ID_BLOCK);
51
+
52
+ qos_object_start_hw(&pdev8->obj);
53
+
54
+ dev8 = &pdev8->vdev;
55
+ features = qvirtio_get_features(dev8);
56
+ g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ),
57
+ ==,
58
+ (1u << VIRTIO_BLK_F_MQ));
59
+ features = features & ~(QVIRTIO_F_BAD_FEATURE |
60
+ (1u << VIRTIO_RING_F_INDIRECT_DESC) |
61
+ (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
62
+ (1u << VIRTIO_BLK_F_SCSI) |
63
+ (1u << VIRTIO_BLK_F_MQ));
64
+ qvirtio_set_features(dev8, features);
65
+
66
+ num_queues = qvirtio_config_readw(dev8,
67
+ offsetof(struct virtio_blk_config, num_queues));
68
+ g_assert_cmpint(num_queues, ==, 8);
69
+
70
+ qvirtio_pci_device_disable(pdev8);
71
+ qos_object_destroy(&pdev8->obj);
72
+
73
+ /* unplug secondary disk */
74
+ qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
53
+}
75
+}
54
+
76
+
55
static void bdrv_replace_child_noperm(BdrvChild *child,
77
/*
56
BlockDriverState *new_bs)
78
* Check that setting the vring addr on a non-existent virtqueue does
79
* not crash.
80
@@ -XXX,XX +XXX,XX @@ static void quit_storage_daemon(void *qmp_test_state)
81
g_free(qmp_test_state);
82
}
83
84
-static char *start_vhost_user_blk(GString *cmd_line, int vus_instances)
85
+static char *start_vhost_user_blk(GString *cmd_line, int vus_instances,
86
+ int num_queues)
57
{
87
{
58
diff --git a/include/block/block.h b/include/block/block.h
88
const char *vhost_user_blk_bin = qtest_qemu_storage_daemon_binary();
59
index XXXXXXX..XXXXXXX 100644
89
int fd, qmp_fd, i;
60
--- a/include/block/block.h
90
@@ -XXX,XX +XXX,XX @@ static char *start_vhost_user_blk(GString *cmd_line, int vus_instances)
61
+++ b/include/block/block.h
91
g_string_append_printf(storage_daemon_command,
62
@@ -XXX,XX +XXX,XX @@ enum {
92
"--blockdev driver=file,node-name=disk%d,filename=%s "
63
};
93
"--export type=vhost-user-blk,id=disk%d,addr.type=unix,addr.path=%s,"
64
94
- "node-name=disk%i,writable=on ",
65
char *bdrv_perm_names(uint64_t perm);
95
- i, img_path, i, sock_path, i);
66
+uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm);
96
+ "node-name=disk%i,writable=on,num-queues=%d ",
67
97
+ i, img_path, i, sock_path, i, num_queues);
68
/* disk I/O throttling */
98
69
void bdrv_init(void);
99
g_string_append_printf(cmd_line, "-chardev socket,id=char%d,path=%s ",
100
i + 1, sock_path);
101
@@ -XXX,XX +XXX,XX @@ static char *start_vhost_user_blk(GString *cmd_line, int vus_instances)
102
103
static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg)
104
{
105
- start_vhost_user_blk(cmd_line, 1);
106
+ start_vhost_user_blk(cmd_line, 1, 1);
107
return arg;
108
}
109
110
@@ -XXX,XX +XXX,XX @@ static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg)
111
static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *arg)
112
{
113
/* "-chardev socket,id=char2" is used for pci_hotplug*/
114
- start_vhost_user_blk(cmd_line, 2);
115
+ start_vhost_user_blk(cmd_line, 2, 1);
116
+ return arg;
117
+}
118
+
119
+static void *vhost_user_blk_multiqueue_test_setup(GString *cmd_line, void *arg)
120
+{
121
+ start_vhost_user_blk(cmd_line, 2, 8);
122
return arg;
123
}
124
125
@@ -XXX,XX +XXX,XX @@ static void register_vhost_user_blk_test(void)
126
127
opts.before = vhost_user_blk_hotplug_test_setup;
128
qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts);
129
+
130
+ opts.before = vhost_user_blk_multiqueue_test_setup;
131
+ qos_add_test("multiqueue", "vhost-user-blk-pci", multiqueue, &opts);
132
}
133
134
libqos_init(register_vhost_user_blk_test);
70
--
135
--
71
2.24.1
136
2.26.2
72
137
73
diff view generated by jsdifflib
1
Sometimes it is useful to be able to add a node to the block graph that
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
takes or unshare a certain set of permissions for debugging purposes.
3
This patch adds this capability to blkdebug.
4
2
5
(Note that you cannot make blkdebug release or share permissions that it
3
bdrv_co_block_status_above has several design problems with handling
6
needs to take or cannot share, because this might result in assertion
4
short backing files:
7
failures in the block layer. But if the blkdebug node has no parents,
8
it will not take any permissions and share everything by default, so you
9
can then freely choose what permissions to take and share.)
10
5
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
1. With want_zeros=true, it may return ret with BDRV_BLOCK_ZERO but
12
Message-id: 20191108123455.39445-4-mreitz@redhat.com
7
without BDRV_BLOCK_ALLOCATED flag, when actually short backing file
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
which produces these after-EOF zeros is inside requested backing
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
sequence.
10
11
2. With want_zero=false, it may return pnum=0 prior to actual EOF,
12
because of EOF of short backing file.
13
14
Fix these things, making logic about short backing files clearer.
15
16
With fixed bdrv_block_status_above we also have to improve is_zero in
17
qcow2 code, otherwise iotest 154 will fail, because with this patch we
18
stop to merge zeros of different types (produced by fully unallocated
19
in the whole backing chain regions vs produced by short backing files).
20
21
Note also, that this patch leaves for another day the general problem
22
around block-status: misuse of BDRV_BLOCK_ALLOCATED as is-fs-allocated
23
vs go-to-backing.
24
25
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
26
Reviewed-by: Alberto Garcia <berto@igalia.com>
27
Reviewed-by: Eric Blake <eblake@redhat.com>
28
Message-id: 20200924194003.22080-2-vsementsov@virtuozzo.com
29
[Fix s/comes/come/ as suggested by Eric Blake
30
--Stefan]
31
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
32
---
16
block/blkdebug.c | 93 +++++++++++++++++++++++++++++++++++++++++++-
33
block/io.c | 68 ++++++++++++++++++++++++++++++++++++++++-----------
17
qapi/block-core.json | 14 ++++++-
34
block/qcow2.c | 16 ++++++++++--
18
2 files changed, 105 insertions(+), 2 deletions(-)
35
2 files changed, 68 insertions(+), 16 deletions(-)
19
36
20
diff --git a/block/blkdebug.c b/block/blkdebug.c
37
diff --git a/block/io.c b/block/io.c
21
index XXXXXXX..XXXXXXX 100644
38
index XXXXXXX..XXXXXXX 100644
22
--- a/block/blkdebug.c
39
--- a/block/io.c
23
+++ b/block/blkdebug.c
40
+++ b/block/io.c
24
@@ -XXX,XX +XXX,XX @@
41
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
25
#include "qemu/cutils.h"
42
int64_t *map,
26
#include "qemu/config-file.h"
43
BlockDriverState **file)
27
#include "block/block_int.h"
44
{
28
+#include "block/qdict.h"
45
+ int ret;
29
#include "qemu/module.h"
46
BlockDriverState *p;
30
#include "qemu/option.h"
47
- int ret = 0;
31
+#include "qapi/qapi-visit-block-core.h"
48
- bool first = true;
32
#include "qapi/qmp/qdict.h"
49
+ int64_t eof = 0;
33
+#include "qapi/qmp/qlist.h"
50
34
#include "qapi/qmp/qstring.h"
51
assert(bs != base);
35
+#include "qapi/qobject-input-visitor.h"
52
- for (p = bs; p != base; p = bdrv_filter_or_cow_bs(p)) {
36
#include "sysemu/qtest.h"
37
38
typedef struct BDRVBlkdebugState {
39
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVBlkdebugState {
40
uint64_t opt_discard;
41
uint64_t max_discard;
42
43
+ uint64_t take_child_perms;
44
+ uint64_t unshare_child_perms;
45
+
53
+
46
/* For blkdebug_refresh_filename() */
54
+ ret = bdrv_co_block_status(bs, want_zero, offset, bytes, pnum, map, file);
47
char *config_file;
55
+ if (ret < 0 || *pnum == 0 || ret & BDRV_BLOCK_ALLOCATED) {
48
49
@@ -XXX,XX +XXX,XX @@ static void blkdebug_parse_filename(const char *filename, QDict *options,
50
qdict_put_str(options, "x-image", filename);
51
}
52
53
+static int blkdebug_parse_perm_list(uint64_t *dest, QDict *options,
54
+ const char *prefix, Error **errp)
55
+{
56
+ int ret = 0;
57
+ QDict *subqdict = NULL;
58
+ QObject *crumpled_subqdict = NULL;
59
+ Visitor *v = NULL;
60
+ BlockPermissionList *perm_list = NULL, *element;
61
+ Error *local_err = NULL;
62
+
63
+ *dest = 0;
64
+
65
+ qdict_extract_subqdict(options, &subqdict, prefix);
66
+ if (!qdict_size(subqdict)) {
67
+ goto out;
68
+ }
69
+
70
+ crumpled_subqdict = qdict_crumple(subqdict, errp);
71
+ if (!crumpled_subqdict) {
72
+ ret = -EINVAL;
73
+ goto out;
74
+ }
75
+
76
+ v = qobject_input_visitor_new(crumpled_subqdict);
77
+ visit_type_BlockPermissionList(v, NULL, &perm_list, &local_err);
78
+ if (local_err) {
79
+ error_propagate(errp, local_err);
80
+ ret = -EINVAL;
81
+ goto out;
82
+ }
83
+
84
+ for (element = perm_list; element; element = element->next) {
85
+ *dest |= bdrv_qapi_perm_to_blk_perm(element->value);
86
+ }
87
+
88
+out:
89
+ qapi_free_BlockPermissionList(perm_list);
90
+ visit_free(v);
91
+ qobject_unref(subqdict);
92
+ qobject_unref(crumpled_subqdict);
93
+ return ret;
94
+}
95
+
96
+static int blkdebug_parse_perms(BDRVBlkdebugState *s, QDict *options,
97
+ Error **errp)
98
+{
99
+ int ret;
100
+
101
+ ret = blkdebug_parse_perm_list(&s->take_child_perms, options,
102
+ "take-child-perms.", errp);
103
+ if (ret < 0) {
104
+ return ret;
56
+ return ret;
105
+ }
57
+ }
106
+
58
+
107
+ ret = blkdebug_parse_perm_list(&s->unshare_child_perms, options,
59
+ if (ret & BDRV_BLOCK_EOF) {
108
+ "unshare-child-perms.", errp);
60
+ eof = offset + *pnum;
109
+ if (ret < 0) {
110
+ return ret;
111
+ }
61
+ }
112
+
62
+
113
+ return 0;
63
+ assert(*pnum <= bytes);
114
+}
64
+ bytes = *pnum;
115
+
65
+
116
static QemuOptsList runtime_opts = {
66
+ for (p = bdrv_filter_or_cow_bs(bs); p != base;
117
.name = "blkdebug",
67
+ p = bdrv_filter_or_cow_bs(p))
118
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
68
+ {
119
@@ -XXX,XX +XXX,XX @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
69
ret = bdrv_co_block_status(p, want_zero, offset, bytes, pnum, map,
120
/* Set initial state */
70
file);
121
s->state = 1;
71
if (ret < 0) {
122
72
- break;
123
+ /* Parse permissions modifiers before opening the image file */
73
+ return ret;
124
+ ret = blkdebug_parse_perms(s, options, errp);
74
}
125
+ if (ret < 0) {
75
- if (ret & BDRV_BLOCK_ZERO && ret & BDRV_BLOCK_EOF && !first) {
126
+ goto out;
76
+ if (*pnum == 0) {
77
/*
78
- * Reading beyond the end of the file continues to read
79
- * zeroes, but we can only widen the result to the
80
- * unallocated length we learned from an earlier
81
- * iteration.
82
+ * The top layer deferred to this layer, and because this layer is
83
+ * short, any zeroes that we synthesize beyond EOF behave as if they
84
+ * were allocated at this layer.
85
+ *
86
+ * We don't include BDRV_BLOCK_EOF into ret, as upper layer may be
87
+ * larger. We'll add BDRV_BLOCK_EOF if needed at function end, see
88
+ * below.
89
*/
90
+ assert(ret & BDRV_BLOCK_EOF);
91
*pnum = bytes;
92
+ if (file) {
93
+ *file = p;
94
+ }
95
+ ret = BDRV_BLOCK_ZERO | BDRV_BLOCK_ALLOCATED;
96
+ break;
97
}
98
- if (ret & (BDRV_BLOCK_ZERO | BDRV_BLOCK_DATA)) {
99
+ if (ret & BDRV_BLOCK_ALLOCATED) {
100
+ /*
101
+ * We've found the node and the status, we must break.
102
+ *
103
+ * Drop BDRV_BLOCK_EOF, as it's not for upper layer, which may be
104
+ * larger. We'll add BDRV_BLOCK_EOF if needed at function end, see
105
+ * below.
106
+ */
107
+ ret &= ~BDRV_BLOCK_EOF;
108
break;
109
}
110
- /* [offset, pnum] unallocated on this layer, which could be only
111
- * the first part of [offset, bytes]. */
112
- bytes = MIN(bytes, *pnum);
113
- first = false;
114
+
115
+ /*
116
+ * OK, [offset, offset + *pnum) region is unallocated on this layer,
117
+ * let's continue the diving.
118
+ */
119
+ assert(*pnum <= bytes);
120
+ bytes = *pnum;
127
+ }
121
+ }
128
+
122
+
129
/* Open the image file */
123
+ if (offset + *pnum == eof) {
130
bs->file = bdrv_open_child(qemu_opt_get(opts, "x-image"), options, "image",
124
+ ret |= BDRV_BLOCK_EOF;
131
bs, &child_file, false, &local_err);
125
}
132
@@ -XXX,XX +XXX,XX @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state,
126
+
133
return 0;
127
return ret;
134
}
128
}
135
129
136
+static void blkdebug_child_perm(BlockDriverState *bs, BdrvChild *c,
130
diff --git a/block/qcow2.c b/block/qcow2.c
137
+ const BdrvChildRole *role,
131
index XXXXXXX..XXXXXXX 100644
138
+ BlockReopenQueue *reopen_queue,
132
--- a/block/qcow2.c
139
+ uint64_t perm, uint64_t shared,
133
+++ b/block/qcow2.c
140
+ uint64_t *nperm, uint64_t *nshared)
134
@@ -XXX,XX +XXX,XX @@ static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
141
+{
135
if (!bytes) {
142
+ BDRVBlkdebugState *s = bs->opaque;
136
return true;
137
}
138
- res = bdrv_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL);
139
- return res >= 0 && (res & BDRV_BLOCK_ZERO) && nr == bytes;
143
+
140
+
144
+ bdrv_filter_default_perms(bs, c, role, reopen_queue, perm, shared,
141
+ /*
145
+ nperm, nshared);
142
+ * bdrv_block_status_above doesn't merge different types of zeros, for
143
+ * example, zeros which come from the region which is unallocated in
144
+ * the whole backing chain, and zeros which come because of a short
145
+ * backing file. So, we need a loop.
146
+ */
147
+ do {
148
+ res = bdrv_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL);
149
+ offset += nr;
150
+ bytes -= nr;
151
+ } while (res >= 0 && (res & BDRV_BLOCK_ZERO) && nr && bytes);
146
+
152
+
147
+ *nperm |= s->take_child_perms;
153
+ return res >= 0 && (res & BDRV_BLOCK_ZERO) && bytes == 0;
148
+ *nshared &= ~s->unshare_child_perms;
154
}
149
+}
155
150
+
156
static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
151
static const char *const blkdebug_strong_runtime_opts[] = {
152
"config",
153
"inject-error.",
154
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = {
155
.bdrv_file_open = blkdebug_open,
156
.bdrv_close = blkdebug_close,
157
.bdrv_reopen_prepare = blkdebug_reopen_prepare,
158
- .bdrv_child_perm = bdrv_filter_default_perms,
159
+ .bdrv_child_perm = blkdebug_child_perm,
160
161
.bdrv_getlength = blkdebug_getlength,
162
.bdrv_refresh_filename = blkdebug_refresh_filename,
163
diff --git a/qapi/block-core.json b/qapi/block-core.json
164
index XXXXXXX..XXXXXXX 100644
165
--- a/qapi/block-core.json
166
+++ b/qapi/block-core.json
167
@@ -XXX,XX +XXX,XX @@
168
#
169
# @set-state: array of state-change descriptions
170
#
171
+# @take-child-perms: Permissions to take on @image in addition to what
172
+# is necessary anyway (which depends on how the
173
+# blkdebug node is used). Defaults to none.
174
+# (since 5.0)
175
+#
176
+# @unshare-child-perms: Permissions not to share on @image in addition
177
+# to what cannot be shared anyway (which depends
178
+# on how the blkdebug node is used). Defaults
179
+# to none. (since 5.0)
180
+#
181
# Since: 2.9
182
##
183
{ 'struct': 'BlockdevOptionsBlkdebug',
184
@@ -XXX,XX +XXX,XX @@
185
'*opt-write-zero': 'int32', '*max-write-zero': 'int32',
186
'*opt-discard': 'int32', '*max-discard': 'int32',
187
'*inject-error': ['BlkdebugInjectErrorOptions'],
188
- '*set-state': ['BlkdebugSetStateOptions'] } }
189
+ '*set-state': ['BlkdebugSetStateOptions'],
190
+ '*take-child-perms': ['BlockPermission'],
191
+ '*unshare-child-perms': ['BlockPermission'] } }
192
193
##
194
# @BlockdevOptionsBlklogwrites:
195
--
157
--
196
2.24.1
158
2.26.2
197
159
198
diff view generated by jsdifflib
Deleted patch
1
Callers can use this new parameter to expect failure during the
2
completion process.
3
1
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: John Snow <jsnow@redhat.com>
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Message-id: 20191108123455.39445-5-mreitz@redhat.com
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
tests/qemu-iotests/iotests.py | 18 ++++++++++++------
11
1 file changed, 12 insertions(+), 6 deletions(-)
12
13
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
14
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/iotests.py
16
+++ b/tests/qemu-iotests/iotests.py
17
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
18
self.assert_no_active_block_jobs()
19
return result
20
21
- def wait_until_completed(self, drive='drive0', check_offset=True, wait=60.0):
22
+ def wait_until_completed(self, drive='drive0', check_offset=True, wait=60.0,
23
+ error=None):
24
'''Wait for a block job to finish, returning the event'''
25
while True:
26
for event in self.vm.get_qmp_events(wait=wait):
27
if event['event'] == 'BLOCK_JOB_COMPLETED':
28
self.assert_qmp(event, 'data/device', drive)
29
- self.assert_qmp_absent(event, 'data/error')
30
- if check_offset:
31
- self.assert_qmp(event, 'data/offset', event['data']['len'])
32
+ if error is None:
33
+ self.assert_qmp_absent(event, 'data/error')
34
+ if check_offset:
35
+ self.assert_qmp(event, 'data/offset',
36
+ event['data']['len'])
37
+ else:
38
+ self.assert_qmp(event, 'data/error', error)
39
self.assert_no_active_block_jobs()
40
return event
41
elif event['event'] == 'JOB_STATUS_CHANGE':
42
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
43
self.assert_qmp(event, 'data/type', 'mirror')
44
self.assert_qmp(event, 'data/offset', event['data']['len'])
45
46
- def complete_and_wait(self, drive='drive0', wait_ready=True):
47
+ def complete_and_wait(self, drive='drive0', wait_ready=True,
48
+ completion_error=None):
49
'''Complete a block job and wait for it to finish'''
50
if wait_ready:
51
self.wait_ready(drive=drive)
52
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
53
result = self.vm.qmp('block-job-complete', device=drive)
54
self.assert_qmp(result, 'return', {})
55
56
- event = self.wait_until_completed(drive=drive)
57
+ event = self.wait_until_completed(drive=drive, error=completion_error)
58
self.assert_qmp(event, 'data/type', 'mirror')
59
60
def pause_wait(self, job_id='job0'):
61
--
62
2.24.1
63
64
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Max Reitz <mreitz@redhat.com>
2
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
3
Tested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
Reviewed-by: John Snow <jsnow@redhat.com>
5
Message-id: 20191108123455.39445-6-mreitz@redhat.com
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
8
tests/qemu-iotests/041 | 44 ++++++++++++++++++++++++++++++++++++++
9
tests/qemu-iotests/041.out | 4 ++--
10
2 files changed, 46 insertions(+), 2 deletions(-)
11
1
12
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
13
index XXXXXXX..XXXXXXX 100755
14
--- a/tests/qemu-iotests/041
15
+++ b/tests/qemu-iotests/041
16
@@ -XXX,XX +XXX,XX @@ class TestOrphanedSource(iotests.QMPTestCase):
17
target='dest-ro')
18
self.assert_qmp(result, 'error/class', 'GenericError')
19
20
+ def test_failing_permission_in_complete(self):
21
+ self.assert_no_active_block_jobs()
22
+
23
+ # Unshare consistent-read on the target
24
+ # (The mirror job does not care)
25
+ result = self.vm.qmp('blockdev-add',
26
+ driver='blkdebug',
27
+ node_name='dest-perm',
28
+ image='dest',
29
+ unshare_child_perms=['consistent-read'])
30
+ self.assert_qmp(result, 'return', {})
31
+
32
+ result = self.vm.qmp('blockdev-mirror', job_id='job', device='src',
33
+ sync='full', target='dest',
34
+ filter_node_name='mirror-filter')
35
+ self.assert_qmp(result, 'return', {})
36
+
37
+ # Require consistent-read on the source
38
+ # (We can only add this node once the job has started, or it
39
+ # will complain that it does not want to run on non-root nodes)
40
+ result = self.vm.qmp('blockdev-add',
41
+ driver='blkdebug',
42
+ node_name='src-perm',
43
+ image='src',
44
+ take_child_perms=['consistent-read'])
45
+ self.assert_qmp(result, 'return', {})
46
+
47
+ # While completing, mirror will attempt to replace src by
48
+ # dest, which must fail because src-perm requires
49
+ # consistent-read but dest-perm does not share it; thus
50
+ # aborting the job when it is supposed to complete
51
+ self.complete_and_wait('job',
52
+ completion_error='Operation not permitted')
53
+
54
+ # Assert that all of our nodes are still there (except for the
55
+ # mirror filter, which should be gone despite the failure)
56
+ nodes = self.vm.qmp('query-named-block-nodes')['return']
57
+ nodes = [node['node-name'] for node in nodes]
58
+
59
+ for expect in ('src', 'src-perm', 'dest', 'dest-perm'):
60
+ self.assertTrue(expect in nodes, '%s disappeared' % expect)
61
+ self.assertFalse('mirror-filter' in nodes,
62
+ 'Mirror filter node did not disappear')
63
+
64
if __name__ == '__main__':
65
iotests.main(supported_fmts=['qcow2', 'qed'],
66
supported_protocols=['file'])
67
diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out
68
index XXXXXXX..XXXXXXX 100644
69
--- a/tests/qemu-iotests/041.out
70
+++ b/tests/qemu-iotests/041.out
71
@@ -XXX,XX +XXX,XX @@
72
-..........................................................................................
73
+...........................................................................................
74
----------------------------------------------------------------------
75
-Ran 90 tests
76
+Ran 91 tests
77
78
OK
79
--
80
2.24.1
81
82
diff view generated by jsdifflib
1
Signed-off-by: Max Reitz <mreitz@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
2
3
Message-id: 20191107163708.833192-13-mreitz@redhat.com
3
In order to reuse bdrv_common_block_status_above in
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
bdrv_is_allocated_above, let's support include_base parameter.
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Message-id: 20200924194003.22080-3-vsementsov@virtuozzo.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
---
11
---
6
tests/qemu-iotests/071 | 4 ++--
12
block/coroutines.h | 2 ++
7
tests/qemu-iotests/174 | 2 +-
13
block/io.c | 21 ++++++++++++++-------
8
tests/qemu-iotests/178 | 4 ++--
14
2 files changed, 16 insertions(+), 7 deletions(-)
9
tests/qemu-iotests/197 | 4 ++--
10
tests/qemu-iotests/215 | 4 ++--
11
5 files changed, 9 insertions(+), 9 deletions(-)
12
15
13
diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
16
diff --git a/block/coroutines.h b/block/coroutines.h
14
index XXXXXXX..XXXXXXX 100755
17
index XXXXXXX..XXXXXXX 100644
15
--- a/tests/qemu-iotests/071
18
--- a/block/coroutines.h
16
+++ b/tests/qemu-iotests/071
19
+++ b/block/coroutines.h
17
@@ -XXX,XX +XXX,XX @@ echo
20
@@ -XXX,XX +XXX,XX @@ bdrv_pwritev(BdrvChild *child, int64_t offset, unsigned int bytes,
18
echo "=== Testing blkverify through filename ==="
21
int coroutine_fn
19
echo
22
bdrv_co_common_block_status_above(BlockDriverState *bs,
20
23
BlockDriverState *base,
21
-TEST_IMG="$TEST_IMG.base" IMGOPTS="" IMGFMT="raw" _make_test_img $IMG_SIZE |\
24
+ bool include_base,
22
+TEST_IMG="$TEST_IMG.base" IMGFMT="raw" _make_test_img --no-opts $IMG_SIZE |\
25
bool want_zero,
23
_filter_imgfmt
26
int64_t offset,
24
_make_test_img $IMG_SIZE
27
int64_t bytes,
25
$QEMU_IO -c "open -o driver=raw,file.driver=blkverify,file.raw.filename=$TEST_IMG.base $TEST_IMG" \
28
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
26
@@ -XXX,XX +XXX,XX @@ echo
29
int generated_co_wrapper
27
echo "=== Testing blkverify through file blockref ==="
30
bdrv_common_block_status_above(BlockDriverState *bs,
28
echo
31
BlockDriverState *base,
29
32
+ bool include_base,
30
-TEST_IMG="$TEST_IMG.base" IMGOPTS="" IMGFMT="raw" _make_test_img $IMG_SIZE |\
33
bool want_zero,
31
+TEST_IMG="$TEST_IMG.base" IMGFMT="raw" _make_test_img --no-opts $IMG_SIZE |\
34
int64_t offset,
32
_filter_imgfmt
35
int64_t bytes,
33
_make_test_img $IMG_SIZE
36
diff --git a/block/io.c b/block/io.c
34
$QEMU_IO -c "open -o driver=raw,file.driver=blkverify,file.raw.filename=$TEST_IMG.base,file.test.driver=$IMGFMT,file.test.file.filename=$TEST_IMG" \
37
index XXXXXXX..XXXXXXX 100644
35
diff --git a/tests/qemu-iotests/174 b/tests/qemu-iotests/174
38
--- a/block/io.c
36
index XXXXXXX..XXXXXXX 100755
39
+++ b/block/io.c
37
--- a/tests/qemu-iotests/174
40
@@ -XXX,XX +XXX,XX @@ early_out:
38
+++ b/tests/qemu-iotests/174
41
int coroutine_fn
39
@@ -XXX,XX +XXX,XX @@ _unsupported_fmt raw
42
bdrv_co_common_block_status_above(BlockDriverState *bs,
40
43
BlockDriverState *base,
41
44
+ bool include_base,
42
size=256K
45
bool want_zero,
43
-IMGFMT=raw IMGKEYSECRET= IMGOPTS= _make_test_img $size | _filter_imgfmt
46
int64_t offset,
44
+IMGFMT=raw IMGKEYSECRET= _make_test_img --no-opts $size | _filter_imgfmt
47
int64_t bytes,
45
48
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
46
echo
49
BlockDriverState *p;
47
echo "== reading wrong format should fail =="
50
int64_t eof = 0;
48
diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178
51
49
index XXXXXXX..XXXXXXX 100755
52
- assert(bs != base);
50
--- a/tests/qemu-iotests/178
53
+ assert(include_base || bs != base);
51
+++ b/tests/qemu-iotests/178
54
+ assert(!include_base || base); /* Can't include NULL base */
52
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG measure -O foo "$TEST_IMG" # unknown image file format
55
53
56
ret = bdrv_co_block_status(bs, want_zero, offset, bytes, pnum, map, file);
54
make_test_img_with_fmt() {
57
- if (ret < 0 || *pnum == 0 || ret & BDRV_BLOCK_ALLOCATED) {
55
# Shadow global variables within this function
58
+ if (ret < 0 || *pnum == 0 || ret & BDRV_BLOCK_ALLOCATED || bs == base) {
56
- local IMGFMT="$1" IMGOPTS=""
59
return ret;
57
- _make_test_img "$2"
60
}
58
+ local IMGFMT="$1"
61
59
+ _make_test_img --no-opts "$2"
62
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
63
assert(*pnum <= bytes);
64
bytes = *pnum;
65
66
- for (p = bdrv_filter_or_cow_bs(bs); p != base;
67
+ for (p = bdrv_filter_or_cow_bs(bs); include_base || p != base;
68
p = bdrv_filter_or_cow_bs(p))
69
{
70
ret = bdrv_co_block_status(p, want_zero, offset, bytes, pnum, map,
71
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
72
break;
73
}
74
75
+ if (p == base) {
76
+ assert(include_base);
77
+ break;
78
+ }
79
+
80
/*
81
* OK, [offset, offset + *pnum) region is unallocated on this layer,
82
* let's continue the diving.
83
@@ -XXX,XX +XXX,XX @@ int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
84
int64_t offset, int64_t bytes, int64_t *pnum,
85
int64_t *map, BlockDriverState **file)
86
{
87
- return bdrv_common_block_status_above(bs, base, true, offset, bytes,
88
+ return bdrv_common_block_status_above(bs, base, false, true, offset, bytes,
89
pnum, map, file);
60
}
90
}
61
91
62
qemu_io_with_fmt() {
92
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
63
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
93
int ret;
64
index XXXXXXX..XXXXXXX 100755
94
int64_t dummy;
65
--- a/tests/qemu-iotests/197
95
66
+++ b/tests/qemu-iotests/197
96
- ret = bdrv_common_block_status_above(bs, bdrv_filter_or_cow_bs(bs), false,
67
@@ -XXX,XX +XXX,XX @@ if [ "$IMGFMT" = "vpc" ]; then
97
- offset, bytes, pnum ? pnum : &dummy,
68
fi
98
- NULL, NULL);
69
_make_test_img 4G
99
+ ret = bdrv_common_block_status_above(bs, bs, true, false, offset,
70
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
100
+ bytes, pnum ? pnum : &dummy, NULL,
71
-IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
101
+ NULL);
72
- _make_test_img -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
102
if (ret < 0) {
73
+IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \
103
return ret;
74
+ _make_test_img --no-opts -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
104
}
75
$QEMU_IO -f qcow2 -c "write -z -u 1M 64k" "$TEST_WRAP" | _filter_qemu_io
76
77
# Ensure that a read of two clusters, but where one is already allocated,
78
diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215
79
index XXXXXXX..XXXXXXX 100755
80
--- a/tests/qemu-iotests/215
81
+++ b/tests/qemu-iotests/215
82
@@ -XXX,XX +XXX,XX @@ if [ "$IMGFMT" = "vpc" ]; then
83
fi
84
_make_test_img 4G
85
$QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io
86
-IMGPROTO=file IMGFMT=qcow2 IMGOPTS= TEST_IMG_FILE="$TEST_WRAP" \
87
- _make_test_img -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
88
+IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \
89
+ _make_test_img --no-opts -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create
90
$QEMU_IO -f qcow2 -c "write -z -u 1M 64k" "$TEST_WRAP" | _filter_qemu_io
91
92
# Ensure that a read of two clusters, but where one is already allocated,
93
--
105
--
94
2.24.1
106
2.26.2
95
107
96
diff view generated by jsdifflib
1
This test can run just fine with other values for refcount_bits, so we
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
should filter the value from qcow2.py's dump-header. In fact, we can
3
filter everything but the feature bits and header extensions, because
4
that is what the test is about.
5
2
6
(036 currently ignores user-specified image options, but that will be
3
We are going to reuse bdrv_common_block_status_above in
7
fixed in the next patch.)
4
bdrv_is_allocated_above. bdrv_is_allocated_above may be called with
5
include_base == false and still bs == base (for ex. from img_rebase()).
8
6
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
So, support this corner case.
10
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
8
11
Message-id: 20191107163708.833192-6-mreitz@redhat.com
9
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Alberto Garcia <berto@igalia.com>
13
Message-id: 20200924194003.22080-4-vsementsov@virtuozzo.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
15
---
14
tests/qemu-iotests/036 | 9 ++++---
16
block/io.c | 6 +++++-
15
tests/qemu-iotests/036.out | 48 --------------------------------------
17
1 file changed, 5 insertions(+), 1 deletion(-)
16
2 files changed, 6 insertions(+), 51 deletions(-)
17
18
18
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
19
diff --git a/block/io.c b/block/io.c
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/036
21
+++ b/tests/qemu-iotests/036
22
@@ -XXX,XX +XXX,XX @@ $PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63
23
24
# Without feature table
25
$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857
26
-$PYTHON qcow2.py "$TEST_IMG" dump-header
27
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
28
+$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
29
_img_info
30
31
# With feature table containing bit 63
32
@@ -XXX,XX +XXX,XX @@ echo === Create image with unknown autoclear feature bit ===
33
echo
34
_make_test_img 64M
35
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 63
36
-$PYTHON qcow2.py "$TEST_IMG" dump-header
37
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
38
+$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
39
40
echo
41
echo === Repair image ===
42
echo
43
_check_test_img -r all
44
45
-$PYTHON qcow2.py "$TEST_IMG" dump-header
46
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
47
+$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
48
49
# success, all done
50
echo "*** done"
51
diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out
52
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
53
--- a/tests/qemu-iotests/036.out
21
--- a/block/io.c
54
+++ b/tests/qemu-iotests/036.out
22
+++ b/block/io.c
55
@@ -XXX,XX +XXX,XX @@ QA output created by 036
23
@@ -XXX,XX +XXX,XX @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
56
=== Image with unknown incompatible feature bit ===
24
BlockDriverState *p;
57
25
int64_t eof = 0;
58
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
26
59
-magic 0x514649fb
27
- assert(include_base || bs != base);
60
-version 3
28
assert(!include_base || base); /* Can't include NULL base */
61
-backing_file_offset 0x0
29
62
-backing_file_size 0x0
30
+ if (!include_base && bs == base) {
63
-cluster_bits 16
31
+ *pnum = bytes;
64
-size 67108864
32
+ return 0;
65
-crypt_method 0
33
+ }
66
-l1_size 1
34
+
67
-l1_table_offset 0x30000
35
ret = bdrv_co_block_status(bs, want_zero, offset, bytes, pnum, map, file);
68
-refcount_table_offset 0x10000
36
if (ret < 0 || *pnum == 0 || ret & BDRV_BLOCK_ALLOCATED || bs == base) {
69
-refcount_table_clusters 1
37
return ret;
70
-nb_snapshots 0
71
-snapshot_offset 0x0
72
incompatible_features [63]
73
compatible_features []
74
autoclear_features []
75
-refcount_order 4
76
-header_length 104
77
-
78
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Unknown incompatible feature: 8000000000000000
79
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Test feature
80
81
@@ -XXX,XX +XXX,XX @@ qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): tes
82
=== Create image with unknown autoclear feature bit ===
83
84
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
85
-magic 0x514649fb
86
-version 3
87
-backing_file_offset 0x0
88
-backing_file_size 0x0
89
-cluster_bits 16
90
-size 67108864
91
-crypt_method 0
92
-l1_size 1
93
-l1_table_offset 0x30000
94
-refcount_table_offset 0x10000
95
-refcount_table_clusters 1
96
-nb_snapshots 0
97
-snapshot_offset 0x0
98
incompatible_features []
99
compatible_features []
100
autoclear_features [63]
101
-refcount_order 4
102
-header_length 104
103
-
104
Header extension:
105
magic 0x6803f857
106
length 192
107
@@ -XXX,XX +XXX,XX @@ data <binary>
108
=== Repair image ===
109
110
No errors were found on the image.
111
-magic 0x514649fb
112
-version 3
113
-backing_file_offset 0x0
114
-backing_file_size 0x0
115
-cluster_bits 16
116
-size 67108864
117
-crypt_method 0
118
-l1_size 1
119
-l1_table_offset 0x30000
120
-refcount_table_offset 0x10000
121
-refcount_table_clusters 1
122
-nb_snapshots 0
123
-snapshot_offset 0x0
124
incompatible_features []
125
compatible_features []
126
autoclear_features []
127
-refcount_order 4
128
-header_length 104
129
-
130
Header extension:
131
magic 0x6803f857
132
length 192
133
--
38
--
134
2.24.1
39
2.26.2
135
40
136
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
qcow2_can_store_new_dirty_bitmap works wrong, as it considers only
3
bdrv_is_allocated_above wrongly handles short backing files: it reports
4
bitmaps already stored in the qcow2 image and ignores persistent
4
after-EOF space as UNALLOCATED which is wrong, as on read the data is
5
BdrvDirtyBitmap objects.
5
generated on the level of short backing file (if all overlays have
6
unallocated areas at that place).
6
7
7
So, let's instead count persistent BdrvDirtyBitmaps. We load all qcow2
8
Reusing bdrv_common_block_status_above fixes the issue and unifies code
8
bitmaps on open, so there should not be any bitmap in the image for
9
path.
9
which we don't have BdrvDirtyBitmaps version. If it is - it's a kind of
10
corruption, and no reason to check for corruptions here (open() and
11
close() are better places for it).
12
10
13
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
Message-id: 20191014115126.15360-2-vsementsov@virtuozzo.com
12
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Reviewed-by: Alberto Garcia <berto@igalia.com>
16
Cc: qemu-stable@nongnu.org
14
Message-id: 20200924194003.22080-5-vsementsov@virtuozzo.com
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
[Fix s/has/have/ as suggested by Eric Blake. Fix s/area/areas/.
16
--Stefan]
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
---
18
---
19
block/qcow2-bitmap.c | 41 ++++++++++++++++++-----------------------
19
block/io.c | 43 +++++--------------------------------------
20
1 file changed, 18 insertions(+), 23 deletions(-)
20
1 file changed, 5 insertions(+), 38 deletions(-)
21
21
22
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
22
diff --git a/block/io.c b/block/io.c
23
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2-bitmap.c
24
--- a/block/io.c
25
+++ b/block/qcow2-bitmap.c
25
+++ b/block/io.c
26
@@ -XXX,XX +XXX,XX @@ bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
26
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
27
Error **errp)
27
* at 'offset + *pnum' may return the same allocation status (in other
28
* words, the result is not necessarily the maximum possible range);
29
* but 'pnum' will only be 0 when end of file is reached.
30
- *
31
*/
32
int bdrv_is_allocated_above(BlockDriverState *top,
33
BlockDriverState *base,
34
bool include_base, int64_t offset,
35
int64_t bytes, int64_t *pnum)
28
{
36
{
29
BDRVQcow2State *s = bs->opaque;
37
- BlockDriverState *intermediate;
30
- bool found;
38
- int ret;
31
- Qcow2BitmapList *bm_list;
39
- int64_t n = bytes;
32
+ BdrvDirtyBitmap *bitmap;
40
-
33
+ uint64_t bitmap_directory_size = 0;
41
- assert(base || !include_base);
34
+ uint32_t nb_bitmaps = 0;
42
-
35
+
43
- intermediate = top;
36
+ if (bdrv_find_dirty_bitmap(bs, name)) {
44
- while (include_base || intermediate != base) {
37
+ error_setg(errp, "Bitmap already exists: %s", name);
45
- int64_t pnum_inter;
38
+ return false;
46
- int64_t size_inter;
39
+ }
47
-
40
48
- assert(intermediate);
41
if (s->qcow_version < 3) {
49
- ret = bdrv_is_allocated(intermediate, offset, bytes, &pnum_inter);
42
/* Without autoclear_features, we would always have to assume
50
- if (ret < 0) {
43
@@ -XXX,XX +XXX,XX @@ bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
51
- return ret;
44
goto fail;
52
- }
53
- if (ret) {
54
- *pnum = pnum_inter;
55
- return 1;
56
- }
57
-
58
- size_inter = bdrv_getlength(intermediate);
59
- if (size_inter < 0) {
60
- return size_inter;
61
- }
62
- if (n > pnum_inter &&
63
- (intermediate == top || offset + pnum_inter < size_inter)) {
64
- n = pnum_inter;
65
- }
66
-
67
- if (intermediate == base) {
68
- break;
69
- }
70
-
71
- intermediate = bdrv_filter_or_cow_bs(intermediate);
72
+ int ret = bdrv_common_block_status_above(top, base, include_base, false,
73
+ offset, bytes, pnum, NULL, NULL);
74
+ if (ret < 0) {
75
+ return ret;
45
}
76
}
46
77
47
- if (s->nb_bitmaps == 0) {
78
- *pnum = n;
48
- return true;
79
- return 0;
49
+ FOR_EACH_DIRTY_BITMAP(bs, bitmap) {
80
+ return !!(ret & BDRV_BLOCK_ALLOCATED);
50
+ if (bdrv_dirty_bitmap_get_persistence(bitmap)) {
81
}
51
+ nb_bitmaps++;
82
52
+ bitmap_directory_size +=
83
int coroutine_fn
53
+ calc_dir_entry_size(strlen(bdrv_dirty_bitmap_name(bitmap)), 0);
54
+ }
55
}
56
+ nb_bitmaps++;
57
+ bitmap_directory_size += calc_dir_entry_size(strlen(name), 0);
58
59
- if (s->nb_bitmaps >= QCOW2_MAX_BITMAPS) {
60
+ if (nb_bitmaps > QCOW2_MAX_BITMAPS) {
61
error_setg(errp,
62
"Maximum number of persistent bitmaps is already reached");
63
goto fail;
64
}
65
66
- if (s->bitmap_directory_size + calc_dir_entry_size(strlen(name), 0) >
67
- QCOW2_MAX_BITMAP_DIRECTORY_SIZE)
68
- {
69
+ if (bitmap_directory_size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) {
70
error_setg(errp, "Not enough space in the bitmap directory");
71
goto fail;
72
}
73
74
- qemu_co_mutex_lock(&s->lock);
75
- bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
76
- s->bitmap_directory_size, errp);
77
- qemu_co_mutex_unlock(&s->lock);
78
- if (bm_list == NULL) {
79
- goto fail;
80
- }
81
-
82
- found = find_bitmap_by_name(bm_list, name);
83
- bitmap_list_free(bm_list);
84
- if (found) {
85
- error_setg(errp, "Bitmap with the same name is already stored");
86
- goto fail;
87
- }
88
-
89
return true;
90
91
fail:
92
--
84
--
93
2.24.1
85
2.26.2
94
86
95
diff view generated by jsdifflib
Deleted patch
1
Probably due to blind copy-pasting, we have several instances of "qocw2"
2
in our iotests. Fix them.
3
1
4
Reported-by: Maxim Levitsky <mlevitsk@redhat.com>
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Message-id: 20191107163708.833192-2-mreitz@redhat.com
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
tests/qemu-iotests/060 | 2 +-
12
tests/qemu-iotests/061 | 2 +-
13
tests/qemu-iotests/062 | 2 +-
14
tests/qemu-iotests/066 | 2 +-
15
tests/qemu-iotests/068 | 2 +-
16
tests/qemu-iotests/108 | 2 +-
17
tests/qemu-iotests/138 | 2 +-
18
tests/qemu-iotests/261 | 2 +-
19
8 files changed, 8 insertions(+), 8 deletions(-)
20
21
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
22
index XXXXXXX..XXXXXXX 100755
23
--- a/tests/qemu-iotests/060
24
+++ b/tests/qemu-iotests/060
25
@@ -XXX,XX +XXX,XX @@ _filter_io_error()
26
. ./common.rc
27
. ./common.filter
28
29
-# This tests qocw2-specific low-level functionality
30
+# This tests qcow2-specific low-level functionality
31
_supported_fmt qcow2
32
_supported_proto file
33
_supported_os Linux
34
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
35
index XXXXXXX..XXXXXXX 100755
36
--- a/tests/qemu-iotests/061
37
+++ b/tests/qemu-iotests/061
38
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
39
. ./common.rc
40
. ./common.filter
41
42
-# This tests qocw2-specific low-level functionality
43
+# This tests qcow2-specific low-level functionality
44
_supported_fmt qcow2
45
_supported_proto file
46
_supported_os Linux
47
diff --git a/tests/qemu-iotests/062 b/tests/qemu-iotests/062
48
index XXXXXXX..XXXXXXX 100755
49
--- a/tests/qemu-iotests/062
50
+++ b/tests/qemu-iotests/062
51
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
52
. ./common.rc
53
. ./common.filter
54
55
-# This tests qocw2-specific low-level functionality
56
+# This tests qcow2-specific low-level functionality
57
_supported_fmt qcow2
58
_supported_proto generic
59
60
diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066
61
index XXXXXXX..XXXXXXX 100755
62
--- a/tests/qemu-iotests/066
63
+++ b/tests/qemu-iotests/066
64
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
65
. ./common.rc
66
. ./common.filter
67
68
-# This tests qocw2-specific low-level functionality
69
+# This tests qcow2-specific low-level functionality
70
_supported_fmt qcow2
71
_supported_proto generic
72
73
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
74
index XXXXXXX..XXXXXXX 100755
75
--- a/tests/qemu-iotests/068
76
+++ b/tests/qemu-iotests/068
77
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
78
. ./common.rc
79
. ./common.filter
80
81
-# This tests qocw2-specific low-level functionality
82
+# This tests qcow2-specific low-level functionality
83
_supported_fmt qcow2
84
_supported_proto generic
85
86
diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108
87
index XXXXXXX..XXXXXXX 100755
88
--- a/tests/qemu-iotests/108
89
+++ b/tests/qemu-iotests/108
90
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
91
. ./common.rc
92
. ./common.filter
93
94
-# This tests qocw2-specific low-level functionality
95
+# This tests qcow2-specific low-level functionality
96
_supported_fmt qcow2
97
_supported_proto file
98
_supported_os Linux
99
diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138
100
index XXXXXXX..XXXXXXX 100755
101
--- a/tests/qemu-iotests/138
102
+++ b/tests/qemu-iotests/138
103
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
104
. ./common.rc
105
. ./common.filter
106
107
-# This tests qocw2-specific low-level functionality
108
+# This tests qcow2-specific low-level functionality
109
_supported_fmt qcow2
110
_supported_proto file
111
_supported_os Linux
112
diff --git a/tests/qemu-iotests/261 b/tests/qemu-iotests/261
113
index XXXXXXX..XXXXXXX 100755
114
--- a/tests/qemu-iotests/261
115
+++ b/tests/qemu-iotests/261
116
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
117
. ./common.rc
118
. ./common.filter
119
120
-# This tests qocw2-specific low-level functionality
121
+# This tests qcow2-specific low-level functionality
122
_supported_fmt qcow2
123
_supported_proto file
124
_supported_os Linux
125
--
126
2.24.1
127
128
diff view generated by jsdifflib
Deleted patch
1
This is useful for tests that want to whitelist fields from dump-header
2
(with grep) but still print all header extensions.
3
1
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
6
Message-id: 20191107163708.833192-3-mreitz@redhat.com
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
9
tests/qemu-iotests/qcow2.py | 5 +++++
10
1 file changed, 5 insertions(+)
11
12
diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py
13
index XXXXXXX..XXXXXXX 100755
14
--- a/tests/qemu-iotests/qcow2.py
15
+++ b/tests/qemu-iotests/qcow2.py
16
@@ -XXX,XX +XXX,XX @@ def cmd_dump_header(fd):
17
h.dump()
18
h.dump_extensions()
19
20
+def cmd_dump_header_exts(fd):
21
+ h = QcowHeader(fd)
22
+ h.dump_extensions()
23
+
24
def cmd_set_header(fd, name, value):
25
try:
26
value = int(value, 0)
27
@@ -XXX,XX +XXX,XX @@ def cmd_set_feature_bit(fd, group, bit):
28
29
cmds = [
30
[ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ],
31
+ [ 'dump-header-exts', cmd_dump_header_exts, 0, 'Dump image header extensions' ],
32
[ 'set-header', cmd_set_header, 2, 'Set a field in the header'],
33
[ 'add-header-ext', cmd_add_header_ext, 2, 'Add a header extension' ],
34
[ 'add-header-ext-stdio', cmd_add_header_ext_stdio, 1, 'Add a header extension, data from stdin' ],
35
--
36
2.24.1
37
38
diff view generated by jsdifflib
1
Print the feature fields as a set of bits so that filtering is easier.
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
These cases are fixed by previous patches around block_status and
4
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
4
is_allocated.
5
Message-id: 20191107163708.833192-4-mreitz@redhat.com
5
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Message-id: 20200924194003.22080-6-vsementsov@virtuozzo.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
---
11
---
8
tests/qemu-iotests/031.out | 36 +++++++++----------
12
tests/qemu-iotests/274 | 20 +++++++++++
9
tests/qemu-iotests/036.out | 18 +++++-----
13
tests/qemu-iotests/274.out | 68 ++++++++++++++++++++++++++++++++++++++
10
tests/qemu-iotests/039.out | 22 ++++++------
14
2 files changed, 88 insertions(+)
11
tests/qemu-iotests/060.out | 20 +++++------
12
tests/qemu-iotests/061.out | 72 ++++++++++++++++++-------------------
13
tests/qemu-iotests/137.out | 2 +-
14
tests/qemu-iotests/qcow2.py | 18 +++++++---
15
7 files changed, 99 insertions(+), 89 deletions(-)
16
15
17
diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out
16
diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274
17
index XXXXXXX..XXXXXXX 100755
18
--- a/tests/qemu-iotests/274
19
+++ b/tests/qemu-iotests/274
20
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('base') as base, \
21
iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
22
iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
23
24
+ iotests.log('=== Testing qemu-img commit (top -> base) ===')
25
+
26
+ create_chain()
27
+ iotests.qemu_img_log('commit', '-b', base, top)
28
+ iotests.img_info_log(base)
29
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, base)
30
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), base)
31
+
32
+ iotests.log('=== Testing QMP active commit (top -> base) ===')
33
+
34
+ create_chain()
35
+ with create_vm() as vm:
36
+ vm.launch()
37
+ vm.qmp_log('block-commit', device='top', base_node='base',
38
+ job_id='job0', auto_dismiss=False)
39
+ vm.run_job('job0', wait=5)
40
+
41
+ iotests.img_info_log(mid)
42
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, base)
43
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), base)
44
45
iotests.log('== Resize tests ==')
46
47
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
18
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/031.out
49
--- a/tests/qemu-iotests/274.out
20
+++ b/tests/qemu-iotests/031.out
50
+++ b/tests/qemu-iotests/274.out
21
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
51
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0
22
refcount_table_clusters 1
52
read 1048576/1048576 bytes at offset 1048576
23
nb_snapshots 0
53
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
24
snapshot_offset 0x0
54
25
-incompatible_features 0x0
55
+=== Testing qemu-img commit (top -> base) ===
26
-compatible_features 0x0
56
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
27
-autoclear_features 0x0
28
+incompatible_features []
29
+compatible_features []
30
+autoclear_features []
31
refcount_order 4
32
header_length 72
33
34
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
35
refcount_table_clusters 1
36
nb_snapshots 0
37
snapshot_offset 0x0
38
-incompatible_features 0x0
39
-compatible_features 0x0
40
-autoclear_features 0x0
41
+incompatible_features []
42
+compatible_features []
43
+autoclear_features []
44
refcount_order 4
45
header_length 72
46
47
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
48
refcount_table_clusters 1
49
nb_snapshots 0
50
snapshot_offset 0x0
51
-incompatible_features 0x0
52
-compatible_features 0x0
53
-autoclear_features 0x0
54
+incompatible_features []
55
+compatible_features []
56
+autoclear_features []
57
refcount_order 4
58
header_length 72
59
60
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
61
refcount_table_clusters 1
62
nb_snapshots 0
63
snapshot_offset 0x0
64
-incompatible_features 0x0
65
-compatible_features 0x0
66
-autoclear_features 0x0
67
+incompatible_features []
68
+compatible_features []
69
+autoclear_features []
70
refcount_order 4
71
header_length 104
72
73
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
74
refcount_table_clusters 1
75
nb_snapshots 0
76
snapshot_offset 0x0
77
-incompatible_features 0x0
78
-compatible_features 0x0
79
-autoclear_features 0x0
80
+incompatible_features []
81
+compatible_features []
82
+autoclear_features []
83
refcount_order 4
84
header_length 104
85
86
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
87
refcount_table_clusters 1
88
nb_snapshots 0
89
snapshot_offset 0x0
90
-incompatible_features 0x0
91
-compatible_features 0x0
92
-autoclear_features 0x0
93
+incompatible_features []
94
+compatible_features []
95
+autoclear_features []
96
refcount_order 4
97
header_length 104
98
99
diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out
100
index XXXXXXX..XXXXXXX 100644
101
--- a/tests/qemu-iotests/036.out
102
+++ b/tests/qemu-iotests/036.out
103
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
104
refcount_table_clusters 1
105
nb_snapshots 0
106
snapshot_offset 0x0
107
-incompatible_features 0x8000000000000000
108
-compatible_features 0x0
109
-autoclear_features 0x0
110
+incompatible_features [63]
111
+compatible_features []
112
+autoclear_features []
113
refcount_order 4
114
header_length 104
115
116
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
117
refcount_table_clusters 1
118
nb_snapshots 0
119
snapshot_offset 0x0
120
-incompatible_features 0x0
121
-compatible_features 0x0
122
-autoclear_features 0x8000000000000000
123
+incompatible_features []
124
+compatible_features []
125
+autoclear_features [63]
126
refcount_order 4
127
header_length 104
128
129
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
130
refcount_table_clusters 1
131
nb_snapshots 0
132
snapshot_offset 0x0
133
-incompatible_features 0x0
134
-compatible_features 0x0
135
-autoclear_features 0x0
136
+incompatible_features []
137
+compatible_features []
138
+autoclear_features []
139
refcount_order 4
140
header_length 104
141
142
diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out
143
index XXXXXXX..XXXXXXX 100644
144
--- a/tests/qemu-iotests/039.out
145
+++ b/tests/qemu-iotests/039.out
146
@@ -XXX,XX +XXX,XX @@ QA output created by 039
147
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
148
wrote 512/512 bytes at offset 0
149
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
150
-incompatible_features 0x0
151
+incompatible_features []
152
No errors were found on the image.
153
154
== Creating a dirty image file ==
155
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
156
wrote 512/512 bytes at offset 0
157
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
158
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
159
-incompatible_features 0x1
160
+incompatible_features [0]
161
ERROR cluster 5 refcount=0 reference=1
162
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
163
164
@@ -XXX,XX +XXX,XX @@ Data may be corrupted, or further writes to the image may corrupt it.
165
== Read-only access must still work ==
166
read 512/512 bytes at offset 0
167
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
168
-incompatible_features 0x1
169
+incompatible_features [0]
170
171
== Repairing the image file must succeed ==
172
ERROR cluster 5 refcount=0 reference=1
173
@@ -XXX,XX +XXX,XX @@ The following inconsistencies were found and repaired:
174
175
Double checking the fixed image now...
176
No errors were found on the image.
177
-incompatible_features 0x0
178
+incompatible_features []
179
180
== Data should still be accessible after repair ==
181
read 512/512 bytes at offset 0
182
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
183
wrote 512/512 bytes at offset 0
184
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
185
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
186
-incompatible_features 0x1
187
+incompatible_features [0]
188
ERROR cluster 5 refcount=0 reference=1
189
Rebuilding refcount structure
190
Repairing cluster 1 refcount=1 reference=0
191
Repairing cluster 2 refcount=1 reference=0
192
wrote 512/512 bytes at offset 0
193
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
194
-incompatible_features 0x0
195
+incompatible_features []
196
197
== Creating an image file with lazy_refcounts=off ==
198
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
199
wrote 512/512 bytes at offset 0
200
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
201
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
202
-incompatible_features 0x0
203
+incompatible_features []
204
No errors were found on the image.
205
206
== Committing to a backing file with lazy_refcounts=on ==
207
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/
208
wrote 512/512 bytes at offset 0
209
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
210
Image committed.
211
-incompatible_features 0x0
212
-incompatible_features 0x0
213
+incompatible_features []
214
+incompatible_features []
215
No errors were found on the image.
216
No errors were found on the image.
217
218
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
219
wrote 512/512 bytes at offset 0
220
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
221
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
222
-incompatible_features 0x1
223
+incompatible_features [0]
224
ERROR cluster 5 refcount=0 reference=1
225
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
226
227
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
228
wrote 512/512 bytes at offset 0
229
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
230
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
231
-incompatible_features 0x0
232
+incompatible_features []
233
No errors were found on the image.
234
*** done
235
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
236
index XXXXXXX..XXXXXXX 100644
237
--- a/tests/qemu-iotests/060.out
238
+++ b/tests/qemu-iotests/060.out
239
@@ -XXX,XX +XXX,XX @@ ERROR cluster 3 refcount=1 reference=3
240
241
1 errors were found on the image.
242
Data may be corrupted, or further writes to the image may corrupt it.
243
-incompatible_features 0x0
244
+incompatible_features []
245
qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with active L1 table); further corruption events will be suppressed
246
write failed: Input/output error
247
-incompatible_features 0x2
248
+incompatible_features [1]
249
image: TEST_DIR/t.IMGFMT
250
file format: IMGFMT
251
virtual size: 64 MiB (67108864 bytes)
252
@@ -XXX,XX +XXX,XX @@ ERROR cluster 2 refcount=1 reference=2
253
254
2 errors were found on the image.
255
Data may be corrupted, or further writes to the image may corrupt it.
256
-incompatible_features 0x0
257
+incompatible_features []
258
qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with refcount block); further corruption events will be suppressed
259
write failed: Input/output error
260
-incompatible_features 0x2
261
+incompatible_features [1]
262
ERROR refcount block 0 refcount=2
263
ERROR cluster 2 refcount=1 reference=2
264
Rebuilding refcount structure
265
@@ -XXX,XX +XXX,XX @@ The following inconsistencies were found and repaired:
266
267
Double checking the fixed image now...
268
No errors were found on the image.
269
-incompatible_features 0x0
270
+incompatible_features []
271
wrote 512/512 bytes at offset 0
272
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
273
-incompatible_features 0x0
274
+incompatible_features []
275
276
=== Testing cluster data reference into inactive L2 table ===
277
278
@@ -XXX,XX +XXX,XX @@ Data may be corrupted, or further writes to the image may corrupt it.
279
280
1 leaked clusters were found on the image.
281
This means waste of disk space, but no harm to data.
282
-incompatible_features 0x0
283
+incompatible_features []
284
qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with inactive L2 table); further corruption events will be suppressed
285
write failed: Input/output error
286
-incompatible_features 0x2
287
+incompatible_features [1]
288
ERROR cluster 4 refcount=1 reference=2
289
Leaked cluster 9 refcount=1 reference=0
290
Repairing cluster 4 refcount=1 reference=2
291
@@ -XXX,XX +XXX,XX @@ The following inconsistencies were found and repaired:
292
293
Double checking the fixed image now...
294
No errors were found on the image.
295
-incompatible_features 0x0
296
+incompatible_features []
297
wrote 512/512 bytes at offset 0
298
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
299
-incompatible_features 0x0
300
+incompatible_features []
301
read 512/512 bytes at offset 0
302
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
303
No errors were found on the image.
304
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
305
index XXXXXXX..XXXXXXX 100644
306
--- a/tests/qemu-iotests/061.out
307
+++ b/tests/qemu-iotests/061.out
308
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
309
refcount_table_clusters 1
310
nb_snapshots 0
311
snapshot_offset 0x0
312
-incompatible_features 0x0
313
-compatible_features 0x1
314
-autoclear_features 0x0
315
+incompatible_features []
316
+compatible_features [0]
317
+autoclear_features []
318
refcount_order 4
319
header_length 104
320
321
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
322
refcount_table_clusters 1
323
nb_snapshots 0
324
snapshot_offset 0x0
325
-incompatible_features 0x0
326
-compatible_features 0x0
327
-autoclear_features 0x0
328
+incompatible_features []
329
+compatible_features []
330
+autoclear_features []
331
refcount_order 4
332
header_length 72
333
334
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
335
refcount_table_clusters 1
336
nb_snapshots 0
337
snapshot_offset 0x0
338
-incompatible_features 0x0
339
-compatible_features 0x1
340
-autoclear_features 0x0
341
+incompatible_features []
342
+compatible_features [0]
343
+autoclear_features []
344
refcount_order 4
345
header_length 104
346
347
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
348
refcount_table_clusters 1
349
nb_snapshots 0
350
snapshot_offset 0x0
351
-incompatible_features 0x0
352
-compatible_features 0x0
353
-autoclear_features 0x0
354
+incompatible_features []
355
+compatible_features []
356
+autoclear_features []
357
refcount_order 4
358
header_length 72
359
360
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
361
refcount_table_clusters 1
362
nb_snapshots 0
363
snapshot_offset 0x0
364
-incompatible_features 0x1
365
-compatible_features 0x1
366
-autoclear_features 0x0
367
+incompatible_features [0]
368
+compatible_features [0]
369
+autoclear_features []
370
refcount_order 4
371
header_length 104
372
373
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x80000
374
refcount_table_clusters 1
375
nb_snapshots 0
376
snapshot_offset 0x0
377
-incompatible_features 0x0
378
-compatible_features 0x0
379
-autoclear_features 0x0
380
+incompatible_features []
381
+compatible_features []
382
+autoclear_features []
383
refcount_order 4
384
header_length 72
385
386
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
387
refcount_table_clusters 1
388
nb_snapshots 0
389
snapshot_offset 0x0
390
-incompatible_features 0x0
391
-compatible_features 0x40000000000
392
-autoclear_features 0x40000000000
393
+incompatible_features []
394
+compatible_features [42]
395
+autoclear_features [42]
396
refcount_order 4
397
header_length 104
398
399
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
400
refcount_table_clusters 1
401
nb_snapshots 0
402
snapshot_offset 0x0
403
-incompatible_features 0x0
404
-compatible_features 0x0
405
-autoclear_features 0x0
406
+incompatible_features []
407
+compatible_features []
408
+autoclear_features []
409
refcount_order 4
410
header_length 72
411
412
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
413
refcount_table_clusters 1
414
nb_snapshots 0
415
snapshot_offset 0x0
416
-incompatible_features 0x0
417
-compatible_features 0x0
418
-autoclear_features 0x0
419
+incompatible_features []
420
+compatible_features []
421
+autoclear_features []
422
refcount_order 4
423
header_length 72
424
425
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
426
refcount_table_clusters 1
427
nb_snapshots 0
428
snapshot_offset 0x0
429
-incompatible_features 0x0
430
-compatible_features 0x1
431
-autoclear_features 0x0
432
+incompatible_features []
433
+compatible_features [0]
434
+autoclear_features []
435
refcount_order 4
436
header_length 104
437
438
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x10000
439
refcount_table_clusters 1
440
nb_snapshots 0
441
snapshot_offset 0x0
442
-incompatible_features 0x1
443
-compatible_features 0x1
444
-autoclear_features 0x0
445
+incompatible_features [0]
446
+compatible_features [0]
447
+autoclear_features []
448
refcount_order 4
449
header_length 104
450
451
@@ -XXX,XX +XXX,XX @@ refcount_table_offset 0x80000
452
refcount_table_clusters 1
453
nb_snapshots 0
454
snapshot_offset 0x0
455
-incompatible_features 0x0
456
-compatible_features 0x0
457
-autoclear_features 0x0
458
+incompatible_features []
459
+compatible_features []
460
+autoclear_features []
461
refcount_order 4
462
header_length 104
463
464
diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out
465
index XXXXXXX..XXXXXXX 100644
466
--- a/tests/qemu-iotests/137.out
467
+++ b/tests/qemu-iotests/137.out
468
@@ -XXX,XX +XXX,XX @@ qemu-io: Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are
469
wrote 512/512 bytes at offset 0
470
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
471
./common.rc: Killed ( VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@" )
472
-incompatible_features 0x0
473
+incompatible_features []
474
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
475
wrote 65536/65536 bytes at offset 0
476
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
477
diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py
478
index XXXXXXX..XXXXXXX 100755
479
--- a/tests/qemu-iotests/qcow2.py
480
+++ b/tests/qemu-iotests/qcow2.py
481
@@ -XXX,XX +XXX,XX @@ class QcowHeader:
482
[ uint64_t, '%#x', 'snapshot_offset' ],
483
484
# Version 3 header fields
485
- [ uint64_t, '%#x', 'incompatible_features' ],
486
- [ uint64_t, '%#x', 'compatible_features' ],
487
- [ uint64_t, '%#x', 'autoclear_features' ],
488
+ [ uint64_t, 'mask', 'incompatible_features' ],
489
+ [ uint64_t, 'mask', 'compatible_features' ],
490
+ [ uint64_t, 'mask', 'autoclear_features' ],
491
[ uint32_t, '%d', 'refcount_order' ],
492
[ uint32_t, '%d', 'header_length' ],
493
];
494
@@ -XXX,XX +XXX,XX @@ class QcowHeader:
495
496
def dump(self):
497
for f in QcowHeader.fields:
498
- print("%-25s" % f[2], f[1] % self.__dict__[f[2]])
499
+ value = self.__dict__[f[2]]
500
+ if f[1] == 'mask':
501
+ bits = []
502
+ for bit in range(64):
503
+ if value & (1 << bit):
504
+ bits.append(bit)
505
+ value_str = str(bits)
506
+ else:
507
+ value_str = f[1] % value
508
+
57
+
509
+ print("%-25s" % f[2], value_str)
58
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
510
print("")
59
+
511
60
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
512
def dump_extensions(self):
61
+
62
+wrote 2097152/2097152 bytes at offset 0
63
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
64
+
65
+Image committed.
66
+
67
+image: TEST_IMG
68
+file format: IMGFMT
69
+virtual size: 2 MiB (2097152 bytes)
70
+cluster_size: 65536
71
+Format specific information:
72
+ compat: 1.1
73
+ compression type: zlib
74
+ lazy refcounts: false
75
+ refcount bits: 16
76
+ corrupt: false
77
+ extended l2: false
78
+
79
+read 1048576/1048576 bytes at offset 0
80
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
81
+
82
+read 1048576/1048576 bytes at offset 1048576
83
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
84
+
85
+=== Testing QMP active commit (top -> base) ===
86
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
87
+
88
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
89
+
90
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
91
+
92
+wrote 2097152/2097152 bytes at offset 0
93
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
94
+
95
+{"execute": "block-commit", "arguments": {"auto-dismiss": false, "base-node": "base", "device": "top", "job-id": "job0"}}
96
+{"return": {}}
97
+{"execute": "job-complete", "arguments": {"id": "job0"}}
98
+{"return": {}}
99
+{"data": {"device": "job0", "len": 1048576, "offset": 1048576, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
100
+{"data": {"device": "job0", "len": 1048576, "offset": 1048576, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
101
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
102
+{"return": {}}
103
+image: TEST_IMG
104
+file format: IMGFMT
105
+virtual size: 1 MiB (1048576 bytes)
106
+cluster_size: 65536
107
+backing file: TEST_DIR/PID-base
108
+backing file format: IMGFMT
109
+Format specific information:
110
+ compat: 1.1
111
+ compression type: zlib
112
+ lazy refcounts: false
113
+ refcount bits: 16
114
+ corrupt: false
115
+ extended l2: false
116
+
117
+read 1048576/1048576 bytes at offset 0
118
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
119
+
120
+read 1048576/1048576 bytes at offset 1048576
121
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
122
+
123
== Resize tests ==
124
=== preallocation=off ===
125
Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=6442450944 lazy_refcounts=off refcount_bits=16
513
--
126
--
514
2.24.1
127
2.26.2
515
128
516
diff view generated by jsdifflib