1
The following changes since commit 801f3db7564dcce8a37a70833c0abe40ec19f8ce:
1
The following changes since commit c6a5fc2ac76c5ab709896ee1b0edd33685a67ed1:
2
2
3
Merge remote-tracking branch 'remotes/philmd/tags/kconfig-20210720' into staging (2021-07-20 19:30:28 +0100)
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 d7ddd0a1618a75b31dc308bb37365ce1da972154:
9
for you to fetch changes up to 98b126f5e3228a346c774e569e26689943b401dd:
10
10
11
linux-aio: limit the batch size using `aio-max-batch` parameter (2021-07-21 13:47:50 +0100)
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
Stefano's performance regression fix for commit 2558cb8dd4 ("linux-aio:
16
- Stefano Garzarella's blkio block driver 'fd' parameter
17
increasing MAX_EVENTS to a larger hardcoded value").
17
- My thread-local blk_io_plug() series
18
18
19
----------------------------------------------------------------
19
----------------------------------------------------------------
20
20
21
Stefano Garzarella (3):
21
Stefan Hajnoczi (6):
22
iothread: generalize iothread_set_param/iothread_get_param
22
block: add blk_io_plug_call() API
23
iothread: add aio-max-batch parameter
23
block/nvme: convert to blk_io_plug_call() API
24
linux-aio: limit the batch size using `aio-max-batch` parameter
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
25
28
26
qapi/misc.json | 6 ++-
29
Stefano Garzarella (2):
27
qapi/qom.json | 7 +++-
30
block/blkio: use qemu_open() to support fd passing for virtio-blk
28
include/block/aio.h | 12 ++++++
31
qapi: add '@fdset' feature for BlockdevOptionsVirtioBlkVhostVdpa
29
include/sysemu/iothread.h | 3 ++
32
30
block/linux-aio.c | 9 ++++-
33
MAINTAINERS | 1 +
31
iothread.c | 82 ++++++++++++++++++++++++++++++++++-----
34
qapi/block-core.json | 6 ++
32
monitor/hmp-cmds.c | 2 +
35
meson.build | 4 +
33
util/aio-posix.c | 12 ++++++
36
include/block/block-io.h | 3 -
34
util/aio-win32.c | 5 +++
37
include/block/block_int-common.h | 11 ---
35
util/async.c | 2 +
38
include/block/raw-aio.h | 14 ---
36
qemu-options.hx | 8 +++-
39
include/sysemu/block-backend-io.h | 13 +--
37
11 files changed, 134 insertions(+), 14 deletions(-)
40
block/blkio.c | 96 ++++++++++++------
41
block/block-backend.c | 22 -----
42
block/file-posix.c | 38 -------
43
block/io.c | 37 -------
44
block/io_uring.c | 44 ++++-----
45
block/linux-aio.c | 41 +++-----
46
block/nvme.c | 44 +++------
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
38
55
39
--
56
--
40
2.31.1
57
2.40.1
41
diff view generated by jsdifflib
New patch
1
1
Introduce a new API for thread-local blk_io_plug() that does not
2
traverse the block graph. The goal is to make blk_io_plug() multi-queue
3
friendly.
4
5
Instead of having block drivers track whether or not we're in a plugged
6
section, provide an API that allows them to defer a function call until
7
we're unplugged: blk_io_plug_call(fn, opaque). If blk_io_plug_call() is
8
called multiple times with the same fn/opaque pair, then fn() is only
9
called once at the end of the function - resulting in batching.
10
11
This patch introduces the API and changes blk_io_plug()/blk_io_unplug().
12
blk_io_plug()/blk_io_unplug() no longer require a BlockBackend argument
13
because the plug state is now thread-local.
14
15
Later patches convert block drivers to blk_io_plug_call() and then we
16
can finally remove .bdrv_co_io_plug() once all block drivers have been
17
converted.
18
19
Signed-off-by: Stefan Hajnoczi <stefanha@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>
25
---
26
MAINTAINERS | 1 +
27
include/sysemu/block-backend-io.h | 13 +--
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;
308
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
309
index XXXXXXX..XXXXXXX 100644
310
--- a/hw/block/virtio-blk.c
311
+++ b/hw/block/virtio-blk.c
312
@@ -XXX,XX +XXX,XX @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
313
bool suppress_notifications = virtio_queue_get_notification(vq);
314
315
aio_context_acquire(blk_get_aio_context(s->blk));
316
- blk_io_plug(s->blk);
317
+ blk_io_plug();
318
319
do {
320
if (suppress_notifications) {
321
@@ -XXX,XX +XXX,XX @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
322
virtio_blk_submit_multireq(s, &mrb);
323
}
324
325
- blk_io_unplug(s->blk);
326
+ blk_io_unplug();
327
aio_context_release(blk_get_aio_context(s->blk));
328
}
329
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',
373
--
374
2.40.1
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
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-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(-)
14
15
diff --git a/block/blkio.c b/block/blkio.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/blkio.c
18
+++ b/block/blkio.c
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)
38
{
39
- if (qatomic_read(&bs->io_plugged) == 0) {
40
- BDRVBlkioState *s = bs->opaque;
41
+ BDRVBlkioState *s = opaque;
42
43
+ WITH_QEMU_LOCK_GUARD(&s->blkio_lock) {
44
blkioq_do_io(s->blkioq, NULL, 0, 0, NULL);
45
}
46
}
47
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, \
138
--
139
2.40.1
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-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(-)
17
18
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/include/block/raw-aio.h
21
+++ b/include/block/raw-aio.h
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
49
}
50
51
static void coroutine_fn raw_co_io_unplug(BlockDriverState *bs)
52
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn raw_co_io_unplug(BlockDriverState *bs)
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)
85
{
86
luring_process_completions(s);
87
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
}
92
}
93
@@ -XXX,XX +XXX,XX @@ static void qemu_luring_poll_ready(void *opaque)
94
static void ioq_init(LuringQueue *io_q)
95
{
96
QSIMPLEQ_INIT(&io_q->submit_queue);
97
- io_q->plugged = 0;
98
io_q->in_queue = 0;
99
io_q->in_flight = 0;
100
io_q->blocked = false;
101
}
102
103
-void luring_io_plug(void)
104
+static void luring_unplug_fn(void *opaque)
105
{
106
- AioContext *ctx = qemu_get_current_aio_context();
107
- LuringState *s = aio_get_linux_io_uring(ctx);
108
- trace_luring_io_plug(s);
109
- s->io_q.plugged++;
110
-}
111
-
112
-void luring_io_unplug(void)
113
-{
114
- AioContext *ctx = qemu_get_current_aio_context();
115
- LuringState *s = aio_get_linux_io_uring(ctx);
116
- assert(s->io_q.plugged);
117
- trace_luring_io_unplug(s, s->io_q.blocked, s->io_q.plugged,
118
- s->io_q.in_queue, s->io_q.in_flight);
119
- if (--s->io_q.plugged == 0 &&
120
- !s->io_q.blocked && s->io_q.in_queue > 0) {
121
+ LuringState *s = opaque;
122
+ trace_luring_unplug_fn(s, s->io_q.blocked, s->io_q.in_queue,
123
+ s->io_q.in_flight);
124
+ if (!s->io_q.blocked && s->io_q.in_queue > 0) {
125
ioq_submit(s);
126
}
127
}
128
@@ -XXX,XX +XXX,XX @@ static int luring_do_submit(int fd, LuringAIOCB *luringcb, LuringState *s,
129
130
QSIMPLEQ_INSERT_TAIL(&s->io_q.submit_queue, luringcb, next);
131
s->io_q.in_queue++;
132
- trace_luring_do_submit(s, s->io_q.blocked, s->io_q.plugged,
133
- s->io_q.in_queue, s->io_q.in_flight);
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"
169
--
170
2.40.1
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
Stop using the .bdrv_co_io_plug() API because it is not multi-queue
2
2
block layer friendly. Use the new blk_io_plug_call() API to batch I/O
3
When there are multiple queues attached to the same AIO context,
3
submission instead.
4
some requests may experience high latency, since in the worst case
4
5
the AIO engine queue is only flushed when it is full (MAX_EVENTS) or
5
Note that a dev_max_batch check is dropped in laio_io_unplug() because
6
there are no more queues plugged.
6
the semantics of unplug_fn() are different from .bdrv_co_unplug():
7
7
1. unplug_fn() is only called when the last blk_io_unplug() call occurs,
8
Commit 2558cb8dd4 ("linux-aio: increasing MAX_EVENTS to a larger
8
not every time blk_io_unplug() is called.
9
hardcoded value") changed MAX_EVENTS from 128 to 1024, to increase
9
2. unplug_fn() is per-thread, not per-BlockDriverState, so there is no
10
the number of in-flight requests. But this change also increased
10
way to get per-BlockDriverState fields like dev_max_batch.
11
the potential maximum batch to 1024 elements.
11
12
12
Therefore this condition cannot be moved to laio_unplug_fn(). It is not
13
When there is a single queue attached to the AIO context, the issue
13
obvious that this condition affects performance in practice, so I am
14
is mitigated from laio_io_unplug() that will flush the queue every
14
removing it instead of trying to come up with a more complex mechanism
15
time is invoked since there can't be others queue plugged.
15
to preserve the condition.
16
16
17
Let's use the new `aio-max-batch` IOThread parameter to mitigate
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
this issue, limiting the number of requests in a batch.
18
Reviewed-by: Eric Blake <eblake@redhat.com>
19
19
Acked-by: Kevin Wolf <kwolf@redhat.com>
20
We also define a default value (32): this value is obtained running
20
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
21
some benchmarks and it represents a good tradeoff between the latency
21
Message-id: 20230530180959.1108766-6-stefanha@redhat.com
22
increase while a request is queued and the cost of the io_submit(2)
23
system call.
24
25
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
26
Message-id: 20210721094211.69853-4-sgarzare@redhat.com
27
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
28
---
23
---
29
block/linux-aio.c | 9 ++++++++-
24
include/block/raw-aio.h | 7 -------
30
1 file changed, 8 insertions(+), 1 deletion(-)
25
block/file-posix.c | 28 ----------------------------
31
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,
32
diff --git a/block/linux-aio.c b/block/linux-aio.c
114
diff --git a/block/linux-aio.c b/block/linux-aio.c
33
index XXXXXXX..XXXXXXX 100644
115
index XXXXXXX..XXXXXXX 100644
34
--- a/block/linux-aio.c
116
--- a/block/linux-aio.c
35
+++ b/block/linux-aio.c
117
+++ b/block/linux-aio.c
36
@@ -XXX,XX +XXX,XX @@
118
@@ -XXX,XX +XXX,XX @@
37
*/
119
#include "qemu/event_notifier.h"
38
#define MAX_EVENTS 1024
120
#include "qemu/coroutine.h"
39
121
#include "qapi/error.h"
40
+/* Maximum number of requests in a batch. (default value) */
122
+#include "sysemu/block-backend.h"
41
+#define DEFAULT_MAX_BATCH 32
123
42
+
124
/* Only used for assertions. */
43
struct qemu_laiocb {
125
#include "qemu/coroutine_int.h"
44
Coroutine *co;
126
@@ -XXX,XX +XXX,XX @@ struct qemu_laiocb {
45
LinuxAioState *ctx;
127
};
46
@@ -XXX,XX +XXX,XX @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
128
47
LinuxAioState *s = laiocb->ctx;
129
typedef struct {
48
struct iocb *iocbs = &laiocb->iocb;
130
- int plugged;
49
QEMUIOVector *qiov = laiocb->qiov;
131
unsigned int in_queue;
50
+ int64_t max_batch = s->aio_context->aio_max_batch ?: DEFAULT_MAX_BATCH;
132
unsigned int in_flight;
51
+
133
bool blocked;
52
+ /* limit the batch with the number of available events */
134
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completions_and_submit(LinuxAioState *s)
53
+ max_batch = MIN_NON_ZERO(MAX_EVENTS - s->io_q.in_flight, max_batch);
135
{
54
136
qemu_laio_process_completions(s);
55
switch (type) {
137
56
case QEMU_AIO_WRITE:
138
- if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
57
@@ -XXX,XX +XXX,XX @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
139
+ if (!QSIMPLEQ_EMPTY(&s->io_q.pending)) {
58
s->io_q.in_queue++;
59
if (!s->io_q.blocked &&
60
(!s->io_q.plugged ||
61
- s->io_q.in_flight + s->io_q.in_queue >= MAX_EVENTS)) {
62
+ s->io_q.in_queue >= max_batch)) {
63
ioq_submit(s);
140
ioq_submit(s);
64
}
141
}
65
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;
66
--
203
--
67
2.31.1
204
2.40.1
68
diff view generated by jsdifflib
New patch
1
No block driver implements .bdrv_co_io_plug() anymore. Get rid of the
2
function pointers.
1
3
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
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(-)
15
16
diff --git a/include/block/block-io.h b/include/block/block-io.h
17
index XXXXXXX..XXXXXXX 100644
18
--- a/include/block/block-io.h
19
+++ b/include/block/block-io.h
20
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx);
21
22
AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c);
23
24
-void coroutine_fn GRAPH_RDLOCK bdrv_co_io_plug(BlockDriverState *bs);
25
-void coroutine_fn GRAPH_RDLOCK bdrv_co_io_unplug(BlockDriverState *bs);
26
-
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
59
diff --git a/block/io.c b/block/io.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/block/io.c
62
+++ b/block/io.c
63
@@ -XXX,XX +XXX,XX @@ void *qemu_try_blockalign0(BlockDriverState *bs, size_t size)
64
return mem;
65
}
66
67
-void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs)
68
-{
69
- BdrvChild *child;
70
- IO_CODE();
71
- assert_bdrv_graph_readable();
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,
107
--
108
2.40.1
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
The `aio-max-batch` parameter will be propagated to AIO engines
3
Some virtio-blk drivers (e.g. virtio-blk-vhost-vdpa) supports the fd
4
and it will be used to control the maximum number of queued requests.
4
passing. Let's expose this to the user, so the management layer
5
can pass the file descriptor of an already opened path.
5
6
6
When there are in queue a number of requests equal to `aio-max-batch`,
7
If the libblkio virtio-blk driver supports fd passing, let's always
7
the engine invokes the system call to forward the requests to the kernel.
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.
8
10
9
This parameter allows us to control the maximum batch size to reduce
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
the latency that requests might accumulate while queued in the AIO
11
engine queue.
12
13
If `aio-max-batch` is equal to 0 (default value), the AIO engine will
14
use its default maximum batch size value.
15
16
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
12
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
17
Message-id: 20210721094211.69853-3-sgarzare@redhat.com
13
Message-id: 20230530071941.8954-2-sgarzare@redhat.com
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
---
15
---
20
qapi/misc.json | 6 ++++-
16
block/blkio.c | 53 ++++++++++++++++++++++++++++++++++++++++++---------
21
qapi/qom.json | 7 ++++-
17
1 file changed, 44 insertions(+), 9 deletions(-)
22
include/block/aio.h | 12 +++++++++
23
include/sysemu/iothread.h | 3 +++
24
iothread.c | 55 +++++++++++++++++++++++++++++++++++----
25
monitor/hmp-cmds.c | 2 ++
26
util/aio-posix.c | 12 +++++++++
27
util/aio-win32.c | 5 ++++
28
util/async.c | 2 ++
29
qemu-options.hx | 8 ++++--
30
10 files changed, 103 insertions(+), 9 deletions(-)
31
18
32
diff --git a/qapi/misc.json b/qapi/misc.json
19
diff --git a/block/blkio.c b/block/blkio.c
33
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
34
--- a/qapi/misc.json
21
--- a/block/blkio.c
35
+++ b/qapi/misc.json
22
+++ b/block/blkio.c
36
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@ static int blkio_virtio_blk_common_open(BlockDriverState *bs,
37
# @poll-shrink: how many ns will be removed from polling time, 0 means that
24
{
38
# it's not configured (since 2.9)
25
const char *path = qdict_get_try_str(options, "path");
39
#
26
BDRVBlkioState *s = bs->opaque;
40
+# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
27
- int ret;
41
+# 0 means that the engine will use its default (since 6.1)
28
+ bool fd_supported = false;
42
+#
29
+ int fd, ret;
43
# Since: 2.0
30
44
##
31
if (!path) {
45
{ 'struct': 'IOThreadInfo',
32
error_setg(errp, "missing 'path' option");
46
@@ -XXX,XX +XXX,XX @@
33
return -EINVAL;
47
'thread-id': 'int',
34
}
48
'poll-max-ns': 'int',
35
49
'poll-grow': 'int',
36
- ret = blkio_set_str(s->blkio, "path", path);
50
- 'poll-shrink': 'int' } }
37
- qdict_del(options, "path");
51
+ 'poll-shrink': 'int',
38
- if (ret < 0) {
52
+ 'aio-max-batch': 'int' } }
39
- error_setg_errno(errp, -ret, "failed to set path: %s",
53
40
- blkio_get_error_msg());
54
##
41
- return ret;
55
# @query-iothreads:
42
- }
56
diff --git a/qapi/qom.json b/qapi/qom.json
43
-
57
index XXXXXXX..XXXXXXX 100644
44
if (!(flags & BDRV_O_NOCACHE)) {
58
--- a/qapi/qom.json
45
error_setg(errp, "cache.direct=off is not supported");
59
+++ b/qapi/qom.json
46
return -EINVAL;
60
@@ -XXX,XX +XXX,XX @@
47
}
61
# algorithm detects it is spending too long polling without
62
# encountering events. 0 selects a default behaviour (default: 0)
63
#
64
+# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
65
+# 0 means that the engine will use its default
66
+# (default:0, since 6.1)
67
+#
68
# Since: 2.0
69
##
70
{ 'struct': 'IothreadProperties',
71
'data': { '*poll-max-ns': 'int',
72
'*poll-grow': 'int',
73
- '*poll-shrink': 'int' } }
74
+ '*poll-shrink': 'int',
75
+ '*aio-max-batch': 'int' } }
76
77
##
78
# @MemoryBackendProperties:
79
diff --git a/include/block/aio.h b/include/block/aio.h
80
index XXXXXXX..XXXXXXX 100644
81
--- a/include/block/aio.h
82
+++ b/include/block/aio.h
83
@@ -XXX,XX +XXX,XX @@ struct AioContext {
84
int64_t poll_grow; /* polling time growth factor */
85
int64_t poll_shrink; /* polling time shrink factor */
86
87
+ /* AIO engine parameters */
88
+ int64_t aio_max_batch; /* maximum number of requests in a batch */
89
+
48
+
90
/*
49
+ if (blkio_get_int(s->blkio, "fd", &fd) == 0) {
91
* List of handlers participating in userspace polling. Protected by
50
+ fd_supported = true;
92
* ctx->list_lock. Iterated and modified mostly by the event loop thread
93
@@ -XXX,XX +XXX,XX @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
94
int64_t grow, int64_t shrink,
95
Error **errp);
96
97
+/**
98
+ * aio_context_set_aio_params:
99
+ * @ctx: the aio context
100
+ * @max_batch: maximum number of requests in a batch, 0 means that the
101
+ * engine will use its default
102
+ */
103
+void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch,
104
+ Error **errp);
105
+
106
#endif
107
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
108
index XXXXXXX..XXXXXXX 100644
109
--- a/include/sysemu/iothread.h
110
+++ b/include/sysemu/iothread.h
111
@@ -XXX,XX +XXX,XX @@ struct IOThread {
112
int64_t poll_max_ns;
113
int64_t poll_grow;
114
int64_t poll_shrink;
115
+
116
+ /* AioContext AIO engine parameters */
117
+ int64_t aio_max_batch;
118
};
119
typedef struct IOThread IOThread;
120
121
diff --git a/iothread.c b/iothread.c
122
index XXXXXXX..XXXXXXX 100644
123
--- a/iothread.c
124
+++ b/iothread.c
125
@@ -XXX,XX +XXX,XX @@ static void iothread_init_gcontext(IOThread *iothread)
126
iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE);
127
}
128
129
+static void iothread_set_aio_context_params(IOThread *iothread, Error **errp)
130
+{
131
+ ERRP_GUARD();
132
+
133
+ aio_context_set_poll_params(iothread->ctx,
134
+ iothread->poll_max_ns,
135
+ iothread->poll_grow,
136
+ iothread->poll_shrink,
137
+ errp);
138
+ if (*errp) {
139
+ return;
140
+ }
51
+ }
141
+
52
+
142
+ aio_context_set_aio_params(iothread->ctx,
53
+ /*
143
+ iothread->aio_max_batch,
54
+ * If the libblkio driver supports fd passing, let's always use qemu_open()
144
+ errp);
55
+ * to open the `path`, so we can handle fd passing from the management
145
+}
56
+ * layer through the "/dev/fdset/N" special path.
57
+ */
58
+ if (fd_supported) {
59
+ int open_flags;
146
+
60
+
147
static void iothread_complete(UserCreatable *obj, Error **errp)
61
+ if (flags & BDRV_O_RDWR) {
148
{
62
+ open_flags = O_RDWR;
149
Error *local_error = NULL;
63
+ } else {
150
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
64
+ open_flags = O_RDONLY;
151
*/
65
+ }
152
iothread_init_gcontext(iothread);
153
154
- aio_context_set_poll_params(iothread->ctx,
155
- iothread->poll_max_ns,
156
- iothread->poll_grow,
157
- iothread->poll_shrink,
158
- &local_error);
159
+ iothread_set_aio_context_params(iothread, &local_error);
160
if (local_error) {
161
error_propagate(errp, local_error);
162
aio_context_unref(iothread->ctx);
163
@@ -XXX,XX +XXX,XX @@ static PollParamInfo poll_grow_info = {
164
static PollParamInfo poll_shrink_info = {
165
"poll-shrink", offsetof(IOThread, poll_shrink),
166
};
167
+static PollParamInfo aio_max_batch_info = {
168
+ "aio-max-batch", offsetof(IOThread, aio_max_batch),
169
+};
170
171
static void iothread_get_param(Object *obj, Visitor *v,
172
const char *name, void *opaque, Error **errp)
173
@@ -XXX,XX +XXX,XX @@ static void iothread_set_poll_param(Object *obj, Visitor *v,
174
}
175
}
176
177
+static void iothread_get_aio_param(Object *obj, Visitor *v,
178
+ const char *name, void *opaque, Error **errp)
179
+{
180
+
66
+
181
+ iothread_get_param(obj, v, name, opaque, errp);
67
+ fd = qemu_open(path, open_flags, errp);
182
+}
68
+ if (fd < 0) {
69
+ return -EINVAL;
70
+ }
183
+
71
+
184
+static void iothread_set_aio_param(Object *obj, Visitor *v,
72
+ ret = blkio_set_int(s->blkio, "fd", fd);
185
+ const char *name, void *opaque, Error **errp)
73
+ if (ret < 0) {
186
+{
74
+ error_setg_errno(errp, -ret, "failed to set fd: %s",
187
+ IOThread *iothread = IOTHREAD(obj);
75
+ blkio_get_error_msg());
188
+
76
+ qemu_close(fd);
189
+ if (!iothread_set_param(obj, v, name, opaque, errp)) {
77
+ return ret;
190
+ return;
78
+ }
79
+ } else {
80
+ ret = blkio_set_str(s->blkio, "path", path);
81
+ if (ret < 0) {
82
+ error_setg_errno(errp, -ret, "failed to set path: %s",
83
+ blkio_get_error_msg());
84
+ return ret;
85
+ }
191
+ }
86
+ }
192
+
87
+
193
+ if (iothread->ctx) {
88
+ qdict_del(options, "path");
194
+ aio_context_set_aio_params(iothread->ctx,
195
+ iothread->aio_max_batch,
196
+ errp);
197
+ }
198
+}
199
+
89
+
200
static void iothread_class_init(ObjectClass *klass, void *class_data)
90
return 0;
201
{
202
UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
203
@@ -XXX,XX +XXX,XX @@ static void iothread_class_init(ObjectClass *klass, void *class_data)
204
iothread_get_poll_param,
205
iothread_set_poll_param,
206
NULL, &poll_shrink_info);
207
+ object_class_property_add(klass, "aio-max-batch", "int",
208
+ iothread_get_aio_param,
209
+ iothread_set_aio_param,
210
+ NULL, &aio_max_batch_info);
211
}
91
}
212
92
213
static const TypeInfo iothread_info = {
214
@@ -XXX,XX +XXX,XX @@ static int query_one_iothread(Object *object, void *opaque)
215
info->poll_max_ns = iothread->poll_max_ns;
216
info->poll_grow = iothread->poll_grow;
217
info->poll_shrink = iothread->poll_shrink;
218
+ info->aio_max_batch = iothread->aio_max_batch;
219
220
QAPI_LIST_APPEND(*tail, info);
221
return 0;
222
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
223
index XXXXXXX..XXXXXXX 100644
224
--- a/monitor/hmp-cmds.c
225
+++ b/monitor/hmp-cmds.c
226
@@ -XXX,XX +XXX,XX @@ void hmp_info_iothreads(Monitor *mon, const QDict *qdict)
227
monitor_printf(mon, " poll-max-ns=%" PRId64 "\n", value->poll_max_ns);
228
monitor_printf(mon, " poll-grow=%" PRId64 "\n", value->poll_grow);
229
monitor_printf(mon, " poll-shrink=%" PRId64 "\n", value->poll_shrink);
230
+ monitor_printf(mon, " aio-max-batch=%" PRId64 "\n",
231
+ value->aio_max_batch);
232
}
233
234
qapi_free_IOThreadInfoList(info_list);
235
diff --git a/util/aio-posix.c b/util/aio-posix.c
236
index XXXXXXX..XXXXXXX 100644
237
--- a/util/aio-posix.c
238
+++ b/util/aio-posix.c
239
@@ -XXX,XX +XXX,XX @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
240
241
aio_notify(ctx);
242
}
243
+
244
+void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch,
245
+ Error **errp)
246
+{
247
+ /*
248
+ * No thread synchronization here, it doesn't matter if an incorrect value
249
+ * is used once.
250
+ */
251
+ ctx->aio_max_batch = max_batch;
252
+
253
+ aio_notify(ctx);
254
+}
255
diff --git a/util/aio-win32.c b/util/aio-win32.c
256
index XXXXXXX..XXXXXXX 100644
257
--- a/util/aio-win32.c
258
+++ b/util/aio-win32.c
259
@@ -XXX,XX +XXX,XX @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
260
error_setg(errp, "AioContext polling is not implemented on Windows");
261
}
262
}
263
+
264
+void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch,
265
+ Error **errp)
266
+{
267
+}
268
diff --git a/util/async.c b/util/async.c
269
index XXXXXXX..XXXXXXX 100644
270
--- a/util/async.c
271
+++ b/util/async.c
272
@@ -XXX,XX +XXX,XX @@ AioContext *aio_context_new(Error **errp)
273
ctx->poll_grow = 0;
274
ctx->poll_shrink = 0;
275
276
+ ctx->aio_max_batch = 0;
277
+
278
return ctx;
279
fail:
280
g_source_destroy(&ctx->source);
281
diff --git a/qemu-options.hx b/qemu-options.hx
282
index XXXXXXX..XXXXXXX 100644
283
--- a/qemu-options.hx
284
+++ b/qemu-options.hx
285
@@ -XXX,XX +XXX,XX @@ SRST
286
287
CN=laptop.example.com,O=Example Home,L=London,ST=London,C=GB
288
289
- ``-object iothread,id=id,poll-max-ns=poll-max-ns,poll-grow=poll-grow,poll-shrink=poll-shrink``
290
+ ``-object iothread,id=id,poll-max-ns=poll-max-ns,poll-grow=poll-grow,poll-shrink=poll-shrink,aio-max-batch=aio-max-batch``
291
Creates a dedicated event loop thread that devices can be
292
assigned to. This is known as an IOThread. By default device
293
emulation happens in vCPU threads or the main event loop thread.
294
@@ -XXX,XX +XXX,XX @@ SRST
295
the polling time when the algorithm detects it is spending too
296
long polling without encountering events.
297
298
- The polling parameters can be modified at run-time using the
299
+ The ``aio-max-batch`` parameter is the maximum number of requests
300
+ in a batch for the AIO engine, 0 means that the engine will use
301
+ its default.
302
+
303
+ The IOThread parameters can be modified at run-time using the
304
``qom-set`` command (where ``iothread1`` is the IOThread's
305
``id``):
306
307
--
93
--
308
2.31.1
94
2.40.1
309
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
Changes in preparation for next patches where we add a new
3
The virtio-blk-vhost-vdpa driver in libblkio 1.3.0 supports the fd
4
parameter not related to the poll mechanism.
4
passing through the new 'fd' property.
5
5
6
Let's add two new generic functions (iothread_set_param and
6
Since now we are using qemu_open() on '@path' if the virtio-blk driver
7
iothread_get_param) that we use to set and get IOThread
7
supports the fd passing, let's announce it.
8
parameters.
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.
9
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>
10
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
17
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
11
Message-id: 20210721094211.69853-2-sgarzare@redhat.com
18
Message-id: 20230530071941.8954-3-sgarzare@redhat.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
20
---
14
iothread.c | 27 +++++++++++++++++++++++----
21
qapi/block-core.json | 6 ++++++
15
1 file changed, 23 insertions(+), 4 deletions(-)
22
meson.build | 4 ++++
23
2 files changed, 10 insertions(+)
16
24
17
diff --git a/iothread.c b/iothread.c
25
diff --git a/qapi/block-core.json b/qapi/block-core.json
18
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
19
--- a/iothread.c
27
--- a/qapi/block-core.json
20
+++ b/iothread.c
28
+++ b/qapi/block-core.json
21
@@ -XXX,XX +XXX,XX @@ static PollParamInfo poll_shrink_info = {
29
@@ -XXX,XX +XXX,XX @@
22
"poll-shrink", offsetof(IOThread, poll_shrink),
30
#
23
};
31
# @path: path to the vhost-vdpa character device.
24
32
#
25
-static void iothread_get_poll_param(Object *obj, Visitor *v,
33
+# Features:
26
+static void iothread_get_param(Object *obj, Visitor *v,
34
+# @fdset: Member @path supports the special "/dev/fdset/N" path
27
const char *name, void *opaque, Error **errp)
35
+# (since 8.1)
28
{
36
+#
29
IOThread *iothread = IOTHREAD(obj);
37
# Since: 7.2
30
@@ -XXX,XX +XXX,XX @@ static void iothread_get_poll_param(Object *obj, Visitor *v,
38
##
31
visit_type_int64(v, name, field, errp);
39
{ 'struct': 'BlockdevOptionsVirtioBlkVhostVdpa',
32
}
40
'data': { 'path': 'str' },
33
41
+ 'features': [ { 'name' :'fdset',
34
-static void iothread_set_poll_param(Object *obj, Visitor *v,
42
+ 'if': 'CONFIG_BLKIO_VHOST_VDPA_FD' } ],
35
+static bool iothread_set_param(Object *obj, Visitor *v,
43
'if': 'CONFIG_BLKIO' }
36
const char *name, void *opaque, Error **errp)
44
37
{
45
##
38
IOThread *iothread = IOTHREAD(obj);
46
diff --git a/meson.build b/meson.build
39
@@ -XXX,XX +XXX,XX @@ static void iothread_set_poll_param(Object *obj, Visitor *v,
47
index XXXXXXX..XXXXXXX 100644
40
int64_t value;
48
--- a/meson.build
41
49
+++ b/meson.build
42
if (!visit_type_int64(v, name, &value, errp)) {
50
@@ -XXX,XX +XXX,XX @@ config_host_data.set('CONFIG_LZO', lzo.found())
43
- return;
51
config_host_data.set('CONFIG_MPATH', mpathpersist.found())
44
+ return false;
52
config_host_data.set('CONFIG_MPATH_NEW_API', mpathpersist_new_api)
45
}
53
config_host_data.set('CONFIG_BLKIO', blkio.found())
46
54
+if blkio.found()
47
if (value < 0) {
55
+ config_host_data.set('CONFIG_BLKIO_VHOST_VDPA_FD',
48
error_setg(errp, "%s value must be in range [0, %" PRId64 "]",
56
+ blkio.version().version_compare('>=1.3.0'))
49
info->name, INT64_MAX);
57
+endif
50
- return;
58
config_host_data.set('CONFIG_CURL', curl.found())
51
+ return false;
59
config_host_data.set('CONFIG_CURSES', curses.found())
52
}
60
config_host_data.set('CONFIG_GBM', gbm.found())
53
54
*field = value;
55
56
+ return true;
57
+}
58
+
59
+static void iothread_get_poll_param(Object *obj, Visitor *v,
60
+ const char *name, void *opaque, Error **errp)
61
+{
62
+
63
+ iothread_get_param(obj, v, name, opaque, errp);
64
+}
65
+
66
+static void iothread_set_poll_param(Object *obj, Visitor *v,
67
+ const char *name, void *opaque, Error **errp)
68
+{
69
+ IOThread *iothread = IOTHREAD(obj);
70
+
71
+ if (!iothread_set_param(obj, v, name, opaque, errp)) {
72
+ return;
73
+ }
74
+
75
if (iothread->ctx) {
76
aio_context_set_poll_params(iothread->ctx,
77
iothread->poll_max_ns,
78
--
61
--
79
2.31.1
62
2.40.1
80
diff view generated by jsdifflib