1
The following changes since commit 9cf289af47bcfae5c75de37d8e5d6fd23705322c:
1
The following changes since commit 66547f416a61e0cb711dc76821890242432ba193:
2
2
3
Merge tag 'qga-pull-request' of gitlab.com:marcandre.lureau/qemu into staging (2022-05-04 03:42:49 -0700)
3
block/nvme: invoke blk_io_plug_call() outside q->lock (2023-07-17 09:17:41 -0400)
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 bef2e050d6a7feb865854c65570c496ac5a8cf53:
9
for you to fetch changes up to 1c38fe69e2b8a05c1762b122292fa7e3662f06fd:
10
10
11
util/event-loop-base: Introduce options to set the thread pool size (2022-05-04 17:02:19 +0100)
11
block/blkio: use blkio_set_int("fd") to check fd support (2023-07-27 15:51:46 -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
Please include these bug fixes in QEMU 8.1. Thanks!
17
used for async I/O.
18
17
19
----------------------------------------------------------------
18
----------------------------------------------------------------
20
19
21
Nicolas Saenz Julienne (3):
20
Hanna Czenczek (1):
22
Introduce event-loop-base abstract class
21
block: Fix pad_request's request restriction
23
util/main-loop: Introduce the main loop into QOM
24
util/event-loop-base: Introduce options to set the thread pool size
25
22
26
qapi/qom.json | 43 ++++++++--
23
Sam Li (1):
27
meson.build | 26 +++---
24
block/file-posix: fix g_file_get_contents return path
28
include/block/aio.h | 10 +++
25
29
include/block/thread-pool.h | 3 +
26
Stefano Garzarella (6):
30
include/qemu/main-loop.h | 10 +++
27
block/blkio: enable the completion eventfd
31
include/sysemu/event-loop-base.h | 41 +++++++++
28
block/blkio: do not use open flags in qemu_open()
32
include/sysemu/iothread.h | 6 +-
29
block/blkio: move blkio_connect() in the drivers functions
33
event-loop-base.c | 140 +++++++++++++++++++++++++++++++
30
block/blkio: retry blkio_connect() if it fails using `fd`
34
iothread.c | 68 +++++----------
31
block/blkio: fall back on using `path` when `fd` setting fails
35
util/aio-posix.c | 1 +
32
block/blkio: use blkio_set_int("fd") to check fd support
36
util/async.c | 20 +++++
33
37
util/main-loop.c | 65 ++++++++++++++
34
block/blkio.c | 132 ++++++++++++++++++++++++++++++---------------
38
util/thread-pool.c | 55 +++++++++++-
35
block/file-posix.c | 6 +--
39
13 files changed, 419 insertions(+), 69 deletions(-)
36
block/io.c | 8 ++-
40
create mode 100644 include/sysemu/event-loop-base.h
37
3 files changed, 97 insertions(+), 49 deletions(-)
41
create mode 100644 event-loop-base.c
42
38
43
--
39
--
44
2.35.1
40
2.41.0
diff view generated by jsdifflib
New patch
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
2
3
Until libblkio 1.3.0, virtio-blk drivers had completion eventfd
4
notifications enabled from the start, but from the next releases
5
this is no longer the case, so we have to explicitly enable them.
6
7
In fact, the libblkio documentation says they could be disabled,
8
so we should always enable them at the start if we want to be
9
sure to get completion eventfd notifications:
10
11
By default, the driver might not generate completion events for
12
requests so it is necessary to explicitly enable the completion
13
file descriptor before use:
14
15
void blkioq_set_completion_fd_enabled(struct blkioq *q, bool enable);
16
17
I discovered this while trying a development version of libblkio:
18
the guest kernel hangs during boot, while probing the device.
19
20
Fixes: fd66dbd424f5 ("blkio: add libblkio block driver")
21
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
22
Message-id: 20230725103744.77343-1-sgarzare@redhat.com
23
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
24
---
25
block/blkio.c | 1 +
26
1 file changed, 1 insertion(+)
27
28
diff --git a/block/blkio.c b/block/blkio.c
29
index XXXXXXX..XXXXXXX 100644
30
--- a/block/blkio.c
31
+++ b/block/blkio.c
32
@@ -XXX,XX +XXX,XX @@ static int blkio_file_open(BlockDriverState *bs, QDict *options, int flags,
33
QLIST_INIT(&s->bounce_bufs);
34
s->blkioq = blkio_get_queue(s->blkio, 0);
35
s->completion_fd = blkioq_get_completion_fd(s->blkioq);
36
+ blkioq_set_completion_fd_enabled(s->blkioq, true);
37
38
blkio_attach_aio_context(bs, bdrv_get_aio_context(bs));
39
return 0;
40
--
41
2.41.0
diff view generated by jsdifflib
New patch
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
2
3
qemu_open() in blkio_virtio_blk_common_open() is used to open the
4
character device (e.g. /dev/vhost-vdpa-0 or /dev/vfio/vfio) or in
5
the future eventually the unix socket.
6
7
In all these cases we cannot open the path in read-only mode,
8
when the `read-only` option of blockdev is on, because the exchange
9
of IOCTL commands for example will fail.
10
11
In order to open the device read-only, we have to use the `read-only`
12
property of the libblkio driver as we already do in blkio_file_open().
13
14
Fixes: cad2ccc395 ("block/blkio: use qemu_open() to support fd passing for virtio-blk")
15
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2225439
16
Reported-by: Qing Wang <qinwang@redhat.com>
17
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
18
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
19
Message-id: 20230726074807.14041-1-sgarzare@redhat.com
20
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
21
---
22
block/blkio.c | 21 ++++++++++++---------
23
1 file changed, 12 insertions(+), 9 deletions(-)
24
25
diff --git a/block/blkio.c b/block/blkio.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/block/blkio.c
28
+++ b/block/blkio.c
29
@@ -XXX,XX +XXX,XX @@ static int blkio_virtio_blk_common_open(BlockDriverState *bs,
30
* layer through the "/dev/fdset/N" special path.
31
*/
32
if (fd_supported) {
33
- int open_flags;
34
-
35
- if (flags & BDRV_O_RDWR) {
36
- open_flags = O_RDWR;
37
- } else {
38
- open_flags = O_RDONLY;
39
- }
40
-
41
- fd = qemu_open(path, open_flags, errp);
42
+ /*
43
+ * `path` can contain the path of a character device
44
+ * (e.g. /dev/vhost-vdpa-0 or /dev/vfio/vfio) or a unix socket.
45
+ *
46
+ * So, we should always open it with O_RDWR flag, also if BDRV_O_RDWR
47
+ * is not set in the open flags, because the exchange of IOCTL commands
48
+ * for example will fail.
49
+ *
50
+ * In order to open the device read-only, we are using the `read-only`
51
+ * property of the libblkio driver in blkio_file_open().
52
+ */
53
+ fd = qemu_open(path, O_RDWR, errp);
54
if (fd < 0) {
55
return -EINVAL;
56
}
57
--
58
2.41.0
59
60
diff view generated by jsdifflib
New patch
1
From: Sam Li <faithilikerun@gmail.com>
1
2
3
The g_file_get_contents() function returns a g_boolean. If it fails, the
4
returned value will be 0 instead of -1. Solve the issue by skipping
5
assigning ret value.
6
7
This issue was found by Matthew Rosato using virtio-blk-{pci,ccw} backed
8
by an NVMe partition e.g. /dev/nvme0n1p1 on s390x.
9
10
Signed-off-by: Sam Li <faithilikerun@gmail.com>
11
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
14
Message-id: 20230727115844.8480-1-faithilikerun@gmail.com
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
16
---
17
block/file-posix.c | 6 ++----
18
1 file changed, 2 insertions(+), 4 deletions(-)
19
20
diff --git a/block/file-posix.c b/block/file-posix.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/block/file-posix.c
23
+++ b/block/file-posix.c
24
@@ -XXX,XX +XXX,XX @@ static int hdev_get_max_hw_transfer(int fd, struct stat *st)
25
static int get_sysfs_str_val(struct stat *st, const char *attribute,
26
char **val) {
27
g_autofree char *sysfspath = NULL;
28
- int ret;
29
size_t len;
30
31
if (!S_ISBLK(st->st_mode)) {
32
@@ -XXX,XX +XXX,XX @@ static int get_sysfs_str_val(struct stat *st, const char *attribute,
33
sysfspath = g_strdup_printf("/sys/dev/block/%u:%u/queue/%s",
34
major(st->st_rdev), minor(st->st_rdev),
35
attribute);
36
- ret = g_file_get_contents(sysfspath, val, &len, NULL);
37
- if (ret == -1) {
38
+ if (!g_file_get_contents(sysfspath, val, &len, NULL)) {
39
return -ENOENT;
40
}
41
42
@@ -XXX,XX +XXX,XX @@ static int get_sysfs_str_val(struct stat *st, const char *attribute,
43
if (*(p + len - 1) == '\n') {
44
*(p + len - 1) = '\0';
45
}
46
- return ret;
47
+ return 0;
48
}
49
#endif
50
51
--
52
2.41.0
53
54
diff view generated by jsdifflib
New patch
1
From: Hanna Czenczek <hreitz@redhat.com>
1
2
3
bdrv_pad_request() relies on requests' lengths not to exceed SIZE_MAX,
4
which bdrv_check_qiov_request() does not guarantee.
5
6
bdrv_check_request32() however will guarantee this, and both of
7
bdrv_pad_request()'s callers (bdrv_co_preadv_part() and
8
bdrv_co_pwritev_part()) already run it before calling
9
bdrv_pad_request(). Therefore, bdrv_pad_request() can safely call
10
bdrv_check_request32() without expecting error, too.
11
12
In effect, this patch will not change guest-visible behavior. It is a
13
clean-up to tighten a condition to match what is guaranteed by our
14
callers, and which exists purely to show clearly why the subsequent
15
assertion (`assert(*bytes <= SIZE_MAX)`) is always true.
16
17
Note there is a difference between the interfaces of
18
bdrv_check_qiov_request() and bdrv_check_request32(): The former takes
19
an errp, the latter does not, so we can no longer just pass
20
&error_abort. Instead, we need to check the returned value. While we
21
do expect success (because the callers have already run this function),
22
an assert(ret == 0) is not much simpler than just to return an error if
23
it occurs, so let us handle errors by returning them up the stack now.
24
25
Reported-by: Peter Maydell <peter.maydell@linaro.org>
26
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
27
Message-id: 20230714085938.202730-1-hreitz@redhat.com
28
Fixes: 18743311b829cafc1737a5f20bc3248d5f91ee2a
29
("block: Collapse padded I/O vecs exceeding IOV_MAX")
30
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
31
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
32
---
33
block/io.c | 8 ++++++--
34
1 file changed, 6 insertions(+), 2 deletions(-)
35
36
diff --git a/block/io.c b/block/io.c
37
index XXXXXXX..XXXXXXX 100644
38
--- a/block/io.c
39
+++ b/block/io.c
40
@@ -XXX,XX +XXX,XX @@ static int bdrv_pad_request(BlockDriverState *bs,
41
int sliced_niov;
42
size_t sliced_head, sliced_tail;
43
44
- bdrv_check_qiov_request(*offset, *bytes, *qiov, *qiov_offset, &error_abort);
45
+ /* Should have been checked by the caller already */
46
+ ret = bdrv_check_request32(*offset, *bytes, *qiov, *qiov_offset);
47
+ if (ret < 0) {
48
+ return ret;
49
+ }
50
51
if (!bdrv_init_padding(bs, *offset, *bytes, write, pad)) {
52
if (padded) {
53
@@ -XXX,XX +XXX,XX @@ static int bdrv_pad_request(BlockDriverState *bs,
54
&sliced_head, &sliced_tail,
55
&sliced_niov);
56
57
- /* Guaranteed by bdrv_check_qiov_request() */
58
+ /* Guaranteed by bdrv_check_request32() */
59
assert(*bytes <= SIZE_MAX);
60
ret = bdrv_create_padded_qiov(bs, pad, sliced_iov, sliced_niov,
61
sliced_head, *bytes);
62
--
63
2.41.0
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
This is in preparation for the next patch, where for virtio-blk
4
based event loops. So let's define a new 'MainLoopClass' that inherits
4
drivers we need to handle the failure of blkio_connect().
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
Let's also rename the *_open() functions to *_connect() to make
10
mark 'MainLoop' as non-deletable.
7
the code reflect the changes applied.
11
8
12
[1] For example:
9
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
13
-object main-loop,id=main-loop,aio-max-batch=<value>
10
Message-id: 20230727161020.84213-2-sgarzare@redhat.com
14
15
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Acked-by: Markus Armbruster <armbru@redhat.com>
18
Message-id: 20220425075723.20019-3-nsaenzju@redhat.com
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
20
---
12
---
21
qapi/qom.json | 13 ++++++++
13
block/blkio.c | 71 ++++++++++++++++++++++++++++++---------------------
22
meson.build | 3 +-
14
1 file changed, 42 insertions(+), 29 deletions(-)
23
include/qemu/main-loop.h | 10 ++++++
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
15
29
diff --git a/qapi/qom.json b/qapi/qom.json
16
diff --git a/block/blkio.c b/block/blkio.c
30
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
31
--- a/qapi/qom.json
18
--- a/block/blkio.c
32
+++ b/qapi/qom.json
19
+++ b/block/blkio.c
33
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ static void blkio_unregister_buf(BlockDriverState *bs, void *host, size_t size)
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);
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
}
21
}
123
}
22
}
124
23
125
+static bool event_loop_base_can_be_deleted(UserCreatable *uc)
24
-static int blkio_io_uring_open(BlockDriverState *bs, QDict *options, int flags,
126
+{
25
- Error **errp)
127
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc);
26
+static int blkio_io_uring_connect(BlockDriverState *bs, QDict *options,
128
+ EventLoopBase *backend = EVENT_LOOP_BASE(uc);
27
+ int flags, Error **errp)
129
+
28
{
130
+ if (bc->can_be_deleted) {
29
const char *filename = qdict_get_str(options, "filename");
131
+ return bc->can_be_deleted(backend);
30
BDRVBlkioState *s = bs->opaque;
31
@@ -XXX,XX +XXX,XX @@ static int blkio_io_uring_open(BlockDriverState *bs, QDict *options, int flags,
32
}
33
}
34
35
+ ret = blkio_connect(s->blkio);
36
+ if (ret < 0) {
37
+ error_setg_errno(errp, -ret, "blkio_connect failed: %s",
38
+ blkio_get_error_msg());
39
+ return ret;
132
+ }
40
+ }
133
+
41
+
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;
42
return 0;
159
}
43
}
160
44
161
+static void main_loop_update_params(EventLoopBase *base, Error **errp)
45
-static int blkio_nvme_io_uring(BlockDriverState *bs, QDict *options, int flags,
162
+{
46
- Error **errp)
163
+ if (!qemu_aio_context) {
47
+static int blkio_nvme_io_uring_connect(BlockDriverState *bs, QDict *options,
164
+ error_setg(errp, "qemu aio context not ready");
48
+ int flags, Error **errp)
165
+ return;
49
{
50
const char *path = qdict_get_try_str(options, "path");
51
BDRVBlkioState *s = bs->opaque;
52
@@ -XXX,XX +XXX,XX @@ static int blkio_nvme_io_uring(BlockDriverState *bs, QDict *options, int flags,
53
return -EINVAL;
54
}
55
56
+ ret = blkio_connect(s->blkio);
57
+ if (ret < 0) {
58
+ error_setg_errno(errp, -ret, "blkio_connect failed: %s",
59
+ blkio_get_error_msg());
60
+ return ret;
166
+ }
61
+ }
167
+
62
+
168
+ aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
63
return 0;
169
+}
64
}
170
+
65
171
+MainLoop *mloop;
66
-static int blkio_virtio_blk_common_open(BlockDriverState *bs,
172
+
67
- QDict *options, int flags, Error **errp)
173
+static void main_loop_init(EventLoopBase *base, Error **errp)
68
+static int blkio_virtio_blk_connect(BlockDriverState *bs, QDict *options,
174
+{
69
+ int flags, Error **errp)
175
+ MainLoop *m = MAIN_LOOP(base);
70
{
176
+
71
const char *path = qdict_get_try_str(options, "path");
177
+ if (mloop) {
72
BDRVBlkioState *s = bs->opaque;
178
+ error_setg(errp, "only one main-loop instance allowed");
73
@@ -XXX,XX +XXX,XX @@ static int blkio_virtio_blk_common_open(BlockDriverState *bs,
179
+ return;
74
}
75
}
76
77
+ ret = blkio_connect(s->blkio);
78
+ if (ret < 0) {
79
+ error_setg_errno(errp, -ret, "blkio_connect failed: %s",
80
+ blkio_get_error_msg());
81
+ return ret;
180
+ }
82
+ }
181
+
83
+
182
+ main_loop_update_params(base, errp);
84
qdict_del(options, "path");
85
86
return 0;
87
@@ -XXX,XX +XXX,XX @@ static int blkio_file_open(BlockDriverState *bs, QDict *options, int flags,
88
return ret;
89
}
90
91
+ if (!(flags & BDRV_O_RDWR)) {
92
+ ret = blkio_set_bool(s->blkio, "read-only", true);
93
+ if (ret < 0) {
94
+ error_setg_errno(errp, -ret, "failed to set read-only: %s",
95
+ blkio_get_error_msg());
96
+ blkio_destroy(&s->blkio);
97
+ return ret;
98
+ }
99
+ }
183
+
100
+
184
+ mloop = m;
101
if (strcmp(blkio_driver, "io_uring") == 0) {
185
+ return;
102
- ret = blkio_io_uring_open(bs, options, flags, errp);
186
+}
103
+ ret = blkio_io_uring_connect(bs, options, flags, errp);
187
+
104
} else if (strcmp(blkio_driver, "nvme-io_uring") == 0) {
188
+static bool main_loop_can_be_deleted(EventLoopBase *base)
105
- ret = blkio_nvme_io_uring(bs, options, flags, errp);
189
+{
106
+ ret = blkio_nvme_io_uring_connect(bs, options, flags, errp);
190
+ return false;
107
} else if (strcmp(blkio_driver, "virtio-blk-vfio-pci") == 0) {
191
+}
108
- ret = blkio_virtio_blk_common_open(bs, options, flags, errp);
192
+
109
+ ret = blkio_virtio_blk_connect(bs, options, flags, errp);
193
+static void main_loop_class_init(ObjectClass *oc, void *class_data)
110
} else if (strcmp(blkio_driver, "virtio-blk-vhost-user") == 0) {
194
+{
111
- ret = blkio_virtio_blk_common_open(bs, options, flags, errp);
195
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(oc);
112
+ ret = blkio_virtio_blk_connect(bs, options, flags, errp);
196
+
113
} else if (strcmp(blkio_driver, "virtio-blk-vhost-vdpa") == 0) {
197
+ bc->init = main_loop_init;
114
- ret = blkio_virtio_blk_common_open(bs, options, flags, errp);
198
+ bc->update_params = main_loop_update_params;
115
+ ret = blkio_virtio_blk_connect(bs, options, flags, errp);
199
+ bc->can_be_deleted = main_loop_can_be_deleted;
116
} else {
200
+}
117
g_assert_not_reached();
201
+
118
}
202
+static const TypeInfo main_loop_info = {
119
@@ -XXX,XX +XXX,XX @@ static int blkio_file_open(BlockDriverState *bs, QDict *options, int flags,
203
+ .name = TYPE_MAIN_LOOP,
120
return ret;
204
+ .parent = TYPE_EVENT_LOOP_BASE,
121
}
205
+ .class_init = main_loop_class_init,
122
206
+ .instance_size = sizeof(MainLoop),
123
- if (!(flags & BDRV_O_RDWR)) {
207
+};
124
- ret = blkio_set_bool(s->blkio, "read-only", true);
208
+
125
- if (ret < 0) {
209
+static void main_loop_register_types(void)
126
- error_setg_errno(errp, -ret, "failed to set read-only: %s",
210
+{
127
- blkio_get_error_msg());
211
+ type_register_static(&main_loop_info);
128
- blkio_destroy(&s->blkio);
212
+}
129
- return ret;
213
+
130
- }
214
+type_init(main_loop_register_types)
131
- }
215
+
132
-
216
static int max_priority;
133
- ret = blkio_connect(s->blkio);
217
134
- if (ret < 0) {
218
#ifndef _WIN32
135
- error_setg_errno(errp, -ret, "blkio_connect failed: %s",
136
- blkio_get_error_msg());
137
- blkio_destroy(&s->blkio);
138
- return ret;
139
- }
140
-
141
ret = blkio_get_bool(s->blkio,
142
"needs-mem-regions",
143
&s->needs_mem_regions);
219
--
144
--
220
2.35.1
145
2.41.0
diff view generated by jsdifflib
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
Introduce the 'event-loop-base' abstract class, it'll hold the
3
libblkio 1.3.0 added support of "fd" property for virtio-blk-vhost-vdpa
4
properties common to all event loops and provide the necessary hooks for
4
driver. In QEMU, starting from commit cad2ccc395 ("block/blkio: use
5
their creation and maintenance. Then have iothread inherit from it.
5
qemu_open() to support fd passing for virtio-blk") we are using
6
`blkio_get_int(..., "fd")` to check if the "fd" property is supported
7
for all the virtio-blk-* driver.
6
8
7
EventLoopBaseClass is defined as user creatable and provides a hook for
9
Unfortunately that property is also available for those driver that do
8
its children to attach themselves to the user creatable class 'complete'
10
not support it, such as virtio-blk-vhost-user.
9
function. It also provides an update_params() callback to propagate
10
property changes onto its children.
11
11
12
The new 'event-loop-base' class will live in the root directory. It is
12
So, `blkio_get_int()` is not enough to check whether the driver supports
13
built on its own using the 'link_whole' option (there are no direct
13
the `fd` property or not. This is because the virito-blk common libblkio
14
function dependencies between the class and its children, it all happens
14
driver only checks whether or not `fd` is set during `blkio_connect()`
15
trough 'constructor' magic). And also imposes new compilation
15
and fails with -EINVAL for those transports that do not support it
16
dependencies:
16
(all except vhost-vdpa for now).
17
17
18
qom <- event-loop-base <- blockdev (iothread.c)
18
So let's handle the `blkio_connect()` failure, retrying it using `path`
19
directly.
19
20
20
And in subsequent patches:
21
Fixes: cad2ccc395 ("block/blkio: use qemu_open() to support fd passing for virtio-blk")
21
22
Suggested-by: Stefan Hajnoczi <stefanha@redhat.com>
22
qom <- event-loop-base <- qemuutil (util/main-loop.c)
23
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
23
24
Message-id: 20230727161020.84213-3-sgarzare@redhat.com
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>
25
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
40
---
26
---
41
qapi/qom.json | 22 +++++--
27
block/blkio.c | 29 +++++++++++++++++++++++++++++
42
meson.build | 23 ++++---
28
1 file changed, 29 insertions(+)
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
29
51
diff --git a/qapi/qom.json b/qapi/qom.json
30
diff --git a/block/blkio.c b/block/blkio.c
52
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
53
--- a/qapi/qom.json
32
--- a/block/blkio.c
54
+++ b/qapi/qom.json
33
+++ b/block/blkio.c
55
@@ -XXX,XX +XXX,XX @@
34
@@ -XXX,XX +XXX,XX @@ static int blkio_virtio_blk_connect(BlockDriverState *bs, QDict *options,
56
'*repeat': 'bool',
35
}
57
'*grab-toggle': 'GrabToggleKeys' } }
36
58
37
ret = blkio_connect(s->blkio);
59
+##
38
+ /*
60
+# @EventLoopBaseProperties:
39
+ * If the libblkio driver doesn't support the `fd` property, blkio_connect()
61
+#
40
+ * will fail with -EINVAL. So let's try calling blkio_connect() again by
62
+# Common properties for event loops
41
+ * directly setting `path`.
63
+#
42
+ */
64
+# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
43
+ if (fd_supported && ret == -EINVAL) {
65
+# 0 means that the engine will use its default.
44
+ qemu_close(fd);
66
+# (default: 0)
67
+#
68
+# Since: 7.1
69
+##
70
+{ 'struct': 'EventLoopBaseProperties',
71
+ 'data': { '*aio-max-batch': 'int' } }
72
+
45
+
73
##
46
+ /*
74
# @IothreadProperties:
47
+ * We need to clear the `fd` property we set previously by setting
75
#
48
+ * it to -1.
76
@@ -XXX,XX +XXX,XX @@
49
+ */
77
# algorithm detects it is spending too long polling without
50
+ ret = blkio_set_int(s->blkio, "fd", -1);
78
# encountering events. 0 selects a default behaviour (default: 0)
51
+ if (ret < 0) {
79
#
52
+ error_setg_errno(errp, -ret, "failed to set fd: %s",
80
-# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
53
+ blkio_get_error_msg());
81
-# 0 means that the engine will use its default
54
+ return ret;
82
-# (default:0, since 6.1)
55
+ }
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
+
56
+
119
+event_loop_base = files('event-loop-base.c')
57
+ ret = blkio_set_str(s->blkio, "path", path);
120
+event_loop_base = static_library('event-loop-base', sources: event_loop_base + genh,
58
+ if (ret < 0) {
121
+ build_by_default: true)
59
+ error_setg_errno(errp, -ret, "failed to set path: %s",
122
+event_loop_base = declare_dependency(link_whole: event_loop_base,
60
+ blkio_get_error_msg());
123
+ dependencies: [qom])
61
+ return ret;
62
+ }
124
+
63
+
125
stub_ss = stub_ss.apply(config_all, strict: false)
64
+ ret = blkio_connect(s->blkio);
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
+ }
65
+ }
284
+
66
+
285
+ if (value < 0) {
67
if (ret < 0) {
286
+ error_setg(errp, "%s value must be in range [0, %" PRId64 "]",
68
error_setg_errno(errp, -ret, "blkio_connect failed: %s",
287
+ info->name, INT64_MAX);
69
blkio_get_error_msg());
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
}
354
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;
489
--
70
--
490
2.35.1
71
2.41.0
diff view generated by jsdifflib
New patch
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
2
3
qemu_open() fails if called with an unix domain socket in this way:
4
-blockdev node-name=drive0,driver=virtio-blk-vhost-user,path=vhost-user-blk.sock,cache.direct=on: Could not open 'vhost-user-blk.sock': No such device or address
5
6
Since virtio-blk-vhost-user does not support fd passing, let`s always fall back
7
on using `path` if we fail the fd passing.
8
9
Fixes: cad2ccc395 ("block/blkio: use qemu_open() to support fd passing for virtio-blk")
10
Reported-by: Qing Wang <qinwang@redhat.com>
11
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
12
Message-id: 20230727161020.84213-4-sgarzare@redhat.com
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
---
15
block/blkio.c | 20 ++++++++++----------
16
1 file changed, 10 insertions(+), 10 deletions(-)
17
18
diff --git a/block/blkio.c b/block/blkio.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/blkio.c
21
+++ b/block/blkio.c
22
@@ -XXX,XX +XXX,XX @@ static int blkio_virtio_blk_connect(BlockDriverState *bs, QDict *options,
23
* In order to open the device read-only, we are using the `read-only`
24
* property of the libblkio driver in blkio_file_open().
25
*/
26
- fd = qemu_open(path, O_RDWR, errp);
27
+ fd = qemu_open(path, O_RDWR, NULL);
28
if (fd < 0) {
29
- return -EINVAL;
30
+ fd_supported = false;
31
+ } else {
32
+ ret = blkio_set_int(s->blkio, "fd", fd);
33
+ if (ret < 0) {
34
+ fd_supported = false;
35
+ qemu_close(fd);
36
+ }
37
}
38
+ }
39
40
- ret = blkio_set_int(s->blkio, "fd", fd);
41
- if (ret < 0) {
42
- error_setg_errno(errp, -ret, "failed to set fd: %s",
43
- blkio_get_error_msg());
44
- qemu_close(fd);
45
- return ret;
46
- }
47
- } else {
48
+ if (!fd_supported) {
49
ret = blkio_set_str(s->blkio, "path", path);
50
if (ret < 0) {
51
error_setg_errno(errp, -ret, "failed to set path: %s",
52
--
53
2.41.0
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
Setting the `fd` property fails with virtio-blk-* libblkio drivers
4
empty, when in demand, it creates new threads until full. This behaviour
4
that do not support fd passing since
5
doesn't play well with latency sensitive workloads where the price of
5
https://gitlab.com/libblkio/libblkio/-/merge_requests/208.
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
Getting the `fd` property, on the other hand, always succeeds for
11
property to set the thread pool size. The threads will be created during
8
virtio-blk-* libblkio drivers even when they don't support fd passing.
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
9
17
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
10
This patch switches to setting the `fd` property because it is a
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
better mechanism for probing fd passing support than getting the `fd`
19
Acked-by: Markus Armbruster <armbru@redhat.com>
12
property.
20
Message-id: 20220425075723.20019-4-nsaenzju@redhat.com
13
14
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
15
Message-id: 20230727161020.84213-5-sgarzare@redhat.com
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
22
---
17
---
23
qapi/qom.json | 10 +++++-
18
block/blkio.c | 2 +-
24
include/block/aio.h | 10 ++++++
19
1 file changed, 1 insertion(+), 1 deletion(-)
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
20
35
diff --git a/qapi/qom.json b/qapi/qom.json
21
diff --git a/block/blkio.c b/block/blkio.c
36
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
37
--- a/qapi/qom.json
23
--- a/block/blkio.c
38
+++ b/qapi/qom.json
24
+++ b/block/blkio.c
39
@@ -XXX,XX +XXX,XX @@
25
@@ -XXX,XX +XXX,XX @@ static int blkio_virtio_blk_connect(BlockDriverState *bs, QDict *options,
40
# 0 means that the engine will use its default.
26
return -EINVAL;
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)
252
{
253
+ ERRP_GUARD();
254
+
255
if (!qemu_aio_context) {
256
error_setg(errp, "qemu aio context not ready");
257
return;
258
}
27
}
259
28
260
aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
29
- if (blkio_get_int(s->blkio, "fd", &fd) == 0) {
261
+ if (*errp) {
30
+ if (blkio_set_int(s->blkio, "fd", -1) == 0) {
262
+ return;
31
fd_supported = true;
263
+ }
32
}
264
+
33
265
+ aio_context_set_thread_pool_params(qemu_aio_context, base->thread_pool_min,
266
+ base->thread_pool_max, errp);
267
}
268
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
--
34
--
371
2.35.1
35
2.41.0
diff view generated by jsdifflib