1
The following changes since commit 55a19ad8b2d0797e3a8fe90ab99a9bb713824059:
1
The following changes since commit 6c769690ac845fa62642a5f93b4e4bd906adab95:
2
2
3
Update version for v2.9.0-rc1 release (2017-03-21 17:13:29 +0000)
3
Merge remote-tracking branch 'remotes/vsementsov/tags/pull-simplebench-2021-05-04' into staging (2021-05-21 12:02:34 +0100)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
https://github.com/codyprime/qemu-kvm-jtc.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 600ac6a0ef5c06418446ef2f37407bddcc51b21c:
9
for you to fetch changes up to 0a6f0c76a030710780ce10d6347a70f098024d21:
10
10
11
blockjob: add devops to blockjob backends (2017-03-22 13:26:27 -0400)
11
coroutine-sleep: introduce qemu_co_sleep (2021-05-21 18:22:33 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches for 2.9
14
Pull request
15
16
(Resent due to an email preparation mistake.)
17
15
----------------------------------------------------------------
18
----------------------------------------------------------------
16
19
17
John Snow (3):
20
Paolo Bonzini (6):
18
blockjob: add block_job_start_shim
21
coroutine-sleep: use a stack-allocated timer
19
block-backend: add drained_begin / drained_end ops
22
coroutine-sleep: disallow NULL QemuCoSleepState** argument
20
blockjob: add devops to blockjob backends
23
coroutine-sleep: allow qemu_co_sleep_wake that wakes nothing
24
coroutine-sleep: move timer out of QemuCoSleepState
25
coroutine-sleep: replace QemuCoSleepState pointer with struct in the
26
API
27
coroutine-sleep: introduce qemu_co_sleep
21
28
22
Paolo Bonzini (1):
29
Philippe Mathieu-Daudé (1):
23
blockjob: avoid recursive AioContext locking
30
bitops.h: Improve find_xxx_bit() documentation
24
31
25
block/block-backend.c | 24 ++++++++++++++--
32
Zenghui Yu (1):
26
blockjob.c | 63 ++++++++++++++++++++++++++++++++----------
33
multi-process: Initialize variables declared with g_auto*
27
include/sysemu/block-backend.h | 8 ++++++
34
28
3 files changed, 79 insertions(+), 16 deletions(-)
35
include/qemu/bitops.h | 15 ++++++--
36
include/qemu/coroutine.h | 27 ++++++++-----
37
block/block-copy.c | 10 ++---
38
block/nbd.c | 14 +++----
39
hw/remote/memory.c | 5 +--
40
hw/remote/proxy.c | 3 +-
41
util/qemu-coroutine-sleep.c | 75 +++++++++++++++++++------------------
42
7 files changed, 79 insertions(+), 70 deletions(-)
29
43
30
--
44
--
31
2.9.3
45
2.31.1
32
46
33
diff view generated by jsdifflib
New patch
1
From: Zenghui Yu <yuzenghui@huawei.com>
1
2
3
Quote docs/devel/style.rst (section "Automatic memory deallocation"):
4
5
* Variables declared with g_auto* MUST always be initialized,
6
otherwise the cleanup function will use uninitialized stack memory
7
8
Initialize @name properly to get rid of the compilation error (using
9
gcc-7.3.0 on CentOS):
10
11
../hw/remote/proxy.c: In function 'pci_proxy_dev_realize':
12
/usr/include/glib-2.0/glib/glib-autocleanups.h:28:3: error: 'name' may be used uninitialized in this function [-Werror=maybe-uninitialized]
13
g_free (*pp);
14
^~~~~~~~~~~~
15
../hw/remote/proxy.c:350:30: note: 'name' was declared here
16
g_autofree char *name;
17
^~~~
18
19
Signed-off-by: Zenghui Yu <yuzenghui@huawei.com>
20
Reviewed-by: Jagannathan Raman <jag.raman@oracle.com>
21
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
22
Reviewed-by: Miroslav Rezanina <mrezanin@redhat.com>
23
Message-id: 20210312112143.1369-1-yuzenghui@huawei.com
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
25
---
26
hw/remote/memory.c | 5 ++---
27
hw/remote/proxy.c | 3 +--
28
2 files changed, 3 insertions(+), 5 deletions(-)
29
30
diff --git a/hw/remote/memory.c b/hw/remote/memory.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/hw/remote/memory.c
33
+++ b/hw/remote/memory.c
34
@@ -XXX,XX +XXX,XX @@ void remote_sysmem_reconfig(MPQemuMsg *msg, Error **errp)
35
36
remote_sysmem_reset();
37
38
- for (region = 0; region < msg->num_fds; region++) {
39
- g_autofree char *name;
40
+ for (region = 0; region < msg->num_fds; region++, suffix++) {
41
+ g_autofree char *name = g_strdup_printf("remote-mem-%u", suffix);
42
subregion = g_new(MemoryRegion, 1);
43
- name = g_strdup_printf("remote-mem-%u", suffix++);
44
memory_region_init_ram_from_fd(subregion, NULL,
45
name, sysmem_info->sizes[region],
46
true, msg->fds[region],
47
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/hw/remote/proxy.c
50
+++ b/hw/remote/proxy.c
51
@@ -XXX,XX +XXX,XX @@ static void probe_pci_info(PCIDevice *dev, Error **errp)
52
PCI_BASE_ADDRESS_SPACE_IO : PCI_BASE_ADDRESS_SPACE_MEMORY;
53
54
if (size) {
55
- g_autofree char *name;
56
+ g_autofree char *name = g_strdup_printf("bar-region-%d", i);
57
pdev->region[i].dev = pdev;
58
pdev->region[i].present = true;
59
if (type == PCI_BASE_ADDRESS_SPACE_MEMORY) {
60
pdev->region[i].memory = true;
61
}
62
- name = g_strdup_printf("bar-region-%d", i);
63
memory_region_init_io(&pdev->region[i].mr, OBJECT(pdev),
64
&proxy_mr_ops, &pdev->region[i],
65
name, size);
66
--
67
2.31.1
68
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
1
2
3
Document the following functions return the bitmap size
4
if no matching bit is found:
5
6
- find_first_bit
7
- find_next_bit
8
- find_last_bit
9
- find_first_zero_bit
10
- find_next_zero_bit
11
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
13
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Message-id: 20210510200758.2623154-2-philmd@redhat.com
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
---
18
include/qemu/bitops.h | 15 ++++++++++++---
19
1 file changed, 12 insertions(+), 3 deletions(-)
20
21
diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
22
index XXXXXXX..XXXXXXX 100644
23
--- a/include/qemu/bitops.h
24
+++ b/include/qemu/bitops.h
25
@@ -XXX,XX +XXX,XX @@ static inline int test_bit(long nr, const unsigned long *addr)
26
* @addr: The address to start the search at
27
* @size: The maximum size to search
28
*
29
- * Returns the bit number of the first set bit, or size.
30
+ * Returns the bit number of the last set bit,
31
+ * or @size if there is no set bit in the bitmap.
32
*/
33
unsigned long find_last_bit(const unsigned long *addr,
34
unsigned long size);
35
@@ -XXX,XX +XXX,XX @@ unsigned long find_last_bit(const unsigned long *addr,
36
* @addr: The address to base the search on
37
* @offset: The bitnumber to start searching at
38
* @size: The bitmap size in bits
39
+ *
40
+ * Returns the bit number of the next set bit,
41
+ * or @size if there are no further set bits in the bitmap.
42
*/
43
unsigned long find_next_bit(const unsigned long *addr,
44
unsigned long size,
45
@@ -XXX,XX +XXX,XX @@ unsigned long find_next_bit(const unsigned long *addr,
46
* @addr: The address to base the search on
47
* @offset: The bitnumber to start searching at
48
* @size: The bitmap size in bits
49
+ *
50
+ * Returns the bit number of the next cleared bit,
51
+ * or @size if there are no further clear bits in the bitmap.
52
*/
53
54
unsigned long find_next_zero_bit(const unsigned long *addr,
55
@@ -XXX,XX +XXX,XX @@ unsigned long find_next_zero_bit(const unsigned long *addr,
56
* @addr: The address to start the search at
57
* @size: The maximum size to search
58
*
59
- * Returns the bit number of the first set bit.
60
+ * Returns the bit number of the first set bit,
61
+ * or @size if there is no set bit in the bitmap.
62
*/
63
static inline unsigned long find_first_bit(const unsigned long *addr,
64
unsigned long size)
65
@@ -XXX,XX +XXX,XX @@ static inline unsigned long find_first_bit(const unsigned long *addr,
66
* @addr: The address to start the search at
67
* @size: The maximum size to search
68
*
69
- * Returns the bit number of the first cleared bit.
70
+ * Returns the bit number of the first cleared bit,
71
+ * or @size if there is no clear bit in the bitmap.
72
*/
73
static inline unsigned long find_first_zero_bit(const unsigned long *addr,
74
unsigned long size)
75
--
76
2.31.1
77
diff view generated by jsdifflib
New patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
2
3
The lifetime of the timer is well-known (it cannot outlive
4
qemu_co_sleep_ns_wakeable, because it's deleted by the time the
5
coroutine resumes), so it is not necessary to place it on the heap.
6
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Message-id: 20210517100548.28806-2-pbonzini@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
12
util/qemu-coroutine-sleep.c | 9 ++++-----
13
1 file changed, 4 insertions(+), 5 deletions(-)
14
15
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/util/qemu-coroutine-sleep.c
18
+++ b/util/qemu-coroutine-sleep.c
19
@@ -XXX,XX +XXX,XX @@ static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
20
21
struct QemuCoSleepState {
22
Coroutine *co;
23
- QEMUTimer *ts;
24
+ QEMUTimer ts;
25
QemuCoSleepState **user_state_pointer;
26
};
27
28
@@ -XXX,XX +XXX,XX @@ void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
29
if (sleep_state->user_state_pointer) {
30
*sleep_state->user_state_pointer = NULL;
31
}
32
- timer_del(sleep_state->ts);
33
+ timer_del(&sleep_state->ts);
34
aio_co_wake(sleep_state->co);
35
}
36
37
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
38
AioContext *ctx = qemu_get_current_aio_context();
39
QemuCoSleepState state = {
40
.co = qemu_coroutine_self(),
41
- .ts = aio_timer_new(ctx, type, SCALE_NS, co_sleep_cb, &state),
42
.user_state_pointer = sleep_state,
43
};
44
45
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
46
abort();
47
}
48
49
+ aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, &state);
50
if (sleep_state) {
51
*sleep_state = &state;
52
}
53
- timer_mod(state.ts, qemu_clock_get_ns(type) + ns);
54
+ timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
55
qemu_coroutine_yield();
56
if (sleep_state) {
57
/*
58
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
59
*/
60
assert(*sleep_state == NULL);
61
}
62
- timer_free(state.ts);
63
}
64
--
65
2.31.1
66
diff view generated by jsdifflib
New patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
2
3
Simplify the code by removing conditionals. qemu_co_sleep_ns
4
can simply point the argument to an on-stack temporary.
5
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Message-id: 20210517100548.28806-3-pbonzini@redhat.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
11
include/qemu/coroutine.h | 5 +++--
12
util/qemu-coroutine-sleep.c | 18 +++++-------------
13
2 files changed, 8 insertions(+), 15 deletions(-)
14
15
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
16
index XXXXXXX..XXXXXXX 100644
17
--- a/include/qemu/coroutine.h
18
+++ b/include/qemu/coroutine.h
19
@@ -XXX,XX +XXX,XX @@ typedef struct QemuCoSleepState QemuCoSleepState;
20
21
/**
22
* Yield the coroutine for a given duration. During this yield, @sleep_state
23
- * (if not NULL) is set to an opaque pointer, which may be used for
24
+ * is set to an opaque pointer, which may be used for
25
* qemu_co_sleep_wake(). Be careful, the pointer is set back to zero when the
26
* timer fires. Don't save the obtained value to other variables and don't call
27
* qemu_co_sleep_wake from another aio context.
28
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
29
QemuCoSleepState **sleep_state);
30
static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
31
{
32
- qemu_co_sleep_ns_wakeable(type, ns, NULL);
33
+ QemuCoSleepState *unused = NULL;
34
+ qemu_co_sleep_ns_wakeable(type, ns, &unused);
35
}
36
37
/**
38
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/util/qemu-coroutine-sleep.c
41
+++ b/util/qemu-coroutine-sleep.c
42
@@ -XXX,XX +XXX,XX @@ void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
43
qemu_co_sleep_ns__scheduled, NULL);
44
45
assert(scheduled == qemu_co_sleep_ns__scheduled);
46
- if (sleep_state->user_state_pointer) {
47
- *sleep_state->user_state_pointer = NULL;
48
- }
49
+ *sleep_state->user_state_pointer = NULL;
50
timer_del(&sleep_state->ts);
51
aio_co_wake(sleep_state->co);
52
}
53
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
54
}
55
56
aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, &state);
57
- if (sleep_state) {
58
- *sleep_state = &state;
59
- }
60
+ *sleep_state = &state;
61
timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
62
qemu_coroutine_yield();
63
- if (sleep_state) {
64
- /*
65
- * Note that *sleep_state is cleared during qemu_co_sleep_wake
66
- * before resuming this coroutine.
67
- */
68
- assert(*sleep_state == NULL);
69
- }
70
+
71
+ /* qemu_co_sleep_wake clears *sleep_state before resuming this coroutine. */
72
+ assert(*sleep_state == NULL);
73
}
74
--
75
2.31.1
76
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Allow block backends to forward drain requests to their devices/users.
3
All callers of qemu_co_sleep_wake are checking whether they are passing
4
The initial intended purpose for this patch is to allow BBs to forward
4
a NULL argument inside the pointer-to-pointer: do the check in
5
requests along to BlockJobs, which will want to pause if their associated
5
qemu_co_sleep_wake itself.
6
BB has entered a drained region.
7
6
8
Signed-off-by: John Snow <jsnow@redhat.com>
7
As a side effect, qemu_co_sleep_wake can be called more than once and
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
8
it will only wake the coroutine once; after the first time, the argument
10
Message-id: 20170316212351.13797-3-jsnow@redhat.com
9
will be set to NULL via *sleep_state->user_state_pointer. However, this
11
Signed-off-by: Jeff Cody <jcody@redhat.com>
10
would not be safe unless co_sleep_cb keeps using the QemuCoSleepState*
11
directly, so make it go through the pointer-to-pointer instead.
12
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
15
Message-id: 20210517100548.28806-4-pbonzini@redhat.com
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
17
---
13
block/block-backend.c | 24 ++++++++++++++++++++++--
18
block/block-copy.c | 4 +---
14
include/sysemu/block-backend.h | 8 ++++++++
19
block/nbd.c | 8 ++------
15
2 files changed, 30 insertions(+), 2 deletions(-)
20
util/qemu-coroutine-sleep.c | 21 ++++++++++++---------
21
3 files changed, 15 insertions(+), 18 deletions(-)
16
22
17
diff --git a/block/block-backend.c b/block/block-backend.c
23
diff --git a/block/block-copy.c b/block/block-copy.c
18
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
19
--- a/block/block-backend.c
25
--- a/block/block-copy.c
20
+++ b/block/block-backend.c
26
+++ b/block/block-copy.c
21
@@ -XXX,XX +XXX,XX @@ struct BlockBackend {
27
@@ -XXX,XX +XXX,XX @@ out:
22
bool allow_write_beyond_eof;
28
23
29
void block_copy_kick(BlockCopyCallState *call_state)
24
NotifierList remove_bs_notifiers, insert_bs_notifiers;
25
+
26
+ int quiesce_counter;
27
};
28
29
typedef struct BlockBackendAIOCB {
30
@@ -XXX,XX +XXX,XX @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
31
void *opaque)
32
{
30
{
33
/* All drivers that use blk_set_dev_ops() are qdevified and we want to keep
31
- if (call_state->sleep_state) {
34
- * it that way, so we can assume blk->dev is a DeviceState if blk->dev_ops
32
- qemu_co_sleep_wake(call_state->sleep_state);
35
- * is set. */
33
- }
36
+ * it that way, so we can assume blk->dev, if present, is a DeviceState if
34
+ qemu_co_sleep_wake(call_state->sleep_state);
37
+ * blk->dev_ops is set. Non-device users may use dev_ops without device. */
35
}
38
assert(!blk->legacy_dev);
36
39
37
/*
40
blk->dev_ops = ops;
38
diff --git a/block/nbd.c b/block/nbd.c
41
blk->dev_opaque = opaque;
39
index XXXXXXX..XXXXXXX 100644
42
+
40
--- a/block/nbd.c
43
+ /* Are we currently quiesced? Should we enforce this right now? */
41
+++ b/block/nbd.c
44
+ if (blk->quiesce_counter && ops->drained_begin) {
42
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn nbd_client_co_drain_begin(BlockDriverState *bs)
45
+ ops->drained_begin(opaque);
43
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
44
45
s->drained = true;
46
- if (s->connection_co_sleep_ns_state) {
47
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
48
- }
49
+ qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
50
51
nbd_co_establish_connection_cancel(bs, false);
52
53
@@ -XXX,XX +XXX,XX @@ static void nbd_teardown_connection(BlockDriverState *bs)
54
55
s->state = NBD_CLIENT_QUIT;
56
if (s->connection_co) {
57
- if (s->connection_co_sleep_ns_state) {
58
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
59
- }
60
+ qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
61
nbd_co_establish_connection_cancel(bs, true);
62
}
63
if (qemu_in_coroutine()) {
64
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/util/qemu-coroutine-sleep.c
67
+++ b/util/qemu-coroutine-sleep.c
68
@@ -XXX,XX +XXX,XX @@ struct QemuCoSleepState {
69
70
void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
71
{
72
- /* Write of schedule protected by barrier write in aio_co_schedule */
73
- const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled,
74
- qemu_co_sleep_ns__scheduled, NULL);
75
+ if (sleep_state) {
76
+ /* Write of schedule protected by barrier write in aio_co_schedule */
77
+ const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled,
78
+ qemu_co_sleep_ns__scheduled, NULL);
79
80
- assert(scheduled == qemu_co_sleep_ns__scheduled);
81
- *sleep_state->user_state_pointer = NULL;
82
- timer_del(&sleep_state->ts);
83
- aio_co_wake(sleep_state->co);
84
+ assert(scheduled == qemu_co_sleep_ns__scheduled);
85
+ *sleep_state->user_state_pointer = NULL;
86
+ timer_del(&sleep_state->ts);
87
+ aio_co_wake(sleep_state->co);
46
+ }
88
+ }
47
}
89
}
48
90
49
/*
91
static void co_sleep_cb(void *opaque)
50
@@ -XXX,XX +XXX,XX @@ static void blk_root_drained_begin(BdrvChild *child)
51
{
92
{
52
BlockBackend *blk = child->opaque;
93
- qemu_co_sleep_wake(opaque);
53
94
+ QemuCoSleepState **sleep_state = opaque;
54
+ if (++blk->quiesce_counter == 1) {
95
+ qemu_co_sleep_wake(*sleep_state);
55
+ if (blk->dev_ops && blk->dev_ops->drained_begin) {
56
+ blk->dev_ops->drained_begin(blk->dev_opaque);
57
+ }
58
+ }
59
+
60
/* Note that blk->root may not be accessible here yet if we are just
61
* attaching to a BlockDriverState that is drained. Use child instead. */
62
63
@@ -XXX,XX +XXX,XX @@ static void blk_root_drained_begin(BdrvChild *child)
64
static void blk_root_drained_end(BdrvChild *child)
65
{
66
BlockBackend *blk = child->opaque;
67
+ assert(blk->quiesce_counter);
68
69
assert(blk->public.io_limits_disabled);
70
--blk->public.io_limits_disabled;
71
+
72
+ if (--blk->quiesce_counter == 0) {
73
+ if (blk->dev_ops && blk->dev_ops->drained_end) {
74
+ blk->dev_ops->drained_end(blk->dev_opaque);
75
+ }
76
+ }
77
}
96
}
78
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
97
79
index XXXXXXX..XXXXXXX 100644
98
void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
80
--- a/include/sysemu/block-backend.h
99
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
81
+++ b/include/sysemu/block-backend.h
100
abort();
82
@@ -XXX,XX +XXX,XX @@ typedef struct BlockDevOps {
101
}
83
* Runs when the size changed (e.g. monitor command block_resize)
102
84
*/
103
- aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, &state);
85
void (*resize_cb)(void *opaque);
104
+ aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, sleep_state);
86
+ /*
105
*sleep_state = &state;
87
+ * Runs when the backend receives a drain request.
106
timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
88
+ */
107
qemu_coroutine_yield();
89
+ void (*drained_begin)(void *opaque);
90
+ /*
91
+ * Runs when the backend's last drain request ends.
92
+ */
93
+ void (*drained_end)(void *opaque);
94
} BlockDevOps;
95
96
/* This struct is embedded in (the private) BlockBackend struct and contains
97
--
108
--
98
2.9.3
109
2.31.1
99
110
100
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
This lets us hook into drained_begin and drained_end requests from the
3
This simplification is enabled by the previous patch. Now aio_co_wake
4
backend level, which is particularly useful for making sure that all
4
will only be called once, therefore we do not care about a spurious
5
jobs associated with a particular node (whether the source or the target)
5
firing of the timer after a qemu_co_sleep_wake.
6
receive a drain request.
7
6
8
Suggested-by: Kevin Wolf <kwolf@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Signed-off-by: John Snow <jsnow@redhat.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
10
Reviewed-by: Jeff Cody <jcody@redhat.com>
9
Message-id: 20210517100548.28806-5-pbonzini@redhat.com
11
Message-id: 20170316212351.13797-4-jsnow@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Jeff Cody <jcody@redhat.com>
13
---
11
---
14
blockjob.c | 29 ++++++++++++++++++++++++-----
12
util/qemu-coroutine-sleep.c | 8 ++++----
15
1 file changed, 24 insertions(+), 5 deletions(-)
13
1 file changed, 4 insertions(+), 4 deletions(-)
16
14
17
diff --git a/blockjob.c b/blockjob.c
15
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
18
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
19
--- a/blockjob.c
17
--- a/util/qemu-coroutine-sleep.c
20
+++ b/blockjob.c
18
+++ b/util/qemu-coroutine-sleep.c
21
@@ -XXX,XX +XXX,XX @@ static const BdrvChildRole child_job = {
19
@@ -XXX,XX +XXX,XX @@ static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
22
.stay_at_node = true,
20
21
struct QemuCoSleepState {
22
Coroutine *co;
23
- QEMUTimer ts;
24
QemuCoSleepState **user_state_pointer;
23
};
25
};
24
26
25
+static void block_job_drained_begin(void *opaque)
27
@@ -XXX,XX +XXX,XX @@ void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
26
+{
28
27
+ BlockJob *job = opaque;
29
assert(scheduled == qemu_co_sleep_ns__scheduled);
28
+ block_job_pause(job);
30
*sleep_state->user_state_pointer = NULL;
29
+}
31
- timer_del(&sleep_state->ts);
30
+
32
aio_co_wake(sleep_state->co);
31
+static void block_job_drained_end(void *opaque)
33
}
32
+{
34
}
33
+ BlockJob *job = opaque;
35
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
34
+ block_job_resume(job);
36
QemuCoSleepState **sleep_state)
35
+}
36
+
37
+static const BlockDevOps block_job_dev_ops = {
38
+ .drained_begin = block_job_drained_begin,
39
+ .drained_end = block_job_drained_end,
40
+};
41
+
42
BlockJob *block_job_next(BlockJob *job)
43
{
37
{
44
if (!job) {
38
AioContext *ctx = qemu_get_current_aio_context();
45
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
39
+ QEMUTimer ts;
40
QemuCoSleepState state = {
41
.co = qemu_coroutine_self(),
42
.user_state_pointer = sleep_state,
43
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
44
abort();
46
}
45
}
47
46
48
job = g_malloc0(driver->instance_size);
47
- aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, sleep_state);
49
- error_setg(&job->blocker, "block device is in use by block job: %s",
48
+ aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, sleep_state);
50
- BlockJobType_lookup[driver->job_type]);
49
*sleep_state = &state;
51
- block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort);
50
- timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
52
- bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
51
+ timer_mod(&ts, qemu_clock_get_ns(type) + ns);
53
-
52
qemu_coroutine_yield();
54
job->driver = driver;
53
+ timer_del(&ts);
55
job->id = g_strdup(job_id);
54
56
job->blk = blk;
55
/* qemu_co_sleep_wake clears *sleep_state before resuming this coroutine. */
57
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
56
assert(*sleep_state == NULL);
58
job->paused = true;
59
job->pause_count = 1;
60
job->refcnt = 1;
61
+
62
+ error_setg(&job->blocker, "block device is in use by block job: %s",
63
+ BlockJobType_lookup[driver->job_type]);
64
+ block_job_add_bdrv(job, "main node", bs, 0, BLK_PERM_ALL, &error_abort);
65
bs->job = job;
66
67
+ blk_set_dev_ops(blk, &block_job_dev_ops, job);
68
+ bdrv_op_unblock(bs, BLOCK_OP_TYPE_DATAPLANE, job->blocker);
69
+
70
QLIST_INSERT_HEAD(&block_jobs, job, job_list);
71
72
blk_add_aio_context_notifier(blk, block_job_attached_aio_context,
73
--
57
--
74
2.9.3
58
2.31.1
75
59
76
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
The purpose of this shim is to allow us to pause pre-started jobs.
3
Right now, users of qemu_co_sleep_ns_wakeable are simply passing
4
The purpose of *that* is to allow us to buffer a pause request that
4
a pointer to QemuCoSleepState by reference to the function. But
5
will be able to take effect before the job ever does any work, allowing
5
QemuCoSleepState really is just a Coroutine*; making the
6
us to create jobs during a quiescent state (under which they will be
6
content of the struct public is just as efficient and lets us
7
automatically paused), then resuming the jobs after the critical section
7
skip the user_state_pointer indirection.
8
in any order, either:
8
9
9
Since the usage is changed, take the occasion to rename the
10
(1) -block_job_start
10
struct to QemuCoSleep.
11
-block_job_resume (via e.g. drained_end)
11
12
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
(2) -block_job_resume (via e.g. drained_end)
13
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
14
-block_job_start
14
Message-id: 20210517100548.28806-6-pbonzini@redhat.com
15
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
16
The problem that requires a startup wrapper is the idea that a job must
17
start in the busy=true state only its first time-- all subsequent entries
18
require busy to be false, and the toggling of this state is otherwise
19
handled during existing pause and yield points.
20
21
The wrapper simply allows us to mandate that a job can "start," set busy
22
to true, then immediately pause only if necessary. We could avoid
23
requiring a wrapper, but all jobs would need to do it, so it's been
24
factored out here.
25
26
Signed-off-by: John Snow <jsnow@redhat.com>
27
Reviewed-by: Jeff Cody <jcody@redhat.com>
28
Message-id: 20170316212351.13797-2-jsnow@redhat.com
29
Signed-off-by: Jeff Cody <jcody@redhat.com>
30
---
16
---
31
blockjob.c | 26 +++++++++++++++++++-------
17
include/qemu/coroutine.h | 23 +++++++++++----------
32
1 file changed, 19 insertions(+), 7 deletions(-)
18
block/block-copy.c | 8 ++++----
33
19
block/nbd.c | 10 ++++-----
34
diff --git a/blockjob.c b/blockjob.c
20
util/qemu-coroutine-sleep.c | 41 ++++++++++++++++---------------------
35
index XXXXXXX..XXXXXXX 100644
21
4 files changed, 39 insertions(+), 43 deletions(-)
36
--- a/blockjob.c
22
37
+++ b/blockjob.c
23
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
38
@@ -XXX,XX +XXX,XX @@ static bool block_job_started(BlockJob *job)
24
index XXXXXXX..XXXXXXX 100644
39
return job->co;
25
--- a/include/qemu/coroutine.h
40
}
26
+++ b/include/qemu/coroutine.h
41
27
@@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_wrlock(CoRwlock *lock);
42
+/**
28
*/
43
+ * All jobs must allow a pause point before entering their job proper. This
29
void qemu_co_rwlock_unlock(CoRwlock *lock);
44
+ * ensures that jobs can be paused prior to being started, then resumed later.
30
45
+ */
31
-typedef struct QemuCoSleepState QemuCoSleepState;
46
+static void coroutine_fn block_job_co_entry(void *opaque)
32
+typedef struct QemuCoSleep {
33
+ Coroutine *to_wake;
34
+} QemuCoSleep;
35
36
/**
37
- * Yield the coroutine for a given duration. During this yield, @sleep_state
38
- * is set to an opaque pointer, which may be used for
39
- * qemu_co_sleep_wake(). Be careful, the pointer is set back to zero when the
40
- * timer fires. Don't save the obtained value to other variables and don't call
41
- * qemu_co_sleep_wake from another aio context.
42
+ * Yield the coroutine for a given duration. Initializes @w so that,
43
+ * during this yield, it can be passed to qemu_co_sleep_wake() to
44
+ * terminate the sleep.
45
*/
46
-void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
47
- QemuCoSleepState **sleep_state);
48
+void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
49
+ QEMUClockType type, int64_t ns);
50
+
51
static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
52
{
53
- QemuCoSleepState *unused = NULL;
54
- qemu_co_sleep_ns_wakeable(type, ns, &unused);
55
+ QemuCoSleep w = { 0 };
56
+ qemu_co_sleep_ns_wakeable(&w, type, ns);
57
}
58
59
/**
60
@@ -XXX,XX +XXX,XX @@ static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
61
* qemu_co_sleep_ns() and should be checked to be non-NULL before calling
62
* qemu_co_sleep_wake().
63
*/
64
-void qemu_co_sleep_wake(QemuCoSleepState *sleep_state);
65
+void qemu_co_sleep_wake(QemuCoSleep *w);
66
67
/**
68
* Yield until a file descriptor becomes readable
69
diff --git a/block/block-copy.c b/block/block-copy.c
70
index XXXXXXX..XXXXXXX 100644
71
--- a/block/block-copy.c
72
+++ b/block/block-copy.c
73
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyCallState {
74
/* State */
75
int ret;
76
bool finished;
77
- QemuCoSleepState *sleep_state;
78
+ QemuCoSleep sleep;
79
bool cancelled;
80
81
/* OUT parameters */
82
@@ -XXX,XX +XXX,XX @@ block_copy_dirty_clusters(BlockCopyCallState *call_state)
83
if (ns > 0) {
84
block_copy_task_end(task, -EAGAIN);
85
g_free(task);
86
- qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, ns,
87
- &call_state->sleep_state);
88
+ qemu_co_sleep_ns_wakeable(&call_state->sleep,
89
+ QEMU_CLOCK_REALTIME, ns);
90
continue;
91
}
92
}
93
@@ -XXX,XX +XXX,XX @@ out:
94
95
void block_copy_kick(BlockCopyCallState *call_state)
96
{
97
- qemu_co_sleep_wake(call_state->sleep_state);
98
+ qemu_co_sleep_wake(&call_state->sleep);
99
}
100
101
/*
102
diff --git a/block/nbd.c b/block/nbd.c
103
index XXXXXXX..XXXXXXX 100644
104
--- a/block/nbd.c
105
+++ b/block/nbd.c
106
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVNBDState {
107
CoQueue free_sema;
108
Coroutine *connection_co;
109
Coroutine *teardown_co;
110
- QemuCoSleepState *connection_co_sleep_ns_state;
111
+ QemuCoSleep reconnect_sleep;
112
bool drained;
113
bool wait_drained_end;
114
int in_flight;
115
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn nbd_client_co_drain_begin(BlockDriverState *bs)
116
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
117
118
s->drained = true;
119
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
120
+ qemu_co_sleep_wake(&s->reconnect_sleep);
121
122
nbd_co_establish_connection_cancel(bs, false);
123
124
@@ -XXX,XX +XXX,XX @@ static void nbd_teardown_connection(BlockDriverState *bs)
125
126
s->state = NBD_CLIENT_QUIT;
127
if (s->connection_co) {
128
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
129
+ qemu_co_sleep_wake(&s->reconnect_sleep);
130
nbd_co_establish_connection_cancel(bs, true);
131
}
132
if (qemu_in_coroutine()) {
133
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s)
134
}
135
bdrv_inc_in_flight(s->bs);
136
} else {
137
- qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, timeout,
138
- &s->connection_co_sleep_ns_state);
139
+ qemu_co_sleep_ns_wakeable(&s->reconnect_sleep,
140
+ QEMU_CLOCK_REALTIME, timeout);
141
if (s->drained) {
142
continue;
143
}
144
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
145
index XXXXXXX..XXXXXXX 100644
146
--- a/util/qemu-coroutine-sleep.c
147
+++ b/util/qemu-coroutine-sleep.c
148
@@ -XXX,XX +XXX,XX @@
149
150
static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
151
152
-struct QemuCoSleepState {
153
+void qemu_co_sleep_wake(QemuCoSleep *w)
47
+{
154
+{
48
+ BlockJob *job = opaque;
155
Coroutine *co;
49
+
156
- QemuCoSleepState **user_state_pointer;
50
+ assert(job && job->driver && job->driver->start);
157
-};
51
+ block_job_pause_point(job);
158
52
+ job->driver->start(job);
159
-void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
53
+}
160
-{
54
+
161
- if (sleep_state) {
55
void block_job_start(BlockJob *job)
162
+ co = w->to_wake;
56
{
163
+ w->to_wake = NULL;
57
assert(job && !block_job_started(job) && job->paused &&
164
+ if (co) {
58
- !job->busy && job->driver->start);
165
/* Write of schedule protected by barrier write in aio_co_schedule */
59
- job->co = qemu_coroutine_create(job->driver->start, job);
166
- const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled,
60
- if (--job->pause_count == 0) {
167
+ const char *scheduled = qatomic_cmpxchg(&co->scheduled,
61
- job->paused = false;
168
qemu_co_sleep_ns__scheduled, NULL);
62
- job->busy = true;
169
63
- qemu_coroutine_enter(job->co);
170
assert(scheduled == qemu_co_sleep_ns__scheduled);
64
- }
171
- *sleep_state->user_state_pointer = NULL;
65
+ job->driver && job->driver->start);
172
- aio_co_wake(sleep_state->co);
66
+ job->co = qemu_coroutine_create(block_job_co_entry, job);
173
+ aio_co_wake(co);
67
+ job->pause_count--;
174
}
68
+ job->busy = true;
175
}
69
+ job->paused = false;
176
70
+ qemu_coroutine_enter(job->co);
177
static void co_sleep_cb(void *opaque)
71
}
178
{
72
179
- QemuCoSleepState **sleep_state = opaque;
73
void block_job_ref(BlockJob *job)
180
- qemu_co_sleep_wake(*sleep_state);
181
+ QemuCoSleep *w = opaque;
182
+ qemu_co_sleep_wake(w);
183
}
184
185
-void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
186
- QemuCoSleepState **sleep_state)
187
+void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
188
+ QEMUClockType type, int64_t ns)
189
{
190
+ Coroutine *co = qemu_coroutine_self();
191
AioContext *ctx = qemu_get_current_aio_context();
192
QEMUTimer ts;
193
- QemuCoSleepState state = {
194
- .co = qemu_coroutine_self(),
195
- .user_state_pointer = sleep_state,
196
- };
197
198
- const char *scheduled = qatomic_cmpxchg(&state.co->scheduled, NULL,
199
- qemu_co_sleep_ns__scheduled);
200
+ const char *scheduled = qatomic_cmpxchg(&co->scheduled, NULL,
201
+ qemu_co_sleep_ns__scheduled);
202
if (scheduled) {
203
fprintf(stderr,
204
"%s: Co-routine was already scheduled in '%s'\n",
205
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
206
abort();
207
}
208
209
- aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, sleep_state);
210
- *sleep_state = &state;
211
+ w->to_wake = co;
212
+ aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w),
213
timer_mod(&ts, qemu_clock_get_ns(type) + ns);
214
qemu_coroutine_yield();
215
timer_del(&ts);
216
217
- /* qemu_co_sleep_wake clears *sleep_state before resuming this coroutine. */
218
- assert(*sleep_state == NULL);
219
+ /* w->to_wake is cleared before resuming this coroutine. */
220
+ assert(w->to_wake == NULL);
221
}
74
--
222
--
75
2.9.3
223
2.31.1
76
224
77
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Streaming or any other block job hangs when performed on a block device
3
Allow using QemuCoSleep to sleep forever until woken by qemu_co_sleep_wake.
4
that has a non-default iothread. This happens because the AioContext
4
This makes the logic of qemu_co_sleep_ns_wakeable easy to understand.
5
is acquired twice by block_job_defer_to_main_loop_bh and then released
6
only once by BDRV_POLL_WHILE. (Insert rants on recursive mutexes, which
7
unfortunately are a temporary but necessary evil for iothreads at the
8
moment).
9
5
10
Luckily, the reason for the double acquisition is simple; the function
6
In the future we will introduce an API that can work even if the
11
acquires the AioContext for both the job iothread and the BDS iothread,
7
sleep and wake happen from different threads. For now, initializing
12
in case the BDS iothread was changed while the job was running. It
8
w->to_wake after timer_mod is fine because the timer can only fire in
13
is therefore enough to skip the second acquisition when the two
9
the same AioContext.
14
AioContexts are one and the same.
15
10
11
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
12
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
17
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Message-id: 20210517100548.28806-7-pbonzini@redhat.com
18
Reviewed-by: Jeff Cody <jcody@redhat.com>
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Message-id: 1490118490-5597-1-git-send-email-pbonzini@redhat.com
20
Signed-off-by: Jeff Cody <jcody@redhat.com>
21
---
15
---
22
blockjob.c | 8 ++++++--
16
include/qemu/coroutine.h | 5 +++++
23
1 file changed, 6 insertions(+), 2 deletions(-)
17
util/qemu-coroutine-sleep.c | 26 +++++++++++++++++++-------
18
2 files changed, 24 insertions(+), 7 deletions(-)
24
19
25
diff --git a/blockjob.c b/blockjob.c
20
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
26
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
27
--- a/blockjob.c
22
--- a/include/qemu/coroutine.h
28
+++ b/blockjob.c
23
+++ b/include/qemu/coroutine.h
29
@@ -XXX,XX +XXX,XX @@ static void block_job_defer_to_main_loop_bh(void *opaque)
24
@@ -XXX,XX +XXX,XX @@ typedef struct QemuCoSleep {
30
25
void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
31
/* Fetch BDS AioContext again, in case it has changed */
26
QEMUClockType type, int64_t ns);
32
aio_context = blk_get_aio_context(data->job->blk);
27
33
- aio_context_acquire(aio_context);
28
+/**
34
+ if (aio_context != data->aio_context) {
29
+ * Yield the coroutine until the next call to qemu_co_sleep_wake.
35
+ aio_context_acquire(aio_context);
30
+ */
36
+ }
31
+void coroutine_fn qemu_co_sleep(QemuCoSleep *w);
37
32
+
38
data->job->deferred_to_main_loop = false;
33
static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
39
data->fn(data->job, data->opaque);
34
{
40
35
QemuCoSleep w = { 0 };
41
- aio_context_release(aio_context);
36
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
42
+ if (aio_context != data->aio_context) {
37
index XXXXXXX..XXXXXXX 100644
43
+ aio_context_release(aio_context);
38
--- a/util/qemu-coroutine-sleep.c
44
+ }
39
+++ b/util/qemu-coroutine-sleep.c
45
40
@@ -XXX,XX +XXX,XX @@ static void co_sleep_cb(void *opaque)
46
aio_context_release(data->aio_context);
41
qemu_co_sleep_wake(w);
47
42
}
43
44
-void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
45
- QEMUClockType type, int64_t ns)
46
+void coroutine_fn qemu_co_sleep(QemuCoSleep *w)
47
{
48
Coroutine *co = qemu_coroutine_self();
49
- AioContext *ctx = qemu_get_current_aio_context();
50
- QEMUTimer ts;
51
52
const char *scheduled = qatomic_cmpxchg(&co->scheduled, NULL,
53
qemu_co_sleep_ns__scheduled);
54
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
55
}
56
57
w->to_wake = co;
58
- aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w),
59
- timer_mod(&ts, qemu_clock_get_ns(type) + ns);
60
qemu_coroutine_yield();
61
- timer_del(&ts);
62
63
/* w->to_wake is cleared before resuming this coroutine. */
64
assert(w->to_wake == NULL);
65
}
66
+
67
+void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
68
+ QEMUClockType type, int64_t ns)
69
+{
70
+ AioContext *ctx = qemu_get_current_aio_context();
71
+ QEMUTimer ts;
72
+
73
+ aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w);
74
+ timer_mod(&ts, qemu_clock_get_ns(type) + ns);
75
+
76
+ /*
77
+ * The timer will fire in the current AiOContext, so the callback
78
+ * must happen after qemu_co_sleep yields and there is no race
79
+ * between timer_mod and qemu_co_sleep.
80
+ */
81
+ qemu_co_sleep(w);
82
+ timer_del(&ts);
83
+}
48
--
84
--
49
2.9.3
85
2.31.1
50
86
51
diff view generated by jsdifflib