1
The following changes since commit e47f81b617684c4546af286d307b69014a83538a:
1
The following changes since commit 554623226f800acf48a2ed568900c1c968ec9a8b:
2
2
3
Merge remote-tracking branch 'remotes/thibault/tags/samuel-thibault' into staging (2019-02-07 18:53:25 +0000)
3
Merge tag 'qemu-sparc-20220508' of https://github.com/mcayland/qemu into staging (2022-05-08 17:03:26 -0500)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
git://github.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 55140166667bb555c5d05165b93b25557d2e6397:
9
for you to fetch changes up to 3dc584abeef0e1277c2de8c1c1974cb49444eb0a:
10
10
11
tests/virtio-blk: add test for WRITE_ZEROES command (2019-02-11 11:58:17 +0800)
11
virtio-scsi: move request-related items from .h to .c (2022-05-09 10:45:04 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Pull request
14
Pull request
15
15
16
User-visible changes:
16
- Add new thread-pool-min/thread-pool-max parameters to control the thread pool
17
used for async I/O.
17
18
18
* virtio-blk: DISCARD and WRITE_ZEROES support
19
- Fix virtio-scsi IOThread 100% CPU consumption QEMU 7.0 regression.
19
20
20
----------------------------------------------------------------
21
----------------------------------------------------------------
21
22
22
Peter Xu (1):
23
Nicolas Saenz Julienne (3):
23
iothread: fix iothread hang when stop too soon
24
Introduce event-loop-base abstract class
25
util/main-loop: Introduce the main loop into QOM
26
util/event-loop-base: Introduce options to set the thread pool size
24
27
25
Stefano Garzarella (7):
28
Stefan Hajnoczi (6):
26
virtio-blk: cleanup using VirtIOBlock *s and VirtIODevice *vdev
29
virtio-scsi: fix ctrl and event handler functions in dataplane mode
27
virtio-blk: add acct_failed param to virtio_blk_handle_rw_error()
30
virtio-scsi: don't waste CPU polling the event virtqueue
28
virtio-blk: add host_features field in VirtIOBlock
31
virtio-scsi: clean up virtio_scsi_handle_event_vq()
29
virtio-blk: add "discard" and "write-zeroes" properties
32
virtio-scsi: clean up virtio_scsi_handle_ctrl_vq()
30
virtio-blk: add DISCARD and WRITE_ZEROES features
33
virtio-scsi: clean up virtio_scsi_handle_cmd_vq()
31
tests/virtio-blk: change assert on data_size in virtio_blk_request()
34
virtio-scsi: move request-related items from .h to .c
32
tests/virtio-blk: add test for WRITE_ZEROES command
33
35
34
Vladimir Sementsov-Ogievskiy (1):
36
qapi/qom.json | 43 ++++++++--
35
qemugdb/coroutine: fix arch_prctl has unknown return type
37
meson.build | 26 +++---
36
38
include/block/aio.h | 10 +++
37
include/hw/virtio/virtio-blk.h | 5 +-
39
include/block/thread-pool.h | 3 +
38
hw/block/virtio-blk.c | 236 +++++++++++++++++++++++++++++----
40
include/hw/virtio/virtio-scsi.h | 43 ----------
39
hw/core/machine.c | 2 +
41
include/hw/virtio/virtio.h | 1 +
40
iothread.c | 6 +-
42
include/qemu/main-loop.h | 10 +++
41
tests/virtio-blk-test.c | 75 ++++++++++-
43
include/sysemu/event-loop-base.h | 41 +++++++++
42
scripts/qemugdb/coroutine.py | 2 +-
44
include/sysemu/iothread.h | 6 +-
43
6 files changed, 297 insertions(+), 29 deletions(-)
45
event-loop-base.c | 140 +++++++++++++++++++++++++++++++
46
hw/scsi/virtio-scsi-dataplane.c | 2 +-
47
hw/scsi/virtio-scsi.c | 101 +++++++++++++++-------
48
hw/virtio/virtio.c | 13 +++
49
iothread.c | 68 +++++----------
50
util/aio-posix.c | 1 +
51
util/async.c | 20 +++++
52
util/main-loop.c | 65 ++++++++++++++
53
util/thread-pool.c | 55 +++++++++++-
54
18 files changed, 505 insertions(+), 143 deletions(-)
55
create mode 100644 include/sysemu/event-loop-base.h
56
create mode 100644 event-loop-base.c
44
57
45
--
58
--
46
2.20.1
59
2.35.1
47
48
diff view generated by jsdifflib
1
From: Peter Xu <peterx@redhat.com>
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
2
3
Lukas reported an hard to reproduce QMP iothread hang on s390 that
3
Introduce the 'event-loop-base' abstract class, it'll hold the
4
QEMU might hang at pthread_join() of the QMP monitor iothread before
4
properties common to all event loops and provide the necessary hooks for
5
quitting:
5
their creation and maintenance. Then have iothread inherit from it.
6
6
7
Thread 1
7
EventLoopBaseClass is defined as user creatable and provides a hook for
8
#0 0x000003ffad10932c in pthread_join
8
its children to attach themselves to the user creatable class 'complete'
9
#1 0x0000000109e95750 in qemu_thread_join
9
function. It also provides an update_params() callback to propagate
10
at /home/thuth/devel/qemu/util/qemu-thread-posix.c:570
10
property changes onto its children.
11
#2 0x0000000109c95a1c in iothread_stop
11
12
#3 0x0000000109bb0874 in monitor_cleanup
12
The new 'event-loop-base' class will live in the root directory. It is
13
#4 0x0000000109b55042 in main
13
built on its own using the 'link_whole' option (there are no direct
14
14
function dependencies between the class and its children, it all happens
15
While the iothread is still in the main loop:
15
trough 'constructor' magic). And also imposes new compilation
16
16
dependencies:
17
Thread 4
17
18
#0 0x000003ffad0010e4 in ??
18
qom <- event-loop-base <- blockdev (iothread.c)
19
#1 0x000003ffad553958 in g_main_context_iterate.isra.19
19
20
#2 0x000003ffad553d90 in g_main_loop_run
20
And in subsequent patches:
21
#3 0x0000000109c9585a in iothread_run
21
22
at /home/thuth/devel/qemu/iothread.c:74
22
qom <- event-loop-base <- qemuutil (util/main-loop.c)
23
#4 0x0000000109e94752 in qemu_thread_start
23
24
at /home/thuth/devel/qemu/util/qemu-thread-posix.c:502
24
All this forced some amount of reordering in meson.build:
25
#5 0x000003ffad10825a in start_thread
25
26
#6 0x000003ffad00dcf2 in thread_start
26
- Moved qom build definition before qemuutil. Doing it the other way
27
27
around (i.e. moving qemuutil after qom) isn't possible as a lot of
28
IMHO it's because there's a race between the main thread and iothread
28
core libraries that live in between the two depend on it.
29
when stopping the thread in following sequence:
29
30
30
- Process the 'hw' subdir earlier, as it introduces files into the
31
main thread iothread
31
'qom' source set.
32
=========== ==============
32
33
aio_poll()
33
No functional changes intended.
34
iothread_get_g_main_context
34
35
set iothread->worker_context
35
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
36
iothread_stop
36
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
37
schedule iothread_stop_bh
37
Acked-by: Markus Armbruster <armbru@redhat.com>
38
execute iothread_stop_bh [1]
38
Message-id: 20220425075723.20019-2-nsaenzju@redhat.com
39
set iothread->running=false
40
(since main_loop==NULL so
41
skip to quit main loop.
42
Note: although main_loop is
43
NULL but worker_context is
44
not!)
45
atomic_read(&iothread->worker_context) [2]
46
create main_loop object
47
g_main_loop_run() [3]
48
pthread_join() [4]
49
50
We can see that when execute iothread_stop_bh() at [1] it's possible
51
that main_loop is still NULL because it's only created until the first
52
check of the worker_context later at [2]. Then the iothread will hang
53
in the main loop [3] and it'll starve the main thread too [4].
54
55
Here the simple solution should be that we check again the "running"
56
variable before check against worker_context.
57
58
CC: Thomas Huth <thuth@redhat.com>
59
CC: Dr. David Alan Gilbert <dgilbert@redhat.com>
60
CC: Stefan Hajnoczi <stefanha@redhat.com>
61
CC: Lukáš Doktor <ldoktor@redhat.com>
62
CC: Markus Armbruster <armbru@redhat.com>
63
CC: Eric Blake <eblake@redhat.com>
64
CC: Paolo Bonzini <pbonzini@redhat.com>
65
Reported-by: Lukáš Doktor <ldoktor@redhat.com>
66
Signed-off-by: Peter Xu <peterx@redhat.com>
67
Tested-by: Thomas Huth <thuth@redhat.com>
68
Message-id: 20190129051432.22023-1-peterx@redhat.com
69
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
39
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
70
---
40
---
71
iothread.c | 6 +++++-
41
qapi/qom.json | 22 +++++--
72
1 file changed, 5 insertions(+), 1 deletion(-)
42
meson.build | 23 ++++---
73
43
include/sysemu/event-loop-base.h | 36 +++++++++++
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
51
diff --git a/qapi/qom.json b/qapi/qom.json
52
index XXXXXXX..XXXXXXX 100644
53
--- a/qapi/qom.json
54
+++ b/qapi/qom.json
55
@@ -XXX,XX +XXX,XX @@
56
'*repeat': 'bool',
57
'*grab-toggle': 'GrabToggleKeys' } }
58
59
+##
60
+# @EventLoopBaseProperties:
61
+#
62
+# Common properties for event loops
63
+#
64
+# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
65
+# 0 means that the engine will use its default.
66
+# (default: 0)
67
+#
68
+# Since: 7.1
69
+##
70
+{ 'struct': 'EventLoopBaseProperties',
71
+ 'data': { '*aio-max-batch': 'int' } }
72
+
73
##
74
# @IothreadProperties:
75
#
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
+}
271
+
272
+static void event_loop_base_set_param(Object *obj, Visitor *v,
273
+ const char *name, void *opaque, Error **errp)
274
+{
275
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(obj);
276
+ EventLoopBase *base = EVENT_LOOP_BASE(obj);
277
+ EventLoopBaseParamInfo *info = opaque;
278
+ int64_t *field = (void *)base + info->offset;
279
+ int64_t value;
280
+
281
+ if (!visit_type_int64(v, name, &value, errp)) {
282
+ return;
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);
74
diff --git a/iothread.c b/iothread.c
339
diff --git a/iothread.c b/iothread.c
75
index XXXXXXX..XXXXXXX 100644
340
index XXXXXXX..XXXXXXX 100644
76
--- a/iothread.c
341
--- a/iothread.c
77
+++ b/iothread.c
342
+++ b/iothread.c
78
@@ -XXX,XX +XXX,XX @@ static void *iothread_run(void *opaque)
343
@@ -XXX,XX +XXX,XX @@
79
while (iothread->running) {
344
#include "qemu/module.h"
80
aio_poll(iothread->ctx, true);
345
#include "block/aio.h"
81
346
#include "block/block.h"
82
- if (atomic_read(&iothread->worker_context)) {
347
+#include "sysemu/event-loop-base.h"
83
+ /*
348
#include "sysemu/iothread.h"
84
+ * We must check the running state again in case it was
349
#include "qapi/error.h"
85
+ * changed in previous aio_poll()
350
#include "qapi/qapi-commands-misc.h"
86
+ */
351
@@ -XXX,XX +XXX,XX @@ static void iothread_init_gcontext(IOThread *iothread)
87
+ if (iothread->running && atomic_read(&iothread->worker_context)) {
352
iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE);
88
GMainLoop *loop;
353
}
89
354
90
g_main_context_push_thread_default(iothread->worker_context);
355
-static void iothread_set_aio_context_params(IOThread *iothread, Error **errp)
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
}
417
}
418
419
-static void iothread_get_aio_param(Object *obj, Visitor *v,
420
- const char *name, void *opaque, Error **errp)
421
-{
422
- IOThreadParamInfo *info = opaque;
423
-
424
- iothread_get_param(obj, v, name, info, errp);
425
-}
426
-
427
-static void iothread_set_aio_param(Object *obj, Visitor *v,
428
- const char *name, void *opaque, Error **errp)
429
-{
430
- IOThread *iothread = IOTHREAD(obj);
431
- IOThreadParamInfo *info = opaque;
432
-
433
- if (!iothread_set_param(obj, v, name, info, errp)) {
434
- return;
435
- }
436
-
437
- if (iothread->ctx) {
438
- aio_context_set_aio_params(iothread->ctx,
439
- iothread->aio_max_batch,
440
- errp);
441
- }
442
-}
443
-
444
static void iothread_class_init(ObjectClass *klass, void *class_data)
445
{
446
- UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
447
- ucc->complete = iothread_complete;
448
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(klass);
449
+
450
+ bc->init = iothread_init;
451
+ bc->update_params = iothread_set_aio_context_params;
452
453
object_class_property_add(klass, "poll-max-ns", "int",
454
iothread_get_poll_param,
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
};
478
479
static void iothread_register_types(void)
480
@@ -XXX,XX +XXX,XX @@ static int query_one_iothread(Object *object, void *opaque)
481
info->poll_max_ns = iothread->poll_max_ns;
482
info->poll_grow = iothread->poll_grow;
483
info->poll_shrink = iothread->poll_shrink;
484
- info->aio_max_batch = iothread->aio_max_batch;
485
+ info->aio_max_batch = iothread->parent_obj.aio_max_batch;
486
487
QAPI_LIST_APPEND(*tail, info);
488
return 0;
91
--
489
--
92
2.20.1
490
2.35.1
93
94
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
2
3
This patch adds the support of DISCARD and WRITE_ZEROES commands,
3
'event-loop-base' provides basic property handling for all 'AioContext'
4
that have been introduced in the virtio-blk protocol to have
4
based event loops. So let's define a new 'MainLoopClass' that inherits
5
better performance when using SSD backend.
5
from it. This will permit tweaking the main loop's properties through
6
6
qapi as well as through the command line using the '-object' keyword[1].
7
We support only one segment per request since multiple segments
7
Only one instance of 'MainLoopClass' might be created at any time.
8
are not widely used and there are no userspace APIs that allow
8
9
applications to submit multiple segments in a single call.
9
'EventLoopBaseClass' learns a new callback, 'can_be_deleted()' so as to
10
10
mark 'MainLoop' as non-deletable.
11
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
11
12
[1] For example:
13
-object main-loop,id=main-loop,aio-max-batch=<value>
14
15
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
17
Acked-by: Markus Armbruster <armbru@redhat.com>
14
Acked-by: Pankaj Gupta <pagupta@redhat.com>
18
Message-id: 20220425075723.20019-3-nsaenzju@redhat.com
15
Message-id: 20190208134950.187665-5-sgarzare@redhat.com
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
---
20
---
18
include/hw/virtio/virtio-blk.h | 2 +
21
qapi/qom.json | 13 ++++++++
19
hw/block/virtio-blk.c | 184 +++++++++++++++++++++++++++++++++
22
meson.build | 3 +-
20
2 files changed, 186 insertions(+)
23
include/qemu/main-loop.h | 10 ++++++
21
24
include/sysemu/event-loop-base.h | 1 +
22
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
25
event-loop-base.c | 13 ++++++++
23
index XXXXXXX..XXXXXXX 100644
26
util/main-loop.c | 56 ++++++++++++++++++++++++++++++++
24
--- a/include/hw/virtio/virtio-blk.h
27
6 files changed, 95 insertions(+), 1 deletion(-)
25
+++ b/include/hw/virtio/virtio-blk.h
28
26
@@ -XXX,XX +XXX,XX @@ struct VirtIOBlkConf
29
diff --git a/qapi/qom.json b/qapi/qom.json
27
uint32_t request_merging;
30
index XXXXXXX..XXXXXXX 100644
28
uint16_t num_queues;
31
--- a/qapi/qom.json
29
uint16_t queue_size;
32
+++ b/qapi/qom.json
30
+ uint32_t max_discard_sectors;
33
@@ -XXX,XX +XXX,XX @@
31
+ uint32_t max_write_zeroes_sectors;
34
'*poll-grow': 'int',
35
'*poll-shrink': 'int' } }
36
37
+##
38
+# @MainLoopProperties:
39
+#
40
+# Properties for the main-loop object.
41
+#
42
+# Since: 7.1
43
+##
44
+{ 'struct': 'MainLoopProperties',
45
+ 'base': 'EventLoopBaseProperties',
46
+ 'data': {} }
47
+
48
##
49
# @MemoryBackendProperties:
50
#
51
@@ -XXX,XX +XXX,XX @@
52
{ 'name': 'input-linux',
53
'if': 'CONFIG_LINUX' },
54
'iothread',
55
+ 'main-loop',
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
68
index XXXXXXX..XXXXXXX 100644
69
--- a/meson.build
70
+++ b/meson.build
71
@@ -XXX,XX +XXX,XX @@ libqemuutil = static_library('qemuutil',
72
sources: util_ss.sources() + stub_ss.sources() + genh,
73
dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman])
74
qemuutil = declare_dependency(link_with: libqemuutil,
75
- sources: genh + version_res)
76
+ sources: genh + version_res,
77
+ dependencies: [event_loop_base])
78
79
if have_system or have_user
80
decodetree = generator(find_program('scripts/decodetree.py'),
81
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
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);
32
};
114
};
33
115
34
struct VirtIOBlockDataPlane;
116
struct EventLoopBase {
35
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
117
diff --git a/event-loop-base.c b/event-loop-base.c
36
index XXXXXXX..XXXXXXX 100644
118
index XXXXXXX..XXXXXXX 100644
37
--- a/hw/block/virtio-blk.c
119
--- a/event-loop-base.c
38
+++ b/hw/block/virtio-blk.c
120
+++ b/event-loop-base.c
39
@@ -XXX,XX +XXX,XX @@ out:
121
@@ -XXX,XX +XXX,XX @@ static void event_loop_base_complete(UserCreatable *uc, Error **errp)
40
aio_context_release(blk_get_aio_context(s->conf.conf.blk));
122
}
41
}
123
}
42
124
43
+static void virtio_blk_discard_write_zeroes_complete(void *opaque, int ret)
125
+static bool event_loop_base_can_be_deleted(UserCreatable *uc)
44
+{
126
+{
45
+ VirtIOBlockReq *req = opaque;
127
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc);
46
+ VirtIOBlock *s = req->dev;
128
+ EventLoopBase *backend = EVENT_LOOP_BASE(uc);
47
+ bool is_write_zeroes = (virtio_ldl_p(VIRTIO_DEVICE(s), &req->out.type) &
129
+
48
+ ~VIRTIO_BLK_T_BARRIER) == VIRTIO_BLK_T_WRITE_ZEROES;
130
+ if (bc->can_be_deleted) {
49
+
131
+ return bc->can_be_deleted(backend);
50
+ aio_context_acquire(blk_get_aio_context(s->conf.conf.blk));
51
+ if (ret) {
52
+ if (virtio_blk_handle_rw_error(req, -ret, false, is_write_zeroes)) {
53
+ goto out;
54
+ }
55
+ }
132
+ }
56
+
133
+
57
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
134
+ return true;
58
+ if (is_write_zeroes) {
135
+}
59
+ block_acct_done(blk_get_stats(s->blk), &req->acct);
136
+
60
+ }
137
static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
61
+ virtio_blk_free_request(req);
138
{
62
+
139
UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
63
+out:
140
ucc->complete = event_loop_base_complete;
64
+ aio_context_release(blk_get_aio_context(s->conf.conf.blk));
141
+ ucc->can_be_deleted = event_loop_base_can_be_deleted;
65
+}
142
66
+
143
object_class_property_add(klass, "aio-max-batch", "int",
67
#ifdef __linux__
144
event_loop_base_get_param,
68
145
diff --git a/util/main-loop.c b/util/main-loop.c
69
typedef struct {
146
index XXXXXXX..XXXXXXX 100644
70
@@ -XXX,XX +XXX,XX @@ static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
147
--- a/util/main-loop.c
71
return true;
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;
72
}
159
}
73
160
74
+static uint8_t virtio_blk_handle_discard_write_zeroes(VirtIOBlockReq *req,
161
+static void main_loop_update_params(EventLoopBase *base, Error **errp)
75
+ struct virtio_blk_discard_write_zeroes *dwz_hdr, bool is_write_zeroes)
162
+{
76
+{
163
+ if (!qemu_aio_context) {
77
+ VirtIOBlock *s = req->dev;
164
+ error_setg(errp, "qemu aio context not ready");
78
+ VirtIODevice *vdev = VIRTIO_DEVICE(s);
79
+ uint64_t sector;
80
+ uint32_t num_sectors, flags, max_sectors;
81
+ uint8_t err_status;
82
+ int bytes;
83
+
84
+ sector = virtio_ldq_p(vdev, &dwz_hdr->sector);
85
+ num_sectors = virtio_ldl_p(vdev, &dwz_hdr->num_sectors);
86
+ flags = virtio_ldl_p(vdev, &dwz_hdr->flags);
87
+ max_sectors = is_write_zeroes ? s->conf.max_write_zeroes_sectors :
88
+ s->conf.max_discard_sectors;
89
+
90
+ /*
91
+ * max_sectors is at most BDRV_REQUEST_MAX_SECTORS, this check
92
+ * make us sure that "num_sectors << BDRV_SECTOR_BITS" can fit in
93
+ * the integer variable.
94
+ */
95
+ if (unlikely(num_sectors > max_sectors)) {
96
+ err_status = VIRTIO_BLK_S_IOERR;
97
+ goto err;
98
+ }
99
+
100
+ bytes = num_sectors << BDRV_SECTOR_BITS;
101
+
102
+ if (unlikely(!virtio_blk_sect_range_ok(s, sector, bytes))) {
103
+ err_status = VIRTIO_BLK_S_IOERR;
104
+ goto err;
105
+ }
106
+
107
+ /*
108
+ * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for discard
109
+ * and write zeroes commands if any unknown flag is set.
110
+ */
111
+ if (unlikely(flags & ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) {
112
+ err_status = VIRTIO_BLK_S_UNSUPP;
113
+ goto err;
114
+ }
115
+
116
+ if (is_write_zeroes) { /* VIRTIO_BLK_T_WRITE_ZEROES */
117
+ int blk_aio_flags = 0;
118
+
119
+ if (flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) {
120
+ blk_aio_flags |= BDRV_REQ_MAY_UNMAP;
121
+ }
122
+
123
+ block_acct_start(blk_get_stats(s->blk), &req->acct, bytes,
124
+ BLOCK_ACCT_WRITE);
125
+
126
+ blk_aio_pwrite_zeroes(s->blk, sector << BDRV_SECTOR_BITS,
127
+ bytes, blk_aio_flags,
128
+ virtio_blk_discard_write_zeroes_complete, req);
129
+ } else { /* VIRTIO_BLK_T_DISCARD */
130
+ /*
131
+ * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for
132
+ * discard commands if the unmap flag is set.
133
+ */
134
+ if (unlikely(flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) {
135
+ err_status = VIRTIO_BLK_S_UNSUPP;
136
+ goto err;
137
+ }
138
+
139
+ blk_aio_pdiscard(s->blk, sector << BDRV_SECTOR_BITS, bytes,
140
+ virtio_blk_discard_write_zeroes_complete, req);
141
+ }
142
+
143
+ return VIRTIO_BLK_S_OK;
144
+
145
+err:
146
+ if (is_write_zeroes) {
147
+ block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_WRITE);
148
+ }
149
+ return err_status;
150
+}
151
+
152
static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
153
{
154
uint32_t type;
155
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
156
virtio_blk_free_request(req);
157
break;
158
}
159
+ /*
160
+ * VIRTIO_BLK_T_DISCARD and VIRTIO_BLK_T_WRITE_ZEROES are defined with
161
+ * VIRTIO_BLK_T_OUT flag set. We masked this flag in the switch statement,
162
+ * so we must mask it for these requests, then we will check if it is set.
163
+ */
164
+ case VIRTIO_BLK_T_DISCARD & ~VIRTIO_BLK_T_OUT:
165
+ case VIRTIO_BLK_T_WRITE_ZEROES & ~VIRTIO_BLK_T_OUT:
166
+ {
167
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
168
+ size_t out_len = iov_size(out_iov, out_num);
169
+ bool is_write_zeroes = (type & ~VIRTIO_BLK_T_BARRIER) ==
170
+ VIRTIO_BLK_T_WRITE_ZEROES;
171
+ uint8_t err_status;
172
+
173
+ /*
174
+ * Unsupported if VIRTIO_BLK_T_OUT is not set or the request contains
175
+ * more than one segment.
176
+ */
177
+ if (unlikely(!(type & VIRTIO_BLK_T_OUT) ||
178
+ out_len > sizeof(dwz_hdr))) {
179
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
180
+ virtio_blk_free_request(req);
181
+ return 0;
182
+ }
183
+
184
+ if (unlikely(iov_to_buf(out_iov, out_num, 0, &dwz_hdr,
185
+ sizeof(dwz_hdr)) != sizeof(dwz_hdr))) {
186
+ virtio_error(vdev, "virtio-blk discard/write_zeroes header"
187
+ " too short");
188
+ return -1;
189
+ }
190
+
191
+ err_status = virtio_blk_handle_discard_write_zeroes(req, &dwz_hdr,
192
+ is_write_zeroes);
193
+ if (err_status != VIRTIO_BLK_S_OK) {
194
+ virtio_blk_req_complete(req, err_status);
195
+ virtio_blk_free_request(req);
196
+ }
197
+
198
+ break;
199
+ }
200
default:
201
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
202
virtio_blk_free_request(req);
203
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
204
blkcfg.alignment_offset = 0;
205
blkcfg.wce = blk_enable_write_cache(s->blk);
206
virtio_stw_p(vdev, &blkcfg.num_queues, s->conf.num_queues);
207
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_DISCARD)) {
208
+ virtio_stl_p(vdev, &blkcfg.max_discard_sectors,
209
+ s->conf.max_discard_sectors);
210
+ virtio_stl_p(vdev, &blkcfg.discard_sector_alignment,
211
+ blk_size >> BDRV_SECTOR_BITS);
212
+ /*
213
+ * We support only one segment per request since multiple segments
214
+ * are not widely used and there are no userspace APIs that allow
215
+ * applications to submit multiple segments in a single call.
216
+ */
217
+ virtio_stl_p(vdev, &blkcfg.max_discard_seg, 1);
218
+ }
219
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_WRITE_ZEROES)) {
220
+ virtio_stl_p(vdev, &blkcfg.max_write_zeroes_sectors,
221
+ s->conf.max_write_zeroes_sectors);
222
+ blkcfg.write_zeroes_may_unmap = 1;
223
+ virtio_stl_p(vdev, &blkcfg.max_write_zeroes_seg, 1);
224
+ }
225
memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
226
}
227
228
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
229
return;
230
}
231
232
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_DISCARD) &&
233
+ (!conf->max_discard_sectors ||
234
+ conf->max_discard_sectors > BDRV_REQUEST_MAX_SECTORS)) {
235
+ error_setg(errp, "invalid max-discard-sectors property (%" PRIu32 ")"
236
+ ", must be between 1 and %d",
237
+ conf->max_discard_sectors, (int)BDRV_REQUEST_MAX_SECTORS);
238
+ return;
165
+ return;
239
+ }
166
+ }
240
+
167
+
241
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_WRITE_ZEROES) &&
168
+ aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
242
+ (!conf->max_write_zeroes_sectors ||
169
+}
243
+ conf->max_write_zeroes_sectors > BDRV_REQUEST_MAX_SECTORS)) {
170
+
244
+ error_setg(errp, "invalid max-write-zeroes-sectors property (%" PRIu32
171
+MainLoop *mloop;
245
+ "), must be between 1 and %d",
172
+
246
+ conf->max_write_zeroes_sectors,
173
+static void main_loop_init(EventLoopBase *base, Error **errp)
247
+ (int)BDRV_REQUEST_MAX_SECTORS);
174
+{
175
+ MainLoop *m = MAIN_LOOP(base);
176
+
177
+ if (mloop) {
178
+ error_setg(errp, "only one main-loop instance allowed");
248
+ return;
179
+ return;
249
+ }
180
+ }
250
+
181
+
251
virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
182
+ main_loop_update_params(base, errp);
252
sizeof(struct virtio_blk_config));
183
+
253
184
+ mloop = m;
254
@@ -XXX,XX +XXX,XX @@ static Property virtio_blk_properties[] = {
185
+ return;
255
VIRTIO_BLK_F_DISCARD, true),
186
+}
256
DEFINE_PROP_BIT64("write-zeroes", VirtIOBlock, host_features,
187
+
257
VIRTIO_BLK_F_WRITE_ZEROES, true),
188
+static bool main_loop_can_be_deleted(EventLoopBase *base)
258
+ DEFINE_PROP_UINT32("max-discard-sectors", VirtIOBlock,
189
+{
259
+ conf.max_discard_sectors, BDRV_REQUEST_MAX_SECTORS),
190
+ return false;
260
+ DEFINE_PROP_UINT32("max-write-zeroes-sectors", VirtIOBlock,
191
+}
261
+ conf.max_write_zeroes_sectors, BDRV_REQUEST_MAX_SECTORS),
192
+
262
DEFINE_PROP_END_OF_LIST(),
193
+static void main_loop_class_init(ObjectClass *oc, void *class_data)
263
};
194
+{
264
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
265
--
219
--
266
2.20.1
220
2.35.1
267
268
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
2
3
In several part we still using req->dev or VIRTIO_DEVICE(req->dev)
3
The thread pool regulates itself: when idle, it kills threads until
4
when we have already defined s and vdev pointers:
4
empty, when in demand, it creates new threads until full. This behaviour
5
VirtIOBlock *s = req->dev;
5
doesn't play well with latency sensitive workloads where the price of
6
VirtIODevice *vdev = VIRTIO_DEVICE(s);
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.
7
9
8
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
10
In order to mitigate this let's introduce a new 'EventLoopBase'
9
Reviewed-by: Liam Merwick <liam.merwick@oracle.com>
11
property to set the thread pool size. The threads will be created during
10
Message-id: 20190208142347.214815-1-sgarzare@redhat.com
12
the pool's initialization or upon updating the property's value, remain
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
17
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Acked-by: Markus Armbruster <armbru@redhat.com>
20
Message-id: 20220425075723.20019-4-nsaenzju@redhat.com
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
22
---
13
hw/block/virtio-blk.c | 22 +++++++++-------------
23
qapi/qom.json | 10 +++++-
14
1 file changed, 9 insertions(+), 13 deletions(-)
24
include/block/aio.h | 10 ++++++
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(-)
15
34
16
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
35
diff --git a/qapi/qom.json b/qapi/qom.json
17
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/block/virtio-blk.c
37
--- a/qapi/qom.json
19
+++ b/hw/block/virtio-blk.c
38
+++ b/qapi/qom.json
20
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
39
@@ -XXX,XX +XXX,XX @@
21
static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
40
# 0 means that the engine will use its default.
22
bool is_read)
41
# (default: 0)
42
#
43
+# @thread-pool-min: minimum number of threads reserved in the thread pool
44
+# (default:0)
45
+#
46
+# @thread-pool-max: maximum number of threads the thread pool can contain
47
+# (default:64)
48
+#
49
# Since: 7.1
50
##
51
{ 'struct': 'EventLoopBaseProperties',
52
- 'data': { '*aio-max-batch': 'int' } }
53
+ 'data': { '*aio-max-batch': 'int',
54
+ '*thread-pool-min': 'int',
55
+ '*thread-pool-max': 'int' } }
56
57
##
58
# @IothreadProperties:
59
diff --git a/include/block/aio.h b/include/block/aio.h
60
index XXXXXXX..XXXXXXX 100644
61
--- a/include/block/aio.h
62
+++ b/include/block/aio.h
63
@@ -XXX,XX +XXX,XX @@ struct AioContext {
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
+
95
typedef int ThreadPoolFunc(void *opaque);
96
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
+ }
229
+
230
+ ctx->thread_pool_min = min;
231
+ ctx->thread_pool_max = max;
232
+
233
+ if (ctx->thread_pool) {
234
+ thread_pool_update_params(ctx->thread_pool, ctx);
235
+ }
236
+}
237
diff --git a/util/main-loop.c b/util/main-loop.c
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)
23
{
252
{
24
- BlockErrorAction action = blk_get_error_action(req->dev->blk,
253
+ ERRP_GUARD();
25
- is_read, error);
254
+
26
VirtIOBlock *s = req->dev;
255
if (!qemu_aio_context) {
27
+ BlockErrorAction action = blk_get_error_action(s->blk, is_read, error);
256
error_setg(errp, "qemu aio context not ready");
28
257
return;
29
if (action == BLOCK_ERROR_ACTION_STOP) {
30
/* Break the link as the next request is going to be parsed from the
31
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_flush_complete(void *opaque, int ret)
32
}
258
}
33
259
34
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
260
aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
35
- block_acct_done(blk_get_stats(req->dev->blk), &req->acct);
261
+ if (*errp) {
36
+ block_acct_done(blk_get_stats(s->blk), &req->acct);
262
+ return;
37
virtio_blk_free_request(req);
263
+ }
38
264
+
39
out:
265
+ aio_context_set_thread_pool_params(qemu_aio_context, base->thread_pool_min,
40
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
266
+ base->thread_pool_max, errp);
41
- sizeof(struct virtio_blk_inhdr);
267
}
42
iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr));
268
43
269
MainLoop *mloop;
44
- type = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);
270
diff --git a/util/thread-pool.c b/util/thread-pool.c
45
+ type = virtio_ldl_p(vdev, &req->out.type);
271
index XXXXXXX..XXXXXXX 100644
46
272
--- a/util/thread-pool.c
47
/* VIRTIO_BLK_T_OUT defines the command direction. VIRTIO_BLK_T_BARRIER
273
+++ b/util/thread-pool.c
48
* is an optional flag. Although a guest should not send this flag if
274
@@ -XXX,XX +XXX,XX @@ struct ThreadPool {
49
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
275
QemuMutex lock;
50
case VIRTIO_BLK_T_IN:
276
QemuCond worker_stopped;
51
{
277
QemuSemaphore sem;
52
bool is_write = type & VIRTIO_BLK_T_OUT;
278
- int max_threads;
53
- req->sector_num = virtio_ldq_p(VIRTIO_DEVICE(req->dev),
279
QEMUBH *new_thread_bh;
54
- &req->out.sector);
280
55
+ req->sector_num = virtio_ldq_p(vdev, &req->out.sector);
281
/* The following variables are only accessed from one AioContext. */
56
282
@@ -XXX,XX +XXX,XX @@ struct ThreadPool {
57
if (is_write) {
283
int new_threads; /* backlog of threads we need to create */
58
qemu_iovec_init_external(&req->qiov, out_iov, out_num);
284
int pending_threads; /* threads created but not running yet */
59
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
285
bool stopping;
60
req->qiov.size / BDRV_SECTOR_SIZE);
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;
61
}
320
}
62
321
63
- if (!virtio_blk_sect_range_ok(req->dev, req->sector_num,
322
@@ -XXX,XX +XXX,XX @@ void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg)
64
- req->qiov.size)) {
323
thread_pool_submit_aio(pool, func, arg, NULL, NULL);
65
+ if (!virtio_blk_sect_range_ok(s, req->sector_num, req->qiov.size)) {
324
}
66
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
325
67
- block_acct_invalid(blk_get_stats(req->dev->blk),
326
+void thread_pool_update_params(ThreadPool *pool, AioContext *ctx)
68
+ block_acct_invalid(blk_get_stats(s->blk),
327
+{
69
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
328
+ qemu_mutex_lock(&pool->lock);
70
virtio_blk_free_request(req);
329
+
71
return 0;
330
+ pool->min_threads = ctx->thread_pool_min;
72
}
331
+ pool->max_threads = ctx->thread_pool_max;
73
332
+
74
- block_acct_start(blk_get_stats(req->dev->blk),
333
+ /*
75
- &req->acct, req->qiov.size,
334
+ * We either have to:
76
+ block_acct_start(blk_get_stats(s->blk), &req->acct, req->qiov.size,
335
+ * - Increase the number available of threads until over the min_threads
77
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
336
+ * threshold.
78
337
+ * - Decrease the number of available threads until under the max_threads
79
/* merge would exceed maximum number of requests or IO direction
338
+ * threshold.
80
* changes */
339
+ * - Do nothing. The current number of threads fall in between the min and
81
if (mrb->num_reqs > 0 && (mrb->num_reqs == VIRTIO_BLK_MAX_MERGE_REQS ||
340
+ * max thresholds. We'll let the pool manage itself.
82
is_write != mrb->is_write ||
341
+ */
83
- !req->dev->conf.request_merging)) {
342
+ for (int i = pool->cur_threads; i < pool->min_threads; i++) {
84
- virtio_blk_submit_multireq(req->dev->blk, mrb);
343
+ spawn_thread(pool);
85
+ !s->conf.request_merging)) {
344
+ }
86
+ virtio_blk_submit_multireq(s->blk, mrb);
345
+
87
}
346
+ for (int i = pool->cur_threads; i > pool->max_threads; i--) {
88
347
+ qemu_sem_post(&pool->sem);
89
assert(mrb->num_reqs < VIRTIO_BLK_MAX_MERGE_REQS);
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)
90
--
370
--
91
2.20.1
371
2.35.1
92
93
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
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.
2
5
3
If the WRITE_ZEROES feature is enabled, we check this command
6
It failed to convert the ctrl and event virtqueue handler functions,
4
in the test_basic().
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.
5
10
6
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
11
Convert the ctrl and event virtqueue handler functions now so they
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
operate correctly when called from the dataplane code path. Avoid code
8
Acked-by: Thomas Huth <thuth@redhat.com>
13
duplication by extracting this code into a helper function.
9
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
14
10
Acked-by: Pankaj Gupta <pagupta@redhat.com>
15
Fixes: f34e8d8b8d48d73f36a67b6d5e492ef9784b5012 ("virtio-scsi: prepare virtio_scsi_handle_cmd for dataplane")
11
Message-id: 20190208134950.187665-7-sgarzare@redhat.com
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]
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
23
---
14
tests/virtio-blk-test.c | 60 +++++++++++++++++++++++++++++++++++++++++
24
hw/scsi/virtio-scsi.c | 42 +++++++++++++++++++++++++++---------------
15
1 file changed, 60 insertions(+)
25
1 file changed, 27 insertions(+), 15 deletions(-)
16
26
17
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
27
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
18
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/virtio-blk-test.c
29
--- a/hw/scsi/virtio-scsi.c
20
+++ b/tests/virtio-blk-test.c
30
+++ b/hw/scsi/virtio-scsi.c
21
@@ -XXX,XX +XXX,XX @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
31
@@ -XXX,XX +XXX,XX @@ bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
22
32
return progress;
23
guest_free(alloc, req_addr);
33
}
24
34
25
+ if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
35
+/*
26
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
36
+ * If dataplane is configured but not yet started, do so now and return true on
27
+ void *expected;
37
+ * success.
28
+
38
+ *
29
+ /*
39
+ * Dataplane is started by the core virtio code but virtqueue handler functions
30
+ * WRITE_ZEROES request on the same sector of previous test where
40
+ * can also be invoked when a guest kicks before DRIVER_OK, so this helper
31
+ * we wrote "TEST".
41
+ * function helps us deal with manually starting ioeventfd in that case.
32
+ */
42
+ */
33
+ req.type = VIRTIO_BLK_T_WRITE_ZEROES;
43
+static bool virtio_scsi_defer_to_dataplane(VirtIOSCSI *s)
34
+ req.data = (char *) &dwz_hdr;
44
+{
35
+ dwz_hdr.sector = 0;
45
+ if (!s->ctx || s->dataplane_started) {
36
+ dwz_hdr.num_sectors = 1;
46
+ return false;
37
+ dwz_hdr.flags = 0;
38
+
39
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
40
+
41
+ free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
42
+ qvirtqueue_add(vq, req_addr + 16, sizeof(dwz_hdr), false, true);
43
+ qvirtqueue_add(vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false);
44
+
45
+ qvirtqueue_kick(dev, vq, free_head);
46
+
47
+ qvirtio_wait_used_elem(dev, vq, free_head, NULL,
48
+ QVIRTIO_BLK_TIMEOUT_US);
49
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
50
+ g_assert_cmpint(status, ==, 0);
51
+
52
+ guest_free(alloc, req_addr);
53
+
54
+ /* Read request to check if the sector contains all zeroes */
55
+ req.type = VIRTIO_BLK_T_IN;
56
+ req.ioprio = 1;
57
+ req.sector = 0;
58
+ req.data = g_malloc0(512);
59
+
60
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
61
+
62
+ g_free(req.data);
63
+
64
+ free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
65
+ qvirtqueue_add(vq, req_addr + 16, 512, true, true);
66
+ qvirtqueue_add(vq, req_addr + 528, 1, true, false);
67
+
68
+ qvirtqueue_kick(dev, vq, free_head);
69
+
70
+ qvirtio_wait_used_elem(dev, vq, free_head, NULL,
71
+ QVIRTIO_BLK_TIMEOUT_US);
72
+ status = readb(req_addr + 528);
73
+ g_assert_cmpint(status, ==, 0);
74
+
75
+ data = g_malloc(512);
76
+ expected = g_malloc0(512);
77
+ memread(req_addr + 16, data, 512);
78
+ g_assert_cmpmem(data, 512, expected, 512);
79
+ g_free(expected);
80
+ g_free(data);
81
+
82
+ guest_free(alloc, req_addr);
83
+ }
47
+ }
84
+
48
+
85
if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
49
+ virtio_device_start_ioeventfd(&s->parent_obj.parent_obj);
86
/* Write and read with 2 descriptor layout */
50
+ return !s->dataplane_fenced;
87
/* Write request */
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);
88
--
101
--
89
2.20.1
102
2.35.1
90
91
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
The virtio-scsi event virtqueue is not emptied by its handler function.
2
This is typical for rx virtqueues where the device uses buffers when
3
some event occurs (e.g. a packet is received, an error condition
4
happens, etc).
2
5
3
The size of data in the virtio_blk_request must be a multiple
6
Polling non-empty virtqueues wastes CPU cycles. We are not waiting for
4
of 512 bytes for IN and OUT requests, or a multiple of the size
7
new buffers to become available, we are waiting for an event to occur,
5
of struct virtio_blk_discard_write_zeroes for DISCARD and
8
so it's a misuse of CPU resources to poll for buffers.
6
WRITE_ZEROES requests.
7
9
8
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
10
Introduce the new virtio_queue_aio_attach_host_notifier_no_poll() API,
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
which is identical to virtio_queue_aio_attach_host_notifier() except
10
Reviewed-by: Thomas Huth <thuth@redhat.com>
12
that it does not poll the virtqueue.
11
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
13
12
Acked-by: Pankaj Gupta <pagupta@redhat.com>
14
Before this patch the following command-line consumed 100% CPU in the
13
Message-id: 20190208134950.187665-6-sgarzare@redhat.com
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>
27
Tested-by: Nir Soffer <nsoffer@redhat.com>
28
Message-id: 20220427143541.119567-3-stefanha@redhat.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
29
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
30
---
16
tests/virtio-blk-test.c | 15 ++++++++++++++-
31
include/hw/virtio/virtio.h | 1 +
17
1 file changed, 14 insertions(+), 1 deletion(-)
32
hw/scsi/virtio-scsi-dataplane.c | 2 +-
33
hw/virtio/virtio.c | 13 +++++++++++++
34
3 files changed, 15 insertions(+), 1 deletion(-)
18
35
19
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
36
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
20
index XXXXXXX..XXXXXXX 100644
37
index XXXXXXX..XXXXXXX 100644
21
--- a/tests/virtio-blk-test.c
38
--- a/include/hw/virtio/virtio.h
22
+++ b/tests/virtio-blk-test.c
39
+++ b/include/hw/virtio/virtio.h
23
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
40
@@ -XXX,XX +XXX,XX @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
24
uint64_t addr;
41
void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled);
25
uint8_t status = 0xFF;
42
void virtio_queue_host_notifier_read(EventNotifier *n);
26
43
void virtio_queue_aio_attach_host_notifier(VirtQueue *vq, AioContext *ctx);
27
- g_assert_cmpuint(data_size % 512, ==, 0);
44
+void virtio_queue_aio_attach_host_notifier_no_poll(VirtQueue *vq, AioContext *ctx);
28
+ switch (req->type) {
45
void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx);
29
+ case VIRTIO_BLK_T_IN:
46
VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector);
30
+ case VIRTIO_BLK_T_OUT:
47
VirtQueue *virtio_vector_next_queue(VirtQueue *vq);
31
+ g_assert_cmpuint(data_size % 512, ==, 0);
48
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
32
+ break;
49
index XXXXXXX..XXXXXXX 100644
33
+ case VIRTIO_BLK_T_DISCARD:
50
--- a/hw/scsi/virtio-scsi-dataplane.c
34
+ case VIRTIO_BLK_T_WRITE_ZEROES:
51
+++ b/hw/scsi/virtio-scsi-dataplane.c
35
+ g_assert_cmpuint(data_size %
52
@@ -XXX,XX +XXX,XX @@ int virtio_scsi_dataplane_start(VirtIODevice *vdev)
36
+ sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
53
37
+ break;
54
aio_context_acquire(s->ctx);
38
+ default:
55
virtio_queue_aio_attach_host_notifier(vs->ctrl_vq, s->ctx);
39
+ g_assert_cmpuint(data_size, ==, 0);
56
- virtio_queue_aio_attach_host_notifier(vs->event_vq, s->ctx);
40
+ }
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
}
68
69
+/*
70
+ * Same as virtio_queue_aio_attach_host_notifier() but without polling. Use
71
+ * this for rx virtqueues and similar cases where the virtqueue handler
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
+ */
75
+void virtio_queue_aio_attach_host_notifier_no_poll(VirtQueue *vq, AioContext *ctx)
76
+{
77
+ aio_set_event_notifier(ctx, &vq->host_notifier, true,
78
+ virtio_queue_host_notifier_read,
79
+ NULL, NULL);
80
+}
41
+
81
+
42
addr = guest_alloc(alloc, sizeof(*req) + data_size);
82
void virtio_queue_aio_detach_host_notifier(VirtQueue *vq, AioContext *ctx)
43
83
{
44
virtio_blk_fix_request(d, req);
84
aio_set_event_notifier(ctx, &vq->host_notifier, true, NULL, NULL, NULL);
45
--
85
--
46
2.20.1
86
2.35.1
47
48
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
virtio_scsi_handle_event_vq() is only called from hw/scsi/virtio-scsi.c
2
now and its return value is no longer used. Remove the function
3
prototype from virtio-scsi.h and drop the return value.
2
4
3
Since configurable features for virtio-blk are growing, this patch
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
adds host_features field in the struct VirtIOBlock. (as in virtio-net)
6
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
5
In this way, we can avoid to add new fields for new properties and
7
Message-id: 20220427143541.119567-4-stefanha@redhat.com
6
we can directly set VIRTIO_BLK_F* flags in the host_features.
7
8
We update "config-wce" and "scsi" property definition to use the new
9
host_features field without change the behaviour.
10
11
Suggested-by: Michael S. Tsirkin <mst@redhat.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
14
Acked-by: Pankaj Gupta <pagupta@redhat.com>
15
Message-id: 20190208134950.187665-3-sgarzare@redhat.com
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
---
9
---
18
include/hw/virtio/virtio-blk.h | 3 +--
10
include/hw/virtio/virtio-scsi.h | 1 -
19
hw/block/virtio-blk.c | 16 +++++++++-------
11
hw/scsi/virtio-scsi.c | 4 +---
20
2 files changed, 10 insertions(+), 9 deletions(-)
12
2 files changed, 1 insertion(+), 4 deletions(-)
21
13
22
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
14
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
23
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
24
--- a/include/hw/virtio/virtio-blk.h
16
--- a/include/hw/virtio/virtio-scsi.h
25
+++ b/include/hw/virtio/virtio-blk.h
17
+++ b/include/hw/virtio/virtio-scsi.h
26
@@ -XXX,XX +XXX,XX @@ struct VirtIOBlkConf
18
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_common_realize(DeviceState *dev,
27
BlockConf conf;
19
Error **errp);
28
IOThread *iothread;
20
29
char *serial;
21
void virtio_scsi_common_unrealize(DeviceState *dev);
30
- uint32_t scsi;
22
-bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq);
31
- uint32_t config_wce;
23
bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq);
32
uint32_t request_merging;
24
bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq);
33
uint16_t num_queues;
25
void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req);
34
uint16_t queue_size;
26
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
35
@@ -XXX,XX +XXX,XX @@ typedef struct VirtIOBlock {
36
bool dataplane_disabled;
37
bool dataplane_started;
38
struct VirtIOBlockDataPlane *dataplane;
39
+ uint64_t host_features;
40
} VirtIOBlock;
41
42
typedef struct VirtIOBlockReq {
43
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
44
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
45
--- a/hw/block/virtio-blk.c
28
--- a/hw/scsi/virtio-scsi.c
46
+++ b/hw/block/virtio-blk.c
29
+++ b/hw/scsi/virtio-scsi.c
47
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_scsi_req(VirtIOBlockReq *req)
30
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
48
*/
31
virtio_scsi_complete_req(req);
49
scsi = (void *)elem->in_sg[elem->in_num - 2].iov_base;
32
}
50
33
51
- if (!blk->conf.scsi) {
34
-bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq)
52
+ if (!virtio_has_feature(blk->host_features, VIRTIO_BLK_F_SCSI)) {
35
+static void virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq)
53
status = VIRTIO_BLK_S_UNSUPP;
36
{
54
goto fail;
37
if (s->events_dropped) {
38
virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
39
- return true;
55
}
40
}
56
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
41
- return false;
57
{
42
}
58
VirtIOBlock *s = VIRTIO_BLK(vdev);
43
59
44
static void virtio_scsi_handle_event(VirtIODevice *vdev, VirtQueue *vq)
60
+ /* Firstly sync all virtio-blk possible supported features */
61
+ features |= s->host_features;
62
+
63
virtio_add_feature(&features, VIRTIO_BLK_F_SEG_MAX);
64
virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY);
65
virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY);
66
virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE);
67
if (virtio_has_feature(features, VIRTIO_F_VERSION_1)) {
68
- if (s->conf.scsi) {
69
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_SCSI)) {
70
error_setg(errp, "Please set scsi=off for virtio-blk devices in order to use virtio 1.0");
71
return 0;
72
}
73
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
74
virtio_add_feature(&features, VIRTIO_BLK_F_SCSI);
75
}
76
77
- if (s->conf.config_wce) {
78
- virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE);
79
- }
80
if (blk_enable_write_cache(s->blk)) {
81
virtio_add_feature(&features, VIRTIO_BLK_F_WCE);
82
}
83
@@ -XXX,XX +XXX,XX @@ static Property virtio_blk_properties[] = {
84
DEFINE_BLOCK_ERROR_PROPERTIES(VirtIOBlock, conf.conf),
85
DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, conf.conf),
86
DEFINE_PROP_STRING("serial", VirtIOBlock, conf.serial),
87
- DEFINE_PROP_BIT("config-wce", VirtIOBlock, conf.config_wce, 0, true),
88
+ DEFINE_PROP_BIT64("config-wce", VirtIOBlock, host_features,
89
+ VIRTIO_BLK_F_CONFIG_WCE, true),
90
#ifdef __linux__
91
- DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, false),
92
+ DEFINE_PROP_BIT64("scsi", VirtIOBlock, host_features,
93
+ VIRTIO_BLK_F_SCSI, false),
94
#endif
95
DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
96
true),
97
--
45
--
98
2.20.1
46
2.35.1
99
100
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
virtio_scsi_handle_ctrl_vq() is only called from hw/scsi/virtio-scsi.c
2
now and its return value is no longer used. Remove the function
3
prototype from virtio-scsi.h and drop the return value.
2
4
3
We add acct_failed param in order to use virtio_blk_handle_rw_error()
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
also when is not required to call block_acct_failed(). (eg. a discard
6
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
5
operation is failed)
7
Message-id: 20220427143541.119567-5-stefanha@redhat.com
6
7
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
10
Acked-by: Pankaj Gupta <pagupta@redhat.com>
11
Message-id: 20190208134950.187665-2-sgarzare@redhat.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
9
---
14
hw/block/virtio-blk.c | 10 ++++++----
10
include/hw/virtio/virtio-scsi.h | 1 -
15
1 file changed, 6 insertions(+), 4 deletions(-)
11
hw/scsi/virtio-scsi.c | 5 +----
12
2 files changed, 1 insertion(+), 5 deletions(-)
16
13
17
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
14
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
18
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/block/virtio-blk.c
16
--- a/include/hw/virtio/virtio-scsi.h
20
+++ b/hw/block/virtio-blk.c
17
+++ b/include/hw/virtio/virtio-scsi.h
21
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
18
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_common_realize(DeviceState *dev,
19
20
void virtio_scsi_common_unrealize(DeviceState *dev);
21
bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq);
22
-bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq);
23
void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req);
24
void virtio_scsi_free_req(VirtIOSCSIReq *req);
25
void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
26
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/scsi/virtio-scsi.c
29
+++ b/hw/scsi/virtio-scsi.c
30
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_ctrl_req(VirtIOSCSI *s, VirtIOSCSIReq *req)
31
}
22
}
32
}
23
33
24
static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
34
-bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
25
- bool is_read)
35
+static void virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
26
+ bool is_read, bool acct_failed)
27
{
36
{
28
VirtIOBlock *s = req->dev;
37
VirtIOSCSIReq *req;
29
BlockErrorAction action = blk_get_error_action(s->blk, is_read, error);
38
- bool progress = false;
30
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
39
31
s->rq = req;
40
while ((req = virtio_scsi_pop_req(s, vq))) {
32
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
41
- progress = true;
33
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
42
virtio_scsi_handle_ctrl_req(s, req);
34
- block_acct_failed(blk_get_stats(s->blk), &req->acct);
35
+ if (acct_failed) {
36
+ block_acct_failed(blk_get_stats(s->blk), &req->acct);
37
+ }
38
virtio_blk_free_request(req);
39
}
43
}
40
44
- return progress;
41
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_rw_complete(void *opaque, int ret)
45
}
42
* the memory until the request is completed (which will
46
43
* happen on the other side of the migration).
47
/*
44
*/
45
- if (virtio_blk_handle_rw_error(req, -ret, is_read)) {
46
+ if (virtio_blk_handle_rw_error(req, -ret, is_read, true)) {
47
continue;
48
}
49
}
50
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_flush_complete(void *opaque, int ret)
51
52
aio_context_acquire(blk_get_aio_context(s->conf.conf.blk));
53
if (ret) {
54
- if (virtio_blk_handle_rw_error(req, -ret, 0)) {
55
+ if (virtio_blk_handle_rw_error(req, -ret, 0, true)) {
56
goto out;
57
}
58
}
59
--
48
--
60
2.20.1
49
2.35.1
61
62
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
virtio_scsi_handle_cmd_vq() is only called from hw/scsi/virtio-scsi.c
2
now and its return value is no longer used. Remove the function
3
prototype from virtio-scsi.h and drop the return value.
2
4
3
qemu coroutine command results in following error output:
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
6
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
5
Python Exception <class 'gdb.error'> 'arch_prctl' has unknown return
7
Message-id: 20220427143541.119567-6-stefanha@redhat.com
6
type; cast the call to its declared return type: Error occurred in
7
Python command: 'arch_prctl' has unknown return type; cast the call to
8
its declared return type
9
10
Fix it by giving it what it wants: arch_prctl return type.
11
12
Information on the topic:
13
https://sourceware.org/gdb/onlinedocs/gdb/Calling.html
14
15
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Message-id: 20190206151425.105871-1-vsementsov@virtuozzo.com
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
---
9
---
19
scripts/qemugdb/coroutine.py | 2 +-
10
include/hw/virtio/virtio-scsi.h | 1 -
20
1 file changed, 1 insertion(+), 1 deletion(-)
11
hw/scsi/virtio-scsi.c | 5 +----
12
2 files changed, 1 insertion(+), 5 deletions(-)
21
13
22
diff --git a/scripts/qemugdb/coroutine.py b/scripts/qemugdb/coroutine.py
14
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
23
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
24
--- a/scripts/qemugdb/coroutine.py
16
--- a/include/hw/virtio/virtio-scsi.h
25
+++ b/scripts/qemugdb/coroutine.py
17
+++ b/include/hw/virtio/virtio-scsi.h
26
@@ -XXX,XX +XXX,XX @@ def get_fs_base():
18
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_common_realize(DeviceState *dev,
27
pthread_self().'''
19
Error **errp);
28
# %rsp - 120 is scratch space according to the SystemV ABI
20
29
old = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)')
21
void virtio_scsi_common_unrealize(DeviceState *dev);
30
- gdb.execute('call arch_prctl(0x1003, $rsp - 120)', False, True)
22
-bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq);
31
+ gdb.execute('call (int)arch_prctl(0x1003, $rsp - 120)', False, True)
23
void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req);
32
fs_base = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)')
24
void virtio_scsi_free_req(VirtIOSCSIReq *req);
33
gdb.execute('set *(uint64_t*)($rsp - 120) = %s' % old, False, True)
25
void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
34
return fs_base
26
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/scsi/virtio-scsi.c
29
+++ b/hw/scsi/virtio-scsi.c
30
@@ -XXX,XX +XXX,XX @@ static void virtio_scsi_handle_cmd_req_submit(VirtIOSCSI *s, VirtIOSCSIReq *req)
31
scsi_req_unref(sreq);
32
}
33
34
-bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
35
+static void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
36
{
37
VirtIOSCSIReq *req, *next;
38
int ret = 0;
39
bool suppress_notifications = virtio_queue_get_notification(vq);
40
- bool progress = false;
41
42
QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
43
44
@@ -XXX,XX +XXX,XX @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
45
}
46
47
while ((req = virtio_scsi_pop_req(s, vq))) {
48
- progress = true;
49
ret = virtio_scsi_handle_cmd_req_prepare(s, req);
50
if (!ret) {
51
QTAILQ_INSERT_TAIL(&reqs, req, next);
52
@@ -XXX,XX +XXX,XX @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
53
QTAILQ_FOREACH_SAFE(req, &reqs, next, next) {
54
virtio_scsi_handle_cmd_req_submit(s, req);
55
}
56
- return progress;
57
}
58
59
static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq)
35
--
60
--
36
2.20.1
61
2.35.1
37
38
diff view generated by jsdifflib
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
There is no longer a need to expose the request and related APIs in
2
virtio-scsi.h since there are no callers outside virtio-scsi.c.
2
3
3
In order to avoid migration issues, we enable DISCARD and
4
Note the block comment in VirtIOSCSIReq has been adjusted to meet the
4
WRITE_ZEROES features only for machine type >= 4.0
5
coding style.
5
6
6
As discussed with Michael S. Tsirkin and Stefan Hajnoczi on the
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
list [1], DISCARD operation should not have security implications
8
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
8
(eg. page cache attacks), so we can enable it by default.
9
Message-id: 20220427143541.119567-7-stefanha@redhat.com
9
10
[1] https://lists.gnu.org/archive/html/qemu-devel/2019-02/msg00504.html
11
12
Suggested-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
13
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
16
Acked-by: Pankaj Gupta <pagupta@redhat.com>
17
Message-id: 20190208134950.187665-4-sgarzare@redhat.com
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
---
11
---
20
hw/block/virtio-blk.c | 4 ++++
12
include/hw/virtio/virtio-scsi.h | 40 -----------------------------
21
hw/core/machine.c | 2 ++
13
hw/scsi/virtio-scsi.c | 45 ++++++++++++++++++++++++++++++---
22
2 files changed, 6 insertions(+)
14
2 files changed, 41 insertions(+), 44 deletions(-)
23
15
24
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
16
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
25
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
26
--- a/hw/block/virtio-blk.c
18
--- a/include/hw/virtio/virtio-scsi.h
27
+++ b/hw/block/virtio-blk.c
19
+++ b/include/hw/virtio/virtio-scsi.h
28
@@ -XXX,XX +XXX,XX @@ static Property virtio_blk_properties[] = {
20
@@ -XXX,XX +XXX,XX @@ struct VirtIOSCSI {
29
DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128),
21
uint32_t host_features;
30
DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD,
31
IOThread *),
32
+ DEFINE_PROP_BIT64("discard", VirtIOBlock, host_features,
33
+ VIRTIO_BLK_F_DISCARD, true),
34
+ DEFINE_PROP_BIT64("write-zeroes", VirtIOBlock, host_features,
35
+ VIRTIO_BLK_F_WRITE_ZEROES, true),
36
DEFINE_PROP_END_OF_LIST(),
37
};
22
};
38
23
39
diff --git a/hw/core/machine.c b/hw/core/machine.c
24
-typedef struct VirtIOSCSIReq {
25
- /* Note:
26
- * - fields up to resp_iov are initialized by virtio_scsi_init_req;
27
- * - fields starting at vring are zeroed by virtio_scsi_init_req.
28
- * */
29
- VirtQueueElement elem;
30
-
31
- VirtIOSCSI *dev;
32
- VirtQueue *vq;
33
- QEMUSGList qsgl;
34
- QEMUIOVector resp_iov;
35
-
36
- union {
37
- /* Used for two-stage request submission */
38
- QTAILQ_ENTRY(VirtIOSCSIReq) next;
39
-
40
- /* Used for cancellation of request during TMFs */
41
- int remaining;
42
- };
43
-
44
- SCSIRequest *sreq;
45
- size_t resp_size;
46
- enum SCSIXferMode mode;
47
- union {
48
- VirtIOSCSICmdResp cmd;
49
- VirtIOSCSICtrlTMFResp tmf;
50
- VirtIOSCSICtrlANResp an;
51
- VirtIOSCSIEvent event;
52
- } resp;
53
- union {
54
- VirtIOSCSICmdReq cmd;
55
- VirtIOSCSICtrlTMFReq tmf;
56
- VirtIOSCSICtrlANReq an;
57
- } req;
58
-} VirtIOSCSIReq;
59
-
60
static inline void virtio_scsi_acquire(VirtIOSCSI *s)
61
{
62
if (s->ctx) {
63
@@ -XXX,XX +XXX,XX @@ void virtio_scsi_common_realize(DeviceState *dev,
64
Error **errp);
65
66
void virtio_scsi_common_unrealize(DeviceState *dev);
67
-void virtio_scsi_init_req(VirtIOSCSI *s, VirtQueue *vq, VirtIOSCSIReq *req);
68
-void virtio_scsi_free_req(VirtIOSCSIReq *req);
69
-void virtio_scsi_push_event(VirtIOSCSI *s, SCSIDevice *dev,
70
- uint32_t event, uint32_t reason);
71
72
void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp);
73
int virtio_scsi_dataplane_start(VirtIODevice *s);
74
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
40
index XXXXXXX..XXXXXXX 100644
75
index XXXXXXX..XXXXXXX 100644
41
--- a/hw/core/machine.c
76
--- a/hw/scsi/virtio-scsi.c
42
+++ b/hw/core/machine.c
77
+++ b/hw/scsi/virtio-scsi.c
43
@@ -XXX,XX +XXX,XX @@ GlobalProperty hw_compat_3_1[] = {
78
@@ -XXX,XX +XXX,XX @@
44
{ "usb-kbd", "serial", "42" },
79
#include "hw/virtio/virtio-access.h"
45
{ "usb-mouse", "serial", "42" },
80
#include "trace.h"
46
{ "usb-kbd", "serial", "42" },
81
47
+ { "virtio-blk-device", "discard", "false" },
82
+typedef struct VirtIOSCSIReq {
48
+ { "virtio-blk-device", "write-zeroes", "false" },
83
+ /*
49
};
84
+ * Note:
50
const size_t hw_compat_3_1_len = G_N_ELEMENTS(hw_compat_3_1);
85
+ * - fields up to resp_iov are initialized by virtio_scsi_init_req;
51
86
+ * - fields starting at vring are zeroed by virtio_scsi_init_req.
87
+ */
88
+ VirtQueueElement elem;
89
+
90
+ VirtIOSCSI *dev;
91
+ VirtQueue *vq;
92
+ QEMUSGList qsgl;
93
+ QEMUIOVector resp_iov;
94
+
95
+ union {
96
+ /* Used for two-stage request submission */
97
+ QTAILQ_ENTRY(VirtIOSCSIReq) next;
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;
52
--
151
--
53
2.20.1
152
2.35.1
54
55
diff view generated by jsdifflib