1
The following changes since commit 417296c8d8588f782018d01a317f88957e9786d6:
1
The following changes since commit c6a5fc2ac76c5ab709896ee1b0edd33685a67ed1:
2
2
3
tests/qtest/netdev-socket: Raise connection timeout to 60 seconds (2023-02-09 11:23:53 +0000)
3
decodetree: Add --output-null for meson testing (2023-05-31 19:56:42 -0700)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to acbc8aee5b09222dc6a5cb88306b67bcbe37e30b:
9
for you to fetch changes up to 98b126f5e3228a346c774e569e26689943b401dd:
10
10
11
iotests/detect-zeroes-registered-buf: add new test (2023-02-09 10:22:30 -0500)
11
qapi: add '@fdset' feature for BlockdevOptionsVirtioBlkVhostVdpa (2023-06-01 11:08:21 -0400)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Pull request
14
Pull request
15
15
16
A few fixes that I've picked up.
16
- Stefano Garzarella's blkio block driver 'fd' parameter
17
- My thread-local blk_io_plug() series
17
18
18
----------------------------------------------------------------
19
----------------------------------------------------------------
19
20
20
Akihiko Odaki (1):
21
Stefan Hajnoczi (6):
21
vhost-user-fs: Back up vqs before cleaning up vhost_dev
22
block: add blk_io_plug_call() API
23
block/nvme: convert to blk_io_plug_call() API
24
block/blkio: convert to blk_io_plug_call() API
25
block/io_uring: convert to blk_io_plug_call() API
26
block/linux-aio: convert to blk_io_plug_call() API
27
block: remove bdrv_co_io_plug() API
22
28
23
Emanuele Giuseppe Esposito (1):
29
Stefano Garzarella (2):
24
virtio-blk: add missing AioContext lock
30
block/blkio: use qemu_open() to support fd passing for virtio-blk
31
qapi: add '@fdset' feature for BlockdevOptionsVirtioBlkVhostVdpa
25
32
26
Stefan Hajnoczi (4):
33
MAINTAINERS | 1 +
27
block: fix detect-zeroes= with BDRV_REQ_REGISTERED_BUF
34
qapi/block-core.json | 6 ++
28
qemu-io: use BdrvRequestFlags instead of int
35
meson.build | 4 +
29
qemu-io: add -r option to register I/O buffer
36
include/block/block-io.h | 3 -
30
iotests/detect-zeroes-registered-buf: add new test
37
include/block/block_int-common.h | 11 ---
31
38
include/block/raw-aio.h | 14 ---
32
block/io.c | 3 +
39
include/sysemu/block-backend-io.h | 13 +--
33
hw/block/virtio-blk.c | 5 +
40
block/blkio.c | 96 ++++++++++++------
34
hw/virtio/vhost-user-fs.c | 4 +-
41
block/block-backend.c | 22 -----
35
qemu-io-cmds.c | 215 +++++++++++-------
42
block/file-posix.c | 38 -------
36
.../tests/detect-zeroes-registered-buf | 58 +++++
43
block/io.c | 37 -------
37
.../tests/detect-zeroes-registered-buf.out | 7 +
44
block/io_uring.c | 44 ++++-----
38
6 files changed, 210 insertions(+), 82 deletions(-)
45
block/linux-aio.c | 41 +++-----
39
create mode 100755 tests/qemu-iotests/tests/detect-zeroes-registered-buf
46
block/nvme.c | 44 +++------
40
create mode 100644 tests/qemu-iotests/tests/detect-zeroes-registered-buf.out
47
block/plug.c | 159 ++++++++++++++++++++++++++++++
48
hw/block/dataplane/xen-block.c | 8 +-
49
hw/block/virtio-blk.c | 4 +-
50
hw/scsi/virtio-scsi.c | 6 +-
51
block/meson.build | 1 +
52
block/trace-events | 6 +-
53
20 files changed, 293 insertions(+), 265 deletions(-)
54
create mode 100644 block/plug.c
41
55
42
--
56
--
43
2.39.1
57
2.40.1
diff view generated by jsdifflib
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
Introduce a new API for thread-local blk_io_plug() that does not
2
2
traverse the block graph. The goal is to make blk_io_plug() multi-queue
3
virtio_blk_update_config() calls blk_get_geometry and blk_getlength,
3
friendly.
4
and both functions eventually end up calling bdrv_poll_co when not
4
5
running in a coroutine:
5
Instead of having block drivers track whether or not we're in a plugged
6
- blk_getlength is a co_wrapper_mixed function
6
section, provide an API that allows them to defer a function call until
7
- blk_get_geometry calls bdrv_get_geometry -> bdrv_nb_sectors, a
7
we're unplugged: blk_io_plug_call(fn, opaque). If blk_io_plug_call() is
8
co_wrapper_mixed function too
8
called multiple times with the same fn/opaque pair, then fn() is only
9
9
called once at the end of the function - resulting in batching.
10
Since we are not running in a coroutine, we need to take s->blk
10
11
AioContext lock, otherwise bdrv_poll_co will inevitably call
11
This patch introduces the API and changes blk_io_plug()/blk_io_unplug().
12
AIO_WAIT_WHILE and therefore try to un unlock() an AioContext lock
12
blk_io_plug()/blk_io_unplug() no longer require a BlockBackend argument
13
that was never acquired.
13
because the plug state is now thread-local.
14
14
15
RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=2167838
15
Later patches convert block drivers to blk_io_plug_call() and then we
16
16
can finally remove .bdrv_co_io_plug() once all block drivers have been
17
Steps to reproduce the issue: simply boot a VM with
17
converted.
18
-object '{"qom-type":"iothread","id":"iothread1"}' \
18
19
-blockdev '{"driver":"file","filename":"$QCOW2","aio":"native","node-name":"libvirt-1-storage","cache":{"direct":true,"no-flush":false},"auto-read-only":true,"discard":"unmap"}' \
20
-blockdev '{"node-name":"libvirt-1-format","read-only":false,"cache":{"direct":true,"no-flush":false},"driver":"qcow2","file":"libvirt-1-storage"}' \
21
-device virtio-blk-pci,iothread=iothread1,drive=libvirt-1-format,id=virtio-disk0,bootindex=1,write-cache=on
22
23
and observe that it will fail not manage to boot with "qemu_mutex_unlock_impl: Operation not permitted"
24
25
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
26
Acked-by: Michael S. Tsirkin <mst@redhat.com>
27
Tested-by: Lukáš Doktor <ldoktor@redhat.com>
28
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
29
Message-Id: <20230208111148.1040083-1-eesposit@redhat.com>
20
Reviewed-by: Eric Blake <eblake@redhat.com>
21
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
22
Acked-by: Kevin Wolf <kwolf@redhat.com>
23
Message-id: 20230530180959.1108766-2-stefanha@redhat.com
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
30
---
25
---
31
hw/block/virtio-blk.c | 5 +++++
26
MAINTAINERS | 1 +
32
1 file changed, 5 insertions(+)
27
include/sysemu/block-backend-io.h | 13 +--
33
28
block/block-backend.c | 22 -----
29
block/plug.c | 159 ++++++++++++++++++++++++++++++
30
hw/block/dataplane/xen-block.c | 8 +-
31
hw/block/virtio-blk.c | 4 +-
32
hw/scsi/virtio-scsi.c | 6 +-
33
block/meson.build | 1 +
34
8 files changed, 173 insertions(+), 41 deletions(-)
35
create mode 100644 block/plug.c
36
37
diff --git a/MAINTAINERS b/MAINTAINERS
38
index XXXXXXX..XXXXXXX 100644
39
--- a/MAINTAINERS
40
+++ b/MAINTAINERS
41
@@ -XXX,XX +XXX,XX @@ F: util/aio-*.c
42
F: util/aio-*.h
43
F: util/fdmon-*.c
44
F: block/io.c
45
+F: block/plug.c
46
F: migration/block*
47
F: include/block/aio.h
48
F: include/block/aio-wait.h
49
diff --git a/include/sysemu/block-backend-io.h b/include/sysemu/block-backend-io.h
50
index XXXXXXX..XXXXXXX 100644
51
--- a/include/sysemu/block-backend-io.h
52
+++ b/include/sysemu/block-backend-io.h
53
@@ -XXX,XX +XXX,XX @@ void blk_iostatus_set_err(BlockBackend *blk, int error);
54
int blk_get_max_iov(BlockBackend *blk);
55
int blk_get_max_hw_iov(BlockBackend *blk);
56
57
-/*
58
- * blk_io_plug/unplug are thread-local operations. This means that multiple
59
- * IOThreads can simultaneously call plug/unplug, but the caller must ensure
60
- * that each unplug() is called in the same IOThread of the matching plug().
61
- */
62
-void coroutine_fn blk_co_io_plug(BlockBackend *blk);
63
-void co_wrapper blk_io_plug(BlockBackend *blk);
64
-
65
-void coroutine_fn blk_co_io_unplug(BlockBackend *blk);
66
-void co_wrapper blk_io_unplug(BlockBackend *blk);
67
+void blk_io_plug(void);
68
+void blk_io_unplug(void);
69
+void blk_io_plug_call(void (*fn)(void *), void *opaque);
70
71
AioContext *blk_get_aio_context(BlockBackend *blk);
72
BlockAcctStats *blk_get_stats(BlockBackend *blk);
73
diff --git a/block/block-backend.c b/block/block-backend.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/block/block-backend.c
76
+++ b/block/block-backend.c
77
@@ -XXX,XX +XXX,XX @@ void blk_add_insert_bs_notifier(BlockBackend *blk, Notifier *notify)
78
notifier_list_add(&blk->insert_bs_notifiers, notify);
79
}
80
81
-void coroutine_fn blk_co_io_plug(BlockBackend *blk)
82
-{
83
- BlockDriverState *bs = blk_bs(blk);
84
- IO_CODE();
85
- GRAPH_RDLOCK_GUARD();
86
-
87
- if (bs) {
88
- bdrv_co_io_plug(bs);
89
- }
90
-}
91
-
92
-void coroutine_fn blk_co_io_unplug(BlockBackend *blk)
93
-{
94
- BlockDriverState *bs = blk_bs(blk);
95
- IO_CODE();
96
- GRAPH_RDLOCK_GUARD();
97
-
98
- if (bs) {
99
- bdrv_co_io_unplug(bs);
100
- }
101
-}
102
-
103
BlockAcctStats *blk_get_stats(BlockBackend *blk)
104
{
105
IO_CODE();
106
diff --git a/block/plug.c b/block/plug.c
107
new file mode 100644
108
index XXXXXXX..XXXXXXX
109
--- /dev/null
110
+++ b/block/plug.c
111
@@ -XXX,XX +XXX,XX @@
112
+/* SPDX-License-Identifier: GPL-2.0-or-later */
113
+/*
114
+ * Block I/O plugging
115
+ *
116
+ * Copyright Red Hat.
117
+ *
118
+ * This API defers a function call within a blk_io_plug()/blk_io_unplug()
119
+ * section, allowing multiple calls to batch up. This is a performance
120
+ * optimization that is used in the block layer to submit several I/O requests
121
+ * at once instead of individually:
122
+ *
123
+ * blk_io_plug(); <-- start of plugged region
124
+ * ...
125
+ * blk_io_plug_call(my_func, my_obj); <-- deferred my_func(my_obj) call
126
+ * blk_io_plug_call(my_func, my_obj); <-- another
127
+ * blk_io_plug_call(my_func, my_obj); <-- another
128
+ * ...
129
+ * blk_io_unplug(); <-- end of plugged region, my_func(my_obj) is called once
130
+ *
131
+ * This code is actually generic and not tied to the block layer. If another
132
+ * subsystem needs this functionality, it could be renamed.
133
+ */
134
+
135
+#include "qemu/osdep.h"
136
+#include "qemu/coroutine-tls.h"
137
+#include "qemu/notify.h"
138
+#include "qemu/thread.h"
139
+#include "sysemu/block-backend.h"
140
+
141
+/* A function call that has been deferred until unplug() */
142
+typedef struct {
143
+ void (*fn)(void *);
144
+ void *opaque;
145
+} UnplugFn;
146
+
147
+/* Per-thread state */
148
+typedef struct {
149
+ unsigned count; /* how many times has plug() been called? */
150
+ GArray *unplug_fns; /* functions to call at unplug time */
151
+} Plug;
152
+
153
+/* Use get_ptr_plug() to fetch this thread-local value */
154
+QEMU_DEFINE_STATIC_CO_TLS(Plug, plug);
155
+
156
+/* Called at thread cleanup time */
157
+static void blk_io_plug_atexit(Notifier *n, void *value)
158
+{
159
+ Plug *plug = get_ptr_plug();
160
+ g_array_free(plug->unplug_fns, TRUE);
161
+}
162
+
163
+/* This won't involve coroutines, so use __thread */
164
+static __thread Notifier blk_io_plug_atexit_notifier;
165
+
166
+/**
167
+ * blk_io_plug_call:
168
+ * @fn: a function pointer to be invoked
169
+ * @opaque: a user-defined argument to @fn()
170
+ *
171
+ * Call @fn(@opaque) immediately if not within a blk_io_plug()/blk_io_unplug()
172
+ * section.
173
+ *
174
+ * Otherwise defer the call until the end of the outermost
175
+ * blk_io_plug()/blk_io_unplug() section in this thread. If the same
176
+ * @fn/@opaque pair has already been deferred, it will only be called once upon
177
+ * blk_io_unplug() so that accumulated calls are batched into a single call.
178
+ *
179
+ * The caller must ensure that @opaque is not freed before @fn() is invoked.
180
+ */
181
+void blk_io_plug_call(void (*fn)(void *), void *opaque)
182
+{
183
+ Plug *plug = get_ptr_plug();
184
+
185
+ /* Call immediately if we're not plugged */
186
+ if (plug->count == 0) {
187
+ fn(opaque);
188
+ return;
189
+ }
190
+
191
+ GArray *array = plug->unplug_fns;
192
+ if (!array) {
193
+ array = g_array_new(FALSE, FALSE, sizeof(UnplugFn));
194
+ plug->unplug_fns = array;
195
+ blk_io_plug_atexit_notifier.notify = blk_io_plug_atexit;
196
+ qemu_thread_atexit_add(&blk_io_plug_atexit_notifier);
197
+ }
198
+
199
+ UnplugFn *fns = (UnplugFn *)array->data;
200
+ UnplugFn new_fn = {
201
+ .fn = fn,
202
+ .opaque = opaque,
203
+ };
204
+
205
+ /*
206
+ * There won't be many, so do a linear search. If this becomes a bottleneck
207
+ * then a binary search (glib 2.62+) or different data structure could be
208
+ * used.
209
+ */
210
+ for (guint i = 0; i < array->len; i++) {
211
+ if (memcmp(&fns[i], &new_fn, sizeof(new_fn)) == 0) {
212
+ return; /* already exists */
213
+ }
214
+ }
215
+
216
+ g_array_append_val(array, new_fn);
217
+}
218
+
219
+/**
220
+ * blk_io_plug: Defer blk_io_plug_call() functions until blk_io_unplug()
221
+ *
222
+ * blk_io_plug/unplug are thread-local operations. This means that multiple
223
+ * threads can simultaneously call plug/unplug, but the caller must ensure that
224
+ * each unplug() is called in the same thread of the matching plug().
225
+ *
226
+ * Nesting is supported. blk_io_plug_call() functions are only called at the
227
+ * outermost blk_io_unplug().
228
+ */
229
+void blk_io_plug(void)
230
+{
231
+ Plug *plug = get_ptr_plug();
232
+
233
+ assert(plug->count < UINT32_MAX);
234
+
235
+ plug->count++;
236
+}
237
+
238
+/**
239
+ * blk_io_unplug: Run any pending blk_io_plug_call() functions
240
+ *
241
+ * There must have been a matching blk_io_plug() call in the same thread prior
242
+ * to this blk_io_unplug() call.
243
+ */
244
+void blk_io_unplug(void)
245
+{
246
+ Plug *plug = get_ptr_plug();
247
+
248
+ assert(plug->count > 0);
249
+
250
+ if (--plug->count > 0) {
251
+ return;
252
+ }
253
+
254
+ GArray *array = plug->unplug_fns;
255
+ if (!array) {
256
+ return;
257
+ }
258
+
259
+ UnplugFn *fns = (UnplugFn *)array->data;
260
+
261
+ for (guint i = 0; i < array->len; i++) {
262
+ fns[i].fn(fns[i].opaque);
263
+ }
264
+
265
+ /*
266
+ * This resets the array without freeing memory so that appending is cheap
267
+ * in the future.
268
+ */
269
+ g_array_set_size(array, 0);
270
+}
271
diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c
272
index XXXXXXX..XXXXXXX 100644
273
--- a/hw/block/dataplane/xen-block.c
274
+++ b/hw/block/dataplane/xen-block.c
275
@@ -XXX,XX +XXX,XX @@ static bool xen_block_handle_requests(XenBlockDataPlane *dataplane)
276
* is below us.
277
*/
278
if (inflight_atstart > IO_PLUG_THRESHOLD) {
279
- blk_io_plug(dataplane->blk);
280
+ blk_io_plug();
281
}
282
while (rc != rp) {
283
/* pull request from ring */
284
@@ -XXX,XX +XXX,XX @@ static bool xen_block_handle_requests(XenBlockDataPlane *dataplane)
285
286
if (inflight_atstart > IO_PLUG_THRESHOLD &&
287
batched >= inflight_atstart) {
288
- blk_io_unplug(dataplane->blk);
289
+ blk_io_unplug();
290
}
291
xen_block_do_aio(request);
292
if (inflight_atstart > IO_PLUG_THRESHOLD) {
293
if (batched >= inflight_atstart) {
294
- blk_io_plug(dataplane->blk);
295
+ blk_io_plug();
296
batched = 0;
297
} else {
298
batched++;
299
@@ -XXX,XX +XXX,XX @@ static bool xen_block_handle_requests(XenBlockDataPlane *dataplane)
300
}
301
}
302
if (inflight_atstart > IO_PLUG_THRESHOLD) {
303
- blk_io_unplug(dataplane->blk);
304
+ blk_io_unplug();
305
}
306
307
return done_something;
34
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
308
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
35
index XXXXXXX..XXXXXXX 100644
309
index XXXXXXX..XXXXXXX 100644
36
--- a/hw/block/virtio-blk.c
310
--- a/hw/block/virtio-blk.c
37
+++ b/hw/block/virtio-blk.c
311
+++ b/hw/block/virtio-blk.c
38
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
312
@@ -XXX,XX +XXX,XX @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
39
uint64_t capacity;
313
bool suppress_notifications = virtio_queue_get_notification(vq);
40
int64_t length;
314
41
int blk_size = conf->logical_block_size;
315
aio_context_acquire(blk_get_aio_context(s->blk));
42
+ AioContext *ctx;
316
- blk_io_plug(s->blk);
43
+
317
+ blk_io_plug();
44
+ ctx = blk_get_aio_context(s->blk);
318
45
+ aio_context_acquire(ctx);
319
do {
46
320
if (suppress_notifications) {
47
blk_get_geometry(s->blk, &capacity);
321
@@ -XXX,XX +XXX,XX @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
48
memset(&blkcfg, 0, sizeof(blkcfg));
322
virtio_blk_submit_multireq(s, &mrb);
49
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
323
}
50
* per track (cylinder).
324
51
*/
325
- blk_io_unplug(s->blk);
52
length = blk_getlength(s->blk);
326
+ blk_io_unplug();
53
+ aio_context_release(ctx);
327
aio_context_release(blk_get_aio_context(s->blk));
54
if (length > 0 && length / conf->heads / conf->secs % blk_size) {
328
}
55
blkcfg.geometry.sectors = conf->secs & ~s->sector_mask;
329
56
} else {
330
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
331
index XXXXXXX..XXXXXXX 100644
332
--- a/hw/scsi/virtio-scsi.c
333
+++ b/hw/scsi/virtio-scsi.c
334
@@ -XXX,XX +XXX,XX @@ static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req)
335
return -ENOBUFS;
336
}
337
scsi_req_ref(req->sreq);
338
- blk_io_plug(d->conf.blk);
339
+ blk_io_plug();
340
object_unref(OBJECT(d));
341
return 0;
342
}
343
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req)
344
if (scsi_req_enqueue(sreq)) {
345
scsi_req_continue(sreq);
346
}
347
- blk_io_unplug(sreq->dev->conf.blk);
348
+ blk_io_unplug();
349
scsi_req_unref(sreq);
350
}
351
352
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
353
while (!QTAILQ_EMPTY(&reqs)) {
354
req = QTAILQ_FIRST(&reqs);
355
QTAILQ_REMOVE(&reqs, req, next);
356
- blk_io_unplug(req->sreq->dev->conf.blk);
357
+ blk_io_unplug();
358
scsi_req_unref(req->sreq);
359
virtqueue_detach_element(req->vq, &req->elem, 0);
360
virtio_scsi_free_req(req);
361
diff --git a/block/meson.build b/block/meson.build
362
index XXXXXXX..XXXXXXX 100644
363
--- a/block/meson.build
364
+++ b/block/meson.build
365
@@ -XXX,XX +XXX,XX @@ block_ss.add(files(
366
'mirror.c',
367
'nbd.c',
368
'null.c',
369
+ 'plug.c',
370
'qapi.c',
371
'qcow2-bitmap.c',
372
'qcow2-cache.c',
57
--
373
--
58
2.39.1
374
2.40.1
59
60
diff view generated by jsdifflib
New patch
1
Stop using the .bdrv_co_io_plug() API because it is not multi-queue
2
block layer friendly. Use the new blk_io_plug_call() API to batch I/O
3
submission instead.
1
4
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
8
Acked-by: Kevin Wolf <kwolf@redhat.com>
9
Message-id: 20230530180959.1108766-3-stefanha@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
block/nvme.c | 44 ++++++++++++--------------------------------
13
block/trace-events | 1 -
14
2 files changed, 12 insertions(+), 33 deletions(-)
15
16
diff --git a/block/nvme.c b/block/nvme.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/block/nvme.c
19
+++ b/block/nvme.c
20
@@ -XXX,XX +XXX,XX @@
21
#include "qemu/vfio-helpers.h"
22
#include "block/block-io.h"
23
#include "block/block_int.h"
24
+#include "sysemu/block-backend.h"
25
#include "sysemu/replay.h"
26
#include "trace.h"
27
28
@@ -XXX,XX +XXX,XX @@ struct BDRVNVMeState {
29
int blkshift;
30
31
uint64_t max_transfer;
32
- bool plugged;
33
34
bool supports_write_zeroes;
35
bool supports_discard;
36
@@ -XXX,XX +XXX,XX @@ static void nvme_kick(NVMeQueuePair *q)
37
{
38
BDRVNVMeState *s = q->s;
39
40
- if (s->plugged || !q->need_kick) {
41
+ if (!q->need_kick) {
42
return;
43
}
44
trace_nvme_kick(s, q->index);
45
@@ -XXX,XX +XXX,XX @@ static bool nvme_process_completion(NVMeQueuePair *q)
46
NvmeCqe *c;
47
48
trace_nvme_process_completion(s, q->index, q->inflight);
49
- if (s->plugged) {
50
- trace_nvme_process_completion_queue_plugged(s, q->index);
51
- return false;
52
- }
53
54
/*
55
* Support re-entrancy when a request cb() function invokes aio_poll().
56
@@ -XXX,XX +XXX,XX @@ static void nvme_trace_command(const NvmeCmd *cmd)
57
}
58
}
59
60
+static void nvme_unplug_fn(void *opaque)
61
+{
62
+ NVMeQueuePair *q = opaque;
63
+
64
+ QEMU_LOCK_GUARD(&q->lock);
65
+ nvme_kick(q);
66
+ nvme_process_completion(q);
67
+}
68
+
69
static void nvme_submit_command(NVMeQueuePair *q, NVMeRequest *req,
70
NvmeCmd *cmd, BlockCompletionFunc cb,
71
void *opaque)
72
@@ -XXX,XX +XXX,XX @@ static void nvme_submit_command(NVMeQueuePair *q, NVMeRequest *req,
73
q->sq.tail * NVME_SQ_ENTRY_BYTES, cmd, sizeof(*cmd));
74
q->sq.tail = (q->sq.tail + 1) % NVME_QUEUE_SIZE;
75
q->need_kick++;
76
- nvme_kick(q);
77
- nvme_process_completion(q);
78
+ blk_io_plug_call(nvme_unplug_fn, q);
79
qemu_mutex_unlock(&q->lock);
80
}
81
82
@@ -XXX,XX +XXX,XX @@ static void nvme_attach_aio_context(BlockDriverState *bs,
83
}
84
}
85
86
-static void coroutine_fn nvme_co_io_plug(BlockDriverState *bs)
87
-{
88
- BDRVNVMeState *s = bs->opaque;
89
- assert(!s->plugged);
90
- s->plugged = true;
91
-}
92
-
93
-static void coroutine_fn nvme_co_io_unplug(BlockDriverState *bs)
94
-{
95
- BDRVNVMeState *s = bs->opaque;
96
- assert(s->plugged);
97
- s->plugged = false;
98
- for (unsigned i = INDEX_IO(0); i < s->queue_count; i++) {
99
- NVMeQueuePair *q = s->queues[i];
100
- qemu_mutex_lock(&q->lock);
101
- nvme_kick(q);
102
- nvme_process_completion(q);
103
- qemu_mutex_unlock(&q->lock);
104
- }
105
-}
106
-
107
static bool nvme_register_buf(BlockDriverState *bs, void *host, size_t size,
108
Error **errp)
109
{
110
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nvme = {
111
.bdrv_detach_aio_context = nvme_detach_aio_context,
112
.bdrv_attach_aio_context = nvme_attach_aio_context,
113
114
- .bdrv_co_io_plug = nvme_co_io_plug,
115
- .bdrv_co_io_unplug = nvme_co_io_unplug,
116
-
117
.bdrv_register_buf = nvme_register_buf,
118
.bdrv_unregister_buf = nvme_unregister_buf,
119
};
120
diff --git a/block/trace-events b/block/trace-events
121
index XXXXXXX..XXXXXXX 100644
122
--- a/block/trace-events
123
+++ b/block/trace-events
124
@@ -XXX,XX +XXX,XX @@ nvme_kick(void *s, unsigned q_index) "s %p q #%u"
125
nvme_dma_flush_queue_wait(void *s) "s %p"
126
nvme_error(int cmd_specific, int sq_head, int sqid, int cid, int status) "cmd_specific %d sq_head %d sqid %d cid %d status 0x%x"
127
nvme_process_completion(void *s, unsigned q_index, int inflight) "s %p q #%u inflight %d"
128
-nvme_process_completion_queue_plugged(void *s, unsigned q_index) "s %p q #%u"
129
nvme_complete_command(void *s, unsigned q_index, int cid) "s %p q #%u cid %d"
130
nvme_submit_command(void *s, unsigned q_index, int cid) "s %p q #%u cid %d"
131
nvme_submit_command_raw(int c0, int c1, int c2, int c3, int c4, int c5, int c6, int c7) "%02x %02x %02x %02x %02x %02x %02x %02x"
132
--
133
2.40.1
diff view generated by jsdifflib
1
From: Akihiko Odaki <akihiko.odaki@daynix.com>
1
Stop using the .bdrv_co_io_plug() API because it is not multi-queue
2
block layer friendly. Use the new blk_io_plug_call() API to batch I/O
3
submission instead.
2
4
3
vhost_dev_cleanup() clears vhost_dev so back up its vqs member to free
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
the memory pointed by the member.
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
8
Acked-by: Kevin Wolf <kwolf@redhat.com>
9
Message-id: 20230530180959.1108766-4-stefanha@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
block/blkio.c | 43 ++++++++++++++++++++++++-------------------
13
1 file changed, 24 insertions(+), 19 deletions(-)
5
14
6
Fixes: 98fc1ada4c ("virtio: add vhost-user-fs base device")
15
diff --git a/block/blkio.c b/block/blkio.c
7
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Message-Id: <20230130140225.77964-1-akihiko.odaki@daynix.com>
10
---
11
hw/virtio/vhost-user-fs.c | 4 ++--
12
1 file changed, 2 insertions(+), 2 deletions(-)
13
14
diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/virtio/vhost-user-fs.c
17
--- a/block/blkio.c
17
+++ b/hw/virtio/vhost-user-fs.c
18
+++ b/block/blkio.c
18
@@ -XXX,XX +XXX,XX @@ static void vuf_device_unrealize(DeviceState *dev)
19
@@ -XXX,XX +XXX,XX @@
20
#include "qemu/error-report.h"
21
#include "qapi/qmp/qdict.h"
22
#include "qemu/module.h"
23
+#include "sysemu/block-backend.h"
24
#include "exec/memory.h" /* for ram_block_discard_disable() */
25
26
#include "block/block-io.h"
27
@@ -XXX,XX +XXX,XX @@ static void blkio_detach_aio_context(BlockDriverState *bs)
28
NULL, NULL, NULL);
29
}
30
31
-/* Call with s->blkio_lock held to submit I/O after enqueuing a new request */
32
-static void blkio_submit_io(BlockDriverState *bs)
33
+/*
34
+ * Called by blk_io_unplug() or immediately if not plugged. Called without
35
+ * blkio_lock.
36
+ */
37
+static void blkio_unplug_fn(void *opaque)
19
{
38
{
20
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
39
- if (qatomic_read(&bs->io_plugged) == 0) {
21
VHostUserFS *fs = VHOST_USER_FS(dev);
40
- BDRVBlkioState *s = bs->opaque;
22
+ struct vhost_virtqueue *vhost_vqs = fs->vhost_dev.vqs;
41
+ BDRVBlkioState *s = opaque;
23
int i;
42
24
43
+ WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
25
/* This will stop vhost backend if appropriate. */
44
blkioq_do_io(s->blkioq, NULL, 0, 0, NULL);
26
@@ -XXX,XX +XXX,XX @@ static void vuf_device_unrealize(DeviceState *dev)
27
}
45
}
28
g_free(fs->req_vqs);
29
virtio_cleanup(vdev);
30
- g_free(fs->vhost_dev.vqs);
31
- fs->vhost_dev.vqs = NULL;
32
+ g_free(vhost_vqs);
33
}
46
}
34
47
35
static struct vhost_dev *vuf_get_vhost(VirtIODevice *vdev)
48
+/*
49
+ * Schedule I/O submission after enqueuing a new request. Called without
50
+ * blkio_lock.
51
+ */
52
+static void blkio_submit_io(BlockDriverState *bs)
53
+{
54
+ BDRVBlkioState *s = bs->opaque;
55
+
56
+ blk_io_plug_call(blkio_unplug_fn, s);
57
+}
58
+
59
static int coroutine_fn
60
blkio_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
61
{
62
@@ -XXX,XX +XXX,XX @@ blkio_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
63
64
WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
65
blkioq_discard(s->blkioq, offset, bytes, &cod, 0);
66
- blkio_submit_io(bs);
67
}
68
69
+ blkio_submit_io(bs);
70
qemu_coroutine_yield();
71
return cod.ret;
72
}
73
@@ -XXX,XX +XXX,XX @@ blkio_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
74
75
WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
76
blkioq_readv(s->blkioq, offset, iov, iovcnt, &cod, 0);
77
- blkio_submit_io(bs);
78
}
79
80
+ blkio_submit_io(bs);
81
qemu_coroutine_yield();
82
83
if (use_bounce_buffer) {
84
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkio_co_pwritev(BlockDriverState *bs, int64_t offset,
85
86
WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
87
blkioq_writev(s->blkioq, offset, iov, iovcnt, &cod, blkio_flags);
88
- blkio_submit_io(bs);
89
}
90
91
+ blkio_submit_io(bs);
92
qemu_coroutine_yield();
93
94
if (use_bounce_buffer) {
95
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkio_co_flush(BlockDriverState *bs)
96
97
WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
98
blkioq_flush(s->blkioq, &cod, 0);
99
- blkio_submit_io(bs);
100
}
101
102
+ blkio_submit_io(bs);
103
qemu_coroutine_yield();
104
return cod.ret;
105
}
106
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkio_co_pwrite_zeroes(BlockDriverState *bs,
107
108
WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
109
blkioq_write_zeroes(s->blkioq, offset, bytes, &cod, blkio_flags);
110
- blkio_submit_io(bs);
111
}
112
113
+ blkio_submit_io(bs);
114
qemu_coroutine_yield();
115
return cod.ret;
116
}
117
118
-static void coroutine_fn blkio_co_io_unplug(BlockDriverState *bs)
119
-{
120
- BDRVBlkioState *s = bs->opaque;
121
-
122
- WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
123
- blkio_submit_io(bs);
124
- }
125
-}
126
-
127
typedef enum {
128
BMRR_OK,
129
BMRR_SKIP,
130
@@ -XXX,XX +XXX,XX @@ static void blkio_refresh_limits(BlockDriverState *bs, Error **errp)
131
.bdrv_co_pwritev = blkio_co_pwritev, \
132
.bdrv_co_flush_to_disk = blkio_co_flush, \
133
.bdrv_co_pwrite_zeroes = blkio_co_pwrite_zeroes, \
134
- .bdrv_co_io_unplug = blkio_co_io_unplug, \
135
.bdrv_refresh_limits = blkio_refresh_limits, \
136
.bdrv_register_buf = blkio_register_buf, \
137
.bdrv_unregister_buf = blkio_unregister_buf, \
36
--
138
--
37
2.39.1
139
2.40.1
diff view generated by jsdifflib
1
The block layer APIs use BdrvRequestFlags while qemu-io code uses int.
1
Stop using the .bdrv_co_io_plug() API because it is not multi-queue
2
Although the code compiles and runs fine, BdrvRequestFlags is clearer
2
block layer friendly. Use the new blk_io_plug_call() API to batch I/O
3
because it differentiates between other types of flags like bdrv_open()
3
submission instead.
4
flags.
5
4
6
This is purely refactoring.
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
8
Acked-by: Kevin Wolf <kwolf@redhat.com>
9
Message-id: 20230530180959.1108766-5-stefanha@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
include/block/raw-aio.h | 7 -------
13
block/file-posix.c | 10 ----------
14
block/io_uring.c | 44 ++++++++++++++++-------------------------
15
block/trace-events | 5 ++---
16
4 files changed, 19 insertions(+), 47 deletions(-)
7
17
8
Reviewed-by: Eric Blake <eblake@redhat.com>
18
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
9
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-Id: <20230207203719.242926-3-stefanha@redhat.com>
12
---
13
qemu-io-cmds.c | 13 +++++++------
14
1 file changed, 7 insertions(+), 6 deletions(-)
15
16
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
17
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
18
--- a/qemu-io-cmds.c
20
--- a/include/block/raw-aio.h
19
+++ b/qemu-io-cmds.c
21
+++ b/include/block/raw-aio.h
20
@@ -XXX,XX +XXX,XX @@ static int do_pread(BlockBackend *blk, char *buf, int64_t offset,
22
@@ -XXX,XX +XXX,XX @@ int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset,
23
QEMUIOVector *qiov, int type);
24
void luring_detach_aio_context(LuringState *s, AioContext *old_context);
25
void luring_attach_aio_context(LuringState *s, AioContext *new_context);
26
-
27
-/*
28
- * luring_io_plug/unplug work in the thread's current AioContext, therefore the
29
- * caller must ensure that they are paired in the same IOThread.
30
- */
31
-void luring_io_plug(void);
32
-void luring_io_unplug(void);
33
#endif
34
35
#ifdef _WIN32
36
diff --git a/block/file-posix.c b/block/file-posix.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/block/file-posix.c
39
+++ b/block/file-posix.c
40
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_plug(BlockDriverState *bs)
41
laio_io_plug();
42
}
43
#endif
44
-#ifdef CONFIG_LINUX_IO_URING
45
- if (s->use_linux_io_uring) {
46
- luring_io_plug();
47
- }
48
-#endif
21
}
49
}
22
50
23
static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset,
51
static void coroutine_fn raw_co_io_unplug(BlockDriverState *bs)
24
- int64_t bytes, int flags, int64_t *total)
52
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_unplug(BlockDriverState *bs)
25
+ int64_t bytes, BdrvRequestFlags flags, int64_t *total)
53
laio_io_unplug(s->aio_max_batch);
54
}
55
#endif
56
-#ifdef CONFIG_LINUX_IO_URING
57
- if (s->use_linux_io_uring) {
58
- luring_io_unplug();
59
- }
60
-#endif
61
}
62
63
static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs)
64
diff --git a/block/io_uring.c b/block/io_uring.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/block/io_uring.c
67
+++ b/block/io_uring.c
68
@@ -XXX,XX +XXX,XX @@
69
#include "block/raw-aio.h"
70
#include "qemu/coroutine.h"
71
#include "qapi/error.h"
72
+#include "sysemu/block-backend.h"
73
#include "trace.h"
74
75
/* Only used for assertions. */
76
@@ -XXX,XX +XXX,XX @@ typedef struct LuringAIOCB {
77
} LuringAIOCB;
78
79
typedef struct LuringQueue {
80
- int plugged;
81
unsigned int in_queue;
82
unsigned int in_flight;
83
bool blocked;
84
@@ -XXX,XX +XXX,XX @@ static void luring_process_completions_and_submit(LuringState *s)
26
{
85
{
27
int ret;
86
luring_process_completions(s);
28
87
29
@@ -XXX,XX +XXX,XX @@ static int do_pwrite(BlockBackend *blk, char *buf, int64_t offset,
88
- if (!s->io_q.plugged && s->io_q.in_queue > 0) {
89
+ if (s->io_q.in_queue > 0) {
90
ioq_submit(s);
91
}
30
}
92
}
31
93
@@ -XXX,XX +XXX,XX @@ static void qemu_luring_poll_ready(void *opaque)
32
static int do_pwrite_zeroes(BlockBackend *blk, int64_t offset,
94
static void ioq_init(LuringQueue *io_q)
33
- int64_t bytes, int flags, int64_t *total)
34
+ int64_t bytes, BdrvRequestFlags flags,
35
+ int64_t *total)
36
{
95
{
37
int ret = blk_pwrite_zeroes(blk, offset, bytes,
96
QSIMPLEQ_INIT(&io_q->submit_queue);
38
flags | BDRV_REQ_ZERO_WRITE);
97
- io_q->plugged = 0;
39
@@ -XXX,XX +XXX,XX @@ static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov,
98
io_q->in_queue = 0;
99
io_q->in_flight = 0;
100
io_q->blocked = false;
40
}
101
}
41
102
42
static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov,
103
-void luring_io_plug(void)
43
- int64_t offset, int flags, int *total)
104
+static void luring_unplug_fn(void *opaque)
44
+ int64_t offset, BdrvRequestFlags flags, int *total)
45
{
105
{
46
int async_ret = NOT_DONE;
106
- AioContext *ctx = qemu_get_current_aio_context();
47
107
- LuringState *s = aio_get_linux_io_uring(ctx);
48
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
108
- trace_luring_io_plug(s);
49
struct timespec t1, t2;
109
- s->io_q.plugged++;
50
bool Cflag = false, qflag = false, bflag = false;
110
-}
51
bool Pflag = false, zflag = false, cflag = false, sflag = false;
111
-
52
- int flags = 0;
112
-void luring_io_unplug(void)
53
+ BdrvRequestFlags flags = 0;
113
-{
54
int c, cnt, ret;
114
- AioContext *ctx = qemu_get_current_aio_context();
55
char *buf = NULL;
115
- LuringState *s = aio_get_linux_io_uring(ctx);
56
int64_t offset;
116
- assert(s->io_q.plugged);
57
@@ -XXX,XX +XXX,XX @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
117
- trace_luring_io_unplug(s, s->io_q.blocked, s->io_q.plugged,
58
{
118
- s->io_q.in_queue, s->io_q.in_flight);
59
struct timespec t1, t2;
119
- if (--s->io_q.plugged == 0 &&
60
bool Cflag = false, qflag = false;
120
- !s->io_q.blocked && s->io_q.in_queue > 0) {
61
- int flags = 0;
121
+ LuringState *s = opaque;
62
+ BdrvRequestFlags flags = 0;
122
+ trace_luring_unplug_fn(s, s->io_q.blocked, s->io_q.in_queue,
63
int c, cnt, ret;
123
+ s->io_q.in_flight);
64
char *buf;
124
+ if (!s->io_q.blocked && s->io_q.in_queue > 0) {
65
int64_t offset;
125
ioq_submit(s);
66
@@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
126
}
67
int nr_iov, c;
127
}
68
int pattern = 0xcd;
128
@@ -XXX,XX +XXX,XX @@ static int luring_do_submit(int fd, LuringAIOCB *luringcb, LuringState *s,
69
struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
129
70
- int flags = 0;
130
QSIMPLEQ_INSERT_TAIL(&s->io_q.submit_queue, luringcb, next);
71
+ BdrvRequestFlags flags = 0;
131
s->io_q.in_queue++;
72
132
- trace_luring_do_submit(s, s->io_q.blocked, s->io_q.plugged,
73
ctx->blk = blk;
133
- s->io_q.in_queue, s->io_q.in_flight);
74
while ((c = getopt(argc, argv, "CfiqP:uz")) != -1) {
134
- if (!s->io_q.blocked &&
135
- (!s->io_q.plugged ||
136
- s->io_q.in_flight + s->io_q.in_queue >= MAX_ENTRIES)) {
137
- ret = ioq_submit(s);
138
- trace_luring_do_submit_done(s, ret);
139
- return ret;
140
+ trace_luring_do_submit(s, s->io_q.blocked, s->io_q.in_queue,
141
+ s->io_q.in_flight);
142
+ if (!s->io_q.blocked) {
143
+ if (s->io_q.in_flight + s->io_q.in_queue >= MAX_ENTRIES) {
144
+ ret = ioq_submit(s);
145
+ trace_luring_do_submit_done(s, ret);
146
+ return ret;
147
+ }
148
+
149
+ blk_io_plug_call(luring_unplug_fn, s);
150
}
151
return 0;
152
}
153
diff --git a/block/trace-events b/block/trace-events
154
index XXXXXXX..XXXXXXX 100644
155
--- a/block/trace-events
156
+++ b/block/trace-events
157
@@ -XXX,XX +XXX,XX @@ file_paio_submit(void *acb, void *opaque, int64_t offset, int count, int type) "
158
# io_uring.c
159
luring_init_state(void *s, size_t size) "s %p size %zu"
160
luring_cleanup_state(void *s) "%p freed"
161
-luring_io_plug(void *s) "LuringState %p plug"
162
-luring_io_unplug(void *s, int blocked, int plugged, int queued, int inflight) "LuringState %p blocked %d plugged %d queued %d inflight %d"
163
-luring_do_submit(void *s, int blocked, int plugged, int queued, int inflight) "LuringState %p blocked %d plugged %d queued %d inflight %d"
164
+luring_unplug_fn(void *s, int blocked, int queued, int inflight) "LuringState %p blocked %d queued %d inflight %d"
165
+luring_do_submit(void *s, int blocked, int queued, int inflight) "LuringState %p blocked %d queued %d inflight %d"
166
luring_do_submit_done(void *s, int ret) "LuringState %p submitted to kernel %d"
167
luring_co_submit(void *bs, void *s, void *luringcb, int fd, uint64_t offset, size_t nbytes, int type) "bs %p s %p luringcb %p fd %d offset %" PRId64 " nbytes %zd type %d"
168
luring_process_completion(void *s, void *aiocb, int ret) "LuringState %p luringcb %p ret %d"
75
--
169
--
76
2.39.1
170
2.40.1
diff view generated by jsdifflib
New patch
1
1
Stop using the .bdrv_co_io_plug() API because it is not multi-queue
2
block layer friendly. Use the new blk_io_plug_call() API to batch I/O
3
submission instead.
4
5
Note that a dev_max_batch check is dropped in laio_io_unplug() because
6
the semantics of unplug_fn() are different from .bdrv_co_unplug():
7
1. unplug_fn() is only called when the last blk_io_unplug() call occurs,
8
not every time blk_io_unplug() is called.
9
2. unplug_fn() is per-thread, not per-BlockDriverState, so there is no
10
way to get per-BlockDriverState fields like dev_max_batch.
11
12
Therefore this condition cannot be moved to laio_unplug_fn(). It is not
13
obvious that this condition affects performance in practice, so I am
14
removing it instead of trying to come up with a more complex mechanism
15
to preserve the condition.
16
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
Reviewed-by: Eric Blake <eblake@redhat.com>
19
Acked-by: Kevin Wolf <kwolf@redhat.com>
20
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
21
Message-id: 20230530180959.1108766-6-stefanha@redhat.com
22
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
23
---
24
include/block/raw-aio.h | 7 -------
25
block/file-posix.c | 28 ----------------------------
26
block/linux-aio.c | 41 +++++++++++------------------------------
27
3 files changed, 11 insertions(+), 65 deletions(-)
28
29
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
30
index XXXXXXX..XXXXXXX 100644
31
--- a/include/block/raw-aio.h
32
+++ b/include/block/raw-aio.h
33
@@ -XXX,XX +XXX,XX @@ int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov,
34
35
void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context);
36
void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context);
37
-
38
-/*
39
- * laio_io_plug/unplug work in the thread's current AioContext, therefore the
40
- * caller must ensure that they are paired in the same IOThread.
41
- */
42
-void laio_io_plug(void);
43
-void laio_io_unplug(uint64_t dev_max_batch);
44
#endif
45
/* io_uring.c - Linux io_uring implementation */
46
#ifdef CONFIG_LINUX_IO_URING
47
diff --git a/block/file-posix.c b/block/file-posix.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/block/file-posix.c
50
+++ b/block/file-posix.c
51
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset,
52
return raw_co_prw(bs, offset, bytes, qiov, QEMU_AIO_WRITE);
53
}
54
55
-static void coroutine_fn raw_co_io_plug(BlockDriverState *bs)
56
-{
57
- BDRVRawState __attribute__((unused)) *s = bs->opaque;
58
-#ifdef CONFIG_LINUX_AIO
59
- if (s->use_linux_aio) {
60
- laio_io_plug();
61
- }
62
-#endif
63
-}
64
-
65
-static void coroutine_fn raw_co_io_unplug(BlockDriverState *bs)
66
-{
67
- BDRVRawState __attribute__((unused)) *s = bs->opaque;
68
-#ifdef CONFIG_LINUX_AIO
69
- if (s->use_linux_aio) {
70
- laio_io_unplug(s->aio_max_batch);
71
- }
72
-#endif
73
-}
74
-
75
static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs)
76
{
77
BDRVRawState *s = bs->opaque;
78
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
79
.bdrv_co_copy_range_from = raw_co_copy_range_from,
80
.bdrv_co_copy_range_to = raw_co_copy_range_to,
81
.bdrv_refresh_limits = raw_refresh_limits,
82
- .bdrv_co_io_plug = raw_co_io_plug,
83
- .bdrv_co_io_unplug = raw_co_io_unplug,
84
.bdrv_attach_aio_context = raw_aio_attach_aio_context,
85
86
.bdrv_co_truncate = raw_co_truncate,
87
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_device = {
88
.bdrv_co_copy_range_from = raw_co_copy_range_from,
89
.bdrv_co_copy_range_to = raw_co_copy_range_to,
90
.bdrv_refresh_limits = raw_refresh_limits,
91
- .bdrv_co_io_plug = raw_co_io_plug,
92
- .bdrv_co_io_unplug = raw_co_io_unplug,
93
.bdrv_attach_aio_context = raw_aio_attach_aio_context,
94
95
.bdrv_co_truncate = raw_co_truncate,
96
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_cdrom = {
97
.bdrv_co_pwritev = raw_co_pwritev,
98
.bdrv_co_flush_to_disk = raw_co_flush_to_disk,
99
.bdrv_refresh_limits = cdrom_refresh_limits,
100
- .bdrv_co_io_plug = raw_co_io_plug,
101
- .bdrv_co_io_unplug = raw_co_io_unplug,
102
.bdrv_attach_aio_context = raw_aio_attach_aio_context,
103
104
.bdrv_co_truncate = raw_co_truncate,
105
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_cdrom = {
106
.bdrv_co_pwritev = raw_co_pwritev,
107
.bdrv_co_flush_to_disk = raw_co_flush_to_disk,
108
.bdrv_refresh_limits = cdrom_refresh_limits,
109
- .bdrv_co_io_plug = raw_co_io_plug,
110
- .bdrv_co_io_unplug = raw_co_io_unplug,
111
.bdrv_attach_aio_context = raw_aio_attach_aio_context,
112
113
.bdrv_co_truncate = raw_co_truncate,
114
diff --git a/block/linux-aio.c b/block/linux-aio.c
115
index XXXXXXX..XXXXXXX 100644
116
--- a/block/linux-aio.c
117
+++ b/block/linux-aio.c
118
@@ -XXX,XX +XXX,XX @@
119
#include "qemu/event_notifier.h"
120
#include "qemu/coroutine.h"
121
#include "qapi/error.h"
122
+#include "sysemu/block-backend.h"
123
124
/* Only used for assertions. */
125
#include "qemu/coroutine_int.h"
126
@@ -XXX,XX +XXX,XX @@ struct qemu_laiocb {
127
};
128
129
typedef struct {
130
- int plugged;
131
unsigned int in_queue;
132
unsigned int in_flight;
133
bool blocked;
134
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completions_and_submit(LinuxAioState *s)
135
{
136
qemu_laio_process_completions(s);
137
138
- if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
139
+ if (!QSIMPLEQ_EMPTY(&s->io_q.pending)) {
140
ioq_submit(s);
141
}
142
}
143
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_poll_ready(EventNotifier *opaque)
144
static void ioq_init(LaioQueue *io_q)
145
{
146
QSIMPLEQ_INIT(&io_q->pending);
147
- io_q->plugged = 0;
148
io_q->in_queue = 0;
149
io_q->in_flight = 0;
150
io_q->blocked = false;
151
@@ -XXX,XX +XXX,XX @@ static uint64_t laio_max_batch(LinuxAioState *s, uint64_t dev_max_batch)
152
return max_batch;
153
}
154
155
-void laio_io_plug(void)
156
+static void laio_unplug_fn(void *opaque)
157
{
158
- AioContext *ctx = qemu_get_current_aio_context();
159
- LinuxAioState *s = aio_get_linux_aio(ctx);
160
+ LinuxAioState *s = opaque;
161
162
- s->io_q.plugged++;
163
-}
164
-
165
-void laio_io_unplug(uint64_t dev_max_batch)
166
-{
167
- AioContext *ctx = qemu_get_current_aio_context();
168
- LinuxAioState *s = aio_get_linux_aio(ctx);
169
-
170
- assert(s->io_q.plugged);
171
- s->io_q.plugged--;
172
-
173
- /*
174
- * Why max batch checking is performed here:
175
- * Another BDS may have queued requests with a higher dev_max_batch and
176
- * therefore in_queue could now exceed our dev_max_batch. Re-check the max
177
- * batch so we can honor our device's dev_max_batch.
178
- */
179
- if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch) ||
180
- (!s->io_q.plugged &&
181
- !s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending))) {
182
+ if (!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
183
ioq_submit(s);
184
}
185
}
186
@@ -XXX,XX +XXX,XX @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
187
188
QSIMPLEQ_INSERT_TAIL(&s->io_q.pending, laiocb, next);
189
s->io_q.in_queue++;
190
- if (!s->io_q.blocked &&
191
- (!s->io_q.plugged ||
192
- s->io_q.in_queue >= laio_max_batch(s, dev_max_batch))) {
193
- ioq_submit(s);
194
+ if (!s->io_q.blocked) {
195
+ if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch)) {
196
+ ioq_submit(s);
197
+ } else {
198
+ blk_io_plug_call(laio_unplug_fn, s);
199
+ }
200
}
201
202
return 0;
203
--
204
2.40.1
diff view generated by jsdifflib
1
When a write request is converted into a write zeroes request by the
1
No block driver implements .bdrv_co_io_plug() anymore. Get rid of the
2
detect-zeroes= feature, it is no longer associated with an I/O buffer.
2
function pointers.
3
The BDRV_REQ_REGISTERED_BUF flag doesn't make sense without an I/O
4
buffer and must be cleared because bdrv_co_do_pwrite_zeroes() fails with
5
-EINVAL when it's set.
6
3
7
Fiona Ebner <f.ebner@proxmox.com> bisected and diagnosed this QEMU 7.2
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
regression where writes containing zeroes to a blockdev with
5
Reviewed-by: Eric Blake <eblake@redhat.com>
9
discard=unmap,detect-zeroes=unmap fail.
6
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
7
Acked-by: Kevin Wolf <kwolf@redhat.com>
8
Message-id: 20230530180959.1108766-7-stefanha@redhat.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
11
include/block/block-io.h | 3 ---
12
include/block/block_int-common.h | 11 ----------
13
block/io.c | 37 --------------------------------
14
3 files changed, 51 deletions(-)
10
15
11
Buglink: https://gitlab.com/qemu-project/qemu/-/issues/1404
16
diff --git a/include/block/block-io.h b/include/block/block-io.h
12
Fixes: e8b6535533be ("block: add BDRV_REQ_REGISTERED_BUF request flag")
17
index XXXXXXX..XXXXXXX 100644
13
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
18
--- a/include/block/block-io.h
14
Cc: qemu-stable@nongnu.org
19
+++ b/include/block/block-io.h
15
Reviewed-by: Eric Blake <eblake@redhat.com>
20
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx);
16
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
21
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
22
AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c);
18
Message-Id: <20230207203719.242926-2-stefanha@redhat.com>
23
19
---
24
-void coroutine_fn GRAPH_RDLOCK bdrv_co_io_plug(BlockDriverState *bs);
20
block/io.c | 3 +++
25
-void coroutine_fn GRAPH_RDLOCK bdrv_co_io_unplug(BlockDriverState *bs);
21
1 file changed, 3 insertions(+)
26
-
22
27
bool coroutine_fn GRAPH_RDLOCK
28
bdrv_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
29
uint32_t granularity, Error **errp);
30
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
31
index XXXXXXX..XXXXXXX 100644
32
--- a/include/block/block_int-common.h
33
+++ b/include/block/block_int-common.h
34
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
35
void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_debug_event)(
36
BlockDriverState *bs, BlkdebugEvent event);
37
38
- /* io queue for linux-aio */
39
- void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_io_plug)(BlockDriverState *bs);
40
- void coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_io_unplug)(
41
- BlockDriverState *bs);
42
-
43
bool (*bdrv_supports_persistent_dirty_bitmap)(BlockDriverState *bs);
44
45
bool coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_can_store_new_dirty_bitmap)(
46
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
47
unsigned int in_flight;
48
unsigned int serialising_in_flight;
49
50
- /*
51
- * counter for nested bdrv_io_plug.
52
- * Accessed with atomic ops.
53
- */
54
- unsigned io_plugged;
55
-
56
/* do we need to tell the quest if we have a volatile write cache? */
57
int enable_write_cache;
58
23
diff --git a/block/io.c b/block/io.c
59
diff --git a/block/io.c b/block/io.c
24
index XXXXXXX..XXXXXXX 100644
60
index XXXXXXX..XXXXXXX 100644
25
--- a/block/io.c
61
--- a/block/io.c
26
+++ b/block/io.c
62
+++ b/block/io.c
27
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
63
@@ -XXX,XX +XXX,XX @@ void *qemu_try_blockalign0(BlockDriverState *bs, size_t size)
28
if (bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP) {
64
return mem;
29
flags |= BDRV_REQ_MAY_UNMAP;
65
}
30
}
66
31
+
67
-void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs)
32
+ /* Can't use optimization hint with bufferless zero write */
68
-{
33
+ flags &= ~BDRV_REQ_REGISTERED_BUF;
69
- BdrvChild *child;
34
}
70
- IO_CODE();
35
71
- assert_bdrv_graph_readable();
36
if (ret < 0) {
72
-
73
- QLIST_FOREACH(child, &bs->children, next) {
74
- bdrv_co_io_plug(child->bs);
75
- }
76
-
77
- if (qatomic_fetch_inc(&bs->io_plugged) == 0) {
78
- BlockDriver *drv = bs->drv;
79
- if (drv && drv->bdrv_co_io_plug) {
80
- drv->bdrv_co_io_plug(bs);
81
- }
82
- }
83
-}
84
-
85
-void coroutine_fn bdrv_co_io_unplug(BlockDriverState *bs)
86
-{
87
- BdrvChild *child;
88
- IO_CODE();
89
- assert_bdrv_graph_readable();
90
-
91
- assert(bs->io_plugged);
92
- if (qatomic_fetch_dec(&bs->io_plugged) == 1) {
93
- BlockDriver *drv = bs->drv;
94
- if (drv && drv->bdrv_co_io_unplug) {
95
- drv->bdrv_co_io_unplug(bs);
96
- }
97
- }
98
-
99
- QLIST_FOREACH(child, &bs->children, next) {
100
- bdrv_co_io_unplug(child->bs);
101
- }
102
-}
103
-
104
/* Helper that undoes bdrv_register_buf() when it fails partway through */
105
static void GRAPH_RDLOCK
106
bdrv_register_buf_rollback(BlockDriverState *bs, void *host, size_t size,
37
--
107
--
38
2.39.1
108
2.40.1
diff view generated by jsdifflib
1
The blk_register_buf() API is an optimization hint that allows some
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
block drivers to avoid I/O buffer housekeeping or bounce buffers.
3
2
4
Add an -r option to register the I/O buffer so that qemu-io can be used
3
Some virtio-blk drivers (e.g. virtio-blk-vhost-vdpa) supports the fd
5
to test the blk_register_buf() API. The next commit will add a test that
4
passing. Let's expose this to the user, so the management layer
6
uses the new option.
5
can pass the file descriptor of an already opened path.
7
6
8
Reviewed-by: Eric Blake <eblake@redhat.com>
7
If the libblkio virtio-blk driver supports fd passing, let's always
9
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
8
use qemu_open() to open the `path`, so we can handle fd passing
9
from the management layer through the "/dev/fdset/N" special path.
10
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
13
Message-id: 20230530071941.8954-2-sgarzare@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Message-Id: <20230207203719.242926-4-stefanha@redhat.com>
12
---
15
---
13
qemu-io-cmds.c | 204 +++++++++++++++++++++++++++++++------------------
16
block/blkio.c | 53 ++++++++++++++++++++++++++++++++++++++++++---------
14
1 file changed, 129 insertions(+), 75 deletions(-)
17
1 file changed, 44 insertions(+), 9 deletions(-)
15
18
16
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
19
diff --git a/block/blkio.c b/block/blkio.c
17
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
18
--- a/qemu-io-cmds.c
21
--- a/block/blkio.c
19
+++ b/qemu-io-cmds.c
22
+++ b/block/blkio.c
20
@@ -XXX,XX +XXX,XX @@ static int parse_pattern(const char *arg)
23
@@ -XXX,XX +XXX,XX @@ static int blkio_virtio_blk_common_open(BlockDriverState *bs,
21
*/
22
23
#define MISALIGN_OFFSET 16
24
-static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern)
25
+static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern,
26
+ bool register_buf)
27
{
24
{
28
void *buf;
25
const char *path = qdict_get_try_str(options, "path");
29
26
BDRVBlkioState *s = bs->opaque;
30
@@ -XXX,XX +XXX,XX @@ static void *qemu_io_alloc(BlockBackend *blk, size_t len, int pattern)
27
- int ret;
28
+ bool fd_supported = false;
29
+ int fd, ret;
30
31
if (!path) {
32
error_setg(errp, "missing 'path' option");
33
return -EINVAL;
31
}
34
}
32
buf = blk_blockalign(blk, len);
35
33
memset(buf, pattern, len);
36
- ret = blkio_set_str(s->blkio, "path", path);
34
+ if (register_buf) {
37
- qdict_del(options, "path");
35
+ blk_register_buf(blk, buf, len, &error_abort);
38
- if (ret < 0) {
36
+ }
39
- error_setg_errno(errp, -ret, "failed to set path: %s",
37
if (qemuio_misalign) {
40
- blkio_get_error_msg());
38
buf += MISALIGN_OFFSET;
41
- return ret;
39
}
40
return buf;
41
}
42
43
-static void qemu_io_free(void *p)
44
+static void qemu_io_free(BlockBackend *blk, void *p, size_t len,
45
+ bool unregister_buf)
46
{
47
if (qemuio_misalign) {
48
p -= MISALIGN_OFFSET;
49
+ len += MISALIGN_OFFSET;
50
+ }
51
+ if (unregister_buf) {
52
+ blk_unregister_buf(blk, p, len);
53
}
54
qemu_vfree(p);
55
}
56
@@ -XXX,XX +XXX,XX @@ static void qemu_io_free(void *p)
57
* @blk - the block backend where the buffer content is going to be written to
58
* @len - the buffer length
59
* @file_name - the file to read the content from
60
+ * @register_buf - call blk_register_buf()
61
*
62
* Returns: the buffer pointer on success
63
* NULL on error
64
*/
65
static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len,
66
- const char *file_name)
67
+ const char *file_name, bool register_buf)
68
{
69
- char *buf, *buf_origin;
70
+ size_t alloc_len = len + (qemuio_misalign ? MISALIGN_OFFSET : 0);
71
+ char *alloc_buf, *buf, *end;
72
FILE *f = fopen(file_name, "r");
73
int pattern_len;
74
75
@@ -XXX,XX +XXX,XX @@ static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len,
76
return NULL;
77
}
78
79
- if (qemuio_misalign) {
80
- len += MISALIGN_OFFSET;
81
- }
42
- }
82
-
43
-
83
- buf_origin = buf = blk_blockalign(blk, len);
44
if (!(flags & BDRV_O_NOCACHE)) {
84
+ alloc_buf = buf = blk_blockalign(blk, alloc_len);
45
error_setg(errp, "cache.direct=off is not supported");
85
46
return -EINVAL;
86
if (qemuio_misalign) {
87
- buf_origin += MISALIGN_OFFSET;
88
buf += MISALIGN_OFFSET;
89
- len -= MISALIGN_OFFSET;
90
}
47
}
91
48
+
92
- pattern_len = fread(buf_origin, 1, len, f);
49
+ if (blkio_get_int(s->blkio, "fd", &fd) == 0) {
93
+ pattern_len = fread(buf, 1, len, f);
50
+ fd_supported = true;
94
95
if (ferror(f)) {
96
perror(file_name);
97
@@ -XXX,XX +XXX,XX @@ static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len,
98
fclose(f);
99
f = NULL;
100
101
- if (len > pattern_len) {
102
- len -= pattern_len;
103
- buf += pattern_len;
104
-
105
- while (len > 0) {
106
- size_t len_to_copy = MIN(pattern_len, len);
107
-
108
- memcpy(buf, buf_origin, len_to_copy);
109
+ if (register_buf) {
110
+ blk_register_buf(blk, alloc_buf, alloc_len, &error_abort);
111
+ }
51
+ }
112
52
+
113
- len -= len_to_copy;
114
- buf += len_to_copy;
115
- }
116
+ end = buf + len;
117
+ for (char *p = buf + pattern_len; p < end; p += pattern_len) {
118
+ memcpy(p, buf, MIN(pattern_len, end - p));
119
}
120
121
- return buf_origin;
122
+ return buf;
123
124
error:
125
- qemu_io_free(buf_origin);
126
+ /*
53
+ /*
127
+ * This code path is only taken before blk_register_buf() is called, so
54
+ * If the libblkio driver supports fd passing, let's always use qemu_open()
128
+ * hardcode the qemu_io_free() unregister_buf argument to false.
55
+ * to open the `path`, so we can handle fd passing from the management
56
+ * layer through the "/dev/fdset/N" special path.
129
+ */
57
+ */
130
+ qemu_io_free(blk, alloc_buf, alloc_len, false);
58
+ if (fd_supported) {
131
if (f) {
59
+ int open_flags;
132
fclose(f);
60
+
133
}
61
+ if (flags & BDRV_O_RDWR) {
134
@@ -XXX,XX +XXX,XX @@ static void print_report(const char *op, struct timespec *t, int64_t offset,
62
+ open_flags = O_RDWR;
135
*/
63
+ } else {
136
static void *
64
+ open_flags = O_RDONLY;
137
create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov,
65
+ }
138
- int pattern)
66
+
139
+ int pattern, bool register_buf)
67
+ fd = qemu_open(path, open_flags, errp);
140
{
68
+ if (fd < 0) {
141
size_t *sizes = g_new0(size_t, nr_iov);
142
size_t count = 0;
143
@@ -XXX,XX +XXX,XX @@ create_iovec(BlockBackend *blk, QEMUIOVector *qiov, char **argv, int nr_iov,
144
145
qemu_iovec_init(qiov, nr_iov);
146
147
- buf = p = qemu_io_alloc(blk, count, pattern);
148
+ buf = p = qemu_io_alloc(blk, count, pattern, register_buf);
149
150
for (i = 0; i < nr_iov; i++) {
151
qemu_iovec_add(qiov, p, sizes[i]);
152
@@ -XXX,XX +XXX,XX @@ fail:
153
}
154
155
static int do_pread(BlockBackend *blk, char *buf, int64_t offset,
156
- int64_t bytes, int64_t *total)
157
+ int64_t bytes, BdrvRequestFlags flags, int64_t *total)
158
{
159
int ret;
160
161
@@ -XXX,XX +XXX,XX @@ static int do_pread(BlockBackend *blk, char *buf, int64_t offset,
162
return -ERANGE;
163
}
164
165
- ret = blk_pread(blk, offset, bytes, (uint8_t *)buf, 0);
166
+ ret = blk_pread(blk, offset, bytes, (uint8_t *)buf, flags);
167
if (ret < 0) {
168
return ret;
169
}
170
@@ -XXX,XX +XXX,XX @@ static void aio_rw_done(void *opaque, int ret)
171
}
172
173
static int do_aio_readv(BlockBackend *blk, QEMUIOVector *qiov,
174
- int64_t offset, int *total)
175
+ int64_t offset, BdrvRequestFlags flags, int *total)
176
{
177
int async_ret = NOT_DONE;
178
179
- blk_aio_preadv(blk, offset, qiov, 0, aio_rw_done, &async_ret);
180
+ blk_aio_preadv(blk, offset, qiov, flags, aio_rw_done, &async_ret);
181
while (async_ret == NOT_DONE) {
182
main_loop_wait(false);
183
}
184
@@ -XXX,XX +XXX,XX @@ static void read_help(void)
185
" -p, -- ignored for backwards compatibility\n"
186
" -P, -- use a pattern to verify read data\n"
187
" -q, -- quiet mode, do not show I/O statistics\n"
188
+" -r, -- register I/O buffer\n"
189
" -s, -- start offset for pattern verification (only with -P)\n"
190
" -v, -- dump buffer to standard output\n"
191
"\n");
192
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t read_cmd = {
193
.cfunc = read_f,
194
.argmin = 2,
195
.argmax = -1,
196
- .args = "[-abCqv] [-P pattern [-s off] [-l len]] off len",
197
+ .args = "[-abCqrv] [-P pattern [-s off] [-l len]] off len",
198
.oneline = "reads a number of bytes at a specified offset",
199
.help = read_help,
200
};
201
@@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv)
202
int64_t total = 0;
203
int pattern = 0;
204
int64_t pattern_offset = 0, pattern_count = 0;
205
+ BdrvRequestFlags flags = 0;
206
207
- while ((c = getopt(argc, argv, "bCl:pP:qs:v")) != -1) {
208
+ while ((c = getopt(argc, argv, "bCl:pP:qrs:v")) != -1) {
209
switch (c) {
210
case 'b':
211
bflag = true;
212
@@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv)
213
case 'q':
214
qflag = true;
215
break;
216
+ case 'r':
217
+ flags |= BDRV_REQ_REGISTERED_BUF;
218
+ break;
219
case 's':
220
sflag = true;
221
pattern_offset = cvtnum(optarg);
222
@@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv)
223
count);
224
return -EINVAL;
225
}
226
+ if (flags & BDRV_REQ_REGISTERED_BUF) {
227
+ printf("I/O buffer registration is not supported when reading "
228
+ "from vmstate\n");
229
+ return -EINVAL;
69
+ return -EINVAL;
230
+ }
70
+ }
231
}
71
+
232
72
+ ret = blkio_set_int(s->blkio, "fd", fd);
233
- buf = qemu_io_alloc(blk, count, 0xab);
73
+ if (ret < 0) {
234
+ buf = qemu_io_alloc(blk, count, 0xab, flags & BDRV_REQ_REGISTERED_BUF);
74
+ error_setg_errno(errp, -ret, "failed to set fd: %s",
235
75
+ blkio_get_error_msg());
236
clock_gettime(CLOCK_MONOTONIC, &t1);
76
+ qemu_close(fd);
237
if (bflag) {
77
+ return ret;
238
ret = do_load_vmstate(blk, buf, offset, count, &total);
239
} else {
240
- ret = do_pread(blk, buf, offset, count, &total);
241
+ ret = do_pread(blk, buf, offset, count, flags, &total);
242
}
243
clock_gettime(CLOCK_MONOTONIC, &t2);
244
245
@@ -XXX,XX +XXX,XX @@ static int read_f(BlockBackend *blk, int argc, char **argv)
246
print_report("read", &t2, offset, count, total, cnt, Cflag);
247
248
out:
249
- qemu_io_free(buf);
250
+ qemu_io_free(blk, buf, count, flags & BDRV_REQ_REGISTERED_BUF);
251
return ret;
252
}
253
254
@@ -XXX,XX +XXX,XX @@ static void readv_help(void)
255
" Uses multiple iovec buffers if more than one byte range is specified.\n"
256
" -C, -- report statistics in a machine parsable format\n"
257
" -P, -- use a pattern to verify read data\n"
258
-" -v, -- dump buffer to standard output\n"
259
" -q, -- quiet mode, do not show I/O statistics\n"
260
+" -r, -- register I/O buffer\n"
261
+" -v, -- dump buffer to standard output\n"
262
"\n");
263
}
264
265
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t readv_cmd = {
266
.cfunc = readv_f,
267
.argmin = 2,
268
.argmax = -1,
269
- .args = "[-Cqv] [-P pattern] off len [len..]",
270
+ .args = "[-Cqrv] [-P pattern] off len [len..]",
271
.oneline = "reads a number of bytes at a specified offset",
272
.help = readv_help,
273
};
274
@@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
275
QEMUIOVector qiov;
276
int pattern = 0;
277
bool Pflag = false;
278
+ BdrvRequestFlags flags = 0;
279
280
- while ((c = getopt(argc, argv, "CP:qv")) != -1) {
281
+ while ((c = getopt(argc, argv, "CP:qrv")) != -1) {
282
switch (c) {
283
case 'C':
284
Cflag = true;
285
@@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
286
case 'q':
287
qflag = true;
288
break;
289
+ case 'r':
290
+ flags |= BDRV_REQ_REGISTERED_BUF;
291
+ break;
292
case 'v':
293
vflag = true;
294
break;
295
@@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
296
optind++;
297
298
nr_iov = argc - optind;
299
- buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab);
300
+ buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, 0xab,
301
+ flags & BDRV_REQ_REGISTERED_BUF);
302
if (buf == NULL) {
303
return -EINVAL;
304
}
305
306
clock_gettime(CLOCK_MONOTONIC, &t1);
307
- ret = do_aio_readv(blk, &qiov, offset, &total);
308
+ ret = do_aio_readv(blk, &qiov, offset, flags, &total);
309
clock_gettime(CLOCK_MONOTONIC, &t2);
310
311
if (ret < 0) {
312
@@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
313
print_report("read", &t2, offset, qiov.size, total, cnt, Cflag);
314
315
out:
316
+ qemu_io_free(blk, buf, qiov.size, flags & BDRV_REQ_REGISTERED_BUF);
317
qemu_iovec_destroy(&qiov);
318
- qemu_io_free(buf);
319
return ret;
320
}
321
322
@@ -XXX,XX +XXX,XX @@ static void write_help(void)
323
" filled with a set pattern (0xcdcdcdcd).\n"
324
" -b, -- write to the VM state rather than the virtual disk\n"
325
" -c, -- write compressed data with blk_write_compressed\n"
326
+" -C, -- report statistics in a machine parsable format\n"
327
" -f, -- use Force Unit Access semantics\n"
328
" -n, -- with -z, don't allow slow fallback\n"
329
" -p, -- ignored for backwards compatibility\n"
330
" -P, -- use different pattern to fill file\n"
331
+" -q, -- quiet mode, do not show I/O statistics\n"
332
+" -r, -- register I/O buffer\n"
333
" -s, -- use a pattern file to fill the write buffer\n"
334
-" -C, -- report statistics in a machine parsable format\n"
335
-" -q, -- quiet mode, do not show I/O statistics\n"
336
" -u, -- with -z, allow unmapping\n"
337
" -z, -- write zeroes using blk_pwrite_zeroes\n"
338
"\n");
339
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t write_cmd = {
340
.perm = BLK_PERM_WRITE,
341
.argmin = 2,
342
.argmax = -1,
343
- .args = "[-bcCfnquz] [-P pattern | -s source_file] off len",
344
+ .args = "[-bcCfnqruz] [-P pattern | -s source_file] off len",
345
.oneline = "writes a number of bytes at a specified offset",
346
.help = write_help,
347
};
348
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
349
int pattern = 0xcd;
350
const char *file_name = NULL;
351
352
- while ((c = getopt(argc, argv, "bcCfnpP:qs:uz")) != -1) {
353
+ while ((c = getopt(argc, argv, "bcCfnpP:qrs:uz")) != -1) {
354
switch (c) {
355
case 'b':
356
bflag = true;
357
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
358
case 'q':
359
qflag = true;
360
break;
361
+ case 'r':
362
+ flags |= BDRV_REQ_REGISTERED_BUF;
363
+ break;
364
case 's':
365
sflag = true;
366
file_name = optarg;
367
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
368
}
369
}
370
371
- if (!zflag) {
372
+ if (zflag) {
373
+ if (flags & BDRV_REQ_REGISTERED_BUF) {
374
+ printf("cannot combine zero write with registered I/O buffer\n");
375
+ return -EINVAL;
376
+ }
78
+ }
377
+ } else {
79
+ } else {
378
if (sflag) {
80
+ ret = blkio_set_str(s->blkio, "path", path);
379
- buf = qemu_io_alloc_from_file(blk, count, file_name);
81
+ if (ret < 0) {
380
+ buf = qemu_io_alloc_from_file(blk, count, file_name,
82
+ error_setg_errno(errp, -ret, "failed to set path: %s",
381
+ flags & BDRV_REQ_REGISTERED_BUF);
83
+ blkio_get_error_msg());
382
if (!buf) {
84
+ return ret;
383
return -EINVAL;
85
+ }
384
}
86
+ }
385
} else {
87
+
386
- buf = qemu_io_alloc(blk, count, pattern);
88
+ qdict_del(options, "path");
387
+ buf = qemu_io_alloc(blk, count, pattern,
89
+
388
+ flags & BDRV_REQ_REGISTERED_BUF);
389
}
390
}
391
392
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
393
394
out:
395
if (!zflag) {
396
- qemu_io_free(buf);
397
+ qemu_io_free(blk, buf, count, flags & BDRV_REQ_REGISTERED_BUF);
398
}
399
return ret;
400
}
401
@@ -XXX,XX +XXX,XX @@ writev_help(void)
402
"\n"
403
" Writes into a segment of the currently open file, using a buffer\n"
404
" filled with a set pattern (0xcdcdcdcd).\n"
405
-" -P, -- use different pattern to fill file\n"
406
" -C, -- report statistics in a machine parsable format\n"
407
" -f, -- use Force Unit Access semantics\n"
408
+" -P, -- use different pattern to fill file\n"
409
" -q, -- quiet mode, do not show I/O statistics\n"
410
+" -r, -- register I/O buffer\n"
411
"\n");
412
}
413
414
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t writev_cmd = {
415
.perm = BLK_PERM_WRITE,
416
.argmin = 2,
417
.argmax = -1,
418
- .args = "[-Cfq] [-P pattern] off len [len..]",
419
+ .args = "[-Cfqr] [-P pattern] off len [len..]",
420
.oneline = "writes a number of bytes at a specified offset",
421
.help = writev_help,
422
};
423
@@ -XXX,XX +XXX,XX @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
424
int pattern = 0xcd;
425
QEMUIOVector qiov;
426
427
- while ((c = getopt(argc, argv, "CfqP:")) != -1) {
428
+ while ((c = getopt(argc, argv, "CfP:qr")) != -1) {
429
switch (c) {
430
case 'C':
431
Cflag = true;
432
@@ -XXX,XX +XXX,XX @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
433
case 'q':
434
qflag = true;
435
break;
436
+ case 'r':
437
+ flags |= BDRV_REQ_REGISTERED_BUF;
438
+ break;
439
case 'P':
440
pattern = parse_pattern(optarg);
441
if (pattern < 0) {
442
@@ -XXX,XX +XXX,XX @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
443
optind++;
444
445
nr_iov = argc - optind;
446
- buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern);
447
+ buf = create_iovec(blk, &qiov, &argv[optind], nr_iov, pattern,
448
+ flags & BDRV_REQ_REGISTERED_BUF);
449
if (buf == NULL) {
450
return -EINVAL;
451
}
452
@@ -XXX,XX +XXX,XX @@ static int writev_f(BlockBackend *blk, int argc, char **argv)
453
t2 = tsub(t2, t1);
454
print_report("wrote", &t2, offset, qiov.size, total, cnt, Cflag);
455
out:
456
+ qemu_io_free(blk, buf, qiov.size, flags & BDRV_REQ_REGISTERED_BUF);
457
qemu_iovec_destroy(&qiov);
458
- qemu_io_free(buf);
459
return ret;
460
}
461
462
@@ -XXX,XX +XXX,XX @@ struct aio_ctx {
463
bool zflag;
464
BlockAcctCookie acct;
465
int pattern;
466
+ BdrvRequestFlags flags;
467
struct timespec t1;
468
};
469
470
@@ -XXX,XX +XXX,XX @@ static void aio_write_done(void *opaque, int ret)
471
ctx->qiov.size, 1, ctx->Cflag);
472
out:
473
if (!ctx->zflag) {
474
- qemu_io_free(ctx->buf);
475
+ qemu_io_free(ctx->blk, ctx->buf, ctx->qiov.size,
476
+ ctx->flags & BDRV_REQ_REGISTERED_BUF);
477
qemu_iovec_destroy(&ctx->qiov);
478
}
479
g_free(ctx);
480
@@ -XXX,XX +XXX,XX @@ static void aio_read_done(void *opaque, int ret)
481
print_report("read", &t2, ctx->offset, ctx->qiov.size,
482
ctx->qiov.size, 1, ctx->Cflag);
483
out:
484
- qemu_io_free(ctx->buf);
485
+ qemu_io_free(ctx->blk, ctx->buf, ctx->qiov.size,
486
+ ctx->flags & BDRV_REQ_REGISTERED_BUF);
487
qemu_iovec_destroy(&ctx->qiov);
488
g_free(ctx);
489
}
490
@@ -XXX,XX +XXX,XX @@ static void aio_read_help(void)
491
" considered successful once the request is submitted, independently\n"
492
" of potential I/O errors or pattern mismatches.\n"
493
" -C, -- report statistics in a machine parsable format\n"
494
-" -P, -- use a pattern to verify read data\n"
495
" -i, -- treat request as invalid, for exercising stats\n"
496
-" -v, -- dump buffer to standard output\n"
497
+" -P, -- use a pattern to verify read data\n"
498
" -q, -- quiet mode, do not show I/O statistics\n"
499
+" -r, -- register I/O buffer\n"
500
+" -v, -- dump buffer to standard output\n"
501
"\n");
502
}
503
504
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t aio_read_cmd = {
505
.cfunc = aio_read_f,
506
.argmin = 2,
507
.argmax = -1,
508
- .args = "[-Ciqv] [-P pattern] off len [len..]",
509
+ .args = "[-Ciqrv] [-P pattern] off len [len..]",
510
.oneline = "asynchronously reads a number of bytes",
511
.help = aio_read_help,
512
};
513
@@ -XXX,XX +XXX,XX @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
514
struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
515
516
ctx->blk = blk;
517
- while ((c = getopt(argc, argv, "CP:iqv")) != -1) {
518
+ while ((c = getopt(argc, argv, "CiP:qrv")) != -1) {
519
switch (c) {
520
case 'C':
521
ctx->Cflag = true;
522
@@ -XXX,XX +XXX,XX @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
523
case 'q':
524
ctx->qflag = true;
525
break;
526
+ case 'r':
527
+ ctx->flags |= BDRV_REQ_REGISTERED_BUF;
528
+ break;
529
case 'v':
530
ctx->vflag = true;
531
break;
532
@@ -XXX,XX +XXX,XX @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
533
optind++;
534
535
nr_iov = argc - optind;
536
- ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab);
537
+ ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov, 0xab,
538
+ ctx->flags & BDRV_REQ_REGISTERED_BUF);
539
if (ctx->buf == NULL) {
540
block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_READ);
541
g_free(ctx);
542
@@ -XXX,XX +XXX,XX @@ static int aio_read_f(BlockBackend *blk, int argc, char **argv)
543
clock_gettime(CLOCK_MONOTONIC, &ctx->t1);
544
block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
545
BLOCK_ACCT_READ);
546
- blk_aio_preadv(blk, ctx->offset, &ctx->qiov, 0, aio_read_done, ctx);
547
+ blk_aio_preadv(blk, ctx->offset, &ctx->qiov, ctx->flags, aio_read_done,
548
+ ctx);
549
return 0;
90
return 0;
550
}
91
}
551
92
552
@@ -XXX,XX +XXX,XX @@ static void aio_write_help(void)
553
" Note that due to its asynchronous nature, this command will be\n"
554
" considered successful once the request is submitted, independently\n"
555
" of potential I/O errors or pattern mismatches.\n"
556
-" -P, -- use different pattern to fill file\n"
557
" -C, -- report statistics in a machine parsable format\n"
558
" -f, -- use Force Unit Access semantics\n"
559
" -i, -- treat request as invalid, for exercising stats\n"
560
+" -P, -- use different pattern to fill file\n"
561
" -q, -- quiet mode, do not show I/O statistics\n"
562
+" -r, -- register I/O buffer\n"
563
" -u, -- with -z, allow unmapping\n"
564
" -z, -- write zeroes using blk_aio_pwrite_zeroes\n"
565
"\n");
566
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t aio_write_cmd = {
567
.perm = BLK_PERM_WRITE,
568
.argmin = 2,
569
.argmax = -1,
570
- .args = "[-Cfiquz] [-P pattern] off len [len..]",
571
+ .args = "[-Cfiqruz] [-P pattern] off len [len..]",
572
.oneline = "asynchronously writes a number of bytes",
573
.help = aio_write_help,
574
};
575
@@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
576
int nr_iov, c;
577
int pattern = 0xcd;
578
struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
579
- BdrvRequestFlags flags = 0;
580
581
ctx->blk = blk;
582
- while ((c = getopt(argc, argv, "CfiqP:uz")) != -1) {
583
+ while ((c = getopt(argc, argv, "CfiP:qruz")) != -1) {
584
switch (c) {
585
case 'C':
586
ctx->Cflag = true;
587
break;
588
case 'f':
589
- flags |= BDRV_REQ_FUA;
590
+ ctx->flags |= BDRV_REQ_FUA;
591
break;
592
case 'q':
593
ctx->qflag = true;
594
break;
595
+ case 'r':
596
+ ctx->flags |= BDRV_REQ_REGISTERED_BUF;
597
+ break;
598
case 'u':
599
- flags |= BDRV_REQ_MAY_UNMAP;
600
+ ctx->flags |= BDRV_REQ_MAY_UNMAP;
601
break;
602
case 'P':
603
pattern = parse_pattern(optarg);
604
@@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
605
return -EINVAL;
606
}
607
608
- if ((flags & BDRV_REQ_MAY_UNMAP) && !ctx->zflag) {
609
+ if ((ctx->flags & BDRV_REQ_MAY_UNMAP) && !ctx->zflag) {
610
printf("-u requires -z to be specified\n");
611
g_free(ctx);
612
return -EINVAL;
613
@@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
614
return -EINVAL;
615
}
616
617
+ if (ctx->zflag && (ctx->flags & BDRV_REQ_REGISTERED_BUF)) {
618
+ printf("cannot combine zero write with registered I/O buffer\n");
619
+ g_free(ctx);
620
+ return -EINVAL;
621
+ }
622
+
623
ctx->offset = cvtnum(argv[optind]);
624
if (ctx->offset < 0) {
625
int ret = ctx->offset;
626
@@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
627
}
628
629
ctx->qiov.size = count;
630
- blk_aio_pwrite_zeroes(blk, ctx->offset, count, flags, aio_write_done,
631
- ctx);
632
+ blk_aio_pwrite_zeroes(blk, ctx->offset, count, ctx->flags,
633
+ aio_write_done, ctx);
634
} else {
635
nr_iov = argc - optind;
636
ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov,
637
- pattern);
638
+ pattern, ctx->flags & BDRV_REQ_REGISTERED_BUF);
639
if (ctx->buf == NULL) {
640
block_acct_invalid(blk_get_stats(blk), BLOCK_ACCT_WRITE);
641
g_free(ctx);
642
@@ -XXX,XX +XXX,XX @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv)
643
block_acct_start(blk_get_stats(blk), &ctx->acct, ctx->qiov.size,
644
BLOCK_ACCT_WRITE);
645
646
- blk_aio_pwritev(blk, ctx->offset, &ctx->qiov, flags, aio_write_done,
647
- ctx);
648
+ blk_aio_pwritev(blk, ctx->offset, &ctx->qiov, ctx->flags,
649
+ aio_write_done, ctx);
650
}
651
652
return 0;
653
--
93
--
654
2.39.1
94
2.40.1
diff view generated by jsdifflib
1
This regression test demonstrates that detect-zeroes works with
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
registered buffers. Bug details:
3
https://gitlab.com/qemu-project/qemu/-/issues/1404
4
2
5
Reviewed-by: Eric Blake <eblake@redhat.com>
3
The virtio-blk-vhost-vdpa driver in libblkio 1.3.0 supports the fd
6
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
4
passing through the new 'fd' property.
5
6
Since now we are using qemu_open() on '@path' if the virtio-blk driver
7
supports the fd passing, let's announce it.
8
In this way, the management layer can pass the file descriptor of an
9
already opened vhost-vdpa character device. This is useful especially
10
when the device can only be accessed with certain privileges.
11
12
Add the '@fdset' feature only when the virtio-blk-vhost-vdpa driver
13
in libblkio supports it.
14
15
Suggested-by: Markus Armbruster <armbru@redhat.com>
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
18
Message-id: 20230530071941.8954-3-sgarzare@redhat.com
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-Id: <20230207203719.242926-5-stefanha@redhat.com>
9
---
20
---
10
.../tests/detect-zeroes-registered-buf | 58 +++++++++++++++++++
21
qapi/block-core.json | 6 ++++++
11
.../tests/detect-zeroes-registered-buf.out | 7 +++
22
meson.build | 4 ++++
12
2 files changed, 65 insertions(+)
23
2 files changed, 10 insertions(+)
13
create mode 100755 tests/qemu-iotests/tests/detect-zeroes-registered-buf
14
create mode 100644 tests/qemu-iotests/tests/detect-zeroes-registered-buf.out
15
24
16
diff --git a/tests/qemu-iotests/tests/detect-zeroes-registered-buf b/tests/qemu-iotests/tests/detect-zeroes-registered-buf
25
diff --git a/qapi/block-core.json b/qapi/block-core.json
17
new file mode 100755
26
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX
27
--- a/qapi/block-core.json
19
--- /dev/null
28
+++ b/qapi/block-core.json
20
+++ b/tests/qemu-iotests/tests/detect-zeroes-registered-buf
21
@@ -XXX,XX +XXX,XX @@
29
@@ -XXX,XX +XXX,XX @@
22
+#!/usr/bin/env bash
30
#
23
+# group: rw auto quick
31
# @path: path to the vhost-vdpa character device.
32
#
33
+# Features:
34
+# @fdset: Member @path supports the special "/dev/fdset/N" path
35
+# (since 8.1)
24
+#
36
+#
25
+# Check that detect-zeroes=unmap works on writes with registered I/O buffers.
37
# Since: 7.2
26
+# This is a regression test for
38
##
27
+# https://gitlab.com/qemu-project/qemu/-/issues/1404 where I/O requests failed
39
{ 'struct': 'BlockdevOptionsVirtioBlkVhostVdpa',
28
+# unexpectedly.
40
'data': { 'path': 'str' },
29
+#
41
+ 'features': [ { 'name' :'fdset',
30
+# Copyright Red Hat
42
+ 'if': 'CONFIG_BLKIO_VHOST_VDPA_FD' } ],
31
+#
43
'if': 'CONFIG_BLKIO' }
32
+# This program is free software; you can redistribute it and/or modify
44
33
+# it under the terms of the GNU General Public License as published by
45
##
34
+# the Free Software Foundation; either version 2 of the License, or
46
diff --git a/meson.build b/meson.build
35
+# (at your option) any later version.
47
index XXXXXXX..XXXXXXX 100644
36
+#
48
--- a/meson.build
37
+# This program is distributed in the hope that it will be useful,
49
+++ b/meson.build
38
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
50
@@ -XXX,XX +XXX,XX @@ config_host_data.set('CONFIG_LZO', lzo.found())
39
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51
config_host_data.set('CONFIG_MPATH', mpathpersist.found())
40
+# GNU General Public License for more details.
52
config_host_data.set('CONFIG_MPATH_NEW_API', mpathpersist_new_api)
41
+#
53
config_host_data.set('CONFIG_BLKIO', blkio.found())
42
+# You should have received a copy of the GNU General Public License
54
+if blkio.found()
43
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
55
+ config_host_data.set('CONFIG_BLKIO_VHOST_VDPA_FD',
44
+#
56
+ blkio.version().version_compare('>=1.3.0'))
45
+
57
+endif
46
+# creator
58
config_host_data.set('CONFIG_CURL', curl.found())
47
+owner=stefanha@redhat.com
59
config_host_data.set('CONFIG_CURSES', curses.found())
48
+
60
config_host_data.set('CONFIG_GBM', gbm.found())
49
+seq=`basename $0`
50
+echo "QA output created by $seq"
51
+
52
+status=1    # failure is the default!
53
+
54
+_cleanup()
55
+{
56
+    _cleanup_test_img
57
+}
58
+trap "_cleanup; exit \$status" 0 1 2 3 15
59
+
60
+# get standard environment, filters and checks
61
+cd ..
62
+. ./common.rc
63
+. ./common.filter
64
+
65
+_supported_fmt qcow2
66
+_supported_proto generic
67
+
68
+size=128M
69
+_make_test_img $size
70
+IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,discard=unmap,detect-zeroes=unmap"
71
+
72
+echo
73
+echo "== writing zero buffer to image =="
74
+QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS_NO_FMT" $QEMU_IO -c "write -r -P 0 0 4k" --image-opts "$IMGSPEC" | _filter_qemu_io
75
+
76
+# success, all done
77
+echo "*** done"
78
+rm -f $seq.full
79
+status=0
80
diff --git a/tests/qemu-iotests/tests/detect-zeroes-registered-buf.out b/tests/qemu-iotests/tests/detect-zeroes-registered-buf.out
81
new file mode 100644
82
index XXXXXXX..XXXXXXX
83
--- /dev/null
84
+++ b/tests/qemu-iotests/tests/detect-zeroes-registered-buf.out
85
@@ -XXX,XX +XXX,XX @@
86
+QA output created by detect-zeroes-registered-buf
87
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
88
+
89
+== writing zero buffer to image ==
90
+wrote 4096/4096 bytes at offset 0
91
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
92
+*** done
93
--
61
--
94
2.39.1
62
2.40.1
diff view generated by jsdifflib