1
The following changes since commit 554623226f800acf48a2ed568900c1c968ec9a8b:
1
The following changes since commit c6a5fc2ac76c5ab709896ee1b0edd33685a67ed1:
2
2
3
Merge tag 'qemu-sparc-20220508' of https://github.com/mcayland/qemu into staging (2022-05-08 17:03:26 -0500)
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 3dc584abeef0e1277c2de8c1c1974cb49444eb0a:
9
for you to fetch changes up to 98b126f5e3228a346c774e569e26689943b401dd:
10
10
11
virtio-scsi: move request-related items from .h to .c (2022-05-09 10:45:04 +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
- Add new thread-pool-min/thread-pool-max parameters to control the thread pool
16
- Stefano Garzarella's blkio block driver 'fd' parameter
17
used for async I/O.
17
- My thread-local blk_io_plug() series
18
19
- Fix virtio-scsi IOThread 100% CPU consumption QEMU 7.0 regression.
20
18
21
----------------------------------------------------------------
19
----------------------------------------------------------------
22
20
23
Nicolas Saenz Julienne (3):
21
Stefan Hajnoczi (6):
24
Introduce event-loop-base abstract class
22
block: add blk_io_plug_call() API
25
util/main-loop: Introduce the main loop into QOM
23
block/nvme: convert to blk_io_plug_call() API
26
util/event-loop-base: Introduce options to set the thread pool size
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
27
28
28
Stefan Hajnoczi (6):
29
Stefano Garzarella (2):
29
virtio-scsi: fix ctrl and event handler functions in dataplane mode
30
block/blkio: use qemu_open() to support fd passing for virtio-blk
30
virtio-scsi: don't waste CPU polling the event virtqueue
31
qapi: add '@fdset' feature for BlockdevOptionsVirtioBlkVhostVdpa
31
virtio-scsi: clean up virtio_scsi_handle_event_vq()
32
virtio-scsi: clean up virtio_scsi_handle_ctrl_vq()
33
virtio-scsi: clean up virtio_scsi_handle_cmd_vq()
34
virtio-scsi: move request-related items from .h to .c
35
32
36
qapi/qom.json | 43 ++++++++--
33
MAINTAINERS | 1 +
37
meson.build | 26 +++---
34
qapi/block-core.json | 6 ++
38
include/block/aio.h | 10 +++
35
meson.build | 4 +
39
include/block/thread-pool.h | 3 +
36
include/block/block-io.h | 3 -
40
include/hw/virtio/virtio-scsi.h | 43 ----------
37
include/block/block_int-common.h | 11 ---
41
include/hw/virtio/virtio.h | 1 +
38
include/block/raw-aio.h | 14 ---
42
include/qemu/main-loop.h | 10 +++
39
include/sysemu/block-backend-io.h | 13 +--
43
include/sysemu/event-loop-base.h | 41 +++++++++
40
block/blkio.c | 96 ++++++++++++------
44
include/sysemu/iothread.h | 6 +-
41
block/block-backend.c | 22 -----
45
event-loop-base.c | 140 +++++++++++++++++++++++++++++++
42
block/file-posix.c | 38 -------
46
hw/scsi/virtio-scsi-dataplane.c | 2 +-
43
block/io.c | 37 -------
47
hw/scsi/virtio-scsi.c | 101 +++++++++++++++-------
44
block/io_uring.c | 44 ++++-----
48
hw/virtio/virtio.c | 13 +++
45
block/linux-aio.c | 41 +++-----
49
iothread.c | 68 +++++----------
46
block/nvme.c | 44 +++------
50
util/aio-posix.c | 1 +
47
block/plug.c | 159 ++++++++++++++++++++++++++++++
51
util/async.c | 20 +++++
48
hw/block/dataplane/xen-block.c | 8 +-
52
util/main-loop.c | 65 ++++++++++++++
49
hw/block/virtio-blk.c | 4 +-
53
util/thread-pool.c | 55 +++++++++++-
50
hw/scsi/virtio-scsi.c | 6 +-
54
18 files changed, 505 insertions(+), 143 deletions(-)
51
block/meson.build | 1 +
55
create mode 100644 include/sysemu/event-loop-base.h
52
block/trace-events | 6 +-
56
create mode 100644 event-loop-base.c
53
20 files changed, 293 insertions(+), 265 deletions(-)
54
create mode 100644 block/plug.c
57
55
58
--
56
--
59
2.35.1
57
2.40.1
diff view generated by jsdifflib
1
virtio_scsi_handle_cmd_vq() is only called from hw/scsi/virtio-scsi.c
1
Introduce a new API for thread-local blk_io_plug() that does not
2
now and its return value is no longer used. Remove the function
2
traverse the block graph. The goal is to make blk_io_plug() multi-queue
3
prototype from virtio-scsi.h and drop the return value.
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.
4
18
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
20
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Message-id: 20220427143541.119567-6-stefanha@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
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
25
---
10
include/hw/virtio/virtio-scsi.h | 1 -
26
MAINTAINERS | 1 +
11
hw/scsi/virtio-scsi.c | 5 +----
27
include/sysemu/block-backend-io.h | 13 +--
12
2 files changed, 1 insertion(+), 5 deletions(-)
28
block/block-backend.c | 22 -----
13
29
block/plug.c | 159 ++++++++++++++++++++++++++++++
14
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
30
hw/block/dataplane/xen-block.c | 8 +-
15
index XXXXXXX..XXXXXXX 100644
31
hw/block/virtio-blk.c | 4 +-
16
--- a/include/hw/virtio/virtio-scsi.h
32
hw/scsi/virtio-scsi.c | 6 +-
17
+++ b/include/hw/virtio/virtio-scsi.h
33
block/meson.build | 1 +
18
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_common_realize(DeviceState *dev,
34
8 files changed, 173 insertions(+), 41 deletions(-)
19
Error **errp);
35
create mode 100644 block/plug.c
20
36
21
void virtio_scsi_common_unrealize(DeviceState *dev);
37
diff --git a/MAINTAINERS b/MAINTAINERS
22
-bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq);
38
index XXXXXXX..XXXXXXX 100644
23
void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req);
39
--- a/MAINTAINERS
24
void virtio_scsi_free_req(VirtIOSCSIReq *req);
40
+++ b/MAINTAINERS
25
void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
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
26
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
330
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
27
index XXXXXXX..XXXXXXX 100644
331
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/scsi/virtio-scsi.c
332
--- a/hw/scsi/virtio-scsi.c
29
+++ b/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
}
30
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req)
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();
31
scsi_req_unref(sreq);
349
scsi_req_unref(sreq);
32
}
350
}
33
351
34
-bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
352
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
35
+static void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
353
while (!QTAILQ_EMPTY(&reqs)) {
36
{
354
req = QTAILQ_FIRST(&reqs);
37
VirtIOSCSIReq *req, *next;
355
QTAILQ_REMOVE(&reqs, req, next);
38
int ret = 0;
356
- blk_io_unplug(req->sreq->dev->conf.blk);
39
bool suppress_notifications = virtio_queue_get_notification(vq);
357
+ blk_io_unplug();
40
- bool progress = false;
358
scsi_req_unref(req->sreq);
41
359
virtqueue_detach_element(req->vq, &req->elem, 0);
42
QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
360
virtio_scsi_free_req(req);
43
361
diff --git a/block/meson.build b/block/meson.build
44
@@ -XXX,XX +XXX,XX @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
362
index XXXXXXX..XXXXXXX 100644
45
}
363
--- a/block/meson.build
46
364
+++ b/block/meson.build
47
while ((req = virtio_scsi_pop_req(s, vq))) {
365
@@ -XXX,XX +XXX,XX @@ block_ss.add(files(
48
- progress = true;
366
'mirror.c',
49
ret = virtio_scsi_handle_cmd_req_prepare(s, req);
367
'nbd.c',
50
if (!ret) {
368
'null.c',
51
QTAILQ_INSERT_TAIL(&reqs, req, next);
369
+ 'plug.c',
52
@@ -XXX,XX +XXX,XX @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
370
'qapi.c',
53
QTAILQ_FOREACH_SAFE(req, &reqs, next, next) {
371
'qcow2-bitmap.c',
54
virtio_scsi_handle_cmd_req_submit(s, req);
372
'qcow2-cache.c',
55
}
56
- return progress;
57
}
58
59
static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
60
--
373
--
61
2.35.1
374
2.40.1
diff view generated by jsdifflib
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.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
Introduce the 'event-loop-base' abstract class, it'll hold the
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
properties common to all event loops and provide the necessary hooks for
6
Reviewed-by: Eric Blake <eblake@redhat.com>
5
their creation and maintenance. Then have iothread inherit from it.
7
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
6
8
Acked-by: Kevin Wolf <kwolf@redhat.com>
7
EventLoopBaseClass is defined as user creatable and provides a hook for
9
Message-id: 20230530180959.1108766-3-stefanha@redhat.com
8
its children to attach themselves to the user creatable class 'complete'
9
function. It also provides an update_params() callback to propagate
10
property changes onto its children.
11
12
The new 'event-loop-base' class will live in the root directory. It is
13
built on its own using the 'link_whole' option (there are no direct
14
function dependencies between the class and its children, it all happens
15
trough 'constructor' magic). And also imposes new compilation
16
dependencies:
17
18
qom <- event-loop-base <- blockdev (iothread.c)
19
20
And in subsequent patches:
21
22
qom <- event-loop-base <- qemuutil (util/main-loop.c)
23
24
All this forced some amount of reordering in meson.build:
25
26
- Moved qom build definition before qemuutil. Doing it the other way
27
around (i.e. moving qemuutil after qom) isn't possible as a lot of
28
core libraries that live in between the two depend on it.
29
30
- Process the 'hw' subdir earlier, as it introduces files into the
31
'qom' source set.
32
33
No functional changes intended.
34
35
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
36
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
37
Acked-by: Markus Armbruster <armbru@redhat.com>
38
Message-id: 20220425075723.20019-2-nsaenzju@redhat.com
39
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
40
---
11
---
41
qapi/qom.json | 22 +++++--
12
block/nvme.c | 44 ++++++++++++--------------------------------
42
meson.build | 23 ++++---
13
block/trace-events | 1 -
43
include/sysemu/event-loop-base.h | 36 +++++++++++
14
2 files changed, 12 insertions(+), 33 deletions(-)
44
include/sysemu/iothread.h | 6 +-
45
event-loop-base.c | 104 +++++++++++++++++++++++++++++++
46
iothread.c | 65 ++++++-------------
47
6 files changed, 192 insertions(+), 64 deletions(-)
48
create mode 100644 include/sysemu/event-loop-base.h
49
create mode 100644 event-loop-base.c
50
15
51
diff --git a/qapi/qom.json b/qapi/qom.json
16
diff --git a/block/nvme.c b/block/nvme.c
52
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
53
--- a/qapi/qom.json
18
--- a/block/nvme.c
54
+++ b/qapi/qom.json
19
+++ b/block/nvme.c
55
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@
56
'*repeat': 'bool',
21
#include "qemu/vfio-helpers.h"
57
'*grab-toggle': 'GrabToggleKeys' } }
22
#include "block/block-io.h"
58
23
#include "block/block_int.h"
59
+##
24
+#include "sysemu/block-backend.h"
60
+# @EventLoopBaseProperties:
25
#include "sysemu/replay.h"
61
+#
26
#include "trace.h"
62
+# Common properties for event loops
27
63
+#
28
@@ -XXX,XX +XXX,XX @@ struct BDRVNVMeState {
64
+# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
29
int blkshift;
65
+# 0 means that the engine will use its default.
30
66
+# (default: 0)
31
uint64_t max_transfer;
67
+#
32
- bool plugged;
68
+# Since: 7.1
33
69
+##
34
bool supports_write_zeroes;
70
+{ 'struct': 'EventLoopBaseProperties',
35
bool supports_discard;
71
+ 'data': { '*aio-max-batch': 'int' } }
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;
72
+
63
+
73
##
64
+ QEMU_LOCK_GUARD(&q->lock);
74
# @IothreadProperties:
65
+ nvme_kick(q);
75
#
66
+ nvme_process_completion(q);
76
@@ -XXX,XX +XXX,XX @@
77
# algorithm detects it is spending too long polling without
78
# encountering events. 0 selects a default behaviour (default: 0)
79
#
80
-# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
81
-# 0 means that the engine will use its default
82
-# (default:0, since 6.1)
83
+# The @aio-max-batch option is available since 6.1.
84
#
85
# Since: 2.0
86
##
87
{ 'struct': 'IothreadProperties',
88
+ 'base': 'EventLoopBaseProperties',
89
'data': { '*poll-max-ns': 'int',
90
'*poll-grow': 'int',
91
- '*poll-shrink': 'int',
92
- '*aio-max-batch': 'int' } }
93
+ '*poll-shrink': 'int' } }
94
95
##
96
# @MemoryBackendProperties:
97
diff --git a/meson.build b/meson.build
98
index XXXXXXX..XXXXXXX 100644
99
--- a/meson.build
100
+++ b/meson.build
101
@@ -XXX,XX +XXX,XX @@ subdir('qom')
102
subdir('authz')
103
subdir('crypto')
104
subdir('ui')
105
+subdir('hw')
106
107
108
if enable_modules
109
@@ -XXX,XX +XXX,XX @@ if enable_modules
110
modulecommon = declare_dependency(link_whole: libmodulecommon, compile_args: '-DBUILD_DSO')
111
endif
112
113
+qom_ss = qom_ss.apply(config_host, strict: false)
114
+libqom = static_library('qom', qom_ss.sources() + genh,
115
+ dependencies: [qom_ss.dependencies()],
116
+ name_suffix: 'fa')
117
+qom = declare_dependency(link_whole: libqom)
118
+
119
+event_loop_base = files('event-loop-base.c')
120
+event_loop_base = static_library('event-loop-base', sources: event_loop_base + genh,
121
+ build_by_default: true)
122
+event_loop_base = declare_dependency(link_whole: event_loop_base,
123
+ dependencies: [qom])
124
+
125
stub_ss = stub_ss.apply(config_all, strict: false)
126
127
util_ss.add_all(trace_ss)
128
@@ -XXX,XX +XXX,XX @@ subdir('monitor')
129
subdir('net')
130
subdir('replay')
131
subdir('semihosting')
132
-subdir('hw')
133
subdir('tcg')
134
subdir('fpu')
135
subdir('accel')
136
@@ -XXX,XX +XXX,XX @@ qemu_syms = custom_target('qemu.syms', output: 'qemu.syms',
137
capture: true,
138
command: [undefsym, nm, '@INPUT@'])
139
140
-qom_ss = qom_ss.apply(config_host, strict: false)
141
-libqom = static_library('qom', qom_ss.sources() + genh,
142
- dependencies: [qom_ss.dependencies()],
143
- name_suffix: 'fa')
144
-
145
-qom = declare_dependency(link_whole: libqom)
146
-
147
authz_ss = authz_ss.apply(config_host, strict: false)
148
libauthz = static_library('authz', authz_ss.sources() + genh,
149
dependencies: [authz_ss.dependencies()],
150
@@ -XXX,XX +XXX,XX @@ libblockdev = static_library('blockdev', blockdev_ss.sources() + genh,
151
build_by_default: false)
152
153
blockdev = declare_dependency(link_whole: [libblockdev],
154
- dependencies: [block])
155
+ dependencies: [block, event_loop_base])
156
157
qmp_ss = qmp_ss.apply(config_host, strict: false)
158
libqmp = static_library('qmp', qmp_ss.sources() + genh,
159
diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h
160
new file mode 100644
161
index XXXXXXX..XXXXXXX
162
--- /dev/null
163
+++ b/include/sysemu/event-loop-base.h
164
@@ -XXX,XX +XXX,XX @@
165
+/*
166
+ * QEMU event-loop backend
167
+ *
168
+ * Copyright (C) 2022 Red Hat Inc
169
+ *
170
+ * Authors:
171
+ * Nicolas Saenz Julienne <nsaenzju@redhat.com>
172
+ *
173
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
174
+ * See the COPYING file in the top-level directory.
175
+ */
176
+#ifndef QEMU_EVENT_LOOP_BASE_H
177
+#define QEMU_EVENT_LOOP_BASE_H
178
+
179
+#include "qom/object.h"
180
+#include "block/aio.h"
181
+#include "qemu/typedefs.h"
182
+
183
+#define TYPE_EVENT_LOOP_BASE "event-loop-base"
184
+OBJECT_DECLARE_TYPE(EventLoopBase, EventLoopBaseClass,
185
+ EVENT_LOOP_BASE)
186
+
187
+struct EventLoopBaseClass {
188
+ ObjectClass parent_class;
189
+
190
+ void (*init)(EventLoopBase *base, Error **errp);
191
+ void (*update_params)(EventLoopBase *base, Error **errp);
192
+};
193
+
194
+struct EventLoopBase {
195
+ Object parent;
196
+
197
+ /* AioContext AIO engine parameters */
198
+ int64_t aio_max_batch;
199
+};
200
+#endif
201
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
202
index XXXXXXX..XXXXXXX 100644
203
--- a/include/sysemu/iothread.h
204
+++ b/include/sysemu/iothread.h
205
@@ -XXX,XX +XXX,XX @@
206
#include "block/aio.h"
207
#include "qemu/thread.h"
208
#include "qom/object.h"
209
+#include "sysemu/event-loop-base.h"
210
211
#define TYPE_IOTHREAD "iothread"
212
213
struct IOThread {
214
- Object parent_obj;
215
+ EventLoopBase parent_obj;
216
217
QemuThread thread;
218
AioContext *ctx;
219
@@ -XXX,XX +XXX,XX @@ struct IOThread {
220
int64_t poll_max_ns;
221
int64_t poll_grow;
222
int64_t poll_shrink;
223
-
224
- /* AioContext AIO engine parameters */
225
- int64_t aio_max_batch;
226
};
227
typedef struct IOThread IOThread;
228
229
diff --git a/event-loop-base.c b/event-loop-base.c
230
new file mode 100644
231
index XXXXXXX..XXXXXXX
232
--- /dev/null
233
+++ b/event-loop-base.c
234
@@ -XXX,XX +XXX,XX @@
235
+/*
236
+ * QEMU event-loop base
237
+ *
238
+ * Copyright (C) 2022 Red Hat Inc
239
+ *
240
+ * Authors:
241
+ * Stefan Hajnoczi <stefanha@redhat.com>
242
+ * Nicolas Saenz Julienne <nsaenzju@redhat.com>
243
+ *
244
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
245
+ * See the COPYING file in the top-level directory.
246
+ */
247
+
248
+#include "qemu/osdep.h"
249
+#include "qom/object_interfaces.h"
250
+#include "qapi/error.h"
251
+#include "sysemu/event-loop-base.h"
252
+
253
+typedef struct {
254
+ const char *name;
255
+ ptrdiff_t offset; /* field's byte offset in EventLoopBase struct */
256
+} EventLoopBaseParamInfo;
257
+
258
+static EventLoopBaseParamInfo aio_max_batch_info = {
259
+ "aio-max-batch", offsetof(EventLoopBase, aio_max_batch),
260
+};
261
+
262
+static void event_loop_base_get_param(Object *obj, Visitor *v,
263
+ const char *name, void *opaque, Error **errp)
264
+{
265
+ EventLoopBase *event_loop_base = EVENT_LOOP_BASE(obj);
266
+ EventLoopBaseParamInfo *info = opaque;
267
+ int64_t *field = (void *)event_loop_base + info->offset;
268
+
269
+ visit_type_int64(v, name, field, errp);
270
+}
67
+}
271
+
68
+
272
+static void event_loop_base_set_param(Object *obj, Visitor *v,
69
static void nvme_submit_command(NVMeQueuePair *q, NVMeRequest *req,
273
+ const char *name, void *opaque, Error **errp)
70
NvmeCmd *cmd, BlockCompletionFunc cb,
274
+{
71
void *opaque)
275
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(obj);
72
@@ -XXX,XX +XXX,XX @@ static void nvme_submit_command(NVMeQueuePair *q, NVMeRequest *req,
276
+ EventLoopBase *base = EVENT_LOOP_BASE(obj);
73
q->sq.tail * NVME_SQ_ENTRY_BYTES, cmd, sizeof(*cmd));
277
+ EventLoopBaseParamInfo *info = opaque;
74
q->sq.tail = (q->sq.tail + 1) % NVME_QUEUE_SIZE;
278
+ int64_t *field = (void *)base + info->offset;
75
q->need_kick++;
279
+ int64_t value;
76
- nvme_kick(q);
280
+
77
- nvme_process_completion(q);
281
+ if (!visit_type_int64(v, name, &value, errp)) {
78
+ blk_io_plug_call(nvme_unplug_fn, q);
282
+ return;
79
qemu_mutex_unlock(&q->lock);
283
+ }
284
+
285
+ if (value < 0) {
286
+ error_setg(errp, "%s value must be in range [0, %" PRId64 "]",
287
+ info->name, INT64_MAX);
288
+ return;
289
+ }
290
+
291
+ *field = value;
292
+
293
+ if (bc->update_params) {
294
+ bc->update_params(base, errp);
295
+ }
296
+
297
+ return;
298
+}
299
+
300
+static void event_loop_base_complete(UserCreatable *uc, Error **errp)
301
+{
302
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc);
303
+ EventLoopBase *base = EVENT_LOOP_BASE(uc);
304
+
305
+ if (bc->init) {
306
+ bc->init(base, errp);
307
+ }
308
+}
309
+
310
+static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
311
+{
312
+ UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
313
+ ucc->complete = event_loop_base_complete;
314
+
315
+ object_class_property_add(klass, "aio-max-batch", "int",
316
+ event_loop_base_get_param,
317
+ event_loop_base_set_param,
318
+ NULL, &aio_max_batch_info);
319
+}
320
+
321
+static const TypeInfo event_loop_base_info = {
322
+ .name = TYPE_EVENT_LOOP_BASE,
323
+ .parent = TYPE_OBJECT,
324
+ .instance_size = sizeof(EventLoopBase),
325
+ .class_size = sizeof(EventLoopBaseClass),
326
+ .class_init = event_loop_base_class_init,
327
+ .abstract = true,
328
+ .interfaces = (InterfaceInfo[]) {
329
+ { TYPE_USER_CREATABLE },
330
+ { }
331
+ }
332
+};
333
+
334
+static void register_types(void)
335
+{
336
+ type_register_static(&event_loop_base_info);
337
+}
338
+type_init(register_types);
339
diff --git a/iothread.c b/iothread.c
340
index XXXXXXX..XXXXXXX 100644
341
--- a/iothread.c
342
+++ b/iothread.c
343
@@ -XXX,XX +XXX,XX @@
344
#include "qemu/module.h"
345
#include "block/aio.h"
346
#include "block/block.h"
347
+#include "sysemu/event-loop-base.h"
348
#include "sysemu/iothread.h"
349
#include "qapi/error.h"
350
#include "qapi/qapi-commands-misc.h"
351
@@ -XXX,XX +XXX,XX @@ static void iothread_init_gcontext(IOThread *iothread)
352
iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE);
353
}
80
}
354
81
355
-static void iothread_set_aio_context_params(IOThread *iothread, Error **errp)
82
@@ -XXX,XX +XXX,XX @@ static void nvme_attach_aio_context(BlockDriverState *bs,
356
+static void iothread_set_aio_context_params(EventLoopBase *base, Error **errp)
357
{
358
+ IOThread *iothread = IOTHREAD(base);
359
ERRP_GUARD();
360
361
+ if (!iothread->ctx) {
362
+ return;
363
+ }
364
+
365
aio_context_set_poll_params(iothread->ctx,
366
iothread->poll_max_ns,
367
iothread->poll_grow,
368
@@ -XXX,XX +XXX,XX @@ static void iothread_set_aio_context_params(IOThread *iothread, Error **errp)
369
}
370
371
aio_context_set_aio_params(iothread->ctx,
372
- iothread->aio_max_batch,
373
+ iothread->parent_obj.aio_max_batch,
374
errp);
375
}
376
377
-static void iothread_complete(UserCreatable *obj, Error **errp)
378
+
379
+static void iothread_init(EventLoopBase *base, Error **errp)
380
{
381
Error *local_error = NULL;
382
- IOThread *iothread = IOTHREAD(obj);
383
+ IOThread *iothread = IOTHREAD(base);
384
char *thread_name;
385
386
iothread->stopping = false;
387
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
388
*/
389
iothread_init_gcontext(iothread);
390
391
- iothread_set_aio_context_params(iothread, &local_error);
392
+ iothread_set_aio_context_params(base, &local_error);
393
if (local_error) {
394
error_propagate(errp, local_error);
395
aio_context_unref(iothread->ctx);
396
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
397
* to inherit.
398
*/
399
thread_name = g_strdup_printf("IO %s",
400
- object_get_canonical_path_component(OBJECT(obj)));
401
+ object_get_canonical_path_component(OBJECT(base)));
402
qemu_thread_create(&iothread->thread, thread_name, iothread_run,
403
iothread, QEMU_THREAD_JOINABLE);
404
g_free(thread_name);
405
@@ -XXX,XX +XXX,XX @@ static IOThreadParamInfo poll_grow_info = {
406
static IOThreadParamInfo poll_shrink_info = {
407
"poll-shrink", offsetof(IOThread, poll_shrink),
408
};
409
-static IOThreadParamInfo aio_max_batch_info = {
410
- "aio-max-batch", offsetof(IOThread, aio_max_batch),
411
-};
412
413
static void iothread_get_param(Object *obj, Visitor *v,
414
const char *name, IOThreadParamInfo *info, Error **errp)
415
@@ -XXX,XX +XXX,XX @@ static void iothread_set_poll_param(Object *obj, Visitor *v,
416
}
83
}
417
}
84
}
418
85
419
-static void iothread_get_aio_param(Object *obj, Visitor *v,
86
-static void coroutine_fn nvme_co_io_plug(BlockDriverState *bs)
420
- const char *name, void *opaque, Error **errp)
421
-{
87
-{
422
- IOThreadParamInfo *info = opaque;
88
- BDRVNVMeState *s = bs->opaque;
423
-
89
- assert(!s->plugged);
424
- iothread_get_param(obj, v, name, info, errp);
90
- s->plugged = true;
425
-}
91
-}
426
-
92
-
427
-static void iothread_set_aio_param(Object *obj, Visitor *v,
93
-static void coroutine_fn nvme_co_io_unplug(BlockDriverState *bs)
428
- const char *name, void *opaque, Error **errp)
429
-{
94
-{
430
- IOThread *iothread = IOTHREAD(obj);
95
- BDRVNVMeState *s = bs->opaque;
431
- IOThreadParamInfo *info = opaque;
96
- assert(s->plugged);
432
-
97
- s->plugged = false;
433
- if (!iothread_set_param(obj, v, name, info, errp)) {
98
- for (unsigned i = INDEX_IO(0); i < s->queue_count; i++) {
434
- return;
99
- NVMeQueuePair *q = s->queues[i];
435
- }
100
- qemu_mutex_lock(&q->lock);
436
-
101
- nvme_kick(q);
437
- if (iothread->ctx) {
102
- nvme_process_completion(q);
438
- aio_context_set_aio_params(iothread->ctx,
103
- qemu_mutex_unlock(&q->lock);
439
- iothread->aio_max_batch,
440
- errp);
441
- }
104
- }
442
-}
105
-}
443
-
106
-
444
static void iothread_class_init(ObjectClass *klass, void *class_data)
107
static bool nvme_register_buf(BlockDriverState *bs, void *host, size_t size,
108
Error **errp)
445
{
109
{
446
- UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
110
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nvme = {
447
- ucc->complete = iothread_complete;
111
.bdrv_detach_aio_context = nvme_detach_aio_context,
448
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(klass);
112
.bdrv_attach_aio_context = nvme_attach_aio_context,
449
+
113
450
+ bc->init = iothread_init;
114
- .bdrv_co_io_plug = nvme_co_io_plug,
451
+ bc->update_params = iothread_set_aio_context_params;
115
- .bdrv_co_io_unplug = nvme_co_io_unplug,
452
116
-
453
object_class_property_add(klass, "poll-max-ns", "int",
117
.bdrv_register_buf = nvme_register_buf,
454
iothread_get_poll_param,
118
.bdrv_unregister_buf = nvme_unregister_buf,
455
@@ -XXX,XX +XXX,XX @@ static void iothread_class_init(ObjectClass *klass, void *class_data)
456
iothread_get_poll_param,
457
iothread_set_poll_param,
458
NULL, &poll_shrink_info);
459
- object_class_property_add(klass, "aio-max-batch", "int",
460
- iothread_get_aio_param,
461
- iothread_set_aio_param,
462
- NULL, &aio_max_batch_info);
463
}
464
465
static const TypeInfo iothread_info = {
466
.name = TYPE_IOTHREAD,
467
- .parent = TYPE_OBJECT,
468
+ .parent = TYPE_EVENT_LOOP_BASE,
469
.class_init = iothread_class_init,
470
.instance_size = sizeof(IOThread),
471
.instance_init = iothread_instance_init,
472
.instance_finalize = iothread_instance_finalize,
473
- .interfaces = (InterfaceInfo[]) {
474
- {TYPE_USER_CREATABLE},
475
- {}
476
- },
477
};
119
};
478
120
diff --git a/block/trace-events b/block/trace-events
479
static void iothread_register_types(void)
121
index XXXXXXX..XXXXXXX 100644
480
@@ -XXX,XX +XXX,XX @@ static int query_one_iothread(Object *object, void *opaque)
122
--- a/block/trace-events
481
info->poll_max_ns = iothread->poll_max_ns;
123
+++ b/block/trace-events
482
info->poll_grow = iothread->poll_grow;
124
@@ -XXX,XX +XXX,XX @@ nvme_kick(void *s, unsigned q_index) "s %p q #%u"
483
info->poll_shrink = iothread->poll_shrink;
125
nvme_dma_flush_queue_wait(void *s) "s %p"
484
- info->aio_max_batch = iothread->aio_max_batch;
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"
485
+ info->aio_max_batch = iothread->parent_obj.aio_max_batch;
127
nvme_process_completion(void *s, unsigned q_index, int inflight) "s %p q #%u inflight %d"
486
128
-nvme_process_completion_queue_plugged(void *s, unsigned q_index) "s %p q #%u"
487
QAPI_LIST_APPEND(*tail, info);
129
nvme_complete_command(void *s, unsigned q_index, int cid) "s %p q #%u cid %d"
488
return 0;
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"
489
--
132
--
490
2.35.1
133
2.40.1
diff view generated by jsdifflib
1
The virtio-scsi event virtqueue is not emptied by its handler function.
1
Stop using the .bdrv_co_io_plug() API because it is not multi-queue
2
This is typical for rx virtqueues where the device uses buffers when
2
block layer friendly. Use the new blk_io_plug_call() API to batch I/O
3
some event occurs (e.g. a packet is received, an error condition
3
submission instead.
4
happens, etc).
5
4
6
Polling non-empty virtqueues wastes CPU cycles. We are not waiting for
7
new buffers to become available, we are waiting for an event to occur,
8
so it's a misuse of CPU resources to poll for buffers.
9
10
Introduce the new virtio_queue_aio_attach_host_notifier_no_poll() API,
11
which is identical to virtio_queue_aio_attach_host_notifier() except
12
that it does not poll the virtqueue.
13
14
Before this patch the following command-line consumed 100% CPU in the
15
IOThread polling and calling virtio_scsi_handle_event():
16
17
$ qemu-system-x86_64 -M accel=kvm -m 1G -cpu host \
18
--object iothread,id=iothread0 \
19
--device virtio-scsi-pci,iothread=iothread0 \
20
--blockdev file,filename=test.img,aio=native,cache.direct=on,node-name=drive0 \
21
--device scsi-hd,drive=drive0
22
23
After this patch CPU is no longer wasted.
24
25
Reported-by: Nir Soffer <nsoffer@redhat.com>
26
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
27
Tested-by: Nir Soffer <nsoffer@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
28
Message-id: 20220427143541.119567-3-stefanha@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
29
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
30
---
11
---
31
include/hw/virtio/virtio.h | 1 +
12
block/blkio.c | 43 ++++++++++++++++++++++++-------------------
32
hw/scsi/virtio-scsi-dataplane.c | 2 +-
13
1 file changed, 24 insertions(+), 19 deletions(-)
33
hw/virtio/virtio.c | 13 +++++++++++++
34
3 files changed, 15 insertions(+), 1 deletion(-)
35
14
36
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
15
diff --git a/block/blkio.c b/block/blkio.c
37
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
38
--- a/include/hw/virtio/virtio.h
17
--- a/block/blkio.c
39
+++ b/include/hw/virtio/virtio.h
18
+++ b/block/blkio.c
40
@@ -XXX,XX +XXX,XX @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
19
@@ -XXX,XX +XXX,XX @@
41
void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled);
20
#include "qemu/error-report.h"
42
void virtio_queue_host_notifier_read(EventNotifier *n);
21
#include "qapi/qmp/qdict.h"
43
void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx);
22
#include "qemu/module.h"
44
+void virtio_queue_aio_attach_host_notifier_no_poll(VirtQueue *vq, AioContext *ctx);
23
+#include "sysemu/block-backend.h"
45
void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx);
24
#include "exec/memory.h" /* for ram_block_discard_disable() */
46
VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector);
25
47
VirtQueue *virtio_vector_next_queue(VirtQueue *vq);
26
#include "block/block-io.h"
48
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
27
@@ -XXX,XX +XXX,XX @@ static void blkio_detach_aio_context(BlockDriverState *bs)
49
index XXXXXXX..XXXXXXX 100644
28
NULL, NULL, NULL);
50
--- a/hw/scsi/virtio-scsi-dataplane.c
51
+++ b/hw/scsi/virtio-scsi-dataplane.c
52
@@ -XXX,XX +XXX,XX @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev)
53
54
aio_context_acquire(s->ctx);
55
virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx);
56
- virtio_queue_aio_attach_host_notifier(vs->event_vq, s->ctx);
57
+ virtio_queue_aio_attach_host_notifier_no_poll(vs->event_vq, s->ctx);
58
59
for (i = 0; i < vs->conf.num_queues; i++) {
60
virtio_queue_aio_attach_host_notifier(vs->cmd_vqs[i], s->ctx);
61
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
62
index XXXXXXX..XXXXXXX 100644
63
--- a/hw/virtio/virtio.c
64
+++ b/hw/virtio/virtio.c
65
@@ -XXX,XX +XXX,XX @@ void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx)
66
virtio_queue_host_notifier_aio_poll_end);
67
}
29
}
68
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)
69
+/*
33
+/*
70
+ * Same as virtio_queue_aio_attach_host_notifier() but without polling. Use
34
+ * Called by blk_io_unplug() or immediately if not plugged. Called without
71
+ * this for rx virtqueues and similar cases where the virtqueue handler
35
+ * blkio_lock.
72
+ * function does not pop all elements. When the virtqueue is left non-empty
73
+ * polling consumes CPU cycles and should not be used.
74
+ */
36
+ */
75
+void virtio_queue_aio_attach_host_notifier_no_poll(VirtQueue *vq, AioContext *ctx)
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)
76
+{
53
+{
77
+ aio_set_event_notifier(ctx, &vq->host_notifier, true,
54
+ BDRVBlkioState *s = bs->opaque;
78
+ virtio_queue_host_notifier_read,
55
+
79
+ NULL, NULL);
56
+ blk_io_plug_call(blkio_unplug_fn, s);
80
+}
57
+}
81
+
58
+
82
void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx)
59
static int coroutine_fn
60
blkio_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
83
{
61
{
84
aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL, NULL);
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, \
85
--
138
--
86
2.35.1
139
2.40.1
diff view generated by jsdifflib
1
virtio_scsi_handle_ctrl_vq() is only called from hw/scsi/virtio-scsi.c
1
Stop using the .bdrv_co_io_plug() API because it is not multi-queue
2
now and its return value is no longer used. Remove the function
2
block layer friendly. Use the new blk_io_plug_call() API to batch I/O
3
prototype from virtio-scsi.h and drop the return value.
3
submission instead.
4
4
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Message-id: 20220427143541.119567-5-stefanha@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
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
11
---
10
include/hw/virtio/virtio-scsi.h | 1 -
12
include/block/raw-aio.h | 7 -------
11
hw/scsi/virtio-scsi.c | 5 +----
13
block/file-posix.c | 10 ----------
12
2 files changed, 1 insertion(+), 5 deletions(-)
14
block/io_uring.c | 44 ++++++++++++++++-------------------------
15
block/trace-events | 5 ++---
16
4 files changed, 19 insertions(+), 47 deletions(-)
13
17
14
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
18
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
15
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
16
--- a/include/hw/virtio/virtio-scsi.h
20
--- a/include/block/raw-aio.h
17
+++ b/include/hw/virtio/virtio-scsi.h
21
+++ b/include/block/raw-aio.h
18
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_common_realize(DeviceState *dev,
22
@@ -XXX,XX +XXX,XX @@ int coroutine_fn luring_co_submit(BlockDriverState *bs, int fd, uint64_t offset,
19
23
QEMUIOVector *qiov, int type);
20
void virtio_scsi_common_unrealize(DeviceState *dev);
24
void luring_detach_aio_context(LuringState *s, AioContext *old_context);
21
bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq);
25
void luring_attach_aio_context(LuringState *s, AioContext *new_context);
22
-bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq);
26
-
23
void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req);
27
-/*
24
void virtio_scsi_free_req(VirtIOSCSIReq *req);
28
- * luring_io_plug/unplug work in the thread's current AioContext, therefore the
25
void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
29
- * caller must ensure that they are paired in the same IOThread.
26
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
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
27
index XXXXXXX..XXXXXXX 100644
37
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/scsi/virtio-scsi.c
38
--- a/block/file-posix.c
29
+++ b/hw/scsi/virtio-scsi.c
39
+++ b/block/file-posix.c
30
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
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);
31
}
91
}
32
}
92
}
33
93
@@ -XXX,XX +XXX,XX @@ static void qemu_luring_poll_ready(void *opaque)
34
-bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
94
static void ioq_init(LuringQueue *io_q)
35
+static void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
36
{
95
{
37
VirtIOSCSIReq *req;
96
QSIMPLEQ_INIT(&io_q->submit_queue);
38
- bool progress = false;
97
- io_q->plugged = 0;
39
98
io_q->in_queue = 0;
40
while ((req = virtio_scsi_pop_req(s, vq))) {
99
io_q->in_flight = 0;
41
- progress = true;
100
io_q->blocked = false;
42
virtio_scsi_handle_ctrl_req(s, req);
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);
43
}
126
}
44
- return progress;
45
}
127
}
46
128
@@ -XXX,XX +XXX,XX @@ static int luring_do_submit(int fd, LuringAIOCB *luringcb, LuringState *s,
47
/*
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"
48
--
169
--
49
2.35.1
170
2.40.1
diff view generated by jsdifflib
1
There is no longer a need to expose the request and related APIs in
1
Stop using the .bdrv_co_io_plug() API because it is not multi-queue
2
virtio-scsi.h since there are no callers outside virtio-scsi.c.
2
block layer friendly. Use the new blk_io_plug_call() API to batch I/O
3
3
submission instead.
4
Note the block comment in VirtIOSCSIReq has been adjusted to meet the
4
5
coding style.
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.
6
16
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
18
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Message-id: 20220427143541.119567-7-stefanha@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
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
23
---
12
include/hw/virtio/virtio-scsi.h | 40 -----------------------------
24
include/block/raw-aio.h | 7 -------
13
hw/scsi/virtio-scsi.c | 45 ++++++++++++++++++++++++++++++---
25
block/file-posix.c | 28 ----------------------------
14
2 files changed, 41 insertions(+), 44 deletions(-)
26
block/linux-aio.c | 41 +++++++++++------------------------------
15
27
3 files changed, 11 insertions(+), 65 deletions(-)
16
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
28
29
diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h
17
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
18
--- a/include/hw/virtio/virtio-scsi.h
31
--- a/include/block/raw-aio.h
19
+++ b/include/hw/virtio/virtio-scsi.h
32
+++ b/include/block/raw-aio.h
20
@@ -XXX,XX +XXX,XX @@ struct VirtIOSCSI {
33
@@ -XXX,XX +XXX,XX @@ int coroutine_fn laio_co_submit(int fd, uint64_t offset, QEMUIOVector *qiov,
21
uint32_t host_features;
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 {
22
};
127
};
23
128
24
-typedef struct VirtIOSCSIReq {
129
typedef struct {
25
- /* Note:
130
- int plugged;
26
- * - fields up to resp_iov are initialized by virtio_scsi_init_req;
131
unsigned int in_queue;
27
- * - fields starting at vring are zeroed by virtio_scsi_init_req.
132
unsigned int in_flight;
28
- * */
133
bool blocked;
29
- VirtQueueElement elem;
134
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completions_and_submit(LinuxAioState *s)
30
-
135
{
31
- VirtIOSCSI *dev;
136
qemu_laio_process_completions(s);
32
- VirtQueue *vq;
137
33
- QEMUSGList qsgl;
138
- if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
34
- QEMUIOVector resp_iov;
139
+ if (!QSIMPLEQ_EMPTY(&s->io_q.pending)) {
35
-
140
ioq_submit(s);
36
- union {
141
}
37
- /* Used for two-stage request submission */
142
}
38
- QTAILQ_ENTRY(VirtIOSCSIReq) next;
143
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_poll_ready(EventNotifier *opaque)
39
-
144
static void ioq_init(LaioQueue *io_q)
40
- /* Used for cancellation of request during TMFs */
145
{
41
- int remaining;
146
QSIMPLEQ_INIT(&io_q->pending);
42
- };
147
- io_q->plugged = 0;
43
-
148
io_q->in_queue = 0;
44
- SCSIRequest *sreq;
149
io_q->in_flight = 0;
45
- size_t resp_size;
150
io_q->blocked = false;
46
- enum SCSIXferMode mode;
151
@@ -XXX,XX +XXX,XX @@ static uint64_t laio_max_batch(LinuxAioState *s, uint64_t dev_max_batch)
47
- union {
152
return max_batch;
48
- VirtIOSCSICmdResp cmd;
153
}
49
- VirtIOSCSICtrlTMFResp tmf;
154
50
- VirtIOSCSICtrlANResp an;
155
-void laio_io_plug(void)
51
- VirtIOSCSIEvent event;
156
+static void laio_unplug_fn(void *opaque)
52
- } resp;
157
{
53
- union {
158
- AioContext *ctx = qemu_get_current_aio_context();
54
- VirtIOSCSICmdReq cmd;
159
- LinuxAioState *s = aio_get_linux_aio(ctx);
55
- VirtIOSCSICtrlTMFReq tmf;
160
+ LinuxAioState *s = opaque;
56
- VirtIOSCSICtrlANReq an;
161
57
- } req;
162
- s->io_q.plugged++;
58
-} VirtIOSCSIReq;
163
-}
59
-
164
-
60
static inline void virtio_scsi_acquire(VirtIOSCSI *s)
165
-void laio_io_unplug(uint64_t dev_max_batch)
61
{
166
-{
62
if (s->ctx) {
167
- AioContext *ctx = qemu_get_current_aio_context();
63
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_common_realize(DeviceState *dev,
168
- LinuxAioState *s = aio_get_linux_aio(ctx);
64
Error **errp);
169
-
65
170
- assert(s->io_q.plugged);
66
void virtio_scsi_common_unrealize(DeviceState *dev);
171
- s->io_q.plugged--;
67
-void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req);
172
-
68
-void virtio_scsi_free_req(VirtIOSCSIReq *req);
173
- /*
69
-void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
174
- * Why max batch checking is performed here:
70
- uint32_t event, uint32_t reason);
175
- * Another BDS may have queued requests with a higher dev_max_batch and
71
176
- * therefore in_queue could now exceed our dev_max_batch. Re-check the max
72
void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp);
177
- * batch so we can honor our device's dev_max_batch.
73
int virtio_scsi_dataplane_start(VirtIODevice *s);
178
- */
74
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
179
- if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch) ||
75
index XXXXXXX..XXXXXXX 100644
180
- (!s->io_q.plugged &&
76
--- a/hw/scsi/virtio-scsi.c
181
- !s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending))) {
77
+++ b/hw/scsi/virtio-scsi.c
182
+ if (!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
78
@@ -XXX,XX +XXX,XX @@
183
ioq_submit(s);
79
#include "hw/virtio/virtio-access.h"
184
}
80
#include "trace.h"
185
}
81
186
@@ -XXX,XX +XXX,XX @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
82
+typedef struct VirtIOSCSIReq {
187
83
+ /*
188
QSIMPLEQ_INSERT_TAIL(&s->io_q.pending, laiocb, next);
84
+ * Note:
189
s->io_q.in_queue++;
85
+ * - fields up to resp_iov are initialized by virtio_scsi_init_req;
190
- if (!s->io_q.blocked &&
86
+ * - fields starting at vring are zeroed by virtio_scsi_init_req.
191
- (!s->io_q.plugged ||
87
+ */
192
- s->io_q.in_queue >= laio_max_batch(s, dev_max_batch))) {
88
+ VirtQueueElement elem;
193
- ioq_submit(s);
89
+
194
+ if (!s->io_q.blocked) {
90
+ VirtIOSCSI *dev;
195
+ if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch)) {
91
+ VirtQueue *vq;
196
+ ioq_submit(s);
92
+ QEMUSGList qsgl;
197
+ } else {
93
+ QEMUIOVector resp_iov;
198
+ blk_io_plug_call(laio_unplug_fn, s);
94
+
199
+ }
95
+ union {
200
}
96
+ /* Used for two-stage request submission */
201
97
+ QTAILQ_ENTRY(VirtIOSCSIReq) next;
202
return 0;
98
+
99
+ /* Used for cancellation of request during TMFs */
100
+ int remaining;
101
+ };
102
+
103
+ SCSIRequest *sreq;
104
+ size_t resp_size;
105
+ enum SCSIXferMode mode;
106
+ union {
107
+ VirtIOSCSICmdResp cmd;
108
+ VirtIOSCSICtrlTMFResp tmf;
109
+ VirtIOSCSICtrlANResp an;
110
+ VirtIOSCSIEvent event;
111
+ } resp;
112
+ union {
113
+ VirtIOSCSICmdReq cmd;
114
+ VirtIOSCSICtrlTMFReq tmf;
115
+ VirtIOSCSICtrlANReq an;
116
+ } req;
117
+} VirtIOSCSIReq;
118
+
119
static inline int virtio_scsi_get_lun(uint8_t *lun)
120
{
121
return ((lun[2] << 8) | lun[3]) & 0x3FFF;
122
@@ -XXX,XX +XXX,XX @@ static inline SCSIDevice *virtio_scsi_device_get(VirtIOSCSI *s, uint8_t *lun)
123
return scsi_device_get(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun));
124
}
125
126
-void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req)
127
+static void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req)
128
{
129
VirtIODevice *vdev = VIRTIO_DEVICE(s);
130
const size_t zero_skip =
131
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req)
132
memset((uint8_t *)req + zero_skip, 0, sizeof(*req) - zero_skip);
133
}
134
135
-void virtio_scsi_free_req(VirtIOSCSIReq *req)
136
+static void virtio_scsi_free_req(VirtIOSCSIReq *req)
137
{
138
qemu_iovec_destroy(&req->resp_iov);
139
qemu_sglist_destroy(&req->qsgl);
140
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_reset(VirtIODevice *vdev)
141
s->events_dropped = false;
142
}
143
144
-void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
145
- uint32_t event, uint32_t reason)
146
+static void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
147
+ uint32_t event, uint32_t reason)
148
{
149
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
150
VirtIOSCSIReq *req;
151
--
203
--
152
2.35.1
204
2.40.1
diff view generated by jsdifflib
1
virtio_scsi_handle_event_vq() is only called from hw/scsi/virtio-scsi.c
1
No block driver implements .bdrv_co_io_plug() anymore. Get rid of the
2
now and its return value is no longer used. Remove the function
2
function pointers.
3
prototype from virtio-scsi.h and drop the return value.
4
3
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Message-id: 20220427143541.119567-4-stefanha@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
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
10
---
10
include/hw/virtio/virtio-scsi.h | 1 -
11
include/block/block-io.h | 3 ---
11
hw/scsi/virtio-scsi.c | 4 +---
12
include/block/block_int-common.h | 11 ----------
12
2 files changed, 1 insertion(+), 4 deletions(-)
13
block/io.c | 37 --------------------------------
14
3 files changed, 51 deletions(-)
13
15
14
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
16
diff --git a/include/block/block-io.h b/include/block/block-io.h
15
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
16
--- a/include/hw/virtio/virtio-scsi.h
18
--- a/include/block/block-io.h
17
+++ b/include/hw/virtio/virtio-scsi.h
19
+++ b/include/block/block-io.h
18
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_common_realize(DeviceState *dev,
20
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_co_leave(BlockDriverState *bs, AioContext *old_ctx);
19
Error **errp);
21
20
22
AioContext *child_of_bds_get_parent_aio_context(BdrvChild *c);
21
void virtio_scsi_common_unrealize(DeviceState *dev);
23
22
-bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq);
24
-void coroutine_fn GRAPH_RDLOCK bdrv_co_io_plug(BlockDriverState *bs);
23
bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq);
25
-void coroutine_fn GRAPH_RDLOCK bdrv_co_io_unplug(BlockDriverState *bs);
24
bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq);
26
-
25
void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req);
27
bool coroutine_fn GRAPH_RDLOCK
26
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
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
27
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/scsi/virtio-scsi.c
32
--- a/include/block/block_int-common.h
29
+++ b/hw/scsi/virtio-scsi.c
33
+++ b/include/block/block_int-common.h
30
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
34
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
31
virtio_scsi_complete_req(req);
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;
32
}
65
}
33
66
34
-bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq)
67
-void coroutine_fn bdrv_co_io_plug(BlockDriverState *bs)
35
+static void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq)
68
-{
36
{
69
- BdrvChild *child;
37
if (s->events_dropped) {
70
- IO_CODE();
38
virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
71
- assert_bdrv_graph_readable();
39
- return true;
72
-
40
}
73
- QLIST_FOREACH(child, &bs->children, next) {
41
- return false;
74
- bdrv_co_io_plug(child->bs);
42
}
75
- }
43
76
-
44
static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq)
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,
45
--
107
--
46
2.35.1
108
2.40.1
diff view generated by jsdifflib
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
The thread pool regulates itself: when idle, it kills threads until
3
Some virtio-blk drivers (e.g. virtio-blk-vhost-vdpa) supports the fd
4
empty, when in demand, it creates new threads until full. This behaviour
4
passing. Let's expose this to the user, so the management layer
5
doesn't play well with latency sensitive workloads where the price of
5
can pass the file descriptor of an already opened path.
6
creating a new thread is too high. For example, when paired with qemu's
7
'-mlock', or using safety features like SafeStack, creating a new thread
8
has been measured take multiple milliseconds.
9
6
10
In order to mitigate this let's introduce a new 'EventLoopBase'
7
If the libblkio virtio-blk driver supports fd passing, let's always
11
property to set the thread pool size. The threads will be created during
8
use qemu_open() to open the `path`, so we can handle fd passing
12
the pool's initialization or upon updating the property's value, remain
9
from the management layer through the "/dev/fdset/N" special path.
13
available during its lifetime regardless of demand, and destroyed upon
14
freeing it. A properly characterized workload will then be able to
15
configure the pool to avoid any latency spikes.
16
10
17
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Acked-by: Markus Armbruster <armbru@redhat.com>
12
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
20
Message-id: 20220425075723.20019-4-nsaenzju@redhat.com
13
Message-id: 20230530071941.8954-2-sgarzare@redhat.com
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
22
---
15
---
23
qapi/qom.json | 10 +++++-
16
block/blkio.c | 53 ++++++++++++++++++++++++++++++++++++++++++---------
24
include/block/aio.h | 10 ++++++
17
1 file changed, 44 insertions(+), 9 deletions(-)
25
include/block/thread-pool.h | 3 ++
26
include/sysemu/event-loop-base.h | 4 +++
27
event-loop-base.c | 23 +++++++++++++
28
iothread.c | 3 ++
29
util/aio-posix.c | 1 +
30
util/async.c | 20 ++++++++++++
31
util/main-loop.c | 9 ++++++
32
util/thread-pool.c | 55 +++++++++++++++++++++++++++++---
33
10 files changed, 133 insertions(+), 5 deletions(-)
34
18
35
diff --git a/qapi/qom.json b/qapi/qom.json
19
diff --git a/block/blkio.c b/block/blkio.c
36
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
37
--- a/qapi/qom.json
21
--- a/block/blkio.c
38
+++ b/qapi/qom.json
22
+++ b/block/blkio.c
39
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@ static int blkio_virtio_blk_common_open(BlockDriverState *bs,
40
# 0 means that the engine will use its default.
24
{
41
# (default: 0)
25
const char *path = qdict_get_try_str(options, "path");
42
#
26
BDRVBlkioState *s = bs->opaque;
43
+# @thread-pool-min: minimum number of threads reserved in the thread pool
27
- int ret;
44
+# (default:0)
28
+ bool fd_supported = false;
45
+#
29
+ int fd, ret;
46
+# @thread-pool-max: maximum number of threads the thread pool can contain
30
47
+# (default:64)
31
if (!path) {
48
+#
32
error_setg(errp, "missing 'path' option");
49
# Since: 7.1
33
return -EINVAL;
50
##
34
}
51
{ 'struct': 'EventLoopBaseProperties',
35
52
- 'data': { '*aio-max-batch': 'int' } }
36
- ret = blkio_set_str(s->blkio, "path", path);
53
+ 'data': { '*aio-max-batch': 'int',
37
- qdict_del(options, "path");
54
+ '*thread-pool-min': 'int',
38
- if (ret < 0) {
55
+ '*thread-pool-max': 'int' } }
39
- error_setg_errno(errp, -ret, "failed to set path: %s",
56
40
- blkio_get_error_msg());
57
##
41
- return ret;
58
# @IothreadProperties:
42
- }
59
diff --git a/include/block/aio.h b/include/block/aio.h
43
-
60
index XXXXXXX..XXXXXXX 100644
44
if (!(flags & BDRV_O_NOCACHE)) {
61
--- a/include/block/aio.h
45
error_setg(errp, "cache.direct=off is not supported");
62
+++ b/include/block/aio.h
46
return -EINVAL;
63
@@ -XXX,XX +XXX,XX @@ struct AioContext {
47
}
64
QSLIST_HEAD(, Coroutine) scheduled_coroutines;
65
QEMUBH *co_schedule_bh;
66
67
+ int thread_pool_min;
68
+ int thread_pool_max;
69
/* Thread pool for performing work and receiving completion callbacks.
70
* Has its own locking.
71
*/
72
@@ -XXX,XX +XXX,XX @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
73
void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch,
74
Error **errp);
75
76
+/**
77
+ * aio_context_set_thread_pool_params:
78
+ * @ctx: the aio context
79
+ * @min: min number of threads to have readily available in the thread pool
80
+ * @min: max number of threads the thread pool can contain
81
+ */
82
+void aio_context_set_thread_pool_params(AioContext *ctx, int64_t min,
83
+ int64_t max, Error **errp);
84
#endif
85
diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h
86
index XXXXXXX..XXXXXXX 100644
87
--- a/include/block/thread-pool.h
88
+++ b/include/block/thread-pool.h
89
@@ -XXX,XX +XXX,XX @@
90
91
#include "block/block.h"
92
93
+#define THREAD_POOL_MAX_THREADS_DEFAULT 64
94
+
48
+
95
typedef int ThreadPoolFunc(void *opaque);
49
+ if (blkio_get_int(s->blkio, "fd", &fd) == 0) {
96
50
+ fd_supported = true;
97
typedef struct ThreadPool ThreadPool;
98
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool,
99
int coroutine_fn thread_pool_submit_co(ThreadPool *pool,
100
ThreadPoolFunc *func, void *arg);
101
void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg);
102
+void thread_pool_update_params(ThreadPool *pool, struct AioContext *ctx);
103
104
#endif
105
diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h
106
index XXXXXXX..XXXXXXX 100644
107
--- a/include/sysemu/event-loop-base.h
108
+++ b/include/sysemu/event-loop-base.h
109
@@ -XXX,XX +XXX,XX @@ struct EventLoopBase {
110
111
/* AioContext AIO engine parameters */
112
int64_t aio_max_batch;
113
+
114
+ /* AioContext thread pool parameters */
115
+ int64_t thread_pool_min;
116
+ int64_t thread_pool_max;
117
};
118
#endif
119
diff --git a/event-loop-base.c b/event-loop-base.c
120
index XXXXXXX..XXXXXXX 100644
121
--- a/event-loop-base.c
122
+++ b/event-loop-base.c
123
@@ -XXX,XX +XXX,XX @@
124
#include "qemu/osdep.h"
125
#include "qom/object_interfaces.h"
126
#include "qapi/error.h"
127
+#include "block/thread-pool.h"
128
#include "sysemu/event-loop-base.h"
129
130
typedef struct {
131
@@ -XXX,XX +XXX,XX @@ typedef struct {
132
ptrdiff_t offset; /* field's byte offset in EventLoopBase struct */
133
} EventLoopBaseParamInfo;
134
135
+static void event_loop_base_instance_init(Object *obj)
136
+{
137
+ EventLoopBase *base = EVENT_LOOP_BASE(obj);
138
+
139
+ base->thread_pool_max = THREAD_POOL_MAX_THREADS_DEFAULT;
140
+}
141
+
142
static EventLoopBaseParamInfo aio_max_batch_info = {
143
"aio-max-batch", offsetof(EventLoopBase, aio_max_batch),
144
};
145
+static EventLoopBaseParamInfo thread_pool_min_info = {
146
+ "thread-pool-min", offsetof(EventLoopBase, thread_pool_min),
147
+};
148
+static EventLoopBaseParamInfo thread_pool_max_info = {
149
+ "thread-pool-max", offsetof(EventLoopBase, thread_pool_max),
150
+};
151
152
static void event_loop_base_get_param(Object *obj, Visitor *v,
153
const char *name, void *opaque, Error **errp)
154
@@ -XXX,XX +XXX,XX @@ static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
155
event_loop_base_get_param,
156
event_loop_base_set_param,
157
NULL, &aio_max_batch_info);
158
+ object_class_property_add(klass, "thread-pool-min", "int",
159
+ event_loop_base_get_param,
160
+ event_loop_base_set_param,
161
+ NULL, &thread_pool_min_info);
162
+ object_class_property_add(klass, "thread-pool-max", "int",
163
+ event_loop_base_get_param,
164
+ event_loop_base_set_param,
165
+ NULL, &thread_pool_max_info);
166
}
167
168
static const TypeInfo event_loop_base_info = {
169
.name = TYPE_EVENT_LOOP_BASE,
170
.parent = TYPE_OBJECT,
171
.instance_size = sizeof(EventLoopBase),
172
+ .instance_init = event_loop_base_instance_init,
173
.class_size = sizeof(EventLoopBaseClass),
174
.class_init = event_loop_base_class_init,
175
.abstract = true,
176
diff --git a/iothread.c b/iothread.c
177
index XXXXXXX..XXXXXXX 100644
178
--- a/iothread.c
179
+++ b/iothread.c
180
@@ -XXX,XX +XXX,XX @@ static void iothread_set_aio_context_params(EventLoopBase *base, Error **errp)
181
aio_context_set_aio_params(iothread->ctx,
182
iothread->parent_obj.aio_max_batch,
183
errp);
184
+
185
+ aio_context_set_thread_pool_params(iothread->ctx, base->thread_pool_min,
186
+ base->thread_pool_max, errp);
187
}
188
189
190
diff --git a/util/aio-posix.c b/util/aio-posix.c
191
index XXXXXXX..XXXXXXX 100644
192
--- a/util/aio-posix.c
193
+++ b/util/aio-posix.c
194
@@ -XXX,XX +XXX,XX @@
195
196
#include "qemu/osdep.h"
197
#include "block/block.h"
198
+#include "block/thread-pool.h"
199
#include "qemu/main-loop.h"
200
#include "qemu/rcu.h"
201
#include "qemu/rcu_queue.h"
202
diff --git a/util/async.c b/util/async.c
203
index XXXXXXX..XXXXXXX 100644
204
--- a/util/async.c
205
+++ b/util/async.c
206
@@ -XXX,XX +XXX,XX @@ AioContext *aio_context_new(Error **errp)
207
208
ctx->aio_max_batch = 0;
209
210
+ ctx->thread_pool_min = 0;
211
+ ctx->thread_pool_max = THREAD_POOL_MAX_THREADS_DEFAULT;
212
+
213
return ctx;
214
fail:
215
g_source_destroy(&ctx->source);
216
@@ -XXX,XX +XXX,XX @@ void qemu_set_current_aio_context(AioContext *ctx)
217
assert(!get_my_aiocontext());
218
set_my_aiocontext(ctx);
219
}
220
+
221
+void aio_context_set_thread_pool_params(AioContext *ctx, int64_t min,
222
+ int64_t max, Error **errp)
223
+{
224
+
225
+ if (min > max || !max || min > INT_MAX || max > INT_MAX) {
226
+ error_setg(errp, "bad thread-pool-min/thread-pool-max values");
227
+ return;
228
+ }
51
+ }
229
+
52
+
230
+ ctx->thread_pool_min = min;
53
+ /*
231
+ ctx->thread_pool_max = max;
54
+ * If the libblkio driver supports fd passing, let's always use qemu_open()
55
+ * to open the `path`, so we can handle fd passing from the management
56
+ * layer through the "/dev/fdset/N" special path.
57
+ */
58
+ if (fd_supported) {
59
+ int open_flags;
232
+
60
+
233
+ if (ctx->thread_pool) {
61
+ if (flags & BDRV_O_RDWR) {
234
+ thread_pool_update_params(ctx->thread_pool, ctx);
62
+ open_flags = O_RDWR;
235
+ }
63
+ } else {
236
+}
64
+ open_flags = O_RDONLY;
237
diff --git a/util/main-loop.c b/util/main-loop.c
65
+ }
238
index XXXXXXX..XXXXXXX 100644
239
--- a/util/main-loop.c
240
+++ b/util/main-loop.c
241
@@ -XXX,XX +XXX,XX @@
242
#include "sysemu/replay.h"
243
#include "qemu/main-loop.h"
244
#include "block/aio.h"
245
+#include "block/thread-pool.h"
246
#include "qemu/error-report.h"
247
#include "qemu/queue.h"
248
#include "qemu/compiler.h"
249
@@ -XXX,XX +XXX,XX @@ int qemu_init_main_loop(Error **errp)
250
251
static void main_loop_update_params(EventLoopBase *base, Error **errp)
252
{
253
+ ERRP_GUARD();
254
+
66
+
255
if (!qemu_aio_context) {
67
+ fd = qemu_open(path, open_flags, errp);
256
error_setg(errp, "qemu aio context not ready");
68
+ if (fd < 0) {
257
return;
69
+ return -EINVAL;
258
}
70
+ }
259
71
+
260
aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
72
+ ret = blkio_set_int(s->blkio, "fd", fd);
261
+ if (*errp) {
73
+ if (ret < 0) {
262
+ return;
74
+ error_setg_errno(errp, -ret, "failed to set fd: %s",
75
+ blkio_get_error_msg());
76
+ qemu_close(fd);
77
+ return ret;
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
+ }
263
+ }
86
+ }
264
+
87
+
265
+ aio_context_set_thread_pool_params(qemu_aio_context, base->thread_pool_min,
88
+ qdict_del(options, "path");
266
+ base->thread_pool_max, errp);
89
+
90
return 0;
267
}
91
}
268
92
269
MainLoop *mloop;
270
diff --git a/util/thread-pool.c b/util/thread-pool.c
271
index XXXXXXX..XXXXXXX 100644
272
--- a/util/thread-pool.c
273
+++ b/util/thread-pool.c
274
@@ -XXX,XX +XXX,XX @@ struct ThreadPool {
275
QemuMutex lock;
276
QemuCond worker_stopped;
277
QemuSemaphore sem;
278
- int max_threads;
279
QEMUBH *new_thread_bh;
280
281
/* The following variables are only accessed from one AioContext. */
282
@@ -XXX,XX +XXX,XX @@ struct ThreadPool {
283
int new_threads; /* backlog of threads we need to create */
284
int pending_threads; /* threads created but not running yet */
285
bool stopping;
286
+ int min_threads;
287
+ int max_threads;
288
};
289
290
+static inline bool back_to_sleep(ThreadPool *pool, int ret)
291
+{
292
+ /*
293
+ * The semaphore timed out, we should exit the loop except when:
294
+ * - There is work to do, we raced with the signal.
295
+ * - The max threads threshold just changed, we raced with the signal.
296
+ * - The thread pool forces a minimum number of readily available threads.
297
+ */
298
+ if (ret == -1 && (!QTAILQ_EMPTY(&pool->request_list) ||
299
+ pool->cur_threads > pool->max_threads ||
300
+ pool->cur_threads <= pool->min_threads)) {
301
+ return true;
302
+ }
303
+
304
+ return false;
305
+}
306
+
307
static void *worker_thread(void *opaque)
308
{
309
ThreadPool *pool = opaque;
310
@@ -XXX,XX +XXX,XX @@ static void *worker_thread(void *opaque)
311
ret = qemu_sem_timedwait(&pool->sem, 10000);
312
qemu_mutex_lock(&pool->lock);
313
pool->idle_threads--;
314
- } while (ret == -1 && !QTAILQ_EMPTY(&pool->request_list));
315
- if (ret == -1 || pool->stopping) {
316
+ } while (back_to_sleep(pool, ret));
317
+ if (ret == -1 || pool->stopping ||
318
+ pool->cur_threads > pool->max_threads) {
319
break;
320
}
321
322
@@ -XXX,XX +XXX,XX @@ void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg)
323
thread_pool_submit_aio(pool, func, arg, NULL, NULL);
324
}
325
326
+void thread_pool_update_params(ThreadPool *pool, AioContext *ctx)
327
+{
328
+ qemu_mutex_lock(&pool->lock);
329
+
330
+ pool->min_threads = ctx->thread_pool_min;
331
+ pool->max_threads = ctx->thread_pool_max;
332
+
333
+ /*
334
+ * We either have to:
335
+ * - Increase the number available of threads until over the min_threads
336
+ * threshold.
337
+ * - Decrease the number of available threads until under the max_threads
338
+ * threshold.
339
+ * - Do nothing. The current number of threads fall in between the min and
340
+ * max thresholds. We'll let the pool manage itself.
341
+ */
342
+ for (int i = pool->cur_threads; i < pool->min_threads; i++) {
343
+ spawn_thread(pool);
344
+ }
345
+
346
+ for (int i = pool->cur_threads; i > pool->max_threads; i--) {
347
+ qemu_sem_post(&pool->sem);
348
+ }
349
+
350
+ qemu_mutex_unlock(&pool->lock);
351
+}
352
+
353
static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
354
{
355
if (!ctx) {
356
@@ -XXX,XX +XXX,XX @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
357
qemu_mutex_init(&pool->lock);
358
qemu_cond_init(&pool->worker_stopped);
359
qemu_sem_init(&pool->sem, 0);
360
- pool->max_threads = 64;
361
pool->new_thread_bh = aio_bh_new(ctx, spawn_thread_bh_fn, pool);
362
363
QLIST_INIT(&pool->head);
364
QTAILQ_INIT(&pool->request_list);
365
+
366
+ thread_pool_update_params(pool, ctx);
367
}
368
369
ThreadPool *thread_pool_new(AioContext *ctx)
370
--
93
--
371
2.35.1
94
2.40.1
diff view generated by jsdifflib
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
'event-loop-base' provides basic property handling for all 'AioContext'
3
The virtio-blk-vhost-vdpa driver in libblkio 1.3.0 supports the fd
4
based event loops. So let's define a new 'MainLoopClass' that inherits
4
passing through the new 'fd' property.
5
from it. This will permit tweaking the main loop's properties through
6
qapi as well as through the command line using the '-object' keyword[1].
7
Only one instance of 'MainLoopClass' might be created at any time.
8
5
9
'EventLoopBaseClass' learns a new callback, 'can_be_deleted()' so as to
6
Since now we are using qemu_open() on '@path' if the virtio-blk driver
10
mark 'MainLoop' as non-deletable.
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
11
12
[1] For example:
12
Add the '@fdset' feature only when the virtio-blk-vhost-vdpa driver
13
-object main-loop,id=main-loop,aio-max-batch=<value>
13
in libblkio supports it.
14
14
15
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
15
Suggested-by: Markus Armbruster <armbru@redhat.com>
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Acked-by: Markus Armbruster <armbru@redhat.com>
17
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
18
Message-id: 20220425075723.20019-3-nsaenzju@redhat.com
18
Message-id: 20230530071941.8954-3-sgarzare@redhat.com
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
20
---
20
---
21
qapi/qom.json | 13 ++++++++
21
qapi/block-core.json | 6 ++++++
22
meson.build | 3 +-
22
meson.build | 4 ++++
23
include/qemu/main-loop.h | 10 ++++++
23
2 files changed, 10 insertions(+)
24
include/sysemu/event-loop-base.h | 1 +
25
event-loop-base.c | 13 ++++++++
26
util/main-loop.c | 56 ++++++++++++++++++++++++++++++++
27
6 files changed, 95 insertions(+), 1 deletion(-)
28
24
29
diff --git a/qapi/qom.json b/qapi/qom.json
25
diff --git a/qapi/block-core.json b/qapi/block-core.json
30
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
31
--- a/qapi/qom.json
27
--- a/qapi/block-core.json
32
+++ b/qapi/qom.json
28
+++ b/qapi/block-core.json
33
@@ -XXX,XX +XXX,XX @@
29
@@ -XXX,XX +XXX,XX @@
34
'*poll-grow': 'int',
30
#
35
'*poll-shrink': 'int' } }
31
# @path: path to the vhost-vdpa character device.
36
32
#
37
+##
33
+# Features:
38
+# @MainLoopProperties:
34
+# @fdset: Member @path supports the special "/dev/fdset/N" path
35
+# (since 8.1)
39
+#
36
+#
40
+# Properties for the main-loop object.
37
# Since: 7.2
41
+#
42
+# Since: 7.1
43
+##
44
+{ 'struct': 'MainLoopProperties',
45
+ 'base': 'EventLoopBaseProperties',
46
+ 'data': {} }
47
+
48
##
38
##
49
# @MemoryBackendProperties:
39
{ 'struct': 'BlockdevOptionsVirtioBlkVhostVdpa',
50
#
40
'data': { 'path': 'str' },
51
@@ -XXX,XX +XXX,XX @@
41
+ 'features': [ { 'name' :'fdset',
52
{ 'name': 'input-linux',
42
+ 'if': 'CONFIG_BLKIO_VHOST_VDPA_FD' } ],
53
'if': 'CONFIG_LINUX' },
43
'if': 'CONFIG_BLKIO' }
54
'iothread',
44
55
+ 'main-loop',
45
##
56
{ 'name': 'memory-backend-epc',
57
'if': 'CONFIG_LINUX' },
58
'memory-backend-file',
59
@@ -XXX,XX +XXX,XX @@
60
'input-linux': { 'type': 'InputLinuxProperties',
61
'if': 'CONFIG_LINUX' },
62
'iothread': 'IothreadProperties',
63
+ 'main-loop': 'MainLoopProperties',
64
'memory-backend-epc': { 'type': 'MemoryBackendEpcProperties',
65
'if': 'CONFIG_LINUX' },
66
'memory-backend-file': 'MemoryBackendFileProperties',
67
diff --git a/meson.build b/meson.build
46
diff --git a/meson.build b/meson.build
68
index XXXXXXX..XXXXXXX 100644
47
index XXXXXXX..XXXXXXX 100644
69
--- a/meson.build
48
--- a/meson.build
70
+++ b/meson.build
49
+++ b/meson.build
71
@@ -XXX,XX +XXX,XX @@ libqemuutil = static_library('qemuutil',
50
@@ -XXX,XX +XXX,XX @@ config_host_data.set('CONFIG_LZO', lzo.found())
72
sources: util_ss.sources() + stub_ss.sources() + genh,
51
config_host_data.set('CONFIG_MPATH', mpathpersist.found())
73
dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman])
52
config_host_data.set('CONFIG_MPATH_NEW_API', mpathpersist_new_api)
74
qemuutil = declare_dependency(link_with: libqemuutil,
53
config_host_data.set('CONFIG_BLKIO', blkio.found())
75
- sources: genh + version_res)
54
+if blkio.found()
76
+ sources: genh + version_res,
55
+ config_host_data.set('CONFIG_BLKIO_VHOST_VDPA_FD',
77
+ dependencies: [event_loop_base])
56
+ blkio.version().version_compare('>=1.3.0'))
78
57
+endif
79
if have_system or have_user
58
config_host_data.set('CONFIG_CURL', curl.found())
80
decodetree = generator(find_program('scripts/decodetree.py'),
59
config_host_data.set('CONFIG_CURSES', curses.found())
81
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
60
config_host_data.set('CONFIG_GBM', gbm.found())
82
index XXXXXXX..XXXXXXX 100644
83
--- a/include/qemu/main-loop.h
84
+++ b/include/qemu/main-loop.h
85
@@ -XXX,XX +XXX,XX @@
86
#define QEMU_MAIN_LOOP_H
87
88
#include "block/aio.h"
89
+#include "qom/object.h"
90
+#include "sysemu/event-loop-base.h"
91
92
#define SIG_IPI SIGUSR1
93
94
+#define TYPE_MAIN_LOOP "main-loop"
95
+OBJECT_DECLARE_TYPE(MainLoop, MainLoopClass, MAIN_LOOP)
96
+
97
+struct MainLoop {
98
+ EventLoopBase parent_obj;
99
+};
100
+typedef struct MainLoop MainLoop;
101
+
102
/**
103
* qemu_init_main_loop: Set up the process so that it can run the main loop.
104
*
105
diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h
106
index XXXXXXX..XXXXXXX 100644
107
--- a/include/sysemu/event-loop-base.h
108
+++ b/include/sysemu/event-loop-base.h
109
@@ -XXX,XX +XXX,XX @@ struct EventLoopBaseClass {
110
111
void (*init)(EventLoopBase *base, Error **errp);
112
void (*update_params)(EventLoopBase *base, Error **errp);
113
+ bool (*can_be_deleted)(EventLoopBase *base);
114
};
115
116
struct EventLoopBase {
117
diff --git a/event-loop-base.c b/event-loop-base.c
118
index XXXXXXX..XXXXXXX 100644
119
--- a/event-loop-base.c
120
+++ b/event-loop-base.c
121
@@ -XXX,XX +XXX,XX @@ static void event_loop_base_complete(UserCreatable *uc, Error **errp)
122
}
123
}
124
125
+static bool event_loop_base_can_be_deleted(UserCreatable *uc)
126
+{
127
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc);
128
+ EventLoopBase *backend = EVENT_LOOP_BASE(uc);
129
+
130
+ if (bc->can_be_deleted) {
131
+ return bc->can_be_deleted(backend);
132
+ }
133
+
134
+ return true;
135
+}
136
+
137
static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
138
{
139
UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
140
ucc->complete = event_loop_base_complete;
141
+ ucc->can_be_deleted = event_loop_base_can_be_deleted;
142
143
object_class_property_add(klass, "aio-max-batch", "int",
144
event_loop_base_get_param,
145
diff --git a/util/main-loop.c b/util/main-loop.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/util/main-loop.c
148
+++ b/util/main-loop.c
149
@@ -XXX,XX +XXX,XX @@
150
#include "qemu/error-report.h"
151
#include "qemu/queue.h"
152
#include "qemu/compiler.h"
153
+#include "qom/object.h"
154
155
#ifndef _WIN32
156
#include <sys/wait.h>
157
@@ -XXX,XX +XXX,XX @@ int qemu_init_main_loop(Error **errp)
158
return 0;
159
}
160
161
+static void main_loop_update_params(EventLoopBase *base, Error **errp)
162
+{
163
+ if (!qemu_aio_context) {
164
+ error_setg(errp, "qemu aio context not ready");
165
+ return;
166
+ }
167
+
168
+ aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
169
+}
170
+
171
+MainLoop *mloop;
172
+
173
+static void main_loop_init(EventLoopBase *base, Error **errp)
174
+{
175
+ MainLoop *m = MAIN_LOOP(base);
176
+
177
+ if (mloop) {
178
+ error_setg(errp, "only one main-loop instance allowed");
179
+ return;
180
+ }
181
+
182
+ main_loop_update_params(base, errp);
183
+
184
+ mloop = m;
185
+ return;
186
+}
187
+
188
+static bool main_loop_can_be_deleted(EventLoopBase *base)
189
+{
190
+ return false;
191
+}
192
+
193
+static void main_loop_class_init(ObjectClass *oc, void *class_data)
194
+{
195
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(oc);
196
+
197
+ bc->init = main_loop_init;
198
+ bc->update_params = main_loop_update_params;
199
+ bc->can_be_deleted = main_loop_can_be_deleted;
200
+}
201
+
202
+static const TypeInfo main_loop_info = {
203
+ .name = TYPE_MAIN_LOOP,
204
+ .parent = TYPE_EVENT_LOOP_BASE,
205
+ .class_init = main_loop_class_init,
206
+ .instance_size = sizeof(MainLoop),
207
+};
208
+
209
+static void main_loop_register_types(void)
210
+{
211
+ type_register_static(&main_loop_info);
212
+}
213
+
214
+type_init(main_loop_register_types)
215
+
216
static int max_priority;
217
218
#ifndef _WIN32
219
--
61
--
220
2.35.1
62
2.40.1
diff view generated by jsdifflib
Deleted patch
1
Commit f34e8d8b8d48d73f36a67b6d5e492ef9784b5012 ("virtio-scsi: prepare
2
virtio_scsi_handle_cmd for dataplane") prepared the virtio-scsi cmd
3
virtqueue handler function to be used in both the dataplane and
4
non-datpalane code paths.
5
1
6
It failed to convert the ctrl and event virtqueue handler functions,
7
which are not designed to be called from the dataplane code path but
8
will be since the ioeventfd is set up for those virtqueues when
9
dataplane starts.
10
11
Convert the ctrl and event virtqueue handler functions now so they
12
operate correctly when called from the dataplane code path. Avoid code
13
duplication by extracting this code into a helper function.
14
15
Fixes: f34e8d8b8d48d73f36a67b6d5e492ef9784b5012 ("virtio-scsi: prepare virtio_scsi_handle_cmd for dataplane")
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
18
Message-id: 20220427143541.119567-2-stefanha@redhat.com
19
[Fixed s/by used/be used/ typo pointed out by Michael Tokarev
20
<mjt@tls.msk.ru>.
21
--Stefan]
22
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
23
---
24
hw/scsi/virtio-scsi.c | 42 +++++++++++++++++++++++++++---------------
25
1 file changed, 27 insertions(+), 15 deletions(-)
26
27
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/hw/scsi/virtio-scsi.c
30
+++ b/hw/scsi/virtio-scsi.c
31
@@ -XXX,XX +XXX,XX @@ bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
32
return progress;
33
}
34
35
+/*
36
+ * If dataplane is configured but not yet started, do so now and return true on
37
+ * success.
38
+ *
39
+ * Dataplane is started by the core virtio code but virtqueue handler functions
40
+ * can also be invoked when a guest kicks before DRIVER_OK, so this helper
41
+ * function helps us deal with manually starting ioeventfd in that case.
42
+ */
43
+static bool virtio_scsi_defer_to_dataplane(VirtIOSCSI *s)
44
+{
45
+ if (!s->ctx || s->dataplane_started) {
46
+ return false;
47
+ }
48
+
49
+ virtio_device_start_ioeventfd(&s->parent_obj.parent_obj);
50
+ return !s->dataplane_fenced;
51
+}
52
+
53
static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
54
{
55
VirtIOSCSI *s = (VirtIOSCSI *)vdev;
56
57
- if (s->ctx) {
58
- virtio_device_start_ioeventfd(vdev);
59
- if (!s->dataplane_fenced) {
60
- return;
61
- }
62
+ if (virtio_scsi_defer_to_dataplane(s)) {
63
+ return;
64
}
65
+
66
virtio_scsi_acquire(s);
67
virtio_scsi_handle_ctrl_vq(s, vq);
68
virtio_scsi_release(s);
69
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
70
/* use non-QOM casts in the data path */
71
VirtIOSCSI *s = (VirtIOSCSI *)vdev;
72
73
- if (s->ctx && !s->dataplane_started) {
74
- virtio_device_start_ioeventfd(vdev);
75
- if (!s->dataplane_fenced) {
76
- return;
77
- }
78
+ if (virtio_scsi_defer_to_dataplane(s)) {
79
+ return;
80
}
81
+
82
virtio_scsi_acquire(s);
83
virtio_scsi_handle_cmd_vq(s, vq);
84
virtio_scsi_release(s);
85
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq)
86
{
87
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
88
89
- if (s->ctx) {
90
- virtio_device_start_ioeventfd(vdev);
91
- if (!s->dataplane_fenced) {
92
- return;
93
- }
94
+ if (virtio_scsi_defer_to_dataplane(s)) {
95
+ return;
96
}
97
+
98
virtio_scsi_acquire(s);
99
virtio_scsi_handle_event_vq(s, vq);
100
virtio_scsi_release(s);
101
--
102
2.35.1
diff view generated by jsdifflib