1
The following changes since commit f58d9620aa4a514b1227074ff56eefd1334a6225:
1
The following changes since commit 3521ade3510eb5cefb2e27a101667f25dad89935:
2
2
3
Merge remote-tracking branch 'remotes/rth/tags/pull-dt-20180326' into staging (2018-03-27 10:27:34 +0100)
3
Merge remote-tracking branch 'remotes/thuth-gitlab/tags/pull-request-2021-07-29' into staging (2021-07-29 13:17:20 +0100)
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 f5a53faad4bfbf1b86012a13055d2a1a774a42b6:
9
for you to fetch changes up to cc8eecd7f105a1dff5876adeb238a14696061a4a:
10
10
11
MAINTAINERS: add include/block/aio-wait.h (2018-03-27 13:05:48 +0100)
11
MAINTAINERS: Added myself as a reviewer for the NVMe Block Driver (2021-07-29 17:17:34 +0100)
12
13
----------------------------------------------------------------
14
Pull request
15
16
The main fix here is for io_uring. Spurious -EAGAIN errors can happen and the
17
request needs to be resubmitted.
18
19
The MAINTAINERS changes carry no risk and we might as well include them in QEMU
20
6.1.
12
21
13
----------------------------------------------------------------
22
----------------------------------------------------------------
14
23
15
----------------------------------------------------------------
24
Fabian Ebner (1):
25
block/io_uring: resubmit when result is -EAGAIN
16
26
17
Stefan Hajnoczi (4):
27
Philippe Mathieu-Daudé (1):
18
queue: add QSIMPLEQ_PREPEND()
28
MAINTAINERS: Added myself as a reviewer for the NVMe Block Driver
19
coroutine: avoid co_queue_wakeup recursion
20
coroutine: add test-aio coroutine queue chaining test case
21
MAINTAINERS: add include/block/aio-wait.h
22
29
23
MAINTAINERS | 1 +
30
Stefano Garzarella (1):
24
include/qemu/coroutine_int.h | 1 -
31
MAINTAINERS: add Stefano Garzarella as io_uring reviewer
25
include/qemu/queue.h | 8 ++++
32
26
block/io.c | 3 +-
33
MAINTAINERS | 2 ++
27
tests/test-aio.c | 65 ++++++++++++++++++++-----
34
block/io_uring.c | 16 +++++++++++++++-
28
util/qemu-coroutine-lock.c | 34 -------------
35
2 files changed, 17 insertions(+), 1 deletion(-)
29
util/qemu-coroutine.c | 110 +++++++++++++++++++++++--------------------
30
7 files changed, 121 insertions(+), 101 deletions(-)
31
36
32
--
37
--
33
2.14.3
38
2.31.1
34
39
35
diff view generated by jsdifflib
Deleted patch
1
QSIMPLEQ_CONCAT(a, b) joins a = a + b. The new QSIMPLEQ_PREPEND(a, b)
2
API joins a = b + a.
3
1
4
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
6
Message-id: 20180322152834.12656-2-stefanha@redhat.com
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
---
9
include/qemu/queue.h | 8 ++++++++
10
1 file changed, 8 insertions(+)
11
12
diff --git a/include/qemu/queue.h b/include/qemu/queue.h
13
index XXXXXXX..XXXXXXX 100644
14
--- a/include/qemu/queue.h
15
+++ b/include/qemu/queue.h
16
@@ -XXX,XX +XXX,XX @@ struct { \
17
} \
18
} while (/*CONSTCOND*/0)
19
20
+#define QSIMPLEQ_PREPEND(head1, head2) do { \
21
+ if (!QSIMPLEQ_EMPTY((head2))) { \
22
+ *(head2)->sqh_last = (head1)->sqh_first; \
23
+ (head1)->sqh_first = (head2)->sqh_first; \
24
+ QSIMPLEQ_INIT((head2)); \
25
+ } \
26
+} while (/*CONSTCOND*/0)
27
+
28
#define QSIMPLEQ_LAST(head, type, field) \
29
(QSIMPLEQ_EMPTY((head)) ? \
30
NULL : \
31
--
32
2.14.3
33
34
diff view generated by jsdifflib
1
Check that two coroutines can queue each other repeatedly without
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
hitting stack exhaustion.
3
2
4
Switch to qemu_init_main_loop() in main() because coroutines use
3
I've been working with io_uring for a while so I'd like to help
5
qemu_get_aio_context() - they don't know about test-aio's ctx variable.
4
with reviews.
6
5
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
6
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
8
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
7
Message-Id: <20210728131515.131045-1-sgarzare@redhat.com>
9
Message-id: 20180322152834.12656-4-stefanha@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
9
---
12
tests/test-aio.c | 65 ++++++++++++++++++++++++++++++++++++++++++++------------
10
MAINTAINERS | 1 +
13
1 file changed, 52 insertions(+), 13 deletions(-)
11
1 file changed, 1 insertion(+)
14
12
15
diff --git a/tests/test-aio.c b/tests/test-aio.c
13
diff --git a/MAINTAINERS b/MAINTAINERS
16
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/test-aio.c
15
--- a/MAINTAINERS
18
+++ b/tests/test-aio.c
16
+++ b/MAINTAINERS
19
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@ Linux io_uring
20
#include "qemu/timer.h"
18
M: Aarushi Mehta <mehta.aaru20@gmail.com>
21
#include "qemu/sockets.h"
19
M: Julia Suvorova <jusual@redhat.com>
22
#include "qemu/error-report.h"
20
M: Stefan Hajnoczi <stefanha@redhat.com>
23
+#include "qemu/coroutine.h"
21
+R: Stefano Garzarella <sgarzare@redhat.com>
24
+#include "qemu/main-loop.h"
22
L: qemu-block@nongnu.org
25
23
S: Maintained
26
static AioContext *ctx;
24
F: block/io_uring.c
27
28
@@ -XXX,XX +XXX,XX @@ static void test_source_timer_schedule(void)
29
timer_del(&data.timer);
30
}
31
32
+/*
33
+ * Check that aio_co_enter() can chain many times
34
+ *
35
+ * Two coroutines should be able to invoke each other via aio_co_enter() many
36
+ * times without hitting a limit like stack exhaustion. In other words, the
37
+ * calls should be chained instead of nested.
38
+ */
39
+
40
+typedef struct {
41
+ Coroutine *other;
42
+ unsigned i;
43
+ unsigned max;
44
+} ChainData;
45
+
46
+static void coroutine_fn chain(void *opaque)
47
+{
48
+ ChainData *data = opaque;
49
+
50
+ for (data->i = 0; data->i < data->max; data->i++) {
51
+ /* Queue up the other coroutine... */
52
+ aio_co_enter(ctx, data->other);
53
+
54
+ /* ...and give control to it */
55
+ qemu_coroutine_yield();
56
+ }
57
+}
58
+
59
+static void test_queue_chaining(void)
60
+{
61
+ /* This number of iterations hit stack exhaustion in the past: */
62
+ ChainData data_a = { .max = 25000 };
63
+ ChainData data_b = { .max = 25000 };
64
+
65
+ data_b.other = qemu_coroutine_create(chain, &data_a);
66
+ data_a.other = qemu_coroutine_create(chain, &data_b);
67
+
68
+ qemu_coroutine_enter(data_b.other);
69
+
70
+ g_assert_cmpint(data_a.i, ==, data_a.max);
71
+ g_assert_cmpint(data_b.i, ==, data_b.max - 1);
72
+
73
+ /* Allow the second coroutine to terminate */
74
+ qemu_coroutine_enter(data_a.other);
75
+
76
+ g_assert_cmpint(data_b.i, ==, data_b.max);
77
+}
78
79
/* End of tests. */
80
81
int main(int argc, char **argv)
82
{
83
- Error *local_error = NULL;
84
- GSource *src;
85
-
86
- init_clocks(NULL);
87
-
88
- ctx = aio_context_new(&local_error);
89
- if (!ctx) {
90
- error_reportf_err(local_error, "Failed to create AIO Context: ");
91
- exit(1);
92
- }
93
- src = aio_get_g_source(ctx);
94
- g_source_attach(src, NULL);
95
- g_source_unref(src);
96
+ qemu_init_main_loop(&error_fatal);
97
+ ctx = qemu_get_aio_context();
98
99
while (g_main_context_iteration(NULL, false));
100
101
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
102
g_test_add_func("/aio/external-client", test_aio_external_client);
103
g_test_add_func("/aio/timer/schedule", test_timer_schedule);
104
105
+ g_test_add_func("/aio/coroutine/queue-chaining", test_queue_chaining);
106
+
107
g_test_add_func("/aio-gsource/flush", test_source_flush);
108
g_test_add_func("/aio-gsource/bh/schedule", test_source_bh_schedule);
109
g_test_add_func("/aio-gsource/bh/schedule10", test_source_bh_schedule10);
110
--
25
--
111
2.14.3
26
2.31.1
112
27
113
diff view generated by jsdifflib
1
qemu_aio_coroutine_enter() is (indirectly) called recursively when
1
From: Fabian Ebner <f.ebner@proxmox.com>
2
processing co_queue_wakeup. This can lead to stack exhaustion.
3
2
4
This patch rewrites co_queue_wakeup in an iterative fashion (instead of
3
Linux SCSI can throw spurious -EAGAIN in some corner cases in its
5
recursive) with bounded memory usage to prevent stack exhaustion.
4
completion path, which will end up being the result in the completed
5
io_uring request.
6
6
7
qemu_co_queue_run_restart() is inlined into qemu_aio_coroutine_enter()
7
Resubmitting such requests should allow block jobs to complete, even
8
and the qemu_coroutine_enter() call is turned into a loop to avoid
8
if such spurious errors are encountered.
9
recursion.
10
9
11
There is one change that is worth mentioning: Previously, when
10
Co-authored-by: Stefan Hajnoczi <stefanha@gmail.com>
12
coroutine A queued coroutine B, qemu_co_queue_run_restart() entered
11
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
13
coroutine B from coroutine A. If A was terminating then it would still
12
Signed-off-by: Fabian Ebner <f.ebner@proxmox.com>
14
stay alive until B yielded. After this patch B is entered by A's parent
13
Message-id: 20210729091029.65369-1-f.ebner@proxmox.com
15
so that a A can be deleted immediately if it is terminating.
16
17
It is safe to make this change since B could never interact with A if it
18
was terminating anyway.
19
20
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
21
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
22
Message-id: 20180322152834.12656-3-stefanha@redhat.com
23
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
24
---
15
---
25
include/qemu/coroutine_int.h | 1 -
16
block/io_uring.c | 16 +++++++++++++++-
26
block/io.c | 3 +-
17
1 file changed, 15 insertions(+), 1 deletion(-)
27
util/qemu-coroutine-lock.c | 34 -------------
28
util/qemu-coroutine.c | 110 +++++++++++++++++++++++--------------------
29
4 files changed, 60 insertions(+), 88 deletions(-)
30
18
31
diff --git a/include/qemu/coroutine_int.h b/include/qemu/coroutine_int.h
19
diff --git a/block/io_uring.c b/block/io_uring.c
32
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
33
--- a/include/qemu/coroutine_int.h
21
--- a/block/io_uring.c
34
+++ b/include/qemu/coroutine_int.h
22
+++ b/block/io_uring.c
35
@@ -XXX,XX +XXX,XX @@ Coroutine *qemu_coroutine_new(void);
23
@@ -XXX,XX +XXX,XX @@ static void luring_process_completions(LuringState *s)
36
void qemu_coroutine_delete(Coroutine *co);
24
total_bytes = ret + luringcb->total_read;
37
CoroutineAction qemu_coroutine_switch(Coroutine *from, Coroutine *to,
25
38
CoroutineAction action);
26
if (ret < 0) {
39
-void coroutine_fn qemu_co_queue_run_restart(Coroutine *co);
27
- if (ret == -EINTR) {
40
28
+ /*
41
#endif
29
+ * Only writev/readv/fsync requests on regular files or host block
42
diff --git a/block/io.c b/block/io.c
30
+ * devices are submitted. Therefore -EAGAIN is not expected but it's
43
index XXXXXXX..XXXXXXX 100644
31
+ * known to happen sometimes with Linux SCSI. Submit again and hope
44
--- a/block/io.c
32
+ * the request completes successfully.
45
+++ b/block/io.c
33
+ *
46
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs,
34
+ * For more information, see:
47
BdrvCoDrainData data;
35
+ * https://lore.kernel.org/io-uring/20210727165811.284510-3-axboe@kernel.dk/T/#u
48
36
+ *
49
/* Calling bdrv_drain() from a BH ensures the current coroutine yields and
37
+ * If the code is changed to submit other types of requests in the
50
- * other coroutines run if they were queued from
38
+ * future, then this workaround may need to be extended to deal with
51
- * qemu_co_queue_run_restart(). */
39
+ * genuine -EAGAIN results that should not be resubmitted
52
+ * other coroutines run if they were queued by aio_co_enter(). */
40
+ * immediately.
53
41
+ */
54
assert(qemu_in_coroutine());
42
+ if (ret == -EINTR || ret == -EAGAIN) {
55
data = (BdrvCoDrainData) {
43
luring_resubmit(s, luringcb);
56
diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c
44
continue;
57
index XXXXXXX..XXXXXXX 100644
45
}
58
--- a/util/qemu-coroutine-lock.c
59
+++ b/util/qemu-coroutine-lock.c
60
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_queue_wait_impl(CoQueue *queue, QemuLockable *lock)
61
}
62
}
63
64
-/**
65
- * qemu_co_queue_run_restart:
66
- *
67
- * Enter each coroutine that was previously marked for restart by
68
- * qemu_co_queue_next() or qemu_co_queue_restart_all(). This function is
69
- * invoked by the core coroutine code when the current coroutine yields or
70
- * terminates.
71
- */
72
-void qemu_co_queue_run_restart(Coroutine *co)
73
-{
74
- Coroutine *next;
75
- QSIMPLEQ_HEAD(, Coroutine) tmp_queue_wakeup =
76
- QSIMPLEQ_HEAD_INITIALIZER(tmp_queue_wakeup);
77
-
78
- trace_qemu_co_queue_run_restart(co);
79
-
80
- /* Because "co" has yielded, any coroutine that we wakeup can resume it.
81
- * If this happens and "co" terminates, co->co_queue_wakeup becomes
82
- * invalid memory. Therefore, use a temporary queue and do not touch
83
- * the "co" coroutine as soon as you enter another one.
84
- *
85
- * In its turn resumed "co" can populate "co_queue_wakeup" queue with
86
- * new coroutines to be woken up. The caller, who has resumed "co",
87
- * will be responsible for traversing the same queue, which may cause
88
- * a different wakeup order but not any missing wakeups.
89
- */
90
- QSIMPLEQ_CONCAT(&tmp_queue_wakeup, &co->co_queue_wakeup);
91
-
92
- while ((next = QSIMPLEQ_FIRST(&tmp_queue_wakeup))) {
93
- QSIMPLEQ_REMOVE_HEAD(&tmp_queue_wakeup, co_queue_next);
94
- qemu_coroutine_enter(next);
95
- }
96
-}
97
-
98
static bool qemu_co_queue_do_restart(CoQueue *queue, bool single)
99
{
100
Coroutine *next;
101
diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c
102
index XXXXXXX..XXXXXXX 100644
103
--- a/util/qemu-coroutine.c
104
+++ b/util/qemu-coroutine.c
105
@@ -XXX,XX +XXX,XX @@ static void coroutine_delete(Coroutine *co)
106
107
void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co)
108
{
109
- Coroutine *self = qemu_coroutine_self();
110
- CoroutineAction ret;
111
-
112
- /* Cannot rely on the read barrier for co in aio_co_wake(), as there are
113
- * callers outside of aio_co_wake() */
114
- const char *scheduled = atomic_mb_read(&co->scheduled);
115
-
116
- trace_qemu_aio_coroutine_enter(ctx, self, co, co->entry_arg);
117
-
118
- /* if the Coroutine has already been scheduled, entering it again will
119
- * cause us to enter it twice, potentially even after the coroutine has
120
- * been deleted */
121
- if (scheduled) {
122
- fprintf(stderr,
123
- "%s: Co-routine was already scheduled in '%s'\n",
124
- __func__, scheduled);
125
- abort();
126
- }
127
-
128
- if (co->caller) {
129
- fprintf(stderr, "Co-routine re-entered recursively\n");
130
- abort();
131
- }
132
-
133
- co->caller = self;
134
- co->ctx = ctx;
135
-
136
- /* Store co->ctx before anything that stores co. Matches
137
- * barrier in aio_co_wake and qemu_co_mutex_wake.
138
- */
139
- smp_wmb();
140
-
141
- ret = qemu_coroutine_switch(self, co, COROUTINE_ENTER);
142
-
143
- qemu_co_queue_run_restart(co);
144
-
145
- /* Beware, if ret == COROUTINE_YIELD and qemu_co_queue_run_restart()
146
- * has started any other coroutine, "co" might have been reentered
147
- * and even freed by now! So be careful and do not touch it.
148
- */
149
-
150
- switch (ret) {
151
- case COROUTINE_YIELD:
152
- return;
153
- case COROUTINE_TERMINATE:
154
- assert(!co->locks_held);
155
- trace_qemu_coroutine_terminate(co);
156
- coroutine_delete(co);
157
- return;
158
- default:
159
- abort();
160
+ QSIMPLEQ_HEAD(, Coroutine) pending = QSIMPLEQ_HEAD_INITIALIZER(pending);
161
+ Coroutine *from = qemu_coroutine_self();
162
+
163
+ QSIMPLEQ_INSERT_TAIL(&pending, co, co_queue_next);
164
+
165
+ /* Run co and any queued coroutines */
166
+ while (!QSIMPLEQ_EMPTY(&pending)) {
167
+ Coroutine *to = QSIMPLEQ_FIRST(&pending);
168
+ CoroutineAction ret;
169
+
170
+ /* Cannot rely on the read barrier for to in aio_co_wake(), as there are
171
+ * callers outside of aio_co_wake() */
172
+ const char *scheduled = atomic_mb_read(&to->scheduled);
173
+
174
+ QSIMPLEQ_REMOVE_HEAD(&pending, co_queue_next);
175
+
176
+ trace_qemu_aio_coroutine_enter(ctx, from, to, to->entry_arg);
177
+
178
+ /* if the Coroutine has already been scheduled, entering it again will
179
+ * cause us to enter it twice, potentially even after the coroutine has
180
+ * been deleted */
181
+ if (scheduled) {
182
+ fprintf(stderr,
183
+ "%s: Co-routine was already scheduled in '%s'\n",
184
+ __func__, scheduled);
185
+ abort();
186
+ }
187
+
188
+ if (to->caller) {
189
+ fprintf(stderr, "Co-routine re-entered recursively\n");
190
+ abort();
191
+ }
192
+
193
+ to->caller = from;
194
+ to->ctx = ctx;
195
+
196
+ /* Store to->ctx before anything that stores to. Matches
197
+ * barrier in aio_co_wake and qemu_co_mutex_wake.
198
+ */
199
+ smp_wmb();
200
+
201
+ ret = qemu_coroutine_switch(from, to, COROUTINE_ENTER);
202
+
203
+ /* Queued coroutines are run depth-first; previously pending coroutines
204
+ * run after those queued more recently.
205
+ */
206
+ QSIMPLEQ_PREPEND(&pending, &to->co_queue_wakeup);
207
+
208
+ switch (ret) {
209
+ case COROUTINE_YIELD:
210
+ break;
211
+ case COROUTINE_TERMINATE:
212
+ assert(!to->locks_held);
213
+ trace_qemu_coroutine_terminate(to);
214
+ coroutine_delete(to);
215
+ break;
216
+ default:
217
+ abort();
218
+ }
219
}
220
}
221
222
--
46
--
223
2.14.3
47
2.31.1
224
48
225
diff view generated by jsdifflib
1
The include/block/aio-wait.h header file was added by commit
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
7719f3c968c59e1bcda7e177679dc765b59e578f ("block: extract
3
AIO_WAIT_WHILE() from BlockDriverState") without updating MAINTAINERS.
4
2
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
3
I'm interested in following the activity around the NVMe bdrv.
6
Reviewed-by: Eric Blake <eblake@redhat.com>
4
7
Message-id: 20180312132204.23683-1-stefanha@redhat.com
5
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
6
Message-id: 20210728183340.2018313-1-philmd@redhat.com
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
8
---
10
MAINTAINERS | 1 +
9
MAINTAINERS | 1 +
11
1 file changed, 1 insertion(+)
10
1 file changed, 1 insertion(+)
12
11
13
diff --git a/MAINTAINERS b/MAINTAINERS
12
diff --git a/MAINTAINERS b/MAINTAINERS
14
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
15
--- a/MAINTAINERS
14
--- a/MAINTAINERS
16
+++ b/MAINTAINERS
15
+++ b/MAINTAINERS
17
@@ -XXX,XX +XXX,XX @@ F: util/aio-*.c
16
@@ -XXX,XX +XXX,XX @@ F: block/null.c
18
F: block/io.c
17
NVMe Block Driver
19
F: migration/block*
18
M: Stefan Hajnoczi <stefanha@redhat.com>
20
F: include/block/aio.h
19
R: Fam Zheng <fam@euphon.net>
21
+F: include/block/aio-wait.h
20
+R: Philippe Mathieu-Daudé <philmd@redhat.com>
22
F: scripts/qemugdb/aio.py
21
L: qemu-block@nongnu.org
23
T: git git://github.com/stefanha/qemu.git block
22
S: Supported
24
23
F: block/nvme*
25
--
24
--
26
2.14.3
25
2.31.1
27
26
28
diff view generated by jsdifflib