1
The following changes since commit 804b30d25f8d70dc2dea951883ea92235274a50c:
1
The following changes since commit 56f9e46b841c7be478ca038d8d4085d776ab4b0d:
2
2
3
Merge remote-tracking branch 'remotes/legoater/tags/pull-ppc-20220130' into staging (2022-01-31 11:10:08 +0000)
3
Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2017-02-20' into staging (2017-02-20 17:42:47 +0000)
4
4
5
are available in the Git repository at:
5
are available in the git repository at:
6
6
7
https://gitlab.com/hreitz/qemu.git tags/pull-block-2022-02-01
7
git://github.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to 751486c18555169ca4baf59440275d5831140822:
9
for you to fetch changes up to a7b91d35bab97a2d3e779d0c64c9b837b52a6cf7:
10
10
11
block.h: remove outdated comment (2022-02-01 13:28:53 +0100)
11
coroutine-lock: make CoRwlock thread-safe and fair (2017-02-21 11:39:40 +0000)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
14
Pull request
15
- Add support to the iotests to test qcow2's zstd compression mode
15
16
- Fix post-migration block node permissions
16
v2:
17
- iotests fixes (051 and mirror-ready-cancel-error)
17
* Rebased to resolve scsi conflicts
18
- Remove an outdated comment
19
18
20
----------------------------------------------------------------
19
----------------------------------------------------------------
21
Emanuele Giuseppe Esposito (1):
22
block.h: remove outdated comment
23
20
24
Hanna Reitz (3):
21
Paolo Bonzini (24):
25
iotests/MRCE: Write data to source
22
block: move AioContext, QEMUTimer, main-loop to libqemuutil
26
block-backend: Retain permissions after migration
23
aio: introduce aio_co_schedule and aio_co_wake
27
iotests/migration-permissions: New test
24
block-backend: allow blk_prw from coroutine context
25
test-thread-pool: use generic AioContext infrastructure
26
io: add methods to set I/O handlers on AioContext
27
io: make qio_channel_yield aware of AioContexts
28
nbd: convert to use qio_channel_yield
29
coroutine-lock: reschedule coroutine on the AioContext it was running
30
on
31
blkdebug: reschedule coroutine on the AioContext it is running on
32
qed: introduce qed_aio_start_io and qed_aio_next_io_cb
33
aio: push aio_context_acquire/release down to dispatching
34
block: explicitly acquire aiocontext in timers that need it
35
block: explicitly acquire aiocontext in callbacks that need it
36
block: explicitly acquire aiocontext in bottom halves that need it
37
block: explicitly acquire aiocontext in aio callbacks that need it
38
aio-posix: partially inline aio_dispatch into aio_poll
39
async: remove unnecessary inc/dec pairs
40
block: document fields protected by AioContext lock
41
coroutine-lock: make CoMutex thread-safe
42
coroutine-lock: add limited spinning to CoMutex
43
test-aio-multithread: add performance comparison with thread-based
44
mutexes
45
coroutine-lock: place CoMutex before CoQueue in header
46
coroutine-lock: add mutex argument to CoQueue APIs
47
coroutine-lock: make CoRwlock thread-safe and fair
28
48
29
Thomas Huth (1):
49
Makefile.objs | 4 -
30
tests/qemu-iotests: Fix 051 for binaries without 'lsi53c895a'
50
stubs/Makefile.objs | 1 +
31
51
tests/Makefile.include | 19 +-
32
Vladimir Sementsov-Ogievskiy (19):
52
util/Makefile.objs | 6 +-
33
iotests.py: img_info_log(): rename imgopts argument
53
block/nbd-client.h | 2 +-
34
iotests.py: implement unsupported_imgopts
54
block/qed.h | 3 +
35
iotests: specify some unsupported_imgopts for python iotests
55
include/block/aio.h | 38 ++-
36
iotests.py: qemu_img*("create"): support
56
include/block/block_int.h | 64 +++--
37
IMGOPTS='compression_type=zstd'
57
include/io/channel.h | 72 +++++-
38
iotests: drop qemu_img_verbose() helper
58
include/qemu/coroutine.h | 84 ++++---
39
iotests.py: rewrite default luks support in qemu_img
59
include/qemu/coroutine_int.h | 11 +-
40
iotest 303: explicit compression type
60
include/sysemu/block-backend.h | 14 +-
41
iotest 065: explicit compression type
61
tests/iothread.h | 25 ++
42
iotests.py: filter out successful output of qemu-img create
62
block/backup.c | 2 +-
43
iotests.py: filter compression type out
63
block/blkdebug.c | 9 +-
44
iotest 302: use img_info_log() helper
64
block/blkreplay.c | 2 +-
45
qcow2: simple case support for downgrading of qcow2 images with zstd
65
block/block-backend.c | 13 +-
46
iotests/common.rc: introduce _qcow2_dump_header helper
66
block/curl.c | 44 +++-
47
iotests: massive use _qcow2_dump_header
67
block/gluster.c | 9 +-
48
iotest 39: use _qcow2_dump_header
68
block/io.c | 42 +---
49
iotests: bash tests: filter compression type
69
block/iscsi.c | 15 +-
50
iotests 60: more accurate set dirty bit in qcow2 header
70
block/linux-aio.c | 10 +-
51
iotest 214: explicit compression type
71
block/mirror.c | 12 +-
52
iotests: declare lack of support for compresion_type in IMGOPTS
72
block/nbd-client.c | 119 +++++----
53
73
block/nfs.c | 9 +-
54
include/block/block.h | 1 -
74
block/qcow2-cluster.c | 4 +-
55
block/block-backend.c | 11 ++
75
block/qed-cluster.c | 2 +
56
block/qcow2.c | 58 +++++++++-
76
block/qed-table.c | 12 +-
57
tests/qemu-iotests/031 | 11 +-
77
block/qed.c | 58 +++--
58
tests/qemu-iotests/036 | 6 +-
78
block/sheepdog.c | 31 +--
59
tests/qemu-iotests/039 | 22 ++--
79
block/ssh.c | 29 +--
60
tests/qemu-iotests/044 | 8 +-
80
block/throttle-groups.c | 4 +-
61
tests/qemu-iotests/044.out | 1 +
81
block/win32-aio.c | 9 +-
62
tests/qemu-iotests/051 | 9 +-
82
dma-helpers.c | 2 +
63
tests/qemu-iotests/060 | 22 ++--
83
hw/9pfs/9p.c | 2 +-
64
tests/qemu-iotests/060.out | 2 +-
84
hw/block/virtio-blk.c | 19 +-
65
tests/qemu-iotests/061 | 42 ++++----
85
hw/scsi/scsi-bus.c | 2 +
66
tests/qemu-iotests/061.out | 12 +--
86
hw/scsi/scsi-disk.c | 15 ++
67
tests/qemu-iotests/065 | 19 ++--
87
hw/scsi/scsi-generic.c | 20 +-
68
tests/qemu-iotests/082.out | 14 +--
88
hw/scsi/virtio-scsi.c | 7 +
69
tests/qemu-iotests/112 | 3 +-
89
io/channel-command.c | 13 +
70
tests/qemu-iotests/137 | 2 +-
90
io/channel-file.c | 11 +
71
tests/qemu-iotests/149.out | 21 ----
91
io/channel-socket.c | 16 +-
72
tests/qemu-iotests/163 | 3 +-
92
io/channel-tls.c | 12 +
73
tests/qemu-iotests/165 | 3 +-
93
io/channel-watch.c | 6 +
74
tests/qemu-iotests/196 | 3 +-
94
io/channel.c | 97 ++++++--
75
tests/qemu-iotests/198.out | 4 +-
95
nbd/client.c | 2 +-
76
tests/qemu-iotests/206.out | 10 +-
96
nbd/common.c | 9 +-
77
tests/qemu-iotests/209 | 7 +-
97
nbd/server.c | 94 +++-----
78
tests/qemu-iotests/209.out | 2 +
98
stubs/linux-aio.c | 32 +++
79
tests/qemu-iotests/210 | 8 +-
99
stubs/set-fd-handler.c | 11 -
80
tests/qemu-iotests/214 | 2 +-
100
tests/iothread.c | 91 +++++++
81
tests/qemu-iotests/237.out | 3 -
101
tests/test-aio-multithread.c | 463 ++++++++++++++++++++++++++++++++++++
82
tests/qemu-iotests/242 | 3 +-
102
tests/test-thread-pool.c | 12 +-
83
tests/qemu-iotests/242.out | 10 +-
103
aio-posix.c => util/aio-posix.c | 62 ++---
84
tests/qemu-iotests/246 | 3 +-
104
aio-win32.c => util/aio-win32.c | 30 +--
85
tests/qemu-iotests/254 | 3 +-
105
util/aiocb.c | 55 +++++
86
tests/qemu-iotests/255.out | 4 -
106
async.c => util/async.c | 84 ++++++-
87
tests/qemu-iotests/260 | 3 +-
107
iohandler.c => util/iohandler.c | 0
88
tests/qemu-iotests/274 | 3 +-
108
main-loop.c => util/main-loop.c | 0
89
tests/qemu-iotests/274.out | 39 +------
109
util/qemu-coroutine-lock.c | 254 ++++++++++++++++++--
90
tests/qemu-iotests/280.out | 1 -
110
util/qemu-coroutine-sleep.c | 2 +-
91
tests/qemu-iotests/281 | 3 +-
111
util/qemu-coroutine.c | 8 +
92
tests/qemu-iotests/287 | 8 +-
112
qemu-timer.c => util/qemu-timer.c | 0
93
tests/qemu-iotests/290 | 2 +-
113
thread-pool.c => util/thread-pool.c | 8 +-
94
tests/qemu-iotests/296.out | 10 +-
114
trace-events | 11 -
95
tests/qemu-iotests/302 | 4 +-
115
util/trace-events | 17 +-
96
tests/qemu-iotests/302.out | 7 +-
116
67 files changed, 1712 insertions(+), 533 deletions(-)
97
tests/qemu-iotests/303 | 26 +++--
117
create mode 100644 tests/iothread.h
98
tests/qemu-iotests/303.out | 30 +++++-
118
create mode 100644 stubs/linux-aio.c
99
tests/qemu-iotests/common.filter | 8 ++
119
create mode 100644 tests/iothread.c
100
tests/qemu-iotests/common.rc | 22 ++++
120
create mode 100644 tests/test-aio-multithread.c
101
tests/qemu-iotests/iotests.py | 99 +++++++++++------
121
rename aio-posix.c => util/aio-posix.c (94%)
102
.../tests/migrate-bitmaps-postcopy-test | 3 +-
122
rename aio-win32.c => util/aio-win32.c (95%)
103
tests/qemu-iotests/tests/migrate-bitmaps-test | 3 +-
123
create mode 100644 util/aiocb.c
104
.../qemu-iotests/tests/migration-permissions | 101 ++++++++++++++++++
124
rename async.c => util/async.c (82%)
105
.../tests/migration-permissions.out | 5 +
125
rename iohandler.c => util/iohandler.c (100%)
106
.../tests/mirror-ready-cancel-error | 7 +-
126
rename main-loop.c => util/main-loop.c (100%)
107
.../tests/remove-bitmap-from-backing | 3 +-
127
rename qemu-timer.c => util/qemu-timer.c (100%)
108
54 files changed, 483 insertions(+), 236 deletions(-)
128
rename thread-pool.c => util/thread-pool.c (97%)
109
create mode 100755 tests/qemu-iotests/tests/migration-permissions
110
create mode 100644 tests/qemu-iotests/tests/migration-permissions.out
111
129
112
--
130
--
113
2.34.1
131
2.9.3
114
132
115
133
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
qemu_img_verbose() has a drawback of not going through generic
3
AioContext is fairly self contained, the only dependency is QEMUTimer but
4
qemu_img_pipe_and_status(). qemu_img_verbose() is not very popular, so
4
that in turn doesn't need anything else. So move them out of block-obj-y
5
update the only two users to qemu_img_log() and drop qemu_img_verbose()
5
to avoid introducing a dependency from io/ to block-obj-y.
6
at all.
6
7
7
main-loop and its dependency iohandler also need to be moved, because
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
later in this series io/ will call iohandler_get_aio_context.
9
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
9
10
Message-Id: <20211223160144.1097696-6-vsementsov@virtuozzo.com>
10
[Changed copyright "the QEMU team" to "other QEMU contributors" as
11
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
11
suggested by Daniel Berrange and agreed by Paolo.
12
--Stefan]
13
14
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
15
Reviewed-by: Fam Zheng <famz@redhat.com>
16
Message-id: 20170213135235.12274-2-pbonzini@redhat.com
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
18
---
13
tests/qemu-iotests/044 | 5 +++--
19
Makefile.objs | 4 ---
14
tests/qemu-iotests/044.out | 1 +
20
stubs/Makefile.objs | 1 +
15
tests/qemu-iotests/209 | 7 ++++---
21
tests/Makefile.include | 11 ++++----
16
tests/qemu-iotests/209.out | 2 ++
22
util/Makefile.objs | 6 +++-
17
tests/qemu-iotests/iotests.py | 8 --------
23
block/io.c | 29 -------------------
18
5 files changed, 10 insertions(+), 13 deletions(-)
24
stubs/linux-aio.c | 32 +++++++++++++++++++++
19
25
stubs/set-fd-handler.c | 11 --------
20
diff --git a/tests/qemu-iotests/044 b/tests/qemu-iotests/044
26
aio-posix.c => util/aio-posix.c | 2 +-
21
index XXXXXXX..XXXXXXX 100755
27
aio-win32.c => util/aio-win32.c | 0
22
--- a/tests/qemu-iotests/044
28
util/aiocb.c | 55 +++++++++++++++++++++++++++++++++++++
23
+++ b/tests/qemu-iotests/044
29
async.c => util/async.c | 3 +-
24
@@ -XXX,XX +XXX,XX @@ import os
30
iohandler.c => util/iohandler.c | 0
25
import qcow2
31
main-loop.c => util/main-loop.c | 0
26
from qcow2 import QcowHeader
32
qemu-timer.c => util/qemu-timer.c | 0
27
import iotests
33
thread-pool.c => util/thread-pool.c | 2 +-
28
-from iotests import qemu_img, qemu_img_verbose, qemu_io
34
trace-events | 11 --------
29
+from iotests import qemu_img, qemu_img_log, qemu_io
35
util/trace-events | 11 ++++++++
30
import struct
36
17 files changed, 114 insertions(+), 64 deletions(-)
31
import subprocess
37
create mode 100644 stubs/linux-aio.c
32
import sys
38
rename aio-posix.c => util/aio-posix.c (99%)
33
@@ -XXX,XX +XXX,XX @@ class TestRefcountTableGrowth(iotests.QMPTestCase):
39
rename aio-win32.c => util/aio-win32.c (100%)
34
40
create mode 100644 util/aiocb.c
35
def test_grow_refcount_table(self):
41
rename async.c => util/async.c (99%)
36
qemu_io('-c', 'write 3800M 1M', test_img)
42
rename iohandler.c => util/iohandler.c (100%)
37
- qemu_img_verbose('check' , test_img)
43
rename main-loop.c => util/main-loop.c (100%)
38
+ qemu_img_log('check' , test_img)
44
rename qemu-timer.c => util/qemu-timer.c (100%)
39
pass
45
rename thread-pool.c => util/thread-pool.c (99%)
40
46
41
if __name__ == '__main__':
47
diff --git a/Makefile.objs b/Makefile.objs
42
+ iotests.activate_logging()
48
index XXXXXXX..XXXXXXX 100644
43
iotests.main(supported_fmts=['qcow2'],
49
--- a/Makefile.objs
44
supported_protocols=['file'],
50
+++ b/Makefile.objs
45
unsupported_imgopts=['refcount_bits'])
51
@@ -XXX,XX +XXX,XX @@ chardev-obj-y = chardev/
46
diff --git a/tests/qemu-iotests/044.out b/tests/qemu-iotests/044.out
52
#######################################################################
47
index XXXXXXX..XXXXXXX 100644
53
# block-obj-y is code used by both qemu system emulation and qemu-img
48
--- a/tests/qemu-iotests/044.out
54
49
+++ b/tests/qemu-iotests/044.out
55
-block-obj-y = async.o thread-pool.o
50
@@ -XXX,XX +XXX,XX @@
56
block-obj-y += nbd/
51
No errors were found on the image.
57
block-obj-y += block.o blockjob.o
52
7292415/33554432 = 21.73% allocated, 0.00% fragmented, 0.00% compressed clusters
58
-block-obj-y += main-loop.o iohandler.o qemu-timer.o
53
Image end offset: 4296217088
59
-block-obj-$(CONFIG_POSIX) += aio-posix.o
54
+
60
-block-obj-$(CONFIG_WIN32) += aio-win32.o
55
.
61
block-obj-y += block/
56
----------------------------------------------------------------------
62
block-obj-y += qemu-io-cmds.o
57
Ran 1 tests
63
block-obj-$(CONFIG_REPLICATION) += replication.o
58
diff --git a/tests/qemu-iotests/209 b/tests/qemu-iotests/209
64
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
59
index XXXXXXX..XXXXXXX 100755
65
index XXXXXXX..XXXXXXX 100644
60
--- a/tests/qemu-iotests/209
66
--- a/stubs/Makefile.objs
61
+++ b/tests/qemu-iotests/209
67
+++ b/stubs/Makefile.objs
68
@@ -XXX,XX +XXX,XX @@ stub-obj-y += get-vm-name.o
69
stub-obj-y += iothread.o
70
stub-obj-y += iothread-lock.o
71
stub-obj-y += is-daemonized.o
72
+stub-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
73
stub-obj-y += machine-init-done.o
74
stub-obj-y += migr-blocker.o
75
stub-obj-y += monitor.o
76
diff --git a/tests/Makefile.include b/tests/Makefile.include
77
index XXXXXXX..XXXXXXX 100644
78
--- a/tests/Makefile.include
79
+++ b/tests/Makefile.include
80
@@ -XXX,XX +XXX,XX @@ check-unit-y += tests/test-visitor-serialization$(EXESUF)
81
check-unit-y += tests/test-iov$(EXESUF)
82
gcov-files-test-iov-y = util/iov.c
83
check-unit-y += tests/test-aio$(EXESUF)
84
+gcov-files-test-aio-y = util/async.c util/qemu-timer.o
85
+gcov-files-test-aio-$(CONFIG_WIN32) += util/aio-win32.c
86
+gcov-files-test-aio-$(CONFIG_POSIX) += util/aio-posix.c
87
check-unit-y += tests/test-throttle$(EXESUF)
88
gcov-files-test-aio-$(CONFIG_WIN32) = aio-win32.c
89
gcov-files-test-aio-$(CONFIG_POSIX) = aio-posix.c
90
@@ -XXX,XX +XXX,XX @@ tests/check-qjson$(EXESUF): tests/check-qjson.o $(test-util-obj-y)
91
tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(test-qom-obj-y)
92
tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-obj-y)
93
94
-tests/test-char$(EXESUF): tests/test-char.o qemu-timer.o \
95
-    $(test-util-obj-y) $(qtest-obj-y) $(test-block-obj-y) $(chardev-obj-y)
96
+tests/test-char$(EXESUF): tests/test-char.o $(test-util-obj-y) $(qtest-obj-y) $(test-io-obj-y) $(chardev-obj-y)
97
tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
98
tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
99
tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
100
@@ -XXX,XX +XXX,XX @@ tests/test-vmstate$(EXESUF): tests/test-vmstate.o \
101
    migration/vmstate.o migration/qemu-file.o \
102
migration/qemu-file-channel.o migration/qjson.o \
103
    $(test-io-obj-y)
104
-tests/test-timed-average$(EXESUF): tests/test-timed-average.o qemu-timer.o \
105
-    $(test-util-obj-y)
106
+tests/test-timed-average$(EXESUF): tests/test-timed-average.o $(test-util-obj-y)
107
tests/test-base64$(EXESUF): tests/test-base64.o \
108
    libqemuutil.a libqemustub.a
109
tests/ptimer-test$(EXESUF): tests/ptimer-test.o tests/ptimer-test-stubs.o hw/core/ptimer.o libqemustub.a
110
@@ -XXX,XX +XXX,XX @@ tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y)
111
tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
112
tests/pc-cpu-test$(EXESUF): tests/pc-cpu-test.o
113
tests/postcopy-test$(EXESUF): tests/postcopy-test.o
114
-tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-timer.o \
115
+tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o $(test-util-obj-y) \
116
    $(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y) $(libqos-pc-obj-y) \
117
    $(chardev-obj-y)
118
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
119
diff --git a/util/Makefile.objs b/util/Makefile.objs
120
index XXXXXXX..XXXXXXX 100644
121
--- a/util/Makefile.objs
122
+++ b/util/Makefile.objs
123
@@ -XXX,XX +XXX,XX @@
124
util-obj-y = osdep.o cutils.o unicode.o qemu-timer-common.o
125
util-obj-y += bufferiszero.o
126
util-obj-y += lockcnt.o
127
+util-obj-y += aiocb.o async.o thread-pool.o qemu-timer.o
128
+util-obj-y += main-loop.o iohandler.o
129
+util-obj-$(CONFIG_POSIX) += aio-posix.o
130
util-obj-$(CONFIG_POSIX) += compatfd.o
131
util-obj-$(CONFIG_POSIX) += event_notifier-posix.o
132
util-obj-$(CONFIG_POSIX) += mmap-alloc.o
133
util-obj-$(CONFIG_POSIX) += oslib-posix.o
134
util-obj-$(CONFIG_POSIX) += qemu-openpty.o
135
util-obj-$(CONFIG_POSIX) += qemu-thread-posix.o
136
-util-obj-$(CONFIG_WIN32) += event_notifier-win32.o
137
util-obj-$(CONFIG_POSIX) += memfd.o
138
+util-obj-$(CONFIG_WIN32) += aio-win32.o
139
+util-obj-$(CONFIG_WIN32) += event_notifier-win32.o
140
util-obj-$(CONFIG_WIN32) += oslib-win32.o
141
util-obj-$(CONFIG_WIN32) += qemu-thread-win32.o
142
util-obj-y += envlist.o path.o module.o
143
diff --git a/block/io.c b/block/io.c
144
index XXXXXXX..XXXXXXX 100644
145
--- a/block/io.c
146
+++ b/block/io.c
147
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *bdrv_aio_flush(BlockDriverState *bs,
148
return &acb->common;
149
}
150
151
-void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs,
152
- BlockCompletionFunc *cb, void *opaque)
153
-{
154
- BlockAIOCB *acb;
155
-
156
- acb = g_malloc(aiocb_info->aiocb_size);
157
- acb->aiocb_info = aiocb_info;
158
- acb->bs = bs;
159
- acb->cb = cb;
160
- acb->opaque = opaque;
161
- acb->refcnt = 1;
162
- return acb;
163
-}
164
-
165
-void qemu_aio_ref(void *p)
166
-{
167
- BlockAIOCB *acb = p;
168
- acb->refcnt++;
169
-}
170
-
171
-void qemu_aio_unref(void *p)
172
-{
173
- BlockAIOCB *acb = p;
174
- assert(acb->refcnt > 0);
175
- if (--acb->refcnt == 0) {
176
- g_free(acb);
177
- }
178
-}
179
-
180
/**************************************************************/
181
/* Coroutine block device emulation */
182
183
diff --git a/stubs/linux-aio.c b/stubs/linux-aio.c
184
new file mode 100644
185
index XXXXXXX..XXXXXXX
186
--- /dev/null
187
+++ b/stubs/linux-aio.c
188
@@ -XXX,XX +XXX,XX @@
189
+/*
190
+ * Linux native AIO support.
191
+ *
192
+ * Copyright (C) 2009 IBM, Corp.
193
+ * Copyright (C) 2009 Red Hat, Inc.
194
+ *
195
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
196
+ * See the COPYING file in the top-level directory.
197
+ */
198
+#include "qemu/osdep.h"
199
+#include "block/aio.h"
200
+#include "block/raw-aio.h"
201
+
202
+void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context)
203
+{
204
+ abort();
205
+}
206
+
207
+void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context)
208
+{
209
+ abort();
210
+}
211
+
212
+LinuxAioState *laio_init(void)
213
+{
214
+ abort();
215
+}
216
+
217
+void laio_cleanup(LinuxAioState *s)
218
+{
219
+ abort();
220
+}
221
diff --git a/stubs/set-fd-handler.c b/stubs/set-fd-handler.c
222
index XXXXXXX..XXXXXXX 100644
223
--- a/stubs/set-fd-handler.c
224
+++ b/stubs/set-fd-handler.c
225
@@ -XXX,XX +XXX,XX @@ void qemu_set_fd_handler(int fd,
226
{
227
abort();
228
}
229
-
230
-void aio_set_fd_handler(AioContext *ctx,
231
- int fd,
232
- bool is_external,
233
- IOHandler *io_read,
234
- IOHandler *io_write,
235
- AioPollFn *io_poll,
236
- void *opaque)
237
-{
238
- abort();
239
-}
240
diff --git a/aio-posix.c b/util/aio-posix.c
241
similarity index 99%
242
rename from aio-posix.c
243
rename to util/aio-posix.c
244
index XXXXXXX..XXXXXXX 100644
245
--- a/aio-posix.c
246
+++ b/util/aio-posix.c
247
@@ -XXX,XX +XXX,XX @@
248
#include "qemu/rcu_queue.h"
249
#include "qemu/sockets.h"
250
#include "qemu/cutils.h"
251
-#include "trace-root.h"
252
+#include "trace.h"
253
#ifdef CONFIG_EPOLL_CREATE1
254
#include <sys/epoll.h>
255
#endif
256
diff --git a/aio-win32.c b/util/aio-win32.c
257
similarity index 100%
258
rename from aio-win32.c
259
rename to util/aio-win32.c
260
diff --git a/util/aiocb.c b/util/aiocb.c
261
new file mode 100644
262
index XXXXXXX..XXXXXXX
263
--- /dev/null
264
+++ b/util/aiocb.c
265
@@ -XXX,XX +XXX,XX @@
266
+/*
267
+ * BlockAIOCB allocation
268
+ *
269
+ * Copyright (c) 2003-2017 Fabrice Bellard and other QEMU contributors
270
+ *
271
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
272
+ * of this software and associated documentation files (the "Software"), to deal
273
+ * in the Software without restriction, including without limitation the rights
274
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
275
+ * copies of the Software, and to permit persons to whom the Software is
276
+ * furnished to do so, subject to the following conditions:
277
+ *
278
+ * The above copyright notice and this permission notice shall be included in
279
+ * all copies or substantial portions of the Software.
280
+ *
281
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
282
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
283
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
284
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
285
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
286
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
287
+ * THE SOFTWARE.
288
+ */
289
+
290
+#include "qemu/osdep.h"
291
+#include "block/aio.h"
292
+
293
+void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs,
294
+ BlockCompletionFunc *cb, void *opaque)
295
+{
296
+ BlockAIOCB *acb;
297
+
298
+ acb = g_malloc(aiocb_info->aiocb_size);
299
+ acb->aiocb_info = aiocb_info;
300
+ acb->bs = bs;
301
+ acb->cb = cb;
302
+ acb->opaque = opaque;
303
+ acb->refcnt = 1;
304
+ return acb;
305
+}
306
+
307
+void qemu_aio_ref(void *p)
308
+{
309
+ BlockAIOCB *acb = p;
310
+ acb->refcnt++;
311
+}
312
+
313
+void qemu_aio_unref(void *p)
314
+{
315
+ BlockAIOCB *acb = p;
316
+ assert(acb->refcnt > 0);
317
+ if (--acb->refcnt == 0) {
318
+ g_free(acb);
319
+ }
320
+}
321
diff --git a/async.c b/util/async.c
322
similarity index 99%
323
rename from async.c
324
rename to util/async.c
325
index XXXXXXX..XXXXXXX 100644
326
--- a/async.c
327
+++ b/util/async.c
328
@@ -XXX,XX +XXX,XX @@
329
/*
330
- * QEMU System Emulator
331
+ * Data plane event loop
332
*
333
* Copyright (c) 2003-2008 Fabrice Bellard
334
+ * Copyright (c) 2009-2017 QEMU contributors
335
*
336
* Permission is hereby granted, free of charge, to any person obtaining a copy
337
* of this software and associated documentation files (the "Software"), to deal
338
diff --git a/iohandler.c b/util/iohandler.c
339
similarity index 100%
340
rename from iohandler.c
341
rename to util/iohandler.c
342
diff --git a/main-loop.c b/util/main-loop.c
343
similarity index 100%
344
rename from main-loop.c
345
rename to util/main-loop.c
346
diff --git a/qemu-timer.c b/util/qemu-timer.c
347
similarity index 100%
348
rename from qemu-timer.c
349
rename to util/qemu-timer.c
350
diff --git a/thread-pool.c b/util/thread-pool.c
351
similarity index 99%
352
rename from thread-pool.c
353
rename to util/thread-pool.c
354
index XXXXXXX..XXXXXXX 100644
355
--- a/thread-pool.c
356
+++ b/util/thread-pool.c
357
@@ -XXX,XX +XXX,XX @@
358
#include "qemu/queue.h"
359
#include "qemu/thread.h"
360
#include "qemu/coroutine.h"
361
-#include "trace-root.h"
362
+#include "trace.h"
363
#include "block/thread-pool.h"
364
#include "qemu/main-loop.h"
365
366
diff --git a/trace-events b/trace-events
367
index XXXXXXX..XXXXXXX 100644
368
--- a/trace-events
369
+++ b/trace-events
62
@@ -XXX,XX +XXX,XX @@
370
@@ -XXX,XX +XXX,XX @@
63
#
371
#
64
372
# The <format-string> should be a sprintf()-compatible format string.
65
import iotests
373
66
-from iotests import qemu_img_create, qemu_io, qemu_img_verbose, qemu_nbd, \
374
-# aio-posix.c
67
- file_path
375
-run_poll_handlers_begin(void *ctx, int64_t max_ns) "ctx %p max_ns %"PRId64
68
+from iotests import qemu_img_create, qemu_io, qemu_img_log, qemu_nbd, \
376
-run_poll_handlers_end(void *ctx, bool progress) "ctx %p progress %d"
69
+ file_path, log
377
-poll_shrink(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64
70
378
-poll_grow(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64
71
iotests.script_initialize(supported_fmts=['qcow2'])
379
-
72
380
-# thread-pool.c
73
@@ -XXX,XX +XXX,XX @@ qemu_img_create('-f', iotests.imgfmt, disk, '1M')
381
-thread_pool_submit(void *pool, void *req, void *opaque) "pool %p req %p opaque %p"
74
qemu_io('-f', iotests.imgfmt, '-c', 'write 0 512K', disk)
382
-thread_pool_complete(void *pool, void *req, void *opaque, int ret) "pool %p req %p opaque %p ret %d"
75
383
-thread_pool_cancel(void *req, void *opaque) "req %p opaque %p"
76
qemu_nbd('-k', nbd_sock, '-x', 'exp', '-f', iotests.imgfmt, disk)
384
-
77
-qemu_img_verbose('map', '-f', 'raw', '--output=json', nbd_uri)
385
# ioport.c
78
+qemu_img_log('map', '-f', 'raw', '--output=json', nbd_uri)
386
cpu_in(unsigned int addr, char size, unsigned int val) "addr %#x(%c) value %u"
79
+log('done.') # avoid new line at the end of output file
387
cpu_out(unsigned int addr, char size, unsigned int val) "addr %#x(%c) value %u"
80
diff --git a/tests/qemu-iotests/209.out b/tests/qemu-iotests/209.out
388
diff --git a/util/trace-events b/util/trace-events
81
index XXXXXXX..XXXXXXX 100644
389
index XXXXXXX..XXXXXXX 100644
82
--- a/tests/qemu-iotests/209.out
390
--- a/util/trace-events
83
+++ b/tests/qemu-iotests/209.out
391
+++ b/util/trace-events
84
@@ -XXX,XX +XXX,XX @@
392
@@ -XXX,XX +XXX,XX @@
85
[{ "start": 0, "length": 524288, "depth": 0, "present": true, "zero": false, "data": true, "offset": 0},
393
# See docs/tracing.txt for syntax documentation.
86
{ "start": 524288, "length": 524288, "depth": 0, "present": true, "zero": true, "data": false, "offset": 524288}]
394
87
+
395
+# util/aio-posix.c
88
+done.
396
+run_poll_handlers_begin(void *ctx, int64_t max_ns) "ctx %p max_ns %"PRId64
89
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
397
+run_poll_handlers_end(void *ctx, bool progress) "ctx %p progress %d"
90
index XXXXXXX..XXXXXXX 100644
398
+poll_shrink(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64
91
--- a/tests/qemu-iotests/iotests.py
399
+poll_grow(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64
92
+++ b/tests/qemu-iotests/iotests.py
400
+
93
@@ -XXX,XX +XXX,XX @@ def qemu_img_measure(*args):
401
+# util/thread-pool.c
94
def qemu_img_check(*args):
402
+thread_pool_submit(void *pool, void *req, void *opaque) "pool %p req %p opaque %p"
95
return json.loads(qemu_img_pipe("check", "--output", "json", *args))
403
+thread_pool_complete(void *pool, void *req, void *opaque, int ret) "pool %p req %p opaque %p ret %d"
96
404
+thread_pool_cancel(void *req, void *opaque) "req %p opaque %p"
97
-def qemu_img_verbose(*args):
405
+
98
- '''Run qemu-img without suppressing its output and return the exit code'''
406
# util/buffer.c
99
- exitcode = subprocess.call(qemu_img_args + list(args))
407
buffer_resize(const char *buf, size_t olen, size_t len) "%s: old %zd, new %zd"
100
- if exitcode < 0:
408
buffer_move_empty(const char *buf, size_t len, const char *from) "%s: %zd bytes from %s"
101
- sys.stderr.write('qemu-img received signal %i: %s\n'
102
- % (-exitcode, ' '.join(qemu_img_args + list(args))))
103
- return exitcode
104
-
105
def qemu_img_pipe(*args: str) -> str:
106
'''Run qemu-img and return its output'''
107
return qemu_img_pipe_and_status(*args)[0]
108
--
409
--
109
2.34.1
410
2.9.3
110
411
111
412
diff view generated by jsdifflib
1
This test checks that a raw image in use by a virtio-blk device does not
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
share the WRITE permission both before and after migration.
2
3
3
aio_co_wake provides the infrastructure to start a coroutine on a "home"
4
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
4
AioContext. It will be used by CoMutex and CoQueue, so that coroutines
5
don't jump from one context to another when they go to sleep on a
6
mutex or waitqueue. However, it can also be used as a more efficient
7
alternative to one-shot bottom halves, and saves the effort of tracking
8
which AioContext a coroutine is running on.
9
10
aio_co_schedule is the part of aio_co_wake that starts a coroutine
11
on a remove AioContext, but it is also useful to implement e.g.
12
bdrv_set_aio_context callbacks.
13
14
The implementation of aio_co_schedule is based on a lock-free
15
multiple-producer, single-consumer queue. The multiple producers use
16
cmpxchg to add to a LIFO stack. The consumer (a per-AioContext bottom
17
half) grabs all items added so far, inverts the list to make it FIFO,
18
and goes through it one item at a time until it's empty. The data
19
structure was inspired by OSv, which uses it in the very code we'll
20
"port" to QEMU for the thread-safe CoMutex.
21
22
Most of the new code is really tests.
23
24
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
25
Reviewed-by: Fam Zheng <famz@redhat.com>
26
Message-id: 20170213135235.12274-3-pbonzini@redhat.com
27
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
---
28
---
6
.../qemu-iotests/tests/migration-permissions | 101 ++++++++++++++++++
29
tests/Makefile.include | 8 +-
7
.../tests/migration-permissions.out | 5 +
30
include/block/aio.h | 32 +++++++
8
2 files changed, 106 insertions(+)
31
include/qemu/coroutine_int.h | 11 ++-
9
create mode 100755 tests/qemu-iotests/tests/migration-permissions
32
tests/iothread.h | 25 +++++
10
create mode 100644 tests/qemu-iotests/tests/migration-permissions.out
33
tests/iothread.c | 91 ++++++++++++++++++
11
34
tests/test-aio-multithread.c | 213 +++++++++++++++++++++++++++++++++++++++++++
12
diff --git a/tests/qemu-iotests/tests/migration-permissions b/tests/qemu-iotests/tests/migration-permissions
35
util/async.c | 65 +++++++++++++
13
new file mode 100755
36
util/qemu-coroutine.c | 8 ++
14
index XXXXXXX..XXXXXXX
37
util/trace-events | 4 +
15
--- /dev/null
38
9 files changed, 453 insertions(+), 4 deletions(-)
16
+++ b/tests/qemu-iotests/tests/migration-permissions
39
create mode 100644 tests/iothread.h
17
@@ -XXX,XX +XXX,XX @@
40
create mode 100644 tests/iothread.c
18
+#!/usr/bin/env python3
41
create mode 100644 tests/test-aio-multithread.c
19
+# group: migration
42
20
+#
43
diff --git a/tests/Makefile.include b/tests/Makefile.include
21
+# Copyright (C) 2021 Red Hat, Inc.
44
index XXXXXXX..XXXXXXX 100644
22
+#
45
--- a/tests/Makefile.include
23
+# This program is free software; you can redistribute it and/or modify
46
+++ b/tests/Makefile.include
24
+# it under the terms of the GNU General Public License as published by
47
@@ -XXX,XX +XXX,XX @@ check-unit-y += tests/test-aio$(EXESUF)
25
+# the Free Software Foundation; either version 2 of the License, or
48
gcov-files-test-aio-y = util/async.c util/qemu-timer.o
26
+# (at your option) any later version.
49
gcov-files-test-aio-$(CONFIG_WIN32) += util/aio-win32.c
27
+#
50
gcov-files-test-aio-$(CONFIG_POSIX) += util/aio-posix.c
28
+# This program is distributed in the hope that it will be useful,
51
+check-unit-y += tests/test-aio-multithread$(EXESUF)
29
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
52
+gcov-files-test-aio-multithread-y = $(gcov-files-test-aio-y)
30
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53
+gcov-files-test-aio-multithread-y += util/qemu-coroutine.c tests/iothread.c
31
+# GNU General Public License for more details.
54
check-unit-y += tests/test-throttle$(EXESUF)
32
+#
55
-gcov-files-test-aio-$(CONFIG_WIN32) = aio-win32.c
33
+# You should have received a copy of the GNU General Public License
56
-gcov-files-test-aio-$(CONFIG_POSIX) = aio-posix.c
34
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
57
check-unit-y += tests/test-thread-pool$(EXESUF)
35
+#
58
gcov-files-test-thread-pool-y = thread-pool.c
36
+
59
gcov-files-test-hbitmap-y = util/hbitmap.c
37
+import os
60
@@ -XXX,XX +XXX,XX @@ test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \
38
+import iotests
61
    $(test-qom-obj-y)
39
+from iotests import imgfmt, qemu_img_create, qemu_io
62
test-crypto-obj-y = $(crypto-obj-y) $(test-qom-obj-y)
40
+
63
test-io-obj-y = $(io-obj-y) $(test-crypto-obj-y)
41
+
64
-test-block-obj-y = $(block-obj-y) $(test-io-obj-y)
42
+test_img = os.path.join(iotests.test_dir, 'test.img')
65
+test-block-obj-y = $(block-obj-y) $(test-io-obj-y) tests/iothread.o
43
+mig_sock = os.path.join(iotests.sock_dir, 'mig.sock')
66
44
+
67
tests/check-qint$(EXESUF): tests/check-qint.o $(test-util-obj-y)
45
+
68
tests/check-qstring$(EXESUF): tests/check-qstring.o $(test-util-obj-y)
46
+class TestMigrationPermissions(iotests.QMPTestCase):
69
@@ -XXX,XX +XXX,XX @@ tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-obj-y)
47
+ def setUp(self):
70
tests/test-char$(EXESUF): tests/test-char.o $(test-util-obj-y) $(qtest-obj-y) $(test-io-obj-y) $(chardev-obj-y)
48
+ qemu_img_create('-f', imgfmt, test_img, '1M')
71
tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y)
49
+
72
tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y)
50
+ # Set up two VMs (source and destination) accessing the same raw
73
+tests/test-aio-multithread$(EXESUF): tests/test-aio-multithread.o $(test-block-obj-y)
51
+ # image file with a virtio-blk device; prepare the destination for
74
tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
52
+ # migration with .add_incoming() and enable migration events
75
tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y)
53
+ vms = [None, None]
76
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
54
+ for i in range(2):
77
diff --git a/include/block/aio.h b/include/block/aio.h
55
+ vms[i] = iotests.VM(path_suffix=f'{i}')
78
index XXXXXXX..XXXXXXX 100644
56
+ vms[i].add_blockdev(f'file,node-name=prot,filename={test_img}')
79
--- a/include/block/aio.h
57
+ vms[i].add_blockdev(f'{imgfmt},node-name=fmt,file=prot')
80
+++ b/include/block/aio.h
58
+ vms[i].add_device('virtio-blk,drive=fmt')
81
@@ -XXX,XX +XXX,XX @@ typedef void QEMUBHFunc(void *opaque);
59
+
82
typedef bool AioPollFn(void *opaque);
60
+ if i == 1:
83
typedef void IOHandler(void *opaque);
61
+ vms[i].add_incoming(f'unix:{mig_sock}')
84
62
+
85
+struct Coroutine;
63
+ vms[i].launch()
86
struct ThreadPool;
64
+
87
struct LinuxAioState;
65
+ result = vms[i].qmp('migrate-set-capabilities',
88
66
+ capabilities=[
89
@@ -XXX,XX +XXX,XX @@ struct AioContext {
67
+ {'capability': 'events', 'state': True}
90
bool notified;
68
+ ])
91
EventNotifier notifier;
69
+ self.assert_qmp(result, 'return', {})
92
70
+
93
+ QSLIST_HEAD(, Coroutine) scheduled_coroutines;
71
+ self.vm_s = vms[0]
94
+ QEMUBH *co_schedule_bh;
72
+ self.vm_d = vms[1]
95
+
73
+
96
/* Thread pool for performing work and receiving completion callbacks.
74
+ def tearDown(self):
97
* Has its own locking.
75
+ self.vm_s.shutdown()
98
*/
76
+ self.vm_d.shutdown()
99
@@ -XXX,XX +XXX,XX @@ static inline bool aio_node_check(AioContext *ctx, bool is_external)
77
+ try:
100
}
78
+ os.remove(mig_sock)
101
79
+ except FileNotFoundError:
102
/**
80
+ pass
103
+ * aio_co_schedule:
81
+ os.remove(test_img)
104
+ * @ctx: the aio context
82
+
105
+ * @co: the coroutine
83
+ # Migrate an image in use by a virtio-blk device to another VM and
106
+ *
84
+ # verify that the WRITE permission is unshared both before and after
107
+ * Start a coroutine on a remote AioContext.
85
+ # migration
108
+ *
86
+ def test_post_migration_permissions(self):
109
+ * The coroutine must not be entered by anyone else while aio_co_schedule()
87
+ # Try to access the image R/W, which should fail because virtio-blk
110
+ * is active. In addition the coroutine must have yielded unless ctx
88
+ # has not been configured with share-rw=on
111
+ * is the context in which the coroutine is running (i.e. the value of
89
+ log = qemu_io('-f', imgfmt, '-c', 'quit', test_img)
112
+ * qemu_get_current_aio_context() from the coroutine itself).
90
+ if not log.strip():
113
+ */
91
+ print('ERROR (pre-migration): qemu-io should not be able to '
114
+void aio_co_schedule(AioContext *ctx, struct Coroutine *co);
92
+ 'access this image, but it reported no error')
115
+
93
+ else:
116
+/**
94
+ # This is the expected output
117
+ * aio_co_wake:
95
+ assert 'Is another process using the image' in log
118
+ * @co: the coroutine
96
+
119
+ *
97
+ # Now migrate the VM
120
+ * Restart a coroutine on the AioContext where it was running last, thus
98
+ self.vm_s.qmp('migrate', uri=f'unix:{mig_sock}')
121
+ * preventing coroutines from jumping from one context to another when they
99
+ assert self.vm_s.wait_migration(None)
122
+ * go to sleep.
100
+ assert self.vm_d.wait_migration(None)
123
+ *
101
+
124
+ * aio_co_wake may be executed either in coroutine or non-coroutine
102
+ # Try the same qemu-io access again, verifying that the WRITE
125
+ * context. The coroutine must not be entered by anyone else while
103
+ # permission remains unshared
126
+ * aio_co_wake() is active.
104
+ log = qemu_io('-f', imgfmt, '-c', 'quit', test_img)
127
+ */
105
+ if not log.strip():
128
+void aio_co_wake(struct Coroutine *co);
106
+ print('ERROR (post-migration): qemu-io should not be able to '
129
+
107
+ 'access this image, but it reported no error')
130
+/**
108
+ else:
131
* Return the AioContext whose event loop runs in the current thread.
109
+ # This is the expected output
132
*
110
+ assert 'Is another process using the image' in log
133
* If called from an IOThread this will be the IOThread's AioContext. If
111
+
134
diff --git a/include/qemu/coroutine_int.h b/include/qemu/coroutine_int.h
112
+
135
index XXXXXXX..XXXXXXX 100644
113
+if __name__ == '__main__':
136
--- a/include/qemu/coroutine_int.h
114
+ # Only works with raw images because we are testing the
137
+++ b/include/qemu/coroutine_int.h
115
+ # BlockBackend permissions; image format drivers may additionally
138
@@ -XXX,XX +XXX,XX @@ struct Coroutine {
116
+ # unshare permissions and thus tamper with the result
139
CoroutineEntry *entry;
117
+ iotests.main(supported_fmts=['raw'],
140
void *entry_arg;
118
+ supported_protocols=['file'])
141
Coroutine *caller;
119
diff --git a/tests/qemu-iotests/tests/migration-permissions.out b/tests/qemu-iotests/tests/migration-permissions.out
142
+
143
+ /* Only used when the coroutine has terminated. */
144
QSLIST_ENTRY(Coroutine) pool_next;
145
+
146
size_t locks_held;
147
148
- /* Coroutines that should be woken up when we yield or terminate */
149
+ /* Coroutines that should be woken up when we yield or terminate.
150
+ * Only used when the coroutine is running.
151
+ */
152
QSIMPLEQ_HEAD(, Coroutine) co_queue_wakeup;
153
+
154
+ /* Only used when the coroutine has yielded. */
155
+ AioContext *ctx;
156
QSIMPLEQ_ENTRY(Coroutine) co_queue_next;
157
+ QSLIST_ENTRY(Coroutine) co_scheduled_next;
158
};
159
160
Coroutine *qemu_coroutine_new(void);
161
diff --git a/tests/iothread.h b/tests/iothread.h
120
new file mode 100644
162
new file mode 100644
121
index XXXXXXX..XXXXXXX
163
index XXXXXXX..XXXXXXX
122
--- /dev/null
164
--- /dev/null
123
+++ b/tests/qemu-iotests/tests/migration-permissions.out
165
+++ b/tests/iothread.h
124
@@ -XXX,XX +XXX,XX @@
166
@@ -XXX,XX +XXX,XX @@
125
+.
167
+/*
126
+----------------------------------------------------------------------
168
+ * Event loop thread implementation for unit tests
127
+Ran 1 tests
169
+ *
128
+
170
+ * Copyright Red Hat Inc., 2013, 2016
129
+OK
171
+ *
172
+ * Authors:
173
+ * Stefan Hajnoczi <stefanha@redhat.com>
174
+ * Paolo Bonzini <pbonzini@redhat.com>
175
+ *
176
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
177
+ * See the COPYING file in the top-level directory.
178
+ */
179
+#ifndef TEST_IOTHREAD_H
180
+#define TEST_IOTHREAD_H
181
+
182
+#include "block/aio.h"
183
+#include "qemu/thread.h"
184
+
185
+typedef struct IOThread IOThread;
186
+
187
+IOThread *iothread_new(void);
188
+void iothread_join(IOThread *iothread);
189
+AioContext *iothread_get_aio_context(IOThread *iothread);
190
+
191
+#endif
192
diff --git a/tests/iothread.c b/tests/iothread.c
193
new file mode 100644
194
index XXXXXXX..XXXXXXX
195
--- /dev/null
196
+++ b/tests/iothread.c
197
@@ -XXX,XX +XXX,XX @@
198
+/*
199
+ * Event loop thread implementation for unit tests
200
+ *
201
+ * Copyright Red Hat Inc., 2013, 2016
202
+ *
203
+ * Authors:
204
+ * Stefan Hajnoczi <stefanha@redhat.com>
205
+ * Paolo Bonzini <pbonzini@redhat.com>
206
+ *
207
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
208
+ * See the COPYING file in the top-level directory.
209
+ *
210
+ */
211
+
212
+#include "qemu/osdep.h"
213
+#include "qapi/error.h"
214
+#include "block/aio.h"
215
+#include "qemu/main-loop.h"
216
+#include "qemu/rcu.h"
217
+#include "iothread.h"
218
+
219
+struct IOThread {
220
+ AioContext *ctx;
221
+
222
+ QemuThread thread;
223
+ QemuMutex init_done_lock;
224
+ QemuCond init_done_cond; /* is thread initialization done? */
225
+ bool stopping;
226
+};
227
+
228
+static __thread IOThread *my_iothread;
229
+
230
+AioContext *qemu_get_current_aio_context(void)
231
+{
232
+ return my_iothread ? my_iothread->ctx : qemu_get_aio_context();
233
+}
234
+
235
+static void *iothread_run(void *opaque)
236
+{
237
+ IOThread *iothread = opaque;
238
+
239
+ rcu_register_thread();
240
+
241
+ my_iothread = iothread;
242
+ qemu_mutex_lock(&iothread->init_done_lock);
243
+ iothread->ctx = aio_context_new(&error_abort);
244
+ qemu_cond_signal(&iothread->init_done_cond);
245
+ qemu_mutex_unlock(&iothread->init_done_lock);
246
+
247
+ while (!atomic_read(&iothread->stopping)) {
248
+ aio_poll(iothread->ctx, true);
249
+ }
250
+
251
+ rcu_unregister_thread();
252
+ return NULL;
253
+}
254
+
255
+void iothread_join(IOThread *iothread)
256
+{
257
+ iothread->stopping = true;
258
+ aio_notify(iothread->ctx);
259
+ qemu_thread_join(&iothread->thread);
260
+ qemu_cond_destroy(&iothread->init_done_cond);
261
+ qemu_mutex_destroy(&iothread->init_done_lock);
262
+ aio_context_unref(iothread->ctx);
263
+ g_free(iothread);
264
+}
265
+
266
+IOThread *iothread_new(void)
267
+{
268
+ IOThread *iothread = g_new0(IOThread, 1);
269
+
270
+ qemu_mutex_init(&iothread->init_done_lock);
271
+ qemu_cond_init(&iothread->init_done_cond);
272
+ qemu_thread_create(&iothread->thread, NULL, iothread_run,
273
+ iothread, QEMU_THREAD_JOINABLE);
274
+
275
+ /* Wait for initialization to complete */
276
+ qemu_mutex_lock(&iothread->init_done_lock);
277
+ while (iothread->ctx == NULL) {
278
+ qemu_cond_wait(&iothread->init_done_cond,
279
+ &iothread->init_done_lock);
280
+ }
281
+ qemu_mutex_unlock(&iothread->init_done_lock);
282
+ return iothread;
283
+}
284
+
285
+AioContext *iothread_get_aio_context(IOThread *iothread)
286
+{
287
+ return iothread->ctx;
288
+}
289
diff --git a/tests/test-aio-multithread.c b/tests/test-aio-multithread.c
290
new file mode 100644
291
index XXXXXXX..XXXXXXX
292
--- /dev/null
293
+++ b/tests/test-aio-multithread.c
294
@@ -XXX,XX +XXX,XX @@
295
+/*
296
+ * AioContext multithreading tests
297
+ *
298
+ * Copyright Red Hat, Inc. 2016
299
+ *
300
+ * Authors:
301
+ * Paolo Bonzini <pbonzini@redhat.com>
302
+ *
303
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
304
+ * See the COPYING.LIB file in the top-level directory.
305
+ */
306
+
307
+#include "qemu/osdep.h"
308
+#include <glib.h>
309
+#include "block/aio.h"
310
+#include "qapi/error.h"
311
+#include "qemu/coroutine.h"
312
+#include "qemu/thread.h"
313
+#include "qemu/error-report.h"
314
+#include "iothread.h"
315
+
316
+/* AioContext management */
317
+
318
+#define NUM_CONTEXTS 5
319
+
320
+static IOThread *threads[NUM_CONTEXTS];
321
+static AioContext *ctx[NUM_CONTEXTS];
322
+static __thread int id = -1;
323
+
324
+static QemuEvent done_event;
325
+
326
+/* Run a function synchronously on a remote iothread. */
327
+
328
+typedef struct CtxRunData {
329
+ QEMUBHFunc *cb;
330
+ void *arg;
331
+} CtxRunData;
332
+
333
+static void ctx_run_bh_cb(void *opaque)
334
+{
335
+ CtxRunData *data = opaque;
336
+
337
+ data->cb(data->arg);
338
+ qemu_event_set(&done_event);
339
+}
340
+
341
+static void ctx_run(int i, QEMUBHFunc *cb, void *opaque)
342
+{
343
+ CtxRunData data = {
344
+ .cb = cb,
345
+ .arg = opaque
346
+ };
347
+
348
+ qemu_event_reset(&done_event);
349
+ aio_bh_schedule_oneshot(ctx[i], ctx_run_bh_cb, &data);
350
+ qemu_event_wait(&done_event);
351
+}
352
+
353
+/* Starting the iothreads. */
354
+
355
+static void set_id_cb(void *opaque)
356
+{
357
+ int *i = opaque;
358
+
359
+ id = *i;
360
+}
361
+
362
+static void create_aio_contexts(void)
363
+{
364
+ int i;
365
+
366
+ for (i = 0; i < NUM_CONTEXTS; i++) {
367
+ threads[i] = iothread_new();
368
+ ctx[i] = iothread_get_aio_context(threads[i]);
369
+ }
370
+
371
+ qemu_event_init(&done_event, false);
372
+ for (i = 0; i < NUM_CONTEXTS; i++) {
373
+ ctx_run(i, set_id_cb, &i);
374
+ }
375
+}
376
+
377
+/* Stopping the iothreads. */
378
+
379
+static void join_aio_contexts(void)
380
+{
381
+ int i;
382
+
383
+ for (i = 0; i < NUM_CONTEXTS; i++) {
384
+ aio_context_ref(ctx[i]);
385
+ }
386
+ for (i = 0; i < NUM_CONTEXTS; i++) {
387
+ iothread_join(threads[i]);
388
+ }
389
+ for (i = 0; i < NUM_CONTEXTS; i++) {
390
+ aio_context_unref(ctx[i]);
391
+ }
392
+ qemu_event_destroy(&done_event);
393
+}
394
+
395
+/* Basic test for the stuff above. */
396
+
397
+static void test_lifecycle(void)
398
+{
399
+ create_aio_contexts();
400
+ join_aio_contexts();
401
+}
402
+
403
+/* aio_co_schedule test. */
404
+
405
+static Coroutine *to_schedule[NUM_CONTEXTS];
406
+
407
+static bool now_stopping;
408
+
409
+static int count_retry;
410
+static int count_here;
411
+static int count_other;
412
+
413
+static bool schedule_next(int n)
414
+{
415
+ Coroutine *co;
416
+
417
+ co = atomic_xchg(&to_schedule[n], NULL);
418
+ if (!co) {
419
+ atomic_inc(&count_retry);
420
+ return false;
421
+ }
422
+
423
+ if (n == id) {
424
+ atomic_inc(&count_here);
425
+ } else {
426
+ atomic_inc(&count_other);
427
+ }
428
+
429
+ aio_co_schedule(ctx[n], co);
430
+ return true;
431
+}
432
+
433
+static void finish_cb(void *opaque)
434
+{
435
+ schedule_next(id);
436
+}
437
+
438
+static coroutine_fn void test_multi_co_schedule_entry(void *opaque)
439
+{
440
+ g_assert(to_schedule[id] == NULL);
441
+ atomic_mb_set(&to_schedule[id], qemu_coroutine_self());
442
+
443
+ while (!atomic_mb_read(&now_stopping)) {
444
+ int n;
445
+
446
+ n = g_test_rand_int_range(0, NUM_CONTEXTS);
447
+ schedule_next(n);
448
+ qemu_coroutine_yield();
449
+
450
+ g_assert(to_schedule[id] == NULL);
451
+ atomic_mb_set(&to_schedule[id], qemu_coroutine_self());
452
+ }
453
+}
454
+
455
+
456
+static void test_multi_co_schedule(int seconds)
457
+{
458
+ int i;
459
+
460
+ count_here = count_other = count_retry = 0;
461
+ now_stopping = false;
462
+
463
+ create_aio_contexts();
464
+ for (i = 0; i < NUM_CONTEXTS; i++) {
465
+ Coroutine *co1 = qemu_coroutine_create(test_multi_co_schedule_entry, NULL);
466
+ aio_co_schedule(ctx[i], co1);
467
+ }
468
+
469
+ g_usleep(seconds * 1000000);
470
+
471
+ atomic_mb_set(&now_stopping, true);
472
+ for (i = 0; i < NUM_CONTEXTS; i++) {
473
+ ctx_run(i, finish_cb, NULL);
474
+ to_schedule[i] = NULL;
475
+ }
476
+
477
+ join_aio_contexts();
478
+ g_test_message("scheduled %d, queued %d, retry %d, total %d\n",
479
+ count_other, count_here, count_retry,
480
+ count_here + count_other + count_retry);
481
+}
482
+
483
+static void test_multi_co_schedule_1(void)
484
+{
485
+ test_multi_co_schedule(1);
486
+}
487
+
488
+static void test_multi_co_schedule_10(void)
489
+{
490
+ test_multi_co_schedule(10);
491
+}
492
+
493
+/* End of tests. */
494
+
495
+int main(int argc, char **argv)
496
+{
497
+ init_clocks();
498
+
499
+ g_test_init(&argc, &argv, NULL);
500
+ g_test_add_func("/aio/multi/lifecycle", test_lifecycle);
501
+ if (g_test_quick()) {
502
+ g_test_add_func("/aio/multi/schedule", test_multi_co_schedule_1);
503
+ } else {
504
+ g_test_add_func("/aio/multi/schedule", test_multi_co_schedule_10);
505
+ }
506
+ return g_test_run();
507
+}
508
diff --git a/util/async.c b/util/async.c
509
index XXXXXXX..XXXXXXX 100644
510
--- a/util/async.c
511
+++ b/util/async.c
512
@@ -XXX,XX +XXX,XX @@
513
#include "qemu/main-loop.h"
514
#include "qemu/atomic.h"
515
#include "block/raw-aio.h"
516
+#include "qemu/coroutine_int.h"
517
+#include "trace.h"
518
519
/***********************************************************/
520
/* bottom halves (can be seen as timers which expire ASAP) */
521
@@ -XXX,XX +XXX,XX @@ aio_ctx_finalize(GSource *source)
522
}
523
#endif
524
525
+ assert(QSLIST_EMPTY(&ctx->scheduled_coroutines));
526
+ qemu_bh_delete(ctx->co_schedule_bh);
527
+
528
qemu_lockcnt_lock(&ctx->list_lock);
529
assert(!qemu_lockcnt_count(&ctx->list_lock));
530
while (ctx->first_bh) {
531
@@ -XXX,XX +XXX,XX @@ static bool event_notifier_poll(void *opaque)
532
return atomic_read(&ctx->notified);
533
}
534
535
+static void co_schedule_bh_cb(void *opaque)
536
+{
537
+ AioContext *ctx = opaque;
538
+ QSLIST_HEAD(, Coroutine) straight, reversed;
539
+
540
+ QSLIST_MOVE_ATOMIC(&reversed, &ctx->scheduled_coroutines);
541
+ QSLIST_INIT(&straight);
542
+
543
+ while (!QSLIST_EMPTY(&reversed)) {
544
+ Coroutine *co = QSLIST_FIRST(&reversed);
545
+ QSLIST_REMOVE_HEAD(&reversed, co_scheduled_next);
546
+ QSLIST_INSERT_HEAD(&straight, co, co_scheduled_next);
547
+ }
548
+
549
+ while (!QSLIST_EMPTY(&straight)) {
550
+ Coroutine *co = QSLIST_FIRST(&straight);
551
+ QSLIST_REMOVE_HEAD(&straight, co_scheduled_next);
552
+ trace_aio_co_schedule_bh_cb(ctx, co);
553
+ qemu_coroutine_enter(co);
554
+ }
555
+}
556
+
557
AioContext *aio_context_new(Error **errp)
558
{
559
int ret;
560
@@ -XXX,XX +XXX,XX @@ AioContext *aio_context_new(Error **errp)
561
}
562
g_source_set_can_recurse(&ctx->source, true);
563
qemu_lockcnt_init(&ctx->list_lock);
564
+
565
+ ctx->co_schedule_bh = aio_bh_new(ctx, co_schedule_bh_cb, ctx);
566
+ QSLIST_INIT(&ctx->scheduled_coroutines);
567
+
568
aio_set_event_notifier(ctx, &ctx->notifier,
569
false,
570
(EventNotifierHandler *)
571
@@ -XXX,XX +XXX,XX @@ fail:
572
return NULL;
573
}
574
575
+void aio_co_schedule(AioContext *ctx, Coroutine *co)
576
+{
577
+ trace_aio_co_schedule(ctx, co);
578
+ QSLIST_INSERT_HEAD_ATOMIC(&ctx->scheduled_coroutines,
579
+ co, co_scheduled_next);
580
+ qemu_bh_schedule(ctx->co_schedule_bh);
581
+}
582
+
583
+void aio_co_wake(struct Coroutine *co)
584
+{
585
+ AioContext *ctx;
586
+
587
+ /* Read coroutine before co->ctx. Matches smp_wmb in
588
+ * qemu_coroutine_enter.
589
+ */
590
+ smp_read_barrier_depends();
591
+ ctx = atomic_read(&co->ctx);
592
+
593
+ if (ctx != qemu_get_current_aio_context()) {
594
+ aio_co_schedule(ctx, co);
595
+ return;
596
+ }
597
+
598
+ if (qemu_in_coroutine()) {
599
+ Coroutine *self = qemu_coroutine_self();
600
+ assert(self != co);
601
+ QSIMPLEQ_INSERT_TAIL(&self->co_queue_wakeup, co, co_queue_next);
602
+ } else {
603
+ aio_context_acquire(ctx);
604
+ qemu_coroutine_enter(co);
605
+ aio_context_release(ctx);
606
+ }
607
+}
608
+
609
void aio_context_ref(AioContext *ctx)
610
{
611
g_source_ref(&ctx->source);
612
diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c
613
index XXXXXXX..XXXXXXX 100644
614
--- a/util/qemu-coroutine.c
615
+++ b/util/qemu-coroutine.c
616
@@ -XXX,XX +XXX,XX @@
617
#include "qemu/atomic.h"
618
#include "qemu/coroutine.h"
619
#include "qemu/coroutine_int.h"
620
+#include "block/aio.h"
621
622
enum {
623
POOL_BATCH_SIZE = 64,
624
@@ -XXX,XX +XXX,XX @@ void qemu_coroutine_enter(Coroutine *co)
625
}
626
627
co->caller = self;
628
+ co->ctx = qemu_get_current_aio_context();
629
+
630
+ /* Store co->ctx before anything that stores co. Matches
631
+ * barrier in aio_co_wake.
632
+ */
633
+ smp_wmb();
634
+
635
ret = qemu_coroutine_switch(self, co, COROUTINE_ENTER);
636
637
qemu_co_queue_run_restart(co);
638
diff --git a/util/trace-events b/util/trace-events
639
index XXXXXXX..XXXXXXX 100644
640
--- a/util/trace-events
641
+++ b/util/trace-events
642
@@ -XXX,XX +XXX,XX @@ run_poll_handlers_end(void *ctx, bool progress) "ctx %p progress %d"
643
poll_shrink(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64
644
poll_grow(void *ctx, int64_t old, int64_t new) "ctx %p old %"PRId64" new %"PRId64
645
646
+# util/async.c
647
+aio_co_schedule(void *ctx, void *co) "ctx %p co %p"
648
+aio_co_schedule_bh_cb(void *ctx, void *co) "ctx %p co %p"
649
+
650
# util/thread-pool.c
651
thread_pool_submit(void *pool, void *req, void *opaque) "pool %p req %p opaque %p"
652
thread_pool_complete(void *pool, void *req, void *opaque, int ret) "pool %p req %p opaque %p ret %d"
130
--
653
--
131
2.34.1
654
2.9.3
132
655
133
656
diff view generated by jsdifflib
1
After migration, the permissions the guest device wants to impose on its
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
BlockBackend are stored in blk->perm and blk->shared_perm. In
3
blk_root_activate(), we take our permissions, but keep all shared
4
permissions open by calling `blk_set_perm(blk->perm, BLK_PERM_ALL)`.
5
2
6
Only afterwards (immediately or later, depending on the runstate) do we
3
qcow2_create2 calls this. Do not run a nested event loop, as that
7
restrict the shared permissions by calling
4
breaks when aio_co_wake tries to queue the coroutine on the co_queue_wakeup
8
`blk_set_perm(blk->perm, blk->shared_perm)`. Unfortunately, our first
5
list of the currently running one.
9
call with shared_perm=BLK_PERM_ALL has overwritten blk->shared_perm to
10
be BLK_PERM_ALL, so this is a no-op and the set of shared permissions is
11
not restricted.
12
6
13
Fix this bug by saving the set of shared permissions before invoking
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
14
blk_set_perm() with BLK_PERM_ALL and restoring it afterwards.
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
15
9
Reviewed-by: Fam Zheng <famz@redhat.com>
16
Fixes: 5f7772c4d0cf32f4e779fcd5a69ae4dae24aeebf
10
Message-id: 20170213135235.12274-4-pbonzini@redhat.com
17
("block-backend: Defer shared_perm tightening migration
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
completion")
19
Reported-by: Peng Liang <liangpeng10@huawei.com>
20
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
21
Message-Id: <20211125135317.186576-2-hreitz@redhat.com>
22
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
23
Tested-by: Peng Liang <liangpeng10@huawei.com>
24
---
12
---
25
block/block-backend.c | 11 +++++++++++
13
block/block-backend.c | 12 ++++++++----
26
1 file changed, 11 insertions(+)
14
1 file changed, 8 insertions(+), 4 deletions(-)
27
15
28
diff --git a/block/block-backend.c b/block/block-backend.c
16
diff --git a/block/block-backend.c b/block/block-backend.c
29
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
30
--- a/block/block-backend.c
18
--- a/block/block-backend.c
31
+++ b/block/block-backend.c
19
+++ b/block/block-backend.c
32
@@ -XXX,XX +XXX,XX @@ static void blk_root_activate(BdrvChild *child, Error **errp)
20
@@ -XXX,XX +XXX,XX @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
33
{
21
{
34
BlockBackend *blk = child->opaque;
22
QEMUIOVector qiov;
35
Error *local_err = NULL;
23
struct iovec iov;
36
+ uint64_t saved_shared_perm;
24
- Coroutine *co;
37
25
BlkRwCo rwco;
38
if (!blk->disable_perm) {
26
39
return;
27
iov = (struct iovec) {
40
@@ -XXX,XX +XXX,XX @@ static void blk_root_activate(BdrvChild *child, Error **errp)
28
@@ -XXX,XX +XXX,XX @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
41
29
.ret = NOT_DONE,
42
blk->disable_perm = false;
30
};
43
31
44
+ /*
32
- co = qemu_coroutine_create(co_entry, &rwco);
45
+ * blk->shared_perm contains the permissions we want to share once
33
- qemu_coroutine_enter(co);
46
+ * migration is really completely done. For now, we need to share
34
- BDRV_POLL_WHILE(blk_bs(blk), rwco.ret == NOT_DONE);
47
+ * all; but we also need to retain blk->shared_perm, which is
35
+ if (qemu_in_coroutine()) {
48
+ * overwritten by a successful blk_set_perm() call. Save it and
36
+ /* Fast-path if already in coroutine context */
49
+ * restore it below.
37
+ co_entry(&rwco);
50
+ */
38
+ } else {
51
+ saved_shared_perm = blk->shared_perm;
39
+ Coroutine *co = qemu_coroutine_create(co_entry, &rwco);
52
+
40
+ qemu_coroutine_enter(co);
53
blk_set_perm(blk, blk->perm, BLK_PERM_ALL, &local_err);
41
+ BDRV_POLL_WHILE(blk_bs(blk), rwco.ret == NOT_DONE);
54
if (local_err) {
42
+ }
55
error_propagate(errp, local_err);
43
56
blk->disable_perm = true;
44
return rwco.ret;
57
return;
45
}
58
}
59
+ blk->shared_perm = saved_shared_perm;
60
61
if (runstate_check(RUN_STATE_INMIGRATE)) {
62
/* Activation can happen when migration process is still active, for
63
--
46
--
64
2.34.1
47
2.9.3
65
48
66
49
diff view generated by jsdifflib
1
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
The comment "disk I/O throttling" doesn't make any sense at all
3
Once the thread pool starts using aio_co_wake, it will also need
4
any more. It was added in commit 0563e191516 to describe
4
qemu_get_current_aio_context(). Make test-thread-pool create
5
bdrv_io_limits_enable()/disable(), which were removed in commit
5
an AioContext with qemu_init_main_loop, so that stubs/iothread.c
6
97148076, so the comment is just a forgotten leftover.
6
and tests/iothread.c can provide the rest.
7
7
8
Suggested-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
10
Message-Id: <20220131125615.74612-1-eesposit@redhat.com>
10
Reviewed-by: Fam Zheng <famz@redhat.com>
11
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
11
Message-id: 20170213135235.12274-5-pbonzini@redhat.com
12
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
13
---
14
include/block/block.h | 1 -
14
tests/test-thread-pool.c | 12 +++---------
15
1 file changed, 1 deletion(-)
15
1 file changed, 3 insertions(+), 9 deletions(-)
16
16
17
diff --git a/include/block/block.h b/include/block/block.h
17
diff --git a/tests/test-thread-pool.c b/tests/test-thread-pool.c
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/include/block/block.h
19
--- a/tests/test-thread-pool.c
20
+++ b/include/block/block.h
20
+++ b/tests/test-thread-pool.c
21
@@ -XXX,XX +XXX,XX @@ typedef unsigned int BdrvChildRole;
21
@@ -XXX,XX +XXX,XX @@
22
char *bdrv_perm_names(uint64_t perm);
22
#include "qapi/error.h"
23
uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm);
23
#include "qemu/timer.h"
24
24
#include "qemu/error-report.h"
25
-/* disk I/O throttling */
25
+#include "qemu/main-loop.h"
26
void bdrv_init(void);
26
27
void bdrv_init_with_whitelist(void);
27
static AioContext *ctx;
28
bool bdrv_uses_whitelist(void);
28
static ThreadPool *pool;
29
@@ -XXX,XX +XXX,XX @@ static void test_cancel_async(void)
30
int main(int argc, char **argv)
31
{
32
int ret;
33
- Error *local_error = NULL;
34
35
- init_clocks();
36
-
37
- ctx = aio_context_new(&local_error);
38
- if (!ctx) {
39
- error_reportf_err(local_error, "Failed to create AIO Context: ");
40
- exit(1);
41
- }
42
+ qemu_init_main_loop(&error_abort);
43
+ ctx = qemu_get_current_aio_context();
44
pool = aio_get_thread_pool(ctx);
45
46
g_test_init(&argc, &argv, NULL);
47
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
48
49
ret = g_test_run();
50
51
- aio_context_unref(ctx);
52
return ret;
53
}
29
--
54
--
30
2.34.1
55
2.9.3
31
56
32
57
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
compression_type can't be used if we want to create image with
3
This is in preparation for making qio_channel_yield work on
4
compat=0.10. So, skip these tests, not many of them.
4
AioContexts other than the main one.
5
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
7
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Message-Id: <20211223160144.1097696-20-vsementsov@virtuozzo.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
Reviewed-by: Fam Zheng <famz@redhat.com>
10
Message-id: 20170213135235.12274-6-pbonzini@redhat.com
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
12
---
11
tests/qemu-iotests/031 | 5 +++--
13
include/io/channel.h | 25 +++++++++++++++++++++++++
12
tests/qemu-iotests/051 | 5 +++--
14
io/channel-command.c | 13 +++++++++++++
13
tests/qemu-iotests/061 | 6 +++++-
15
io/channel-file.c | 11 +++++++++++
14
tests/qemu-iotests/112 | 3 ++-
16
io/channel-socket.c | 16 +++++++++++-----
15
tests/qemu-iotests/290 | 2 +-
17
io/channel-tls.c | 12 ++++++++++++
16
5 files changed, 14 insertions(+), 7 deletions(-)
18
io/channel-watch.c | 6 ++++++
17
19
io/channel.c | 11 +++++++++++
18
diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
20
7 files changed, 89 insertions(+), 5 deletions(-)
19
index XXXXXXX..XXXXXXX 100755
21
20
--- a/tests/qemu-iotests/031
22
diff --git a/include/io/channel.h b/include/io/channel.h
21
+++ b/tests/qemu-iotests/031
23
index XXXXXXX..XXXXXXX 100644
22
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
24
--- a/include/io/channel.h
23
_supported_fmt qcow2
25
+++ b/include/io/channel.h
24
_supported_proto file fuse
26
@@ -XXX,XX +XXX,XX @@
25
# We want to test compat=0.10, which does not support external data
27
26
-# files or refcount widths other than 16
28
#include "qemu-common.h"
27
-_unsupported_imgopts data_file 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
29
#include "qom/object.h"
28
+# files or refcount widths other than 16 or compression type
30
+#include "block/aio.h"
29
+_unsupported_imgopts data_file compression_type \
31
30
+ 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
32
#define TYPE_QIO_CHANNEL "qio-channel"
31
33
#define QIO_CHANNEL(obj) \
32
CLUSTER_SIZE=65536
34
@@ -XXX,XX +XXX,XX @@ struct QIOChannelClass {
33
35
off_t offset,
34
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
36
int whence,
35
index XXXXXXX..XXXXXXX 100755
37
Error **errp);
36
--- a/tests/qemu-iotests/051
38
+ void (*io_set_aio_fd_handler)(QIOChannel *ioc,
37
+++ b/tests/qemu-iotests/051
39
+ AioContext *ctx,
38
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow2
40
+ IOHandler *io_read,
39
_supported_proto file
41
+ IOHandler *io_write,
40
# A compat=0.10 image is created in this test which does not support anything
42
+ void *opaque);
41
# other than refcount_bits=16;
43
};
42
-# it also will not support an external data file
44
43
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
45
/* General I/O handling functions */
44
+# it also will not support an external data file and compression type
46
@@ -XXX,XX +XXX,XX @@ void qio_channel_yield(QIOChannel *ioc,
45
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file \
47
void qio_channel_wait(QIOChannel *ioc,
46
+ compression_type
48
GIOCondition condition);
47
_require_drivers nbd
49
48
50
+/**
49
if [ "$QEMU_DEFAULT_MACHINE" = "pc" ]; then
51
+ * qio_channel_set_aio_fd_handler:
50
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
52
+ * @ioc: the channel object
51
index XXXXXXX..XXXXXXX 100755
53
+ * @ctx: the AioContext to set the handlers on
52
--- a/tests/qemu-iotests/061
54
+ * @io_read: the read handler
53
+++ b/tests/qemu-iotests/061
55
+ * @io_write: the write handler
54
@@ -XXX,XX +XXX,XX @@ _supported_os Linux
56
+ * @opaque: the opaque value passed to the handler
55
# not work with it;
57
+ *
56
# we have explicit tests for various cluster sizes, the remaining tests
58
+ * This is used internally by qio_channel_yield(). It can
57
# require the default 64k cluster
59
+ * be used by channel implementations to forward the handlers
58
-_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file cluster_size
60
+ * to another channel (e.g. from #QIOChannelTLS to the
59
+# we don't have explicit tests for zstd qcow2 compression type, as zstd may be
61
+ * underlying socket).
60
+# not compiled in. And we can't create compat images with comression type
62
+ */
61
+# extension
63
+void qio_channel_set_aio_fd_handler(QIOChannel *ioc,
62
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file \
64
+ AioContext *ctx,
63
+ cluster_size compression_type
65
+ IOHandler *io_read,
64
66
+ IOHandler *io_write,
65
echo
67
+ void *opaque);
66
echo "=== Testing version downgrade with zero expansion ==="
68
+
67
diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
69
#endif /* QIO_CHANNEL_H */
68
index XXXXXXX..XXXXXXX 100755
70
diff --git a/io/channel-command.c b/io/channel-command.c
69
--- a/tests/qemu-iotests/112
71
index XXXXXXX..XXXXXXX 100644
70
+++ b/tests/qemu-iotests/112
72
--- a/io/channel-command.c
71
@@ -XXX,XX +XXX,XX @@ _supported_proto file fuse
73
+++ b/io/channel-command.c
72
# This test will set refcount_bits on its own which would conflict with the
74
@@ -XXX,XX +XXX,XX @@ static int qio_channel_command_close(QIOChannel *ioc,
73
# manual setting; compat will be overridden as well;
75
}
74
# and external data files do not work well with our refcount testing
76
75
-_unsupported_imgopts refcount_bits 'compat=0.10' data_file
77
76
+# also, compression type is not supported with compat=0.10 used in test
78
+static void qio_channel_command_set_aio_fd_handler(QIOChannel *ioc,
77
+_unsupported_imgopts refcount_bits 'compat=0.10' data_file compression_type
79
+ AioContext *ctx,
78
80
+ IOHandler *io_read,
79
print_refcount_bits()
81
+ IOHandler *io_write,
80
{
82
+ void *opaque)
81
diff --git a/tests/qemu-iotests/290 b/tests/qemu-iotests/290
83
+{
82
index XXXXXXX..XXXXXXX 100755
84
+ QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
83
--- a/tests/qemu-iotests/290
85
+ aio_set_fd_handler(ctx, cioc->readfd, false, io_read, NULL, NULL, opaque);
84
+++ b/tests/qemu-iotests/290
86
+ aio_set_fd_handler(ctx, cioc->writefd, false, NULL, io_write, NULL, opaque);
85
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
87
+}
86
_supported_fmt qcow2
88
+
87
_supported_proto file fuse
89
+
88
_supported_os Linux
90
static GSource *qio_channel_command_create_watch(QIOChannel *ioc,
89
-_unsupported_imgopts 'compat=0.10' refcount_bits data_file
91
GIOCondition condition)
90
+_unsupported_imgopts 'compat=0.10' refcount_bits data_file compression_type
92
{
91
93
@@ -XXX,XX +XXX,XX @@ static void qio_channel_command_class_init(ObjectClass *klass,
92
echo
94
ioc_klass->io_set_blocking = qio_channel_command_set_blocking;
93
echo "### Test 'qemu-io -c discard' on a QCOW2 image without a backing file"
95
ioc_klass->io_close = qio_channel_command_close;
96
ioc_klass->io_create_watch = qio_channel_command_create_watch;
97
+ ioc_klass->io_set_aio_fd_handler = qio_channel_command_set_aio_fd_handler;
98
}
99
100
static const TypeInfo qio_channel_command_info = {
101
diff --git a/io/channel-file.c b/io/channel-file.c
102
index XXXXXXX..XXXXXXX 100644
103
--- a/io/channel-file.c
104
+++ b/io/channel-file.c
105
@@ -XXX,XX +XXX,XX @@ static int qio_channel_file_close(QIOChannel *ioc,
106
}
107
108
109
+static void qio_channel_file_set_aio_fd_handler(QIOChannel *ioc,
110
+ AioContext *ctx,
111
+ IOHandler *io_read,
112
+ IOHandler *io_write,
113
+ void *opaque)
114
+{
115
+ QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
116
+ aio_set_fd_handler(ctx, fioc->fd, false, io_read, io_write, NULL, opaque);
117
+}
118
+
119
static GSource *qio_channel_file_create_watch(QIOChannel *ioc,
120
GIOCondition condition)
121
{
122
@@ -XXX,XX +XXX,XX @@ static void qio_channel_file_class_init(ObjectClass *klass,
123
ioc_klass->io_seek = qio_channel_file_seek;
124
ioc_klass->io_close = qio_channel_file_close;
125
ioc_klass->io_create_watch = qio_channel_file_create_watch;
126
+ ioc_klass->io_set_aio_fd_handler = qio_channel_file_set_aio_fd_handler;
127
}
128
129
static const TypeInfo qio_channel_file_info = {
130
diff --git a/io/channel-socket.c b/io/channel-socket.c
131
index XXXXXXX..XXXXXXX 100644
132
--- a/io/channel-socket.c
133
+++ b/io/channel-socket.c
134
@@ -XXX,XX +XXX,XX @@ qio_channel_socket_set_blocking(QIOChannel *ioc,
135
qemu_set_block(sioc->fd);
136
} else {
137
qemu_set_nonblock(sioc->fd);
138
-#ifdef WIN32
139
- WSAEventSelect(sioc->fd, ioc->event,
140
- FD_READ | FD_ACCEPT | FD_CLOSE |
141
- FD_CONNECT | FD_WRITE | FD_OOB);
142
-#endif
143
}
144
return 0;
145
}
146
@@ -XXX,XX +XXX,XX @@ qio_channel_socket_shutdown(QIOChannel *ioc,
147
return 0;
148
}
149
150
+static void qio_channel_socket_set_aio_fd_handler(QIOChannel *ioc,
151
+ AioContext *ctx,
152
+ IOHandler *io_read,
153
+ IOHandler *io_write,
154
+ void *opaque)
155
+{
156
+ QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
157
+ aio_set_fd_handler(ctx, sioc->fd, false, io_read, io_write, NULL, opaque);
158
+}
159
+
160
static GSource *qio_channel_socket_create_watch(QIOChannel *ioc,
161
GIOCondition condition)
162
{
163
@@ -XXX,XX +XXX,XX @@ static void qio_channel_socket_class_init(ObjectClass *klass,
164
ioc_klass->io_set_cork = qio_channel_socket_set_cork;
165
ioc_klass->io_set_delay = qio_channel_socket_set_delay;
166
ioc_klass->io_create_watch = qio_channel_socket_create_watch;
167
+ ioc_klass->io_set_aio_fd_handler = qio_channel_socket_set_aio_fd_handler;
168
}
169
170
static const TypeInfo qio_channel_socket_info = {
171
diff --git a/io/channel-tls.c b/io/channel-tls.c
172
index XXXXXXX..XXXXXXX 100644
173
--- a/io/channel-tls.c
174
+++ b/io/channel-tls.c
175
@@ -XXX,XX +XXX,XX @@ static int qio_channel_tls_close(QIOChannel *ioc,
176
return qio_channel_close(tioc->master, errp);
177
}
178
179
+static void qio_channel_tls_set_aio_fd_handler(QIOChannel *ioc,
180
+ AioContext *ctx,
181
+ IOHandler *io_read,
182
+ IOHandler *io_write,
183
+ void *opaque)
184
+{
185
+ QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
186
+
187
+ qio_channel_set_aio_fd_handler(tioc->master, ctx, io_read, io_write, opaque);
188
+}
189
+
190
static GSource *qio_channel_tls_create_watch(QIOChannel *ioc,
191
GIOCondition condition)
192
{
193
@@ -XXX,XX +XXX,XX @@ static void qio_channel_tls_class_init(ObjectClass *klass,
194
ioc_klass->io_close = qio_channel_tls_close;
195
ioc_klass->io_shutdown = qio_channel_tls_shutdown;
196
ioc_klass->io_create_watch = qio_channel_tls_create_watch;
197
+ ioc_klass->io_set_aio_fd_handler = qio_channel_tls_set_aio_fd_handler;
198
}
199
200
static const TypeInfo qio_channel_tls_info = {
201
diff --git a/io/channel-watch.c b/io/channel-watch.c
202
index XXXXXXX..XXXXXXX 100644
203
--- a/io/channel-watch.c
204
+++ b/io/channel-watch.c
205
@@ -XXX,XX +XXX,XX @@ GSource *qio_channel_create_socket_watch(QIOChannel *ioc,
206
GSource *source;
207
QIOChannelSocketSource *ssource;
208
209
+#ifdef WIN32
210
+ WSAEventSelect(socket, ioc->event,
211
+ FD_READ | FD_ACCEPT | FD_CLOSE |
212
+ FD_CONNECT | FD_WRITE | FD_OOB);
213
+#endif
214
+
215
source = g_source_new(&qio_channel_socket_source_funcs,
216
sizeof(QIOChannelSocketSource));
217
ssource = (QIOChannelSocketSource *)source;
218
diff --git a/io/channel.c b/io/channel.c
219
index XXXXXXX..XXXXXXX 100644
220
--- a/io/channel.c
221
+++ b/io/channel.c
222
@@ -XXX,XX +XXX,XX @@ GSource *qio_channel_create_watch(QIOChannel *ioc,
223
}
224
225
226
+void qio_channel_set_aio_fd_handler(QIOChannel *ioc,
227
+ AioContext *ctx,
228
+ IOHandler *io_read,
229
+ IOHandler *io_write,
230
+ void *opaque)
231
+{
232
+ QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
233
+
234
+ klass->io_set_aio_fd_handler(ioc, ctx, io_read, io_write, opaque);
235
+}
236
+
237
guint qio_channel_add_watch(QIOChannel *ioc,
238
GIOCondition condition,
239
QIOChannelFunc func,
94
--
240
--
95
2.34.1
241
2.9.3
96
242
97
243
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
The test-case "Corrupted size field in compressed cluster descriptor"
3
Support separate coroutines for reading and writing, and place the
4
heavily depends on zlib compression type. So, make it explicit. This
4
read/write handlers on the AioContext that the QIOChannel is registered
5
way test passes with IMGOPTS='compression_type=zstd'.
5
with.
6
6
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Message-Id: <20211223160144.1097696-19-vsementsov@virtuozzo.com>
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
10
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
10
Reviewed-by: Fam Zheng <famz@redhat.com>
11
Message-id: 20170213135235.12274-7-pbonzini@redhat.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
13
---
12
tests/qemu-iotests/214 | 2 +-
14
include/io/channel.h | 47 ++++++++++++++++++++++++++--
13
1 file changed, 1 insertion(+), 1 deletion(-)
15
io/channel.c | 86 +++++++++++++++++++++++++++++++++++++++-------------
14
16
2 files changed, 109 insertions(+), 24 deletions(-)
15
diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214
17
16
index XXXXXXX..XXXXXXX 100755
18
diff --git a/include/io/channel.h b/include/io/channel.h
17
--- a/tests/qemu-iotests/214
19
index XXXXXXX..XXXXXXX 100644
18
+++ b/tests/qemu-iotests/214
20
--- a/include/io/channel.h
19
@@ -XXX,XX +XXX,XX @@ echo
21
+++ b/include/io/channel.h
20
# The L2 entries of the two compressed clusters are located at
22
@@ -XXX,XX +XXX,XX @@
21
# 0x800000 and 0x800008, their original values are 0x4008000000a00000
23
22
# and 0x4008000000a00802 (5 sectors for compressed data each).
24
#include "qemu-common.h"
23
-_make_test_img 8M -o cluster_size=2M
25
#include "qom/object.h"
24
+_make_test_img 8M -o cluster_size=2M,compression_type=zlib
26
+#include "qemu/coroutine.h"
25
$QEMU_IO -c "write -c -P 0x11 0 2M" -c "write -c -P 0x11 2M 2M" "$TEST_IMG" \
27
#include "block/aio.h"
26
2>&1 | _filter_qemu_io | _filter_testdir
28
29
#define TYPE_QIO_CHANNEL "qio-channel"
30
@@ -XXX,XX +XXX,XX @@ struct QIOChannel {
31
Object parent;
32
unsigned int features; /* bitmask of QIOChannelFeatures */
33
char *name;
34
+ AioContext *ctx;
35
+ Coroutine *read_coroutine;
36
+ Coroutine *write_coroutine;
37
#ifdef _WIN32
38
HANDLE event; /* For use with GSource on Win32 */
39
#endif
40
@@ -XXX,XX +XXX,XX @@ guint qio_channel_add_watch(QIOChannel *ioc,
41
42
43
/**
44
+ * qio_channel_attach_aio_context:
45
+ * @ioc: the channel object
46
+ * @ctx: the #AioContext to set the handlers on
47
+ *
48
+ * Request that qio_channel_yield() sets I/O handlers on
49
+ * the given #AioContext. If @ctx is %NULL, qio_channel_yield()
50
+ * uses QEMU's main thread event loop.
51
+ *
52
+ * You can move a #QIOChannel from one #AioContext to another even if
53
+ * I/O handlers are set for a coroutine. However, #QIOChannel provides
54
+ * no synchronization between the calls to qio_channel_yield() and
55
+ * qio_channel_attach_aio_context().
56
+ *
57
+ * Therefore you should first call qio_channel_detach_aio_context()
58
+ * to ensure that the coroutine is not entered concurrently. Then,
59
+ * while the coroutine has yielded, call qio_channel_attach_aio_context(),
60
+ * and then aio_co_schedule() to place the coroutine on the new
61
+ * #AioContext. The calls to qio_channel_detach_aio_context()
62
+ * and qio_channel_attach_aio_context() should be protected with
63
+ * aio_context_acquire() and aio_context_release().
64
+ */
65
+void qio_channel_attach_aio_context(QIOChannel *ioc,
66
+ AioContext *ctx);
67
+
68
+/**
69
+ * qio_channel_detach_aio_context:
70
+ * @ioc: the channel object
71
+ *
72
+ * Disable any I/O handlers set by qio_channel_yield(). With the
73
+ * help of aio_co_schedule(), this allows moving a coroutine that was
74
+ * paused by qio_channel_yield() to another context.
75
+ */
76
+void qio_channel_detach_aio_context(QIOChannel *ioc);
77
+
78
+/**
79
* qio_channel_yield:
80
* @ioc: the channel object
81
* @condition: the I/O condition to wait for
82
*
83
- * Yields execution from the current coroutine until
84
- * the condition indicated by @condition becomes
85
- * available.
86
+ * Yields execution from the current coroutine until the condition
87
+ * indicated by @condition becomes available. @condition must
88
+ * be either %G_IO_IN or %G_IO_OUT; it cannot contain both. In
89
+ * addition, no two coroutine can be waiting on the same condition
90
+ * and channel at the same time.
91
*
92
* This must only be called from coroutine context
93
*/
94
diff --git a/io/channel.c b/io/channel.c
95
index XXXXXXX..XXXXXXX 100644
96
--- a/io/channel.c
97
+++ b/io/channel.c
98
@@ -XXX,XX +XXX,XX @@
99
#include "qemu/osdep.h"
100
#include "io/channel.h"
101
#include "qapi/error.h"
102
-#include "qemu/coroutine.h"
103
+#include "qemu/main-loop.h"
104
105
bool qio_channel_has_feature(QIOChannel *ioc,
106
QIOChannelFeature feature)
107
@@ -XXX,XX +XXX,XX @@ off_t qio_channel_io_seek(QIOChannel *ioc,
108
}
109
110
111
-typedef struct QIOChannelYieldData QIOChannelYieldData;
112
-struct QIOChannelYieldData {
113
- QIOChannel *ioc;
114
- Coroutine *co;
115
-};
116
+static void qio_channel_set_aio_fd_handlers(QIOChannel *ioc);
117
118
+static void qio_channel_restart_read(void *opaque)
119
+{
120
+ QIOChannel *ioc = opaque;
121
+ Coroutine *co = ioc->read_coroutine;
122
+
123
+ ioc->read_coroutine = NULL;
124
+ qio_channel_set_aio_fd_handlers(ioc);
125
+ aio_co_wake(co);
126
+}
127
128
-static gboolean qio_channel_yield_enter(QIOChannel *ioc,
129
- GIOCondition condition,
130
- gpointer opaque)
131
+static void qio_channel_restart_write(void *opaque)
132
{
133
- QIOChannelYieldData *data = opaque;
134
- qemu_coroutine_enter(data->co);
135
- return FALSE;
136
+ QIOChannel *ioc = opaque;
137
+ Coroutine *co = ioc->write_coroutine;
138
+
139
+ ioc->write_coroutine = NULL;
140
+ qio_channel_set_aio_fd_handlers(ioc);
141
+ aio_co_wake(co);
142
}
143
144
+static void qio_channel_set_aio_fd_handlers(QIOChannel *ioc)
145
+{
146
+ IOHandler *rd_handler = NULL, *wr_handler = NULL;
147
+ AioContext *ctx;
148
+
149
+ if (ioc->read_coroutine) {
150
+ rd_handler = qio_channel_restart_read;
151
+ }
152
+ if (ioc->write_coroutine) {
153
+ wr_handler = qio_channel_restart_write;
154
+ }
155
+
156
+ ctx = ioc->ctx ? ioc->ctx : iohandler_get_aio_context();
157
+ qio_channel_set_aio_fd_handler(ioc, ctx, rd_handler, wr_handler, ioc);
158
+}
159
+
160
+void qio_channel_attach_aio_context(QIOChannel *ioc,
161
+ AioContext *ctx)
162
+{
163
+ AioContext *old_ctx;
164
+ if (ioc->ctx == ctx) {
165
+ return;
166
+ }
167
+
168
+ old_ctx = ioc->ctx ? ioc->ctx : iohandler_get_aio_context();
169
+ qio_channel_set_aio_fd_handler(ioc, old_ctx, NULL, NULL, NULL);
170
+ ioc->ctx = ctx;
171
+ qio_channel_set_aio_fd_handlers(ioc);
172
+}
173
+
174
+void qio_channel_detach_aio_context(QIOChannel *ioc)
175
+{
176
+ ioc->read_coroutine = NULL;
177
+ ioc->write_coroutine = NULL;
178
+ qio_channel_set_aio_fd_handlers(ioc);
179
+ ioc->ctx = NULL;
180
+}
181
182
void coroutine_fn qio_channel_yield(QIOChannel *ioc,
183
GIOCondition condition)
184
{
185
- QIOChannelYieldData data;
186
-
187
assert(qemu_in_coroutine());
188
- data.ioc = ioc;
189
- data.co = qemu_coroutine_self();
190
- qio_channel_add_watch(ioc,
191
- condition,
192
- qio_channel_yield_enter,
193
- &data,
194
- NULL);
195
+ if (condition == G_IO_IN) {
196
+ assert(!ioc->read_coroutine);
197
+ ioc->read_coroutine = qemu_coroutine_self();
198
+ } else if (condition == G_IO_OUT) {
199
+ assert(!ioc->write_coroutine);
200
+ ioc->write_coroutine = qemu_coroutine_self();
201
+ } else {
202
+ abort();
203
+ }
204
+ qio_channel_set_aio_fd_handlers(ioc);
205
qemu_coroutine_yield();
206
}
27
207
28
--
208
--
29
2.34.1
209
2.9.3
30
210
31
211
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
_qcow2_dump_header has filter for compression type, so this change
3
In the client, read the reply headers from a coroutine, switching the
4
makes test pass with IMGOPTS='compression_type=zstd'.
4
read side between the "read header" coroutine and the I/O coroutine that
5
reads the body of the reply.
5
6
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
In the server, if the server can read more requests it will create a new
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
"read request" coroutine as soon as a request has been read. Otherwise,
8
Message-Id: <20211223160144.1097696-16-vsementsov@virtuozzo.com>
9
the new coroutine is created in nbd_request_put.
9
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
10
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
13
Reviewed-by: Fam Zheng <famz@redhat.com>
14
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
15
Message-id: 20170213135235.12274-8-pbonzini@redhat.com
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
17
---
11
tests/qemu-iotests/039 | 2 +-
18
block/nbd-client.h | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
19
block/nbd-client.c | 117 ++++++++++++++++++++++++-----------------------------
20
nbd/client.c | 2 +-
21
nbd/common.c | 9 +----
22
nbd/server.c | 94 +++++++++++++-----------------------------
23
5 files changed, 83 insertions(+), 141 deletions(-)
13
24
14
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
25
diff --git a/block/nbd-client.h b/block/nbd-client.h
15
index XXXXXXX..XXXXXXX 100755
26
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/039
27
--- a/block/nbd-client.h
17
+++ b/tests/qemu-iotests/039
28
+++ b/block/nbd-client.h
18
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG commit "$TEST_IMG"
29
@@ -XXX,XX +XXX,XX @@ typedef struct NBDClientSession {
19
30
20
# The dirty bit must not be set
31
CoMutex send_mutex;
21
_qcow2_dump_header | grep incompatible_features
32
CoQueue free_sema;
22
-$PYTHON qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features
33
- Coroutine *send_coroutine;
23
+_qcow2_dump_header "$TEST_IMG".base | grep incompatible_features
34
+ Coroutine *read_reply_co;
24
35
int in_flight;
25
_check_test_img
36
26
TEST_IMG="$TEST_IMG".base _check_test_img
37
Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
38
diff --git a/block/nbd-client.c b/block/nbd-client.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/block/nbd-client.c
41
+++ b/block/nbd-client.c
42
@@ -XXX,XX +XXX,XX @@
43
#define HANDLE_TO_INDEX(bs, handle) ((handle) ^ ((uint64_t)(intptr_t)bs))
44
#define INDEX_TO_HANDLE(bs, index) ((index) ^ ((uint64_t)(intptr_t)bs))
45
46
-static void nbd_recv_coroutines_enter_all(NBDClientSession *s)
47
+static void nbd_recv_coroutines_enter_all(BlockDriverState *bs)
48
{
49
+ NBDClientSession *s = nbd_get_client_session(bs);
50
int i;
51
52
for (i = 0; i < MAX_NBD_REQUESTS; i++) {
53
@@ -XXX,XX +XXX,XX @@ static void nbd_recv_coroutines_enter_all(NBDClientSession *s)
54
qemu_coroutine_enter(s->recv_coroutine[i]);
55
}
56
}
57
+ BDRV_POLL_WHILE(bs, s->read_reply_co);
58
}
59
60
static void nbd_teardown_connection(BlockDriverState *bs)
61
@@ -XXX,XX +XXX,XX @@ static void nbd_teardown_connection(BlockDriverState *bs)
62
qio_channel_shutdown(client->ioc,
63
QIO_CHANNEL_SHUTDOWN_BOTH,
64
NULL);
65
- nbd_recv_coroutines_enter_all(client);
66
+ nbd_recv_coroutines_enter_all(bs);
67
68
nbd_client_detach_aio_context(bs);
69
object_unref(OBJECT(client->sioc));
70
@@ -XXX,XX +XXX,XX @@ static void nbd_teardown_connection(BlockDriverState *bs)
71
client->ioc = NULL;
72
}
73
74
-static void nbd_reply_ready(void *opaque)
75
+static coroutine_fn void nbd_read_reply_entry(void *opaque)
76
{
77
- BlockDriverState *bs = opaque;
78
- NBDClientSession *s = nbd_get_client_session(bs);
79
+ NBDClientSession *s = opaque;
80
uint64_t i;
81
int ret;
82
83
- if (!s->ioc) { /* Already closed */
84
- return;
85
- }
86
-
87
- if (s->reply.handle == 0) {
88
- /* No reply already in flight. Fetch a header. It is possible
89
- * that another thread has done the same thing in parallel, so
90
- * the socket is not readable anymore.
91
- */
92
+ for (;;) {
93
+ assert(s->reply.handle == 0);
94
ret = nbd_receive_reply(s->ioc, &s->reply);
95
- if (ret == -EAGAIN) {
96
- return;
97
- }
98
if (ret < 0) {
99
- s->reply.handle = 0;
100
- goto fail;
101
+ break;
102
}
103
- }
104
105
- /* There's no need for a mutex on the receive side, because the
106
- * handler acts as a synchronization point and ensures that only
107
- * one coroutine is called until the reply finishes. */
108
- i = HANDLE_TO_INDEX(s, s->reply.handle);
109
- if (i >= MAX_NBD_REQUESTS) {
110
- goto fail;
111
- }
112
+ /* There's no need for a mutex on the receive side, because the
113
+ * handler acts as a synchronization point and ensures that only
114
+ * one coroutine is called until the reply finishes.
115
+ */
116
+ i = HANDLE_TO_INDEX(s, s->reply.handle);
117
+ if (i >= MAX_NBD_REQUESTS || !s->recv_coroutine[i]) {
118
+ break;
119
+ }
120
121
- if (s->recv_coroutine[i]) {
122
- qemu_coroutine_enter(s->recv_coroutine[i]);
123
- return;
124
+ /* We're woken up by the recv_coroutine itself. Note that there
125
+ * is no race between yielding and reentering read_reply_co. This
126
+ * is because:
127
+ *
128
+ * - if recv_coroutine[i] runs on the same AioContext, it is only
129
+ * entered after we yield
130
+ *
131
+ * - if recv_coroutine[i] runs on a different AioContext, reentering
132
+ * read_reply_co happens through a bottom half, which can only
133
+ * run after we yield.
134
+ */
135
+ aio_co_wake(s->recv_coroutine[i]);
136
+ qemu_coroutine_yield();
137
}
138
-
139
-fail:
140
- nbd_teardown_connection(bs);
141
-}
142
-
143
-static void nbd_restart_write(void *opaque)
144
-{
145
- BlockDriverState *bs = opaque;
146
-
147
- qemu_coroutine_enter(nbd_get_client_session(bs)->send_coroutine);
148
+ s->read_reply_co = NULL;
149
}
150
151
static int nbd_co_send_request(BlockDriverState *bs,
152
@@ -XXX,XX +XXX,XX @@ static int nbd_co_send_request(BlockDriverState *bs,
153
QEMUIOVector *qiov)
154
{
155
NBDClientSession *s = nbd_get_client_session(bs);
156
- AioContext *aio_context;
157
int rc, ret, i;
158
159
qemu_co_mutex_lock(&s->send_mutex);
160
@@ -XXX,XX +XXX,XX @@ static int nbd_co_send_request(BlockDriverState *bs,
161
return -EPIPE;
162
}
163
164
- s->send_coroutine = qemu_coroutine_self();
165
- aio_context = bdrv_get_aio_context(bs);
166
-
167
- aio_set_fd_handler(aio_context, s->sioc->fd, false,
168
- nbd_reply_ready, nbd_restart_write, NULL, bs);
169
if (qiov) {
170
qio_channel_set_cork(s->ioc, true);
171
rc = nbd_send_request(s->ioc, request);
172
@@ -XXX,XX +XXX,XX @@ static int nbd_co_send_request(BlockDriverState *bs,
173
} else {
174
rc = nbd_send_request(s->ioc, request);
175
}
176
- aio_set_fd_handler(aio_context, s->sioc->fd, false,
177
- nbd_reply_ready, NULL, NULL, bs);
178
- s->send_coroutine = NULL;
179
qemu_co_mutex_unlock(&s->send_mutex);
180
return rc;
181
}
182
@@ -XXX,XX +XXX,XX @@ static void nbd_co_receive_reply(NBDClientSession *s,
183
{
184
int ret;
185
186
- /* Wait until we're woken up by the read handler. TODO: perhaps
187
- * peek at the next reply and avoid yielding if it's ours? */
188
+ /* Wait until we're woken up by nbd_read_reply_entry. */
189
qemu_coroutine_yield();
190
*reply = s->reply;
191
if (reply->handle != request->handle ||
192
@@ -XXX,XX +XXX,XX @@ static void nbd_coroutine_start(NBDClientSession *s,
193
/* s->recv_coroutine[i] is set as soon as we get the send_lock. */
194
}
195
196
-static void nbd_coroutine_end(NBDClientSession *s,
197
+static void nbd_coroutine_end(BlockDriverState *bs,
198
NBDRequest *request)
199
{
200
+ NBDClientSession *s = nbd_get_client_session(bs);
201
int i = HANDLE_TO_INDEX(s, request->handle);
202
+
203
s->recv_coroutine[i] = NULL;
204
- if (s->in_flight-- == MAX_NBD_REQUESTS) {
205
- qemu_co_queue_next(&s->free_sema);
206
+ s->in_flight--;
207
+ qemu_co_queue_next(&s->free_sema);
208
+
209
+ /* Kick the read_reply_co to get the next reply. */
210
+ if (s->read_reply_co) {
211
+ aio_co_wake(s->read_reply_co);
212
}
213
}
214
215
@@ -XXX,XX +XXX,XX @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
216
} else {
217
nbd_co_receive_reply(client, &request, &reply, qiov);
218
}
219
- nbd_coroutine_end(client, &request);
220
+ nbd_coroutine_end(bs, &request);
221
return -reply.error;
222
}
223
224
@@ -XXX,XX +XXX,XX @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
225
} else {
226
nbd_co_receive_reply(client, &request, &reply, NULL);
227
}
228
- nbd_coroutine_end(client, &request);
229
+ nbd_coroutine_end(bs, &request);
230
return -reply.error;
231
}
232
233
@@ -XXX,XX +XXX,XX @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
234
} else {
235
nbd_co_receive_reply(client, &request, &reply, NULL);
236
}
237
- nbd_coroutine_end(client, &request);
238
+ nbd_coroutine_end(bs, &request);
239
return -reply.error;
240
}
241
242
@@ -XXX,XX +XXX,XX @@ int nbd_client_co_flush(BlockDriverState *bs)
243
} else {
244
nbd_co_receive_reply(client, &request, &reply, NULL);
245
}
246
- nbd_coroutine_end(client, &request);
247
+ nbd_coroutine_end(bs, &request);
248
return -reply.error;
249
}
250
251
@@ -XXX,XX +XXX,XX @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
252
} else {
253
nbd_co_receive_reply(client, &request, &reply, NULL);
254
}
255
- nbd_coroutine_end(client, &request);
256
+ nbd_coroutine_end(bs, &request);
257
return -reply.error;
258
259
}
260
261
void nbd_client_detach_aio_context(BlockDriverState *bs)
262
{
263
- aio_set_fd_handler(bdrv_get_aio_context(bs),
264
- nbd_get_client_session(bs)->sioc->fd,
265
- false, NULL, NULL, NULL, NULL);
266
+ NBDClientSession *client = nbd_get_client_session(bs);
267
+ qio_channel_detach_aio_context(QIO_CHANNEL(client->sioc));
268
}
269
270
void nbd_client_attach_aio_context(BlockDriverState *bs,
271
AioContext *new_context)
272
{
273
- aio_set_fd_handler(new_context, nbd_get_client_session(bs)->sioc->fd,
274
- false, nbd_reply_ready, NULL, NULL, bs);
275
+ NBDClientSession *client = nbd_get_client_session(bs);
276
+ qio_channel_attach_aio_context(QIO_CHANNEL(client->sioc), new_context);
277
+ aio_co_schedule(new_context, client->read_reply_co);
278
}
279
280
void nbd_client_close(BlockDriverState *bs)
281
@@ -XXX,XX +XXX,XX @@ int nbd_client_init(BlockDriverState *bs,
282
/* Now that we're connected, set the socket to be non-blocking and
283
* kick the reply mechanism. */
284
qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL);
285
-
286
+ client->read_reply_co = qemu_coroutine_create(nbd_read_reply_entry, client);
287
nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs));
288
289
logout("Established connection with NBD server\n");
290
diff --git a/nbd/client.c b/nbd/client.c
291
index XXXXXXX..XXXXXXX 100644
292
--- a/nbd/client.c
293
+++ b/nbd/client.c
294
@@ -XXX,XX +XXX,XX @@ ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply)
295
ssize_t ret;
296
297
ret = read_sync(ioc, buf, sizeof(buf));
298
- if (ret < 0) {
299
+ if (ret <= 0) {
300
return ret;
301
}
302
303
diff --git a/nbd/common.c b/nbd/common.c
304
index XXXXXXX..XXXXXXX 100644
305
--- a/nbd/common.c
306
+++ b/nbd/common.c
307
@@ -XXX,XX +XXX,XX @@ ssize_t nbd_wr_syncv(QIOChannel *ioc,
308
}
309
if (len == QIO_CHANNEL_ERR_BLOCK) {
310
if (qemu_in_coroutine()) {
311
- /* XXX figure out if we can create a variant on
312
- * qio_channel_yield() that works with AIO contexts
313
- * and consider using that in this branch */
314
- qemu_coroutine_yield();
315
- } else if (done) {
316
- /* XXX this is needed by nbd_reply_ready. */
317
- qio_channel_wait(ioc,
318
- do_read ? G_IO_IN : G_IO_OUT);
319
+ qio_channel_yield(ioc, do_read ? G_IO_IN : G_IO_OUT);
320
} else {
321
return -EAGAIN;
322
}
323
diff --git a/nbd/server.c b/nbd/server.c
324
index XXXXXXX..XXXXXXX 100644
325
--- a/nbd/server.c
326
+++ b/nbd/server.c
327
@@ -XXX,XX +XXX,XX @@ struct NBDClient {
328
CoMutex send_lock;
329
Coroutine *send_coroutine;
330
331
- bool can_read;
332
-
333
QTAILQ_ENTRY(NBDClient) next;
334
int nb_requests;
335
bool closing;
336
@@ -XXX,XX +XXX,XX @@ struct NBDClient {
337
338
/* That's all folks */
339
340
-static void nbd_set_handlers(NBDClient *client);
341
-static void nbd_unset_handlers(NBDClient *client);
342
-static void nbd_update_can_read(NBDClient *client);
343
+static void nbd_client_receive_next_request(NBDClient *client);
344
345
static gboolean nbd_negotiate_continue(QIOChannel *ioc,
346
GIOCondition condition,
347
@@ -XXX,XX +XXX,XX @@ void nbd_client_put(NBDClient *client)
348
*/
349
assert(client->closing);
350
351
- nbd_unset_handlers(client);
352
+ qio_channel_detach_aio_context(client->ioc);
353
object_unref(OBJECT(client->sioc));
354
object_unref(OBJECT(client->ioc));
355
if (client->tlscreds) {
356
@@ -XXX,XX +XXX,XX @@ static NBDRequestData *nbd_request_get(NBDClient *client)
357
358
assert(client->nb_requests <= MAX_NBD_REQUESTS - 1);
359
client->nb_requests++;
360
- nbd_update_can_read(client);
361
362
req = g_new0(NBDRequestData, 1);
363
nbd_client_get(client);
364
@@ -XXX,XX +XXX,XX @@ static void nbd_request_put(NBDRequestData *req)
365
g_free(req);
366
367
client->nb_requests--;
368
- nbd_update_can_read(client);
369
+ nbd_client_receive_next_request(client);
370
+
371
nbd_client_put(client);
372
}
373
374
@@ -XXX,XX +XXX,XX @@ static void blk_aio_attached(AioContext *ctx, void *opaque)
375
exp->ctx = ctx;
376
377
QTAILQ_FOREACH(client, &exp->clients, next) {
378
- nbd_set_handlers(client);
379
+ qio_channel_attach_aio_context(client->ioc, ctx);
380
+ if (client->recv_coroutine) {
381
+ aio_co_schedule(ctx, client->recv_coroutine);
382
+ }
383
+ if (client->send_coroutine) {
384
+ aio_co_schedule(ctx, client->send_coroutine);
385
+ }
386
}
387
}
388
389
@@ -XXX,XX +XXX,XX @@ static void blk_aio_detach(void *opaque)
390
TRACE("Export %s: Detaching clients from AIO context %p\n", exp->name, exp->ctx);
391
392
QTAILQ_FOREACH(client, &exp->clients, next) {
393
- nbd_unset_handlers(client);
394
+ qio_channel_detach_aio_context(client->ioc);
395
}
396
397
exp->ctx = NULL;
398
@@ -XXX,XX +XXX,XX @@ static ssize_t nbd_co_send_reply(NBDRequestData *req, NBDReply *reply,
399
g_assert(qemu_in_coroutine());
400
qemu_co_mutex_lock(&client->send_lock);
401
client->send_coroutine = qemu_coroutine_self();
402
- nbd_set_handlers(client);
403
404
if (!len) {
405
rc = nbd_send_reply(client->ioc, reply);
406
@@ -XXX,XX +XXX,XX @@ static ssize_t nbd_co_send_reply(NBDRequestData *req, NBDReply *reply,
407
}
408
409
client->send_coroutine = NULL;
410
- nbd_set_handlers(client);
411
qemu_co_mutex_unlock(&client->send_lock);
412
return rc;
413
}
414
@@ -XXX,XX +XXX,XX @@ static ssize_t nbd_co_receive_request(NBDRequestData *req,
415
ssize_t rc;
416
417
g_assert(qemu_in_coroutine());
418
- client->recv_coroutine = qemu_coroutine_self();
419
- nbd_update_can_read(client);
420
-
421
+ assert(client->recv_coroutine == qemu_coroutine_self());
422
rc = nbd_receive_request(client->ioc, request);
423
if (rc < 0) {
424
if (rc != -EAGAIN) {
425
@@ -XXX,XX +XXX,XX @@ static ssize_t nbd_co_receive_request(NBDRequestData *req,
426
427
out:
428
client->recv_coroutine = NULL;
429
- nbd_update_can_read(client);
430
+ nbd_client_receive_next_request(client);
431
432
return rc;
433
}
434
435
-static void nbd_trip(void *opaque)
436
+/* Owns a reference to the NBDClient passed as opaque. */
437
+static coroutine_fn void nbd_trip(void *opaque)
438
{
439
NBDClient *client = opaque;
440
NBDExport *exp = client->exp;
441
NBDRequestData *req;
442
- NBDRequest request;
443
+ NBDRequest request = { 0 }; /* GCC thinks it can be used uninitialized */
444
NBDReply reply;
445
ssize_t ret;
446
int flags;
447
448
TRACE("Reading request.");
449
if (client->closing) {
450
+ nbd_client_put(client);
451
return;
452
}
453
454
@@ -XXX,XX +XXX,XX @@ static void nbd_trip(void *opaque)
455
456
done:
457
nbd_request_put(req);
458
+ nbd_client_put(client);
459
return;
460
461
out:
462
nbd_request_put(req);
463
client_close(client);
464
+ nbd_client_put(client);
465
}
466
467
-static void nbd_read(void *opaque)
468
+static void nbd_client_receive_next_request(NBDClient *client)
469
{
470
- NBDClient *client = opaque;
471
-
472
- if (client->recv_coroutine) {
473
- qemu_coroutine_enter(client->recv_coroutine);
474
- } else {
475
- qemu_coroutine_enter(qemu_coroutine_create(nbd_trip, client));
476
- }
477
-}
478
-
479
-static void nbd_restart_write(void *opaque)
480
-{
481
- NBDClient *client = opaque;
482
-
483
- qemu_coroutine_enter(client->send_coroutine);
484
-}
485
-
486
-static void nbd_set_handlers(NBDClient *client)
487
-{
488
- if (client->exp && client->exp->ctx) {
489
- aio_set_fd_handler(client->exp->ctx, client->sioc->fd, true,
490
- client->can_read ? nbd_read : NULL,
491
- client->send_coroutine ? nbd_restart_write : NULL,
492
- NULL, client);
493
- }
494
-}
495
-
496
-static void nbd_unset_handlers(NBDClient *client)
497
-{
498
- if (client->exp && client->exp->ctx) {
499
- aio_set_fd_handler(client->exp->ctx, client->sioc->fd, true, NULL,
500
- NULL, NULL, NULL);
501
- }
502
-}
503
-
504
-static void nbd_update_can_read(NBDClient *client)
505
-{
506
- bool can_read = client->recv_coroutine ||
507
- client->nb_requests < MAX_NBD_REQUESTS;
508
-
509
- if (can_read != client->can_read) {
510
- client->can_read = can_read;
511
- nbd_set_handlers(client);
512
-
513
- /* There is no need to invoke aio_notify(), since aio_set_fd_handler()
514
- * in nbd_set_handlers() will have taken care of that */
515
+ if (!client->recv_coroutine && client->nb_requests < MAX_NBD_REQUESTS) {
516
+ nbd_client_get(client);
517
+ client->recv_coroutine = qemu_coroutine_create(nbd_trip, client);
518
+ aio_co_schedule(client->exp->ctx, client->recv_coroutine);
519
}
520
}
521
522
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_co_client_start(void *opaque)
523
goto out;
524
}
525
qemu_co_mutex_init(&client->send_lock);
526
- nbd_set_handlers(client);
527
528
if (exp) {
529
QTAILQ_INSERT_TAIL(&exp->clients, client, next);
530
}
531
+
532
+ nbd_client_receive_next_request(client);
533
+
534
out:
535
g_free(data);
536
}
537
@@ -XXX,XX +XXX,XX @@ void nbd_client_new(NBDExport *exp,
538
object_ref(OBJECT(client->sioc));
539
client->ioc = QIO_CHANNEL(sioc);
540
object_ref(OBJECT(client->ioc));
541
- client->can_read = true;
542
client->close = close_fn;
543
544
data->client = client;
27
--
545
--
28
2.34.1
546
2.9.3
29
547
30
548
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
We are going to add filtering in _qcow2_dump_header and want all tests
3
As a small step towards the introduction of multiqueue, we want
4
use it.
4
coroutines to remain on the same AioContext that started them,
5
unless they are moved explicitly with e.g. aio_co_schedule. This patch
6
avoids that coroutines switch AioContext when they use a CoMutex.
7
For now it does not make much of a difference, because the CoMutex
8
is not thread-safe and the AioContext itself is used to protect the
9
CoMutex from concurrent access. However, this is going to change.
5
10
6
The patch is generated by commands:
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
cd tests/qemu-iotests
12
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
sed -ie 's/$PYTHON qcow2.py "$TEST_IMG" dump-header\($\| \)/_qcow2_dump_header\1/' ??? tests/*
13
Reviewed-by: Fam Zheng <famz@redhat.com>
14
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
15
Message-id: 20170213135235.12274-9-pbonzini@redhat.com
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
---
18
util/qemu-coroutine-lock.c | 5 ++---
19
util/trace-events | 1 -
20
2 files changed, 2 insertions(+), 4 deletions(-)
9
21
10
(the difficulty is to avoid converting dump-header-exts)
22
diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c
11
23
index XXXXXXX..XXXXXXX 100644
12
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
24
--- a/util/qemu-coroutine-lock.c
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
25
+++ b/util/qemu-coroutine-lock.c
14
Message-Id: <20211223160144.1097696-15-vsementsov@virtuozzo.com>
26
@@ -XXX,XX +XXX,XX @@
15
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
27
#include "qemu/coroutine.h"
16
---
28
#include "qemu/coroutine_int.h"
17
tests/qemu-iotests/031 | 6 +++---
29
#include "qemu/queue.h"
18
tests/qemu-iotests/036 | 6 +++---
30
+#include "block/aio.h"
19
tests/qemu-iotests/039 | 20 ++++++++++----------
31
#include "trace.h"
20
tests/qemu-iotests/060 | 20 ++++++++++----------
32
21
tests/qemu-iotests/061 | 36 ++++++++++++++++++------------------
33
void qemu_co_queue_init(CoQueue *queue)
22
tests/qemu-iotests/137 | 2 +-
34
@@ -XXX,XX +XXX,XX @@ void qemu_co_queue_run_restart(Coroutine *co)
23
tests/qemu-iotests/287 | 8 ++++----
35
24
7 files changed, 49 insertions(+), 49 deletions(-)
36
static bool qemu_co_queue_do_restart(CoQueue *queue, bool single)
25
37
{
26
diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031
38
- Coroutine *self = qemu_coroutine_self();
27
index XXXXXXX..XXXXXXX 100755
39
Coroutine *next;
28
--- a/tests/qemu-iotests/031
40
29
+++ b/tests/qemu-iotests/031
41
if (QSIMPLEQ_EMPTY(&queue->entries)) {
30
@@ -XXX,XX +XXX,XX @@ for compat in "compat=0.10" "compat=1.1"; do
42
@@ -XXX,XX +XXX,XX @@ static bool qemu_co_queue_do_restart(CoQueue *queue, bool single)
31
echo
43
32
_make_test_img -o $compat 64M
44
while ((next = QSIMPLEQ_FIRST(&queue->entries)) != NULL) {
33
$PYTHON qcow2.py "$TEST_IMG" add-header-ext 0x12345678 "This is a test header extension"
45
QSIMPLEQ_REMOVE_HEAD(&queue->entries, co_queue_next);
34
- $PYTHON qcow2.py "$TEST_IMG" dump-header
46
- QSIMPLEQ_INSERT_TAIL(&self->co_queue_wakeup, next, co_queue_next);
35
+ _qcow2_dump_header
47
- trace_qemu_co_queue_next(next);
36
_check_test_img
48
+ aio_co_wake(next);
37
49
if (single) {
38
echo
50
break;
39
echo === Rewrite header with no backing file ===
51
}
40
echo
52
diff --git a/util/trace-events b/util/trace-events
41
$QEMU_IMG rebase -u -b "" "$TEST_IMG"
53
index XXXXXXX..XXXXXXX 100644
42
- $PYTHON qcow2.py "$TEST_IMG" dump-header
54
--- a/util/trace-events
43
+ _qcow2_dump_header
55
+++ b/util/trace-events
44
_check_test_img
56
@@ -XXX,XX +XXX,XX @@ qemu_coroutine_terminate(void *co) "self %p"
45
57
46
echo
58
# util/qemu-coroutine-lock.c
47
echo === Add a backing file and format ===
59
qemu_co_queue_run_restart(void *co) "co %p"
48
echo
60
-qemu_co_queue_next(void *nxt) "next %p"
49
$QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device "$TEST_IMG"
61
qemu_co_mutex_lock_entry(void *mutex, void *self) "mutex %p self %p"
50
- $PYTHON qcow2.py "$TEST_IMG" dump-header
62
qemu_co_mutex_lock_return(void *mutex, void *self) "mutex %p self %p"
51
+ _qcow2_dump_header
63
qemu_co_mutex_unlock_entry(void *mutex, void *self) "mutex %p self %p"
52
done
53
54
# success, all done
55
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
56
index XXXXXXX..XXXXXXX 100755
57
--- a/tests/qemu-iotests/036
58
+++ b/tests/qemu-iotests/036
59
@@ -XXX,XX +XXX,XX @@ $PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63
60
61
# Without feature table
62
$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857
63
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
64
+_qcow2_dump_header | grep features
65
$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
66
_img_info
67
68
@@ -XXX,XX +XXX,XX @@ echo === Create image with unknown autoclear feature bit ===
69
echo
70
_make_test_img 64M
71
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 63
72
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
73
+_qcow2_dump_header | grep features
74
$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
75
76
echo
77
@@ -XXX,XX +XXX,XX @@ echo === Repair image ===
78
echo
79
_check_test_img -r all
80
81
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep features
82
+_qcow2_dump_header | grep features
83
$PYTHON qcow2.py "$TEST_IMG" dump-header-exts
84
85
# success, all done
86
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
87
index XXXXXXX..XXXXXXX 100755
88
--- a/tests/qemu-iotests/039
89
+++ b/tests/qemu-iotests/039
90
@@ -XXX,XX +XXX,XX @@ _make_test_img -o "compat=1.1,lazy_refcounts=on" $size
91
$QEMU_IO -c "write -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
92
93
# The dirty bit must not be set
94
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
95
+_qcow2_dump_header | grep incompatible_features
96
_check_test_img
97
98
echo
99
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "write -P 0x5a 0 512" \
100
| _filter_qemu_io
101
102
# The dirty bit must be set
103
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
104
+_qcow2_dump_header | grep incompatible_features
105
_check_test_img
106
107
echo
108
@@ -XXX,XX +XXX,XX @@ echo "== Read-only access must still work =="
109
$QEMU_IO -r -c "read -P 0x5a 0 512" "$TEST_IMG" | _filter_qemu_io
110
111
# The dirty bit must be set
112
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
113
+_qcow2_dump_header | grep incompatible_features
114
115
echo
116
echo "== Repairing the image file must succeed =="
117
@@ -XXX,XX +XXX,XX @@ echo "== Repairing the image file must succeed =="
118
_check_test_img -r all
119
120
# The dirty bit must not be set
121
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
122
+_qcow2_dump_header | grep incompatible_features
123
124
echo
125
echo "== Data should still be accessible after repair =="
126
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "write -P 0x5a 0 512" \
127
| _filter_qemu_io
128
129
# The dirty bit must be set
130
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
131
+_qcow2_dump_header | grep incompatible_features
132
133
$QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io
134
135
# The dirty bit must not be set
136
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
137
+_qcow2_dump_header | grep incompatible_features
138
139
echo
140
echo "== Creating an image file with lazy_refcounts=off =="
141
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "write -P 0x5a 0 512" \
142
| _filter_qemu_io
143
144
# The dirty bit must not be set since lazy_refcounts=off
145
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
146
+_qcow2_dump_header | grep incompatible_features
147
_check_test_img
148
149
echo
150
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "write 0 512" "$TEST_IMG" | _filter_qemu_io
151
$QEMU_IMG commit "$TEST_IMG"
152
153
# The dirty bit must not be set
154
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
155
+_qcow2_dump_header | grep incompatible_features
156
$PYTHON qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features
157
158
_check_test_img
159
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "reopen -o lazy-refcounts=on" \
160
| _filter_qemu_io
161
162
# The dirty bit must be set
163
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
164
+_qcow2_dump_header | grep incompatible_features
165
_check_test_img
166
167
_make_test_img -o "compat=1.1,lazy_refcounts=on" $size
168
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "reopen -o lazy-refcounts=off" \
169
| _filter_qemu_io
170
171
# The dirty bit must not be set
172
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
173
+_qcow2_dump_header | grep incompatible_features
174
_check_test_img
175
176
177
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
178
index XXXXXXX..XXXXXXX 100755
179
--- a/tests/qemu-iotests/060
180
+++ b/tests/qemu-iotests/060
181
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$l1_offset" "\x80\x00\x00\x00\x00\x03\x00\x00"
182
_check_test_img
183
184
# The corrupt bit should not be set anyway
185
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
186
+_qcow2_dump_header | grep incompatible_features
187
188
# Try to write something, thereby forcing the corrupt bit to be set
189
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
190
191
# The corrupt bit must now be set
192
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
193
+_qcow2_dump_header | grep incompatible_features
194
195
# This information should be available through qemu-img info
196
_img_info --format-specific
197
@@ -XXX,XX +XXX,XX @@ poke_file "$TEST_IMG" "$(($rb_offset+8))" "\x00\x01"
198
# Redirect new data cluster onto refcount block
199
poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x02\x00\x00"
200
_check_test_img
201
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
202
+_qcow2_dump_header | grep incompatible_features
203
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
204
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
205
+_qcow2_dump_header | grep incompatible_features
206
207
# Try to fix it
208
_check_test_img -r all
209
210
# The corrupt bit should be cleared
211
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
212
+_qcow2_dump_header | grep incompatible_features
213
214
# Look if it's really really fixed
215
$QEMU_IO -c "$OPEN_RW" -c "write -P 0x2a 0 512" | _filter_qemu_io
216
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
217
+_qcow2_dump_header | grep incompatible_features
218
219
echo
220
echo "=== Testing cluster data reference into inactive L2 table ==="
221
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "$OPEN_RW" -c "write -P 2 0 512" | _filter_qemu_io
222
poke_file "$TEST_IMG" "$l2_offset_after_snapshot" \
223
"\x80\x00\x00\x00\x00\x04\x00\x00"
224
_check_test_img
225
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
226
+_qcow2_dump_header | grep incompatible_features
227
$QEMU_IO -c "$OPEN_RW" -c "write -P 3 0 512" | _filter_qemu_io
228
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
229
+_qcow2_dump_header | grep incompatible_features
230
_check_test_img -r all
231
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
232
+_qcow2_dump_header | grep incompatible_features
233
$QEMU_IO -c "$OPEN_RW" -c "write -P 4 0 512" | _filter_qemu_io
234
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
235
+_qcow2_dump_header | grep incompatible_features
236
237
# Check data
238
$QEMU_IO -c "$OPEN_RO" -c "read -P 4 0 512" | _filter_qemu_io
239
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
240
index XXXXXXX..XXXXXXX 100755
241
--- a/tests/qemu-iotests/061
242
+++ b/tests/qemu-iotests/061
243
@@ -XXX,XX +XXX,XX @@ echo "=== Testing version downgrade with zero expansion ==="
244
echo
245
_make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
246
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
247
-$PYTHON qcow2.py "$TEST_IMG" dump-header
248
+_qcow2_dump_header
249
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
250
-$PYTHON qcow2.py "$TEST_IMG" dump-header
251
+_qcow2_dump_header
252
$QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
253
_check_test_img
254
255
@@ -XXX,XX +XXX,XX @@ _make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
256
$QEMU_IO -c "write -z 0 128k" "$TEST_IMG" | _filter_qemu_io
257
$QEMU_IO -c "write -z 32M 128k" "$TEST_IMG" | _filter_qemu_io
258
$QEMU_IO -c map "$TEST_IMG" | _filter_qemu_io
259
-$PYTHON qcow2.py "$TEST_IMG" dump-header
260
+_qcow2_dump_header
261
$QEMU_IMG amend -o "compat=0.10" --image-opts \
262
driver=qcow2,file.filename=$TEST_IMG,l2-cache-entry-size=4096
263
-$PYTHON qcow2.py "$TEST_IMG" dump-header
264
+_qcow2_dump_header
265
$QEMU_IO -c "read -P 0 0 128k" "$TEST_IMG" | _filter_qemu_io
266
$QEMU_IO -c "read -P 0 32M 128k" "$TEST_IMG" | _filter_qemu_io
267
$QEMU_IO -c map "$TEST_IMG" | _filter_qemu_io
268
@@ -XXX,XX +XXX,XX @@ _make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
269
_NO_VALGRIND \
270
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
271
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
272
-$PYTHON qcow2.py "$TEST_IMG" dump-header
273
+_qcow2_dump_header
274
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
275
-$PYTHON qcow2.py "$TEST_IMG" dump-header
276
+_qcow2_dump_header
277
$QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
278
_check_test_img
279
280
@@ -XXX,XX +XXX,XX @@ echo
281
_make_test_img -o "compat=1.1" 64M
282
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit compatible 42
283
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit autoclear 42
284
-$PYTHON qcow2.py "$TEST_IMG" dump-header
285
+_qcow2_dump_header
286
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
287
-$PYTHON qcow2.py "$TEST_IMG" dump-header
288
+_qcow2_dump_header
289
_check_test_img
290
291
echo
292
@@ -XXX,XX +XXX,XX @@ echo "=== Testing version upgrade and resize ==="
293
echo
294
_make_test_img -o "compat=0.10" 64M
295
$QEMU_IO -c "write -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io
296
-$PYTHON qcow2.py "$TEST_IMG" dump-header
297
+_qcow2_dump_header
298
$QEMU_IMG amend -o "compat=1.1,lazy_refcounts=on,size=128M" "$TEST_IMG"
299
-$PYTHON qcow2.py "$TEST_IMG" dump-header
300
+_qcow2_dump_header
301
$QEMU_IO -c "read -P 0x2a 42M 64k" "$TEST_IMG" | _filter_qemu_io
302
_check_test_img
303
304
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "write -P 0x2a 24M 64k" "$TEST_IMG" | _filter_qemu_io
305
$QEMU_IMG snapshot -c foo "$TEST_IMG"
306
$QEMU_IMG resize "$TEST_IMG" 64M &&
307
echo "unexpected pass"
308
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)'
309
+_qcow2_dump_header | grep '^\(version\|size\|nb_snap\)'
310
311
$QEMU_IMG amend -o "compat=1.1,size=128M" "$TEST_IMG" ||
312
echo "unexpected fail"
313
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)'
314
+_qcow2_dump_header | grep '^\(version\|size\|nb_snap\)'
315
316
$QEMU_IMG snapshot -c bar "$TEST_IMG"
317
$QEMU_IMG resize --shrink "$TEST_IMG" 64M ||
318
echo "unexpected fail"
319
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)'
320
+_qcow2_dump_header | grep '^\(version\|size\|nb_snap\)'
321
322
$QEMU_IMG amend -o "compat=0.10,size=32M" "$TEST_IMG" &&
323
echo "unexpected pass"
324
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)'
325
+_qcow2_dump_header | grep '^\(version\|size\|nb_snap\)'
326
327
$QEMU_IMG snapshot -a bar "$TEST_IMG" ||
328
echo "unexpected fail"
329
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)'
330
+_qcow2_dump_header | grep '^\(version\|size\|nb_snap\)'
331
332
$QEMU_IMG snapshot -d bar "$TEST_IMG"
333
$QEMU_IMG amend -o "compat=0.10,size=32M" "$TEST_IMG" ||
334
echo "unexpected fail"
335
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep '^\(version\|size\|nb_snap\)'
336
+_qcow2_dump_header | grep '^\(version\|size\|nb_snap\)'
337
338
_check_test_img
339
340
@@ -XXX,XX +XXX,XX @@ _make_test_img -o "compat=1.1,lazy_refcounts=on" 64M
341
_NO_VALGRIND \
342
$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
343
-c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
344
-$PYTHON qcow2.py "$TEST_IMG" dump-header
345
+_qcow2_dump_header
346
$QEMU_IMG amend -o "lazy_refcounts=off" "$TEST_IMG"
347
-$PYTHON qcow2.py "$TEST_IMG" dump-header
348
+_qcow2_dump_header
349
$QEMU_IO -c "read -P 0x2a 0 128k" "$TEST_IMG" | _filter_qemu_io
350
_check_test_img
351
352
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
353
index XXXXXXX..XXXXXXX 100755
354
--- a/tests/qemu-iotests/137
355
+++ b/tests/qemu-iotests/137
356
@@ -XXX,XX +XXX,XX @@ $QEMU_IO \
357
358
# The dirty bit must not be set
359
# (Filter the external data file bit)
360
-if $PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features \
361
+if _qcow2_dump_header | grep incompatible_features \
362
| grep -q '\<0\>'
363
then
364
echo 'ERROR: Dirty bit set'
365
diff --git a/tests/qemu-iotests/287 b/tests/qemu-iotests/287
366
index XXXXXXX..XXXXXXX 100755
367
--- a/tests/qemu-iotests/287
368
+++ b/tests/qemu-iotests/287
369
@@ -XXX,XX +XXX,XX @@ echo
370
echo "=== Testing compression type incompatible bit setting for zlib ==="
371
echo
372
_make_test_img -o compression_type=zlib 64M
373
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
374
+_qcow2_dump_header | grep incompatible_features
375
376
echo
377
echo "=== Testing compression type incompatible bit setting for zstd ==="
378
echo
379
_make_test_img -o compression_type=zstd 64M
380
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
381
+_qcow2_dump_header | grep incompatible_features
382
383
echo
384
echo "=== Testing zlib with incompatible bit set ==="
385
@@ -XXX,XX +XXX,XX @@ echo
386
_make_test_img -o compression_type=zlib 64M
387
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 3
388
# to make sure the bit was actually set
389
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
390
+_qcow2_dump_header | grep incompatible_features
391
392
if $QEMU_IMG info "$TEST_IMG" >/dev/null 2>&1 ; then
393
echo "Error: The image opened successfully. The image must not be opened."
394
@@ -XXX,XX +XXX,XX @@ echo
395
_make_test_img -o compression_type=zstd 64M
396
$PYTHON qcow2.py "$TEST_IMG" set-header incompatible_features 0
397
# to make sure the bit was actually unset
398
-$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
399
+_qcow2_dump_header | grep incompatible_features
400
401
if $QEMU_IMG info "$TEST_IMG" >/dev/null 2>&1 ; then
402
echo "Error: The image opened successfully. The image must not be opened."
403
--
64
--
404
2.34.1
65
2.9.3
405
66
406
67
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Don't touch other incompatible bits, like compression-type. This makes
3
Keep the coroutine on the same AioContext. Without this change,
4
the test pass with IMGOPTS='compression_type=zstd'.
4
there would be a race between yielding the coroutine and reentering it.
5
While the race cannot happen now, because the code only runs from a single
6
AioContext, this will change with multiqueue support in the block layer.
5
7
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
While doing the change, replace custom bottom half with aio_co_schedule.
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
8
Message-Id: <20211223160144.1097696-18-vsementsov@virtuozzo.com>
10
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
11
Reviewed-by: Fam Zheng <famz@redhat.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
14
Message-id: 20170213135235.12274-10-pbonzini@redhat.com
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
16
---
11
tests/qemu-iotests/060 | 2 +-
17
block/blkdebug.c | 9 +--------
12
1 file changed, 1 insertion(+), 1 deletion(-)
18
1 file changed, 1 insertion(+), 8 deletions(-)
13
19
14
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
20
diff --git a/block/blkdebug.c b/block/blkdebug.c
15
index XXXXXXX..XXXXXXX 100755
21
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/060
22
--- a/block/blkdebug.c
17
+++ b/tests/qemu-iotests/060
23
+++ b/block/blkdebug.c
18
@@ -XXX,XX +XXX,XX @@ _make_test_img 64M
24
@@ -XXX,XX +XXX,XX @@ out:
19
# Let the refblock appear unaligned
25
return ret;
20
poke_file "$TEST_IMG" "$rt_offset" "\x00\x00\x00\x00\xff\xff\x2a\x00"
26
}
21
# Mark the image dirty, thus forcing an automatic check when opening it
27
22
-poke_file "$TEST_IMG" 72 "\x00\x00\x00\x00\x00\x00\x00\x01"
28
-static void error_callback_bh(void *opaque)
23
+$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 0
29
-{
24
# Open the image (qemu should refuse to do so)
30
- Coroutine *co = opaque;
25
$QEMU_IO -c close "$TEST_IMG" 2>&1 | _filter_testdir | _filter_imgfmt
31
- qemu_coroutine_enter(co);
32
-}
33
-
34
static int inject_error(BlockDriverState *bs, BlkdebugRule *rule)
35
{
36
BDRVBlkdebugState *s = bs->opaque;
37
@@ -XXX,XX +XXX,XX @@ static int inject_error(BlockDriverState *bs, BlkdebugRule *rule)
38
}
39
40
if (!immediately) {
41
- aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), error_callback_bh,
42
- qemu_coroutine_self());
43
+ aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self());
44
qemu_coroutine_yield();
45
}
26
46
27
--
47
--
28
2.34.1
48
2.9.3
29
49
30
50
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
We want iotests pass with both the default zlib compression and with
3
qed_aio_start_io and qed_aio_next_io will not have to acquire/release
4
IMGOPTS='compression_type=zstd'.
4
the AioContext, while qed_aio_next_io_cb will. Split the functionality
5
and gain a little type-safety in the process.
5
6
6
Actually the only test that is interested in real compression type in
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
test output is 287 (test for qcow2 compression type), so implement
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
specific option for it.
9
Reviewed-by: Fam Zheng <famz@redhat.com>
10
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
11
Message-id: 20170213135235.12274-11-pbonzini@redhat.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
14
block/qed.c | 39 +++++++++++++++++++++++++--------------
15
1 file changed, 25 insertions(+), 14 deletions(-)
9
16
10
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
17
diff --git a/block/qed.c b/block/qed.c
11
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
12
Message-Id: <20211223160144.1097696-17-vsementsov@virtuozzo.com>
13
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
14
---
15
tests/qemu-iotests/060.out | 2 +-
16
tests/qemu-iotests/061.out | 12 ++++++------
17
tests/qemu-iotests/082.out | 14 +++++++-------
18
tests/qemu-iotests/198.out | 4 ++--
19
tests/qemu-iotests/287 | 8 ++++----
20
tests/qemu-iotests/common.filter | 8 ++++++++
21
tests/qemu-iotests/common.rc | 14 +++++++++++++-
22
7 files changed, 41 insertions(+), 21 deletions(-)
23
24
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
25
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
26
--- a/tests/qemu-iotests/060.out
19
--- a/block/qed.c
27
+++ b/tests/qemu-iotests/060.out
20
+++ b/block/qed.c
28
@@ -XXX,XX +XXX,XX @@ virtual size: 64 MiB (67108864 bytes)
21
@@ -XXX,XX +XXX,XX @@ static CachedL2Table *qed_new_l2_table(BDRVQEDState *s)
29
cluster_size: 65536
22
return l2_table;
30
Format specific information:
31
compat: 1.1
32
- compression type: zlib
33
+ compression type: COMPRESSION_TYPE
34
lazy refcounts: false
35
refcount bits: 16
36
corrupt: true
37
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
38
index XXXXXXX..XXXXXXX 100644
39
--- a/tests/qemu-iotests/061.out
40
+++ b/tests/qemu-iotests/061.out
41
@@ -XXX,XX +XXX,XX @@ virtual size: 64 MiB (67108864 bytes)
42
cluster_size: 65536
43
Format specific information:
44
compat: 1.1
45
- compression type: zlib
46
+ compression type: COMPRESSION_TYPE
47
lazy refcounts: false
48
refcount bits: 16
49
data file: TEST_DIR/t.IMGFMT.data
50
@@ -XXX,XX +XXX,XX @@ virtual size: 64 MiB (67108864 bytes)
51
cluster_size: 65536
52
Format specific information:
53
compat: 1.1
54
- compression type: zlib
55
+ compression type: COMPRESSION_TYPE
56
lazy refcounts: false
57
refcount bits: 16
58
data file: foo
59
@@ -XXX,XX +XXX,XX @@ virtual size: 64 MiB (67108864 bytes)
60
cluster_size: 65536
61
Format specific information:
62
compat: 1.1
63
- compression type: zlib
64
+ compression type: COMPRESSION_TYPE
65
lazy refcounts: false
66
refcount bits: 16
67
data file raw: false
68
@@ -XXX,XX +XXX,XX @@ virtual size: 64 MiB (67108864 bytes)
69
cluster_size: 65536
70
Format specific information:
71
compat: 1.1
72
- compression type: zlib
73
+ compression type: COMPRESSION_TYPE
74
lazy refcounts: false
75
refcount bits: 16
76
data file: TEST_DIR/t.IMGFMT.data
77
@@ -XXX,XX +XXX,XX @@ virtual size: 64 MiB (67108864 bytes)
78
cluster_size: 65536
79
Format specific information:
80
compat: 1.1
81
- compression type: zlib
82
+ compression type: COMPRESSION_TYPE
83
lazy refcounts: false
84
refcount bits: 16
85
data file: TEST_DIR/t.IMGFMT.data
86
@@ -XXX,XX +XXX,XX @@ virtual size: 64 MiB (67108864 bytes)
87
cluster_size: 65536
88
Format specific information:
89
compat: 1.1
90
- compression type: zlib
91
+ compression type: COMPRESSION_TYPE
92
lazy refcounts: false
93
refcount bits: 16
94
data file: TEST_DIR/t.IMGFMT.data
95
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
96
index XXXXXXX..XXXXXXX 100644
97
--- a/tests/qemu-iotests/082.out
98
+++ b/tests/qemu-iotests/082.out
99
@@ -XXX,XX +XXX,XX @@ virtual size: 128 MiB (134217728 bytes)
100
cluster_size: 4096
101
Format specific information:
102
compat: 1.1
103
- compression type: zlib
104
+ compression type: COMPRESSION_TYPE
105
lazy refcounts: true
106
refcount bits: 16
107
corrupt: false
108
@@ -XXX,XX +XXX,XX @@ virtual size: 128 MiB (134217728 bytes)
109
cluster_size: 8192
110
Format specific information:
111
compat: 1.1
112
- compression type: zlib
113
+ compression type: COMPRESSION_TYPE
114
lazy refcounts: true
115
refcount bits: 16
116
corrupt: false
117
@@ -XXX,XX +XXX,XX @@ virtual size: 128 MiB (134217728 bytes)
118
cluster_size: 4096
119
Format specific information:
120
compat: 1.1
121
- compression type: zlib
122
+ compression type: COMPRESSION_TYPE
123
lazy refcounts: true
124
refcount bits: 16
125
corrupt: false
126
@@ -XXX,XX +XXX,XX @@ virtual size: 128 MiB (134217728 bytes)
127
cluster_size: 8192
128
Format specific information:
129
compat: 1.1
130
- compression type: zlib
131
+ compression type: COMPRESSION_TYPE
132
lazy refcounts: true
133
refcount bits: 16
134
corrupt: false
135
@@ -XXX,XX +XXX,XX @@ virtual size: 128 MiB (134217728 bytes)
136
cluster_size: 65536
137
Format specific information:
138
compat: 1.1
139
- compression type: zlib
140
+ compression type: COMPRESSION_TYPE
141
lazy refcounts: true
142
refcount bits: 16
143
corrupt: false
144
@@ -XXX,XX +XXX,XX @@ virtual size: 130 MiB (136314880 bytes)
145
cluster_size: 65536
146
Format specific information:
147
compat: 1.1
148
- compression type: zlib
149
+ compression type: COMPRESSION_TYPE
150
lazy refcounts: false
151
refcount bits: 16
152
corrupt: false
153
@@ -XXX,XX +XXX,XX @@ virtual size: 132 MiB (138412032 bytes)
154
cluster_size: 65536
155
Format specific information:
156
compat: 1.1
157
- compression type: zlib
158
+ compression type: COMPRESSION_TYPE
159
lazy refcounts: true
160
refcount bits: 16
161
corrupt: false
162
diff --git a/tests/qemu-iotests/198.out b/tests/qemu-iotests/198.out
163
index XXXXXXX..XXXXXXX 100644
164
--- a/tests/qemu-iotests/198.out
165
+++ b/tests/qemu-iotests/198.out
166
@@ -XXX,XX +XXX,XX @@ image: json:{ /* filtered */ }
167
file format: IMGFMT
168
virtual size: 16 MiB (16777216 bytes)
169
Format specific information:
170
- compression type: zlib
171
+ compression type: COMPRESSION_TYPE
172
encrypt:
173
ivgen alg: plain64
174
hash alg: sha256
175
@@ -XXX,XX +XXX,XX @@ virtual size: 16 MiB (16777216 bytes)
176
backing file: TEST_DIR/t.IMGFMT.base
177
backing file format: IMGFMT
178
Format specific information:
179
- compression type: zlib
180
+ compression type: COMPRESSION_TYPE
181
encrypt:
182
ivgen alg: plain64
183
hash alg: sha256
184
diff --git a/tests/qemu-iotests/287 b/tests/qemu-iotests/287
185
index XXXXXXX..XXXXXXX 100755
186
--- a/tests/qemu-iotests/287
187
+++ b/tests/qemu-iotests/287
188
@@ -XXX,XX +XXX,XX @@ echo
189
echo "=== Testing compression type incompatible bit setting for zlib ==="
190
echo
191
_make_test_img -o compression_type=zlib 64M
192
-_qcow2_dump_header | grep incompatible_features
193
+_qcow2_dump_header --no-filter-compression | grep incompatible_features
194
195
echo
196
echo "=== Testing compression type incompatible bit setting for zstd ==="
197
echo
198
_make_test_img -o compression_type=zstd 64M
199
-_qcow2_dump_header | grep incompatible_features
200
+_qcow2_dump_header --no-filter-compression | grep incompatible_features
201
202
echo
203
echo "=== Testing zlib with incompatible bit set ==="
204
@@ -XXX,XX +XXX,XX @@ echo
205
_make_test_img -o compression_type=zlib 64M
206
$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 3
207
# to make sure the bit was actually set
208
-_qcow2_dump_header | grep incompatible_features
209
+_qcow2_dump_header --no-filter-compression | grep incompatible_features
210
211
if $QEMU_IMG info "$TEST_IMG" >/dev/null 2>&1 ; then
212
echo "Error: The image opened successfully. The image must not be opened."
213
@@ -XXX,XX +XXX,XX @@ echo
214
_make_test_img -o compression_type=zstd 64M
215
$PYTHON qcow2.py "$TEST_IMG" set-header incompatible_features 0
216
# to make sure the bit was actually unset
217
-_qcow2_dump_header | grep incompatible_features
218
+_qcow2_dump_header --no-filter-compression | grep incompatible_features
219
220
if $QEMU_IMG info "$TEST_IMG" >/dev/null 2>&1 ; then
221
echo "Error: The image opened successfully. The image must not be opened."
222
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
223
index XXXXXXX..XXXXXXX 100644
224
--- a/tests/qemu-iotests/common.filter
225
+++ b/tests/qemu-iotests/common.filter
226
@@ -XXX,XX +XXX,XX @@ _filter_img_info()
227
-e "/block_state_zero: \\(on\\|off\\)/d" \
228
-e "/log_size: [0-9]\\+/d" \
229
-e "s/iters: [0-9]\\+/iters: 1024/" \
230
+ -e 's/\(compression type: \)\(zlib\|zstd\)/\1COMPRESSION_TYPE/' \
231
-e "s/uuid: [-a-f0-9]\\+/uuid: 00000000-0000-0000-0000-000000000000/" | \
232
while IFS='' read -r line; do
233
if [[ $format_specific == 1 ]]; then
234
@@ -XXX,XX +XXX,XX @@ _filter_authz_check_tls()
235
$SED -e 's/TLS x509 authz check for .* is denied/TLS x509 authz check for DISTINGUISHED-NAME is denied/'
236
}
23
}
237
24
238
+_filter_qcow2_compression_type_bit()
25
-static void qed_aio_next_io(void *opaque, int ret);
26
+static void qed_aio_next_io(QEDAIOCB *acb, int ret);
27
+
28
+static void qed_aio_start_io(QEDAIOCB *acb)
239
+{
29
+{
240
+ $SED -e 's/\(incompatible_features\s\+\)\[3\(, \)\?/\1[/' \
30
+ qed_aio_next_io(acb, 0);
241
+ -e 's/\(incompatible_features.*\), 3\]/\1]/' \
242
+ -e 's/\(incompatible_features.*\), 3\(,.*\)/\1\2/'
243
+}
31
+}
244
+
32
+
245
# make sure this script returns success
33
+static void qed_aio_next_io_cb(void *opaque, int ret)
246
true
34
+{
247
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
35
+ QEDAIOCB *acb = opaque;
248
index XXXXXXX..XXXXXXX 100644
36
+
249
--- a/tests/qemu-iotests/common.rc
37
+ qed_aio_next_io(acb, ret);
250
+++ b/tests/qemu-iotests/common.rc
38
+}
251
@@ -XXX,XX +XXX,XX @@ _img_info()
39
252
-e "s#$TEST_DIR#TEST_DIR#g" \
40
static void qed_plug_allocating_write_reqs(BDRVQEDState *s)
253
-e "s#$SOCK_DIR/fuse-#TEST_DIR/#g" \
254
-e "s#$IMGFMT#IMGFMT#g" \
255
+ -e 's/\(compression type: \)\(zlib\|zstd\)/\1COMPRESSION_TYPE/' \
256
-e "/^disk size:/ D" \
257
-e "/actual-size/ D" | \
258
while IFS='' read -r line; do
259
@@ -XXX,XX +XXX,XX @@ _require_one_device_of()
260
261
_qcow2_dump_header()
262
{
41
{
263
+ if [[ "$1" == "--no-filter-compression" ]]; then
42
@@ -XXX,XX +XXX,XX @@ static void qed_unplug_allocating_write_reqs(BDRVQEDState *s)
264
+ local filter_compression=0
43
265
+ shift
44
acb = QSIMPLEQ_FIRST(&s->allocating_write_reqs);
266
+ else
45
if (acb) {
267
+ local filter_compression=1
46
- qed_aio_next_io(acb, 0);
268
+ fi
47
+ qed_aio_start_io(acb);
269
+
48
}
270
img="$1"
271
if [ -z "$img" ]; then
272
img="$TEST_IMG"
273
fi
274
275
- $PYTHON qcow2.py "$img" dump-header
276
+ if [[ $filter_compression == 0 ]]; then
277
+ $PYTHON qcow2.py "$img" dump-header
278
+ else
279
+ $PYTHON qcow2.py "$img" dump-header | _filter_qcow2_compression_type_bit
280
+ fi
281
}
49
}
282
50
283
# make sure this script returns success
51
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
52
QSIMPLEQ_REMOVE_HEAD(&s->allocating_write_reqs, next);
53
acb = QSIMPLEQ_FIRST(&s->allocating_write_reqs);
54
if (acb) {
55
- qed_aio_next_io(acb, 0);
56
+ qed_aio_start_io(acb);
57
} else if (s->header.features & QED_F_NEED_CHECK) {
58
qed_start_need_check_timer(s);
59
}
60
@@ -XXX,XX +XXX,XX @@ static void qed_commit_l2_update(void *opaque, int ret)
61
acb->request.l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
62
assert(acb->request.l2_table != NULL);
63
64
- qed_aio_next_io(opaque, ret);
65
+ qed_aio_next_io(acb, ret);
66
}
67
68
/**
69
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_l2_update(QEDAIOCB *acb, int ret, uint64_t offset)
70
if (need_alloc) {
71
/* Write out the whole new L2 table */
72
qed_write_l2_table(s, &acb->request, 0, s->table_nelems, true,
73
- qed_aio_write_l1_update, acb);
74
+ qed_aio_write_l1_update, acb);
75
} else {
76
/* Write out only the updated part of the L2 table */
77
qed_write_l2_table(s, &acb->request, index, acb->cur_nclusters, false,
78
- qed_aio_next_io, acb);
79
+ qed_aio_next_io_cb, acb);
80
}
81
return;
82
83
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_main(void *opaque, int ret)
84
}
85
86
if (acb->find_cluster_ret == QED_CLUSTER_FOUND) {
87
- next_fn = qed_aio_next_io;
88
+ next_fn = qed_aio_next_io_cb;
89
} else {
90
if (s->bs->backing) {
91
next_fn = qed_aio_write_flush_before_l2_update;
92
@@ -XXX,XX +XXX,XX @@ static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
93
if (acb->flags & QED_AIOCB_ZERO) {
94
/* Skip ahead if the clusters are already zero */
95
if (acb->find_cluster_ret == QED_CLUSTER_ZERO) {
96
- qed_aio_next_io(acb, 0);
97
+ qed_aio_start_io(acb);
98
return;
99
}
100
101
@@ -XXX,XX +XXX,XX @@ static void qed_aio_read_data(void *opaque, int ret,
102
/* Handle zero cluster and backing file reads */
103
if (ret == QED_CLUSTER_ZERO) {
104
qemu_iovec_memset(&acb->cur_qiov, 0, 0, acb->cur_qiov.size);
105
- qed_aio_next_io(acb, 0);
106
+ qed_aio_start_io(acb);
107
return;
108
} else if (ret != QED_CLUSTER_FOUND) {
109
qed_read_backing_file(s, acb->cur_pos, &acb->cur_qiov,
110
- &acb->backing_qiov, qed_aio_next_io, acb);
111
+ &acb->backing_qiov, qed_aio_next_io_cb, acb);
112
return;
113
}
114
115
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
116
bdrv_aio_readv(bs->file, offset / BDRV_SECTOR_SIZE,
117
&acb->cur_qiov, acb->cur_qiov.size / BDRV_SECTOR_SIZE,
118
- qed_aio_next_io, acb);
119
+ qed_aio_next_io_cb, acb);
120
return;
121
122
err:
123
@@ -XXX,XX +XXX,XX @@ err:
124
/**
125
* Begin next I/O or complete the request
126
*/
127
-static void qed_aio_next_io(void *opaque, int ret)
128
+static void qed_aio_next_io(QEDAIOCB *acb, int ret)
129
{
130
- QEDAIOCB *acb = opaque;
131
BDRVQEDState *s = acb_to_s(acb);
132
QEDFindClusterFunc *io_fn = (acb->flags & QED_AIOCB_WRITE) ?
133
qed_aio_write_data : qed_aio_read_data;
134
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *qed_aio_setup(BlockDriverState *bs,
135
qemu_iovec_init(&acb->cur_qiov, qiov->niov);
136
137
/* Start request */
138
- qed_aio_next_io(acb, 0);
139
+ qed_aio_start_io(acb);
140
return &acb->common;
141
}
142
284
--
143
--
285
2.34.1
144
2.9.3
286
145
287
146
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Instead of qemu_img_log("info", ..) use generic helper img_info_log().
3
The AioContext data structures are now protected by list_lock and/or
4
they are walked with FOREACH_RCU primitives. There is no need anymore
5
to acquire the AioContext for the entire duration of aio_dispatch.
6
Instead, just acquire it before and after invoking the callbacks.
7
The next step is then to push it further down.
4
8
5
img_info_log() has smarter logic. For example it use filter_img_info()
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
6
to filter output, which in turns filter a compression type. So it will
10
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
help us in future when we implement a possibility to use zstd
11
Reviewed-by: Fam Zheng <famz@redhat.com>
8
compression by default (with help of some runtime config file or maybe
12
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
9
build option). For now to test you should recompile qemu with a small
13
Message-id: 20170213135235.12274-12-pbonzini@redhat.com
10
addition into block/qcow2.c before
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
"if (qcow2_opts->has_compression_type":
15
---
16
util/aio-posix.c | 25 +++++++++++--------------
17
util/aio-win32.c | 15 +++++++--------
18
util/async.c | 2 ++
19
3 files changed, 20 insertions(+), 22 deletions(-)
12
20
13
if (!qcow2_opts->has_compression_type && version >= 3) {
21
diff --git a/util/aio-posix.c b/util/aio-posix.c
14
qcow2_opts->has_compression_type = true;
15
qcow2_opts->compression_type = QCOW2_COMPRESSION_TYPE_ZSTD;
16
}
17
18
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
19
Reviewed-by: Max Reitz <mreitz@redhat.com>
20
Message-Id: <20211223160144.1097696-12-vsementsov@virtuozzo.com>
21
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
22
---
23
tests/qemu-iotests/302 | 4 +++-
24
tests/qemu-iotests/302.out | 7 +++----
25
2 files changed, 6 insertions(+), 5 deletions(-)
26
27
diff --git a/tests/qemu-iotests/302 b/tests/qemu-iotests/302
28
index XXXXXXX..XXXXXXX 100755
29
--- a/tests/qemu-iotests/302
30
+++ b/tests/qemu-iotests/302
31
@@ -XXX,XX +XXX,XX @@ from iotests import (
32
qemu_img_measure,
33
qemu_io,
34
qemu_nbd_popen,
35
+ img_info_log,
36
)
37
38
iotests.script_initialize(supported_fmts=["qcow2"])
39
@@ -XXX,XX +XXX,XX @@ with tarfile.open(tar_file, "w") as tar:
40
tar_file):
41
42
iotests.log("=== Target image info ===")
43
+ # Not img_info_log as it enforces imgfmt, but now we print info on raw
44
qemu_img_log("info", nbd_uri)
45
46
qemu_img(
47
@@ -XXX,XX +XXX,XX @@ with tarfile.open(tar_file, "w") as tar:
48
nbd_uri)
49
50
iotests.log("=== Converted image info ===")
51
- qemu_img_log("info", nbd_uri)
52
+ img_info_log(nbd_uri)
53
54
iotests.log("=== Converted image check ===")
55
qemu_img_log("check", nbd_uri)
56
diff --git a/tests/qemu-iotests/302.out b/tests/qemu-iotests/302.out
57
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
58
--- a/tests/qemu-iotests/302.out
23
--- a/util/aio-posix.c
59
+++ b/tests/qemu-iotests/302.out
24
+++ b/util/aio-posix.c
60
@@ -XXX,XX +XXX,XX @@ virtual size: 448 KiB (458752 bytes)
25
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx)
61
disk size: unavailable
26
(revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) &&
62
27
aio_node_check(ctx, node->is_external) &&
63
=== Converted image info ===
28
node->io_read) {
64
-image: nbd+unix:///exp?socket=SOCK_DIR/PID-nbd-sock
29
+ aio_context_acquire(ctx);
65
-file format: qcow2
30
node->io_read(node->opaque);
66
+image: TEST_IMG
31
+ aio_context_release(ctx);
67
+file format: IMGFMT
32
68
virtual size: 1 GiB (1073741824 bytes)
33
/* aio_notify() does not count as progress */
69
-disk size: unavailable
34
if (node->opaque != &ctx->notifier) {
70
cluster_size: 65536
35
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx)
71
Format specific information:
36
(revents & (G_IO_OUT | G_IO_ERR)) &&
72
compat: 1.1
37
aio_node_check(ctx, node->is_external) &&
73
- compression type: zlib
38
node->io_write) {
74
+ compression type: COMPRESSION_TYPE
39
+ aio_context_acquire(ctx);
75
lazy refcounts: false
40
node->io_write(node->opaque);
76
refcount bits: 16
41
+ aio_context_release(ctx);
77
corrupt: false
42
progress = true;
43
}
44
45
@@ -XXX,XX +XXX,XX @@ bool aio_dispatch(AioContext *ctx, bool dispatch_fds)
46
}
47
48
/* Run our timers */
49
+ aio_context_acquire(ctx);
50
progress |= timerlistgroup_run_timers(&ctx->tlg);
51
+ aio_context_release(ctx);
52
53
return progress;
54
}
55
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
56
int64_t timeout;
57
int64_t start = 0;
58
59
- aio_context_acquire(ctx);
60
- progress = false;
61
-
62
/* aio_notify can avoid the expensive event_notifier_set if
63
* everything (file descriptors, bottom halves, timers) will
64
* be re-evaluated before the next blocking poll(). This is
65
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
66
start = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
67
}
68
69
- if (try_poll_mode(ctx, blocking)) {
70
- progress = true;
71
- } else {
72
+ aio_context_acquire(ctx);
73
+ progress = try_poll_mode(ctx, blocking);
74
+ aio_context_release(ctx);
75
+
76
+ if (!progress) {
77
assert(npfd == 0);
78
79
/* fill pollfds */
80
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
81
timeout = blocking ? aio_compute_timeout(ctx) : 0;
82
83
/* wait until next event */
84
- if (timeout) {
85
- aio_context_release(ctx);
86
- }
87
if (aio_epoll_check_poll(ctx, pollfds, npfd, timeout)) {
88
AioHandler epoll_handler;
89
90
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
91
} else {
92
ret = qemu_poll_ns(pollfds, npfd, timeout);
93
}
94
- if (timeout) {
95
- aio_context_acquire(ctx);
96
- }
97
}
98
99
if (blocking) {
100
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
101
progress = true;
102
}
103
104
- aio_context_release(ctx);
105
-
106
return progress;
107
}
108
109
diff --git a/util/aio-win32.c b/util/aio-win32.c
110
index XXXXXXX..XXXXXXX 100644
111
--- a/util/aio-win32.c
112
+++ b/util/aio-win32.c
113
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event)
114
(revents || event_notifier_get_handle(node->e) == event) &&
115
node->io_notify) {
116
node->pfd.revents = 0;
117
+ aio_context_acquire(ctx);
118
node->io_notify(node->e);
119
+ aio_context_release(ctx);
120
121
/* aio_notify() does not count as progress */
122
if (node->e != &ctx->notifier) {
123
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event)
124
(node->io_read || node->io_write)) {
125
node->pfd.revents = 0;
126
if ((revents & G_IO_IN) && node->io_read) {
127
+ aio_context_acquire(ctx);
128
node->io_read(node->opaque);
129
+ aio_context_release(ctx);
130
progress = true;
131
}
132
if ((revents & G_IO_OUT) && node->io_write) {
133
+ aio_context_acquire(ctx);
134
node->io_write(node->opaque);
135
+ aio_context_release(ctx);
136
progress = true;
137
}
138
139
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
140
int count;
141
int timeout;
142
143
- aio_context_acquire(ctx);
144
progress = false;
145
146
/* aio_notify can avoid the expensive event_notifier_set if
147
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
148
149
timeout = blocking && !have_select_revents
150
? qemu_timeout_ns_to_ms(aio_compute_timeout(ctx)) : 0;
151
- if (timeout) {
152
- aio_context_release(ctx);
153
- }
154
ret = WaitForMultipleObjects(count, events, FALSE, timeout);
155
if (blocking) {
156
assert(first);
157
atomic_sub(&ctx->notify_me, 2);
158
}
159
- if (timeout) {
160
- aio_context_acquire(ctx);
161
- }
162
163
if (first) {
164
aio_notify_accept(ctx);
165
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
166
progress |= aio_dispatch_handlers(ctx, event);
167
} while (count > 0);
168
169
+ aio_context_acquire(ctx);
170
progress |= timerlistgroup_run_timers(&ctx->tlg);
171
-
172
aio_context_release(ctx);
173
return progress;
174
}
175
diff --git a/util/async.c b/util/async.c
176
index XXXXXXX..XXXXXXX 100644
177
--- a/util/async.c
178
+++ b/util/async.c
179
@@ -XXX,XX +XXX,XX @@ int aio_bh_poll(AioContext *ctx)
180
ret = 1;
181
}
182
bh->idle = 0;
183
+ aio_context_acquire(ctx);
184
aio_bh_call(bh);
185
+ aio_context_release(ctx);
186
}
187
if (bh->deleted) {
188
deleted = true;
78
--
189
--
79
2.34.1
190
2.9.3
80
191
81
192
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
The only "feature" of this "Formatting ..." line is that we have to
3
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
update it every time we add new option. Let's drop it.
4
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
5
5
Reviewed-by: Fam Zheng <famz@redhat.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
7
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
7
Message-id: 20170213135235.12274-13-pbonzini@redhat.com
8
Message-Id: <20211223160144.1097696-10-vsementsov@virtuozzo.com>
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
10
---
9
---
11
tests/qemu-iotests/149.out | 21 ---------------------
10
block/qed.h | 3 +++
12
tests/qemu-iotests/237.out | 3 ---
11
block/curl.c | 2 ++
13
tests/qemu-iotests/255.out | 4 ----
12
block/io.c | 5 +++++
14
tests/qemu-iotests/274.out | 29 -----------------------------
13
block/iscsi.c | 8 ++++++--
15
tests/qemu-iotests/280.out | 1 -
14
block/null.c | 4 ++++
16
tests/qemu-iotests/296.out | 10 +++-------
15
block/qed.c | 12 ++++++++++++
17
tests/qemu-iotests/iotests.py | 10 ++++++++--
16
block/throttle-groups.c | 2 ++
18
7 files changed, 11 insertions(+), 67 deletions(-)
17
util/aio-posix.c | 2 --
19
18
util/aio-win32.c | 2 --
20
diff --git a/tests/qemu-iotests/149.out b/tests/qemu-iotests/149.out
19
util/qemu-coroutine-sleep.c | 2 +-
21
index XXXXXXX..XXXXXXX 100644
20
10 files changed, 35 insertions(+), 7 deletions(-)
22
--- a/tests/qemu-iotests/149.out
21
23
+++ b/tests/qemu-iotests/149.out
22
diff --git a/block/qed.h b/block/qed.h
24
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha1.img
23
index XXXXXXX..XXXXXXX 100644
25
# ================= qemu-img aes-256-xts-plain64-sha1 =================
24
--- a/block/qed.h
26
# Create image
25
+++ b/block/qed.h
27
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain64-sha1.img 4194304M
26
@@ -XXX,XX +XXX,XX @@ enum {
28
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
27
*/
29
28
typedef void QEDFindClusterFunc(void *opaque, int ret, uint64_t offset, size_t len);
30
# Open dev
29
31
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1
30
+void qed_acquire(BDRVQEDState *s);
32
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-twofish-256-xts-plain64-sha1.img
31
+void qed_release(BDRVQEDState *s);
33
# ================= qemu-img twofish-256-xts-plain64-sha1 =================
32
+
34
# Create image
33
/**
35
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=twofish-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img 4194304M
34
* Generic callback for chaining async callbacks
36
-Formatting 'TEST_DIR/luks-twofish-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
35
*/
37
36
diff --git a/block/curl.c b/block/curl.c
38
# Open dev
37
index XXXXXXX..XXXXXXX 100644
39
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1
38
--- a/block/curl.c
40
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-serpent-256-xts-plain64-sha1.img
39
+++ b/block/curl.c
41
# ================= qemu-img serpent-256-xts-plain64-sha1 =================
40
@@ -XXX,XX +XXX,XX @@ static void curl_multi_timeout_do(void *arg)
42
# Create image
41
return;
43
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img 4194304M
42
}
44
-Formatting 'TEST_DIR/luks-serpent-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
43
45
44
+ aio_context_acquire(s->aio_context);
46
# Open dev
45
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
47
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1
46
48
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img
47
curl_multi_check_completion(s);
49
# ================= qemu-img cast5-128-cbc-plain64-sha1 =================
48
+ aio_context_release(s->aio_context);
50
# Create image
49
#else
51
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=cast5-128,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img 4194304M
50
abort();
52
-Formatting 'TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=cast5-128 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 iter-time=10
51
#endif
53
52
diff --git a/block/io.c b/block/io.c
54
# Open dev
53
index XXXXXXX..XXXXXXX 100644
55
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1
54
--- a/block/io.c
56
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-plain-sha1.img
55
+++ b/block/io.c
57
# ================= qemu-img aes-256-cbc-plain-sha1 =================
56
@@ -XXX,XX +XXX,XX @@ void bdrv_aio_cancel(BlockAIOCB *acb)
58
# Create image
57
if (acb->aiocb_info->get_aio_context) {
59
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain-sha1.img 4194304M
58
aio_poll(acb->aiocb_info->get_aio_context(acb), true);
60
-Formatting 'TEST_DIR/luks-aes-256-cbc-plain-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain hash-alg=sha1 iter-time=10
59
} else if (acb->bs) {
61
60
+ /* qemu_aio_ref and qemu_aio_unref are not thread-safe, so
62
# Open dev
61
+ * assert that we're not using an I/O thread. Thread-safe
63
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1
62
+ * code should use bdrv_aio_cancel_async exclusively.
64
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-plain64-sha1.img
63
+ */
65
# ================= qemu-img aes-256-cbc-plain64-sha1 =================
64
+ assert(bdrv_get_aio_context(acb->bs) == qemu_get_aio_context());
66
# Create image
65
aio_poll(bdrv_get_aio_context(acb->bs), true);
67
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img 4194304M
66
} else {
68
-Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 iter-time=10
67
abort();
69
68
diff --git a/block/iscsi.c b/block/iscsi.c
70
# Open dev
69
index XXXXXXX..XXXXXXX 100644
71
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1
70
--- a/block/iscsi.c
72
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img
71
+++ b/block/iscsi.c
73
# ================= qemu-img aes-256-cbc-essiv-sha256-sha1 =================
72
@@ -XXX,XX +XXX,XX @@ static void iscsi_retry_timer_expired(void *opaque)
74
# Create image
73
struct IscsiTask *iTask = opaque;
75
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img 4194304M
74
iTask->complete = 1;
76
-Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10
75
if (iTask->co) {
77
76
- qemu_coroutine_enter(iTask->co);
78
# Open dev
77
+ aio_co_wake(iTask->co);
79
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1
78
}
80
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img
79
}
81
# ================= qemu-img aes-256-xts-essiv-sha256-sha1 =================
80
82
# Create image
81
@@ -XXX,XX +XXX,XX @@ static void iscsi_nop_timed_event(void *opaque)
83
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img 4194304M
82
{
84
-Formatting 'TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10
83
IscsiLun *iscsilun = opaque;
85
84
86
# Open dev
85
+ aio_context_acquire(iscsilun->aio_context);
87
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1
86
if (iscsi_get_nops_in_flight(iscsilun->iscsi) >= MAX_NOP_FAILURES) {
88
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img
87
error_report("iSCSI: NOP timeout. Reconnecting...");
89
# ================= qemu-img aes-128-xts-plain64-sha256-sha1 =================
88
iscsilun->request_timed_out = true;
90
# Create image
89
} else if (iscsi_nop_out_async(iscsilun->iscsi, NULL, NULL, 0, NULL) != 0) {
91
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img 4194304M
90
error_report("iSCSI: failed to sent NOP-Out. Disabling NOP messages.");
92
-Formatting 'TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
91
- return;
93
92
+ goto out;
94
# Open dev
93
}
95
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1
94
96
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img
95
timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
97
# ================= qemu-img aes-192-xts-plain64-sha256-sha1 =================
96
iscsi_set_events(iscsilun);
98
# Create image
97
+
99
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img 4194304M
98
+out:
100
-Formatting 'TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
99
+ aio_context_release(iscsilun->aio_context);
101
100
}
102
# Open dev
101
103
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1
102
static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
104
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-twofish-128-xts-plain64-sha1.img
103
diff --git a/block/null.c b/block/null.c
105
# ================= qemu-img twofish-128-xts-plain64-sha1 =================
104
index XXXXXXX..XXXXXXX 100644
106
# Create image
105
--- a/block/null.c
107
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=twofish-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img 4194304M
106
+++ b/block/null.c
108
-Formatting 'TEST_DIR/luks-twofish-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
107
@@ -XXX,XX +XXX,XX @@ static void null_bh_cb(void *opaque)
109
108
static void null_timer_cb(void *opaque)
110
# Open dev
109
{
111
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1
110
NullAIOCB *acb = opaque;
112
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-serpent-128-xts-plain64-sha1.img
111
+ AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
113
# ================= qemu-img serpent-128-xts-plain64-sha1 =================
112
+
114
# Create image
113
+ aio_context_acquire(ctx);
115
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img 4194304M
114
acb->common.cb(acb->common.opaque, 0);
116
-Formatting 'TEST_DIR/luks-serpent-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
115
+ aio_context_release(ctx);
117
116
timer_deinit(&acb->timer);
118
# Open dev
117
qemu_aio_unref(acb);
119
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1
118
}
120
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-serpent-192-xts-plain64-sha1.img
119
diff --git a/block/qed.c b/block/qed.c
121
# ================= qemu-img serpent-192-xts-plain64-sha1 =================
120
index XXXXXXX..XXXXXXX 100644
122
# Create image
121
--- a/block/qed.c
123
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=serpent-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img 4194304M
122
+++ b/block/qed.c
124
-Formatting 'TEST_DIR/luks-serpent-192-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 iter-time=10
123
@@ -XXX,XX +XXX,XX @@ static void qed_need_check_timer_cb(void *opaque)
125
124
126
# Open dev
125
trace_qed_need_check_timer_cb(s);
127
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1
126
128
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha224.img
127
+ qed_acquire(s);
129
# ================= qemu-img aes-256-xts-plain64-sha224 =================
128
qed_plug_allocating_write_reqs(s);
130
# Create image
129
131
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha224 TEST_DIR/luks-aes-256-xts-plain64-sha224.img 4194304M
130
/* Ensure writes are on disk before clearing flag */
132
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha224.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha224 iter-time=10
131
bdrv_aio_flush(s->bs->file->bs, qed_clear_need_check, s);
133
132
+ qed_release(s);
134
# Open dev
133
+}
135
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha224.img qiotest-145-aes-256-xts-plain64-sha224
134
+
136
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha256.img
135
+void qed_acquire(BDRVQEDState *s)
137
# ================= qemu-img aes-256-xts-plain64-sha256 =================
136
+{
138
# Create image
137
+ aio_context_acquire(bdrv_get_aio_context(s->bs));
139
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha256 TEST_DIR/luks-aes-256-xts-plain64-sha256.img 4194304M
138
+}
140
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha256.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha256 iter-time=10
139
+
141
140
+void qed_release(BDRVQEDState *s)
142
# Open dev
141
+{
143
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256
142
+ aio_context_release(bdrv_get_aio_context(s->bs));
144
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha384.img
143
}
145
# ================= qemu-img aes-256-xts-plain64-sha384 =================
144
146
# Create image
145
static void qed_start_need_check_timer(BDRVQEDState *s)
147
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha384 TEST_DIR/luks-aes-256-xts-plain64-sha384.img 4194304M
146
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
148
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha384.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha384 iter-time=10
147
index XXXXXXX..XXXXXXX 100644
149
148
--- a/block/throttle-groups.c
150
# Open dev
149
+++ b/block/throttle-groups.c
151
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha384.img qiotest-145-aes-256-xts-plain64-sha384
150
@@ -XXX,XX +XXX,XX @@ static void timer_cb(BlockBackend *blk, bool is_write)
152
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-plain64-sha512.img
151
qemu_mutex_unlock(&tg->lock);
153
# ================= qemu-img aes-256-xts-plain64-sha512 =================
152
154
# Create image
153
/* Run the request that was waiting for this timer */
155
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha512 TEST_DIR/luks-aes-256-xts-plain64-sha512.img 4194304M
154
+ aio_context_acquire(blk_get_aio_context(blk));
156
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha512.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha512 iter-time=10
155
empty_queue = !qemu_co_enter_next(&blkp->throttled_reqs[is_write]);
157
156
+ aio_context_release(blk_get_aio_context(blk));
158
# Open dev
157
159
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha512.img qiotest-145-aes-256-xts-plain64-sha512
158
/* If the request queue was empty then we have to take care of
160
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img
159
* scheduling the next one */
161
# ================= qemu-img aes-256-xts-plain64-ripemd160 =================
160
diff --git a/util/aio-posix.c b/util/aio-posix.c
162
# Create image
161
index XXXXXXX..XXXXXXX 100644
163
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=ripemd160 TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img 4194304M
162
--- a/util/aio-posix.c
164
-Formatting 'TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=ripemd160 iter-time=10
163
+++ b/util/aio-posix.c
165
164
@@ -XXX,XX +XXX,XX @@ bool aio_dispatch(AioContext *ctx, bool dispatch_fds)
166
# Open dev
165
}
167
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-ripemd160.img qiotest-145-aes-256-xts-plain64-ripemd160
166
168
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img
167
/* Run our timers */
169
# ================= qemu-img aes-256-xts-plain-sha1-pwallslots =================
168
- aio_context_acquire(ctx);
170
# Create image
169
progress |= timerlistgroup_run_timers(&ctx->tlg);
171
qemu-img create -f luks --object secret,id=sec0,data=c2xvdDE=,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img 4194304M
170
- aio_context_release(ctx);
172
-Formatting 'TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain hash-alg=sha1 iter-time=10
171
173
172
return progress;
174
# Open dev
173
}
175
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots
174
diff --git a/util/aio-win32.c b/util/aio-win32.c
176
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img
175
index XXXXXXX..XXXXXXX 100644
177
# ================= qemu-img aes-256-cbc-essiv-auto-sha1 =================
176
--- a/util/aio-win32.c
178
# Create image
177
+++ b/util/aio-win32.c
179
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img 4194304M
178
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
180
-Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv hash-alg=sha1 iter-time=10
179
progress |= aio_dispatch_handlers(ctx, event);
181
180
} while (count > 0);
182
# Open dev
181
183
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-auto-sha1.img qiotest-145-aes-256-cbc-essiv-auto-sha1
182
- aio_context_acquire(ctx);
184
@@ -XXX,XX +XXX,XX @@ unlink TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img
183
progress |= timerlistgroup_run_timers(&ctx->tlg);
185
# ================= qemu-img aes-256-cbc-plain64-sha256-sha1 =================
184
- aio_context_release(ctx);
186
# Create image
185
return progress;
187
qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,iter-time=10,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img 4194304M
186
}
188
-Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 ivgen-hash-alg=sha256 hash-alg=sha1 iter-time=10
187
189
188
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
190
# Open dev
189
index XXXXXXX..XXXXXXX 100644
191
sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha256-sha1.img qiotest-145-aes-256-cbc-plain64-sha256-sha1
190
--- a/util/qemu-coroutine-sleep.c
192
diff --git a/tests/qemu-iotests/237.out b/tests/qemu-iotests/237.out
191
+++ b/util/qemu-coroutine-sleep.c
193
index XXXXXXX..XXXXXXX 100644
192
@@ -XXX,XX +XXX,XX @@ static void co_sleep_cb(void *opaque)
194
--- a/tests/qemu-iotests/237.out
193
{
195
+++ b/tests/qemu-iotests/237.out
194
CoSleepCB *sleep_cb = opaque;
196
@@ -XXX,XX +XXX,XX @@ Job failed: Cannot find device='this doesn't exist' nor node-name='this doesn't
195
197
196
- qemu_coroutine_enter(sleep_cb->co);
198
=== Other subformats ===
197
+ aio_co_wake(sleep_cb->co);
199
198
}
200
-Formatting 'TEST_DIR/PID-t.vmdk.1', fmt=vmdk size=0 compat6=off hwversion=undefined
199
201
200
void coroutine_fn co_aio_sleep_ns(AioContext *ctx, QEMUClockType type,
202
-Formatting 'TEST_DIR/PID-t.vmdk.2', fmt=vmdk size=0 compat6=off hwversion=undefined
203
204
-Formatting 'TEST_DIR/PID-t.vmdk.3', fmt=vmdk size=0 compat6=off hwversion=undefined
205
206
== Missing extent ==
207
208
diff --git a/tests/qemu-iotests/255.out b/tests/qemu-iotests/255.out
209
index XXXXXXX..XXXXXXX 100644
210
--- a/tests/qemu-iotests/255.out
211
+++ b/tests/qemu-iotests/255.out
212
@@ -XXX,XX +XXX,XX @@ Finishing a commit job with background reads
213
214
=== Create backing chain and start VM ===
215
216
-Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
217
218
-Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
219
220
=== Start background read requests ===
221
222
@@ -XXX,XX +XXX,XX @@ Closing the VM while a job is being cancelled
223
224
=== Create images and start VM ===
225
226
-Formatting 'TEST_DIR/PID-src.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
227
228
-Formatting 'TEST_DIR/PID-dst.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=134217728 lazy_refcounts=off refcount_bits=16
229
230
wrote 1048576/1048576 bytes at offset 0
231
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
232
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
233
index XXXXXXX..XXXXXXX 100644
234
--- a/tests/qemu-iotests/274.out
235
+++ b/tests/qemu-iotests/274.out
236
@@ -XXX,XX +XXX,XX @@
237
== Commit tests ==
238
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
239
240
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
241
242
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
243
244
wrote 2097152/2097152 bytes at offset 0
245
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
246
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
247
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
248
249
=== Testing HMP commit (top -> mid) ===
250
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
251
252
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
253
254
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
255
256
wrote 2097152/2097152 bytes at offset 0
257
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
258
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
259
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
260
261
=== Testing QMP active commit (top -> mid) ===
262
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
263
264
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
265
266
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
267
268
wrote 2097152/2097152 bytes at offset 0
269
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
270
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
271
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
272
273
=== Testing qemu-img commit (top -> base) ===
274
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
275
276
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
277
278
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
279
280
wrote 2097152/2097152 bytes at offset 0
281
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
282
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
283
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
284
285
=== Testing QMP active commit (top -> base) ===
286
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 lazy_refcounts=off refcount_bits=16
287
288
-Formatting 'TEST_DIR/PID-mid', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1048576 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
289
290
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=2097152 backing_file=TEST_DIR/PID-mid backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
291
292
wrote 2097152/2097152 bytes at offset 0
293
2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
294
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
295
296
== Resize tests ==
297
=== preallocation=off ===
298
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=6442450944 lazy_refcounts=off refcount_bits=16
299
300
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1073741824 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
301
302
wrote 65536/65536 bytes at offset 5368709120
303
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
304
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 5368709120
305
{ "start": 1073741824, "length": 7516192768, "depth": 0, "present": true, "zero": true, "data": false}]
306
307
=== preallocation=metadata ===
308
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=34359738368 lazy_refcounts=off refcount_bits=16
309
310
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=32212254720 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
311
312
wrote 65536/65536 bytes at offset 33285996544
313
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
314
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 33285996544
315
{ "start": 34896609280, "length": 536870912, "depth": 0, "present": true, "zero": true, "data": false, "offset": 2685075456}]
316
317
=== preallocation=falloc ===
318
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=10485760 lazy_refcounts=off refcount_bits=16
319
320
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=5242880 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
321
322
wrote 65536/65536 bytes at offset 9437184
323
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
324
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184
325
{ "start": 5242880, "length": 10485760, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}]
326
327
=== preallocation=full ===
328
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=16777216 lazy_refcounts=off refcount_bits=16
329
330
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=8388608 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
331
332
wrote 65536/65536 bytes at offset 11534336
333
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
334
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 11534336
335
{ "start": 8388608, "length": 4194304, "depth": 0, "present": true, "zero": false, "data": true, "offset": 327680}]
336
337
=== preallocation=off ===
338
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=393216 lazy_refcounts=off refcount_bits=16
339
340
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=259072 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
341
342
wrote 65536/65536 bytes at offset 259072
343
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
344
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 259072
345
{ "start": 262144, "length": 262144, "depth": 0, "present": true, "zero": true, "data": false}]
346
347
=== preallocation=off ===
348
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=409600 lazy_refcounts=off refcount_bits=16
349
350
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
351
352
wrote 65536/65536 bytes at offset 344064
353
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
354
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 344064
355
{ "start": 262144, "length": 262144, "depth": 0, "present": true, "zero": true, "data": false}]
356
357
=== preallocation=off ===
358
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=524288 lazy_refcounts=off refcount_bits=16
359
360
-Formatting 'TEST_DIR/PID-top', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=262144 backing_file=TEST_DIR/PID-base backing_fmt=qcow2 lazy_refcounts=off refcount_bits=16
361
362
wrote 65536/65536 bytes at offset 446464
363
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
364
diff --git a/tests/qemu-iotests/280.out b/tests/qemu-iotests/280.out
365
index XXXXXXX..XXXXXXX 100644
366
--- a/tests/qemu-iotests/280.out
367
+++ b/tests/qemu-iotests/280.out
368
@@ -XXX,XX +XXX,XX @@
369
-Formatting 'TEST_DIR/PID-base', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16
370
371
=== Launch VM ===
372
Enabling migration QMP events on VM...
373
diff --git a/tests/qemu-iotests/296.out b/tests/qemu-iotests/296.out
374
index XXXXXXX..XXXXXXX 100644
375
--- a/tests/qemu-iotests/296.out
376
+++ b/tests/qemu-iotests/296.out
377
@@ -XXX,XX +XXX,XX @@
378
-Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
379
380
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
381
{"return": {}}
382
@@ -XXX,XX +XXX,XX @@ Job failed: Failed to get shared "consistent read" lock
383
qemu-img: Failed to get shared "consistent read" lock
384
Is another process using the image [TEST_DIR/test.img]?
385
386
-.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
387
-
388
+.
389
Job failed: Block node is read-only
390
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
391
{"return": {}}
392
@@ -XXX,XX +XXX,XX @@ Job failed: Failed to get shared "consistent read" lock
393
{"return": {}}
394
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
395
{"return": {}}
396
-.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
397
-
398
+.
399
{"return": {}}
400
{"error": {"class": "GenericError", "desc": "Failed to get \"write\" lock"}}
401
-.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
402
-
403
+.
404
{"return": {}}
405
{"return": {}}
406
.
407
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
408
index XXXXXXX..XXXXXXX 100644
409
--- a/tests/qemu-iotests/iotests.py
410
+++ b/tests/qemu-iotests/iotests.py
411
@@ -XXX,XX +XXX,XX @@ def qemu_tool_popen(args: Sequence[str],
412
413
414
def qemu_tool_pipe_and_status(tool: str, args: Sequence[str],
415
- connect_stderr: bool = True) -> Tuple[str, int]:
416
+ connect_stderr: bool = True,
417
+ drop_successful_output: bool = False) \
418
+ -> Tuple[str, int]:
419
"""
420
Run a tool and return both its output and its exit code
421
"""
422
@@ -XXX,XX +XXX,XX @@ def qemu_tool_pipe_and_status(tool: str, args: Sequence[str],
423
cmd = ' '.join(args)
424
sys.stderr.write(f'{tool} received signal \
425
{-subp.returncode}: {cmd}\n')
426
+ if drop_successful_output and subp.returncode == 0:
427
+ output = ''
428
return (output, subp.returncode)
429
430
def qemu_img_create_prepare_args(args: List[str]) -> List[str]:
431
@@ -XXX,XX +XXX,XX @@ def qemu_img_pipe_and_status(*args: str) -> Tuple[str, int]:
432
"""
433
Run qemu-img and return both its output and its exit code
434
"""
435
+ is_create = bool(args and args[0] == 'create')
436
full_args = qemu_img_args + qemu_img_create_prepare_args(list(args))
437
- return qemu_tool_pipe_and_status('qemu-img', full_args)
438
+ return qemu_tool_pipe_and_status('qemu-img', full_args,
439
+ drop_successful_output=is_create)
440
441
def qemu_img(*args: str) -> int:
442
'''Run qemu-img and return the exit code'''
443
--
201
--
444
2.34.1
202
2.9.3
445
203
446
204
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
We want iotests pass with both the default zlib compression and with
3
This covers both file descriptor callbacks and polling callbacks,
4
IMGOPTS='compression_type=zstd'.
4
since they execute related code.
5
5
6
Actually the only test that is interested in real compression type in
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
test output is 287 (test for qcow2 compression type) and it's in bash.
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
So for now we can safely filter out compression type in all qcow2
8
Reviewed-by: Fam Zheng <famz@redhat.com>
9
tests.
9
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
10
Message-id: 20170213135235.12274-14-pbonzini@redhat.com
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
13
block/curl.c | 16 +++++++++++++---
14
block/iscsi.c | 4 ++++
15
block/linux-aio.c | 4 ++++
16
block/nfs.c | 6 ++++++
17
block/sheepdog.c | 29 +++++++++++++++--------------
18
block/ssh.c | 29 +++++++++--------------------
19
block/win32-aio.c | 10 ++++++----
20
hw/block/virtio-blk.c | 5 ++++-
21
hw/scsi/virtio-scsi.c | 7 +++++++
22
util/aio-posix.c | 7 -------
23
util/aio-win32.c | 6 ------
24
11 files changed, 68 insertions(+), 55 deletions(-)
10
25
11
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
26
diff --git a/block/curl.c b/block/curl.c
12
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
27
index XXXXXXX..XXXXXXX 100644
13
Message-Id: <20211223160144.1097696-11-vsementsov@virtuozzo.com>
28
--- a/block/curl.c
14
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
29
+++ b/block/curl.c
15
---
30
@@ -XXX,XX +XXX,XX @@ static void curl_multi_check_completion(BDRVCURLState *s)
16
tests/qemu-iotests/206.out | 10 +++++-----
31
}
17
tests/qemu-iotests/242.out | 10 +++++-----
32
}
18
tests/qemu-iotests/274.out | 10 +++++-----
33
19
tests/qemu-iotests/iotests.py | 2 ++
34
-static void curl_multi_do(void *arg)
20
4 files changed, 17 insertions(+), 15 deletions(-)
35
+static void curl_multi_do_locked(CURLState *s)
21
36
{
22
diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out
37
- CURLState *s = (CURLState *)arg;
23
index XXXXXXX..XXXXXXX 100644
38
CURLSocket *socket, *next_socket;
24
--- a/tests/qemu-iotests/206.out
39
int running;
25
+++ b/tests/qemu-iotests/206.out
40
int r;
26
@@ -XXX,XX +XXX,XX @@ virtual size: 128 MiB (134217728 bytes)
41
@@ -XXX,XX +XXX,XX @@ static void curl_multi_do(void *arg)
27
cluster_size: 65536
42
}
28
Format specific information:
43
}
29
compat: 1.1
44
30
- compression type: zlib
45
+static void curl_multi_do(void *arg)
31
+ compression type: COMPRESSION_TYPE
46
+{
32
lazy refcounts: false
47
+ CURLState *s = (CURLState *)arg;
33
refcount bits: 16
48
+
34
corrupt: false
49
+ aio_context_acquire(s->s->aio_context);
35
@@ -XXX,XX +XXX,XX @@ virtual size: 64 MiB (67108864 bytes)
50
+ curl_multi_do_locked(s);
36
cluster_size: 65536
51
+ aio_context_release(s->s->aio_context);
37
Format specific information:
52
+}
38
compat: 1.1
53
+
39
- compression type: zlib
54
static void curl_multi_read(void *arg)
40
+ compression type: COMPRESSION_TYPE
55
{
41
lazy refcounts: false
56
CURLState *s = (CURLState *)arg;
42
refcount bits: 16
57
43
corrupt: false
58
- curl_multi_do(arg);
44
@@ -XXX,XX +XXX,XX @@ virtual size: 32 MiB (33554432 bytes)
59
+ aio_context_acquire(s->s->aio_context);
45
cluster_size: 2097152
60
+ curl_multi_do_locked(s);
46
Format specific information:
61
curl_multi_check_completion(s->s);
47
compat: 1.1
62
+ aio_context_release(s->s->aio_context);
48
- compression type: zlib
63
}
49
+ compression type: COMPRESSION_TYPE
64
50
lazy refcounts: true
65
static void curl_multi_timeout_do(void *arg)
51
refcount bits: 1
66
diff --git a/block/iscsi.c b/block/iscsi.c
52
corrupt: false
67
index XXXXXXX..XXXXXXX 100644
53
@@ -XXX,XX +XXX,XX @@ backing file: TEST_IMG.base
68
--- a/block/iscsi.c
54
backing file format: IMGFMT
69
+++ b/block/iscsi.c
55
Format specific information:
70
@@ -XXX,XX +XXX,XX @@ iscsi_process_read(void *arg)
56
compat: 0.10
71
IscsiLun *iscsilun = arg;
57
- compression type: zlib
72
struct iscsi_context *iscsi = iscsilun->iscsi;
58
+ compression type: COMPRESSION_TYPE
73
59
refcount bits: 16
74
+ aio_context_acquire(iscsilun->aio_context);
60
75
iscsi_service(iscsi, POLLIN);
61
=== Successful image creation (encrypted) ===
76
iscsi_set_events(iscsilun);
62
@@ -XXX,XX +XXX,XX @@ encrypted: yes
77
+ aio_context_release(iscsilun->aio_context);
63
cluster_size: 65536
78
}
64
Format specific information:
79
65
compat: 1.1
80
static void
66
- compression type: zlib
81
@@ -XXX,XX +XXX,XX @@ iscsi_process_write(void *arg)
67
+ compression type: COMPRESSION_TYPE
82
IscsiLun *iscsilun = arg;
68
lazy refcounts: false
83
struct iscsi_context *iscsi = iscsilun->iscsi;
69
refcount bits: 16
84
70
encrypt:
85
+ aio_context_acquire(iscsilun->aio_context);
71
diff --git a/tests/qemu-iotests/242.out b/tests/qemu-iotests/242.out
86
iscsi_service(iscsi, POLLOUT);
72
index XXXXXXX..XXXXXXX 100644
87
iscsi_set_events(iscsilun);
73
--- a/tests/qemu-iotests/242.out
88
+ aio_context_release(iscsilun->aio_context);
74
+++ b/tests/qemu-iotests/242.out
89
}
75
@@ -XXX,XX +XXX,XX @@ virtual size: 1 MiB (1048576 bytes)
90
76
cluster_size: 65536
91
static int64_t sector_lun2qemu(int64_t sector, IscsiLun *iscsilun)
77
Format specific information:
92
diff --git a/block/linux-aio.c b/block/linux-aio.c
78
compat: 1.1
93
index XXXXXXX..XXXXXXX 100644
79
- compression type: zlib
94
--- a/block/linux-aio.c
80
+ compression type: COMPRESSION_TYPE
95
+++ b/block/linux-aio.c
81
lazy refcounts: false
96
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_completion_cb(EventNotifier *e)
82
refcount bits: 16
97
LinuxAioState *s = container_of(e, LinuxAioState, e);
83
corrupt: false
98
84
@@ -XXX,XX +XXX,XX @@ virtual size: 1 MiB (1048576 bytes)
99
if (event_notifier_test_and_clear(&s->e)) {
85
cluster_size: 65536
100
+ aio_context_acquire(s->aio_context);
86
Format specific information:
101
qemu_laio_process_completions_and_submit(s);
87
compat: 1.1
102
+ aio_context_release(s->aio_context);
88
- compression type: zlib
103
}
89
+ compression type: COMPRESSION_TYPE
104
}
90
lazy refcounts: false
105
91
bitmaps:
106
@@ -XXX,XX +XXX,XX @@ static bool qemu_laio_poll_cb(void *opaque)
92
[0]:
107
return false;
93
@@ -XXX,XX +XXX,XX @@ virtual size: 1 MiB (1048576 bytes)
108
}
94
cluster_size: 65536
109
95
Format specific information:
110
+ aio_context_acquire(s->aio_context);
96
compat: 1.1
111
qemu_laio_process_completions_and_submit(s);
97
- compression type: zlib
112
+ aio_context_release(s->aio_context);
98
+ compression type: COMPRESSION_TYPE
113
return true;
99
lazy refcounts: false
114
}
100
bitmaps:
115
101
[0]:
116
diff --git a/block/nfs.c b/block/nfs.c
102
@@ -XXX,XX +XXX,XX @@ virtual size: 1 MiB (1048576 bytes)
117
index XXXXXXX..XXXXXXX 100644
103
cluster_size: 65536
118
--- a/block/nfs.c
104
Format specific information:
119
+++ b/block/nfs.c
105
compat: 1.1
120
@@ -XXX,XX +XXX,XX @@ static void nfs_set_events(NFSClient *client)
106
- compression type: zlib
121
static void nfs_process_read(void *arg)
107
+ compression type: COMPRESSION_TYPE
122
{
108
lazy refcounts: false
123
NFSClient *client = arg;
109
bitmaps:
124
+
110
[0]:
125
+ aio_context_acquire(client->aio_context);
111
@@ -XXX,XX +XXX,XX @@ virtual size: 1 MiB (1048576 bytes)
126
nfs_service(client->context, POLLIN);
112
cluster_size: 65536
127
nfs_set_events(client);
113
Format specific information:
128
+ aio_context_release(client->aio_context);
114
compat: 1.1
129
}
115
- compression type: zlib
130
116
+ compression type: COMPRESSION_TYPE
131
static void nfs_process_write(void *arg)
117
lazy refcounts: false
132
{
118
bitmaps:
133
NFSClient *client = arg;
119
[0]:
134
+
120
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
135
+ aio_context_acquire(client->aio_context);
121
index XXXXXXX..XXXXXXX 100644
136
nfs_service(client->context, POLLOUT);
122
--- a/tests/qemu-iotests/274.out
137
nfs_set_events(client);
123
+++ b/tests/qemu-iotests/274.out
138
+ aio_context_release(client->aio_context);
124
@@ -XXX,XX +XXX,XX @@ backing file: TEST_DIR/PID-base
139
}
125
backing file format: IMGFMT
140
126
Format specific information:
141
static void nfs_co_init_task(BlockDriverState *bs, NFSRPC *task)
127
compat: 1.1
142
diff --git a/block/sheepdog.c b/block/sheepdog.c
128
- compression type: zlib
143
index XXXXXXX..XXXXXXX 100644
129
+ compression type: COMPRESSION_TYPE
144
--- a/block/sheepdog.c
130
lazy refcounts: false
145
+++ b/block/sheepdog.c
131
refcount bits: 16
146
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int send_co_req(int sockfd, SheepdogReq *hdr, void *data,
132
corrupt: false
147
return ret;
133
@@ -XXX,XX +XXX,XX @@ backing file: TEST_DIR/PID-base
148
}
134
backing file format: IMGFMT
149
135
Format specific information:
150
-static void restart_co_req(void *opaque)
136
compat: 1.1
151
-{
137
- compression type: zlib
152
- Coroutine *co = opaque;
138
+ compression type: COMPRESSION_TYPE
153
-
139
lazy refcounts: false
154
- qemu_coroutine_enter(co);
140
refcount bits: 16
155
-}
141
corrupt: false
156
-
142
@@ -XXX,XX +XXX,XX @@ backing file: TEST_DIR/PID-base
157
typedef struct SheepdogReqCo {
143
backing file format: IMGFMT
158
int sockfd;
144
Format specific information:
159
BlockDriverState *bs;
145
compat: 1.1
160
@@ -XXX,XX +XXX,XX @@ typedef struct SheepdogReqCo {
146
- compression type: zlib
161
unsigned int *rlen;
147
+ compression type: COMPRESSION_TYPE
162
int ret;
148
lazy refcounts: false
163
bool finished;
149
refcount bits: 16
164
+ Coroutine *co;
150
corrupt: false
165
} SheepdogReqCo;
151
@@ -XXX,XX +XXX,XX @@ virtual size: 2 MiB (2097152 bytes)
166
152
cluster_size: 65536
167
+static void restart_co_req(void *opaque)
153
Format specific information:
168
+{
154
compat: 1.1
169
+ SheepdogReqCo *srco = opaque;
155
- compression type: zlib
170
+
156
+ compression type: COMPRESSION_TYPE
171
+ aio_co_wake(srco->co);
157
lazy refcounts: false
172
+}
158
refcount bits: 16
173
+
159
corrupt: false
174
static coroutine_fn void do_co_req(void *opaque)
160
@@ -XXX,XX +XXX,XX @@ backing file: TEST_DIR/PID-base
175
{
161
backing file format: IMGFMT
176
int ret;
162
Format specific information:
177
- Coroutine *co;
163
compat: 1.1
178
SheepdogReqCo *srco = opaque;
164
- compression type: zlib
179
int sockfd = srco->sockfd;
165
+ compression type: COMPRESSION_TYPE
180
SheepdogReq *hdr = srco->hdr;
166
lazy refcounts: false
181
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void do_co_req(void *opaque)
167
refcount bits: 16
182
unsigned int *wlen = srco->wlen;
168
corrupt: false
183
unsigned int *rlen = srco->rlen;
169
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
184
170
index XXXXXXX..XXXXXXX 100644
185
- co = qemu_coroutine_self();
171
--- a/tests/qemu-iotests/iotests.py
186
+ srco->co = qemu_coroutine_self();
172
+++ b/tests/qemu-iotests/iotests.py
187
aio_set_fd_handler(srco->aio_context, sockfd, false,
173
@@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename):
188
- NULL, restart_co_req, NULL, co);
174
'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
189
+ NULL, restart_co_req, NULL, srco);
175
line)
190
176
line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line)
191
ret = send_co_req(sockfd, hdr, data, wlen);
177
+ line = re.sub('(compression type: )(zlib|zstd)', r'\1COMPRESSION_TYPE',
192
if (ret < 0) {
178
+ line)
193
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void do_co_req(void *opaque)
179
lines.append(line)
194
}
180
return '\n'.join(lines)
195
196
aio_set_fd_handler(srco->aio_context, sockfd, false,
197
- restart_co_req, NULL, NULL, co);
198
+ restart_co_req, NULL, NULL, srco);
199
200
ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr));
201
if (ret != sizeof(*hdr)) {
202
@@ -XXX,XX +XXX,XX @@ out:
203
aio_set_fd_handler(srco->aio_context, sockfd, false,
204
NULL, NULL, NULL, NULL);
205
206
+ srco->co = NULL;
207
srco->ret = ret;
208
srco->finished = true;
209
if (srco->bs) {
210
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn aio_read_response(void *opaque)
211
* We've finished all requests which belong to the AIOCB, so
212
* we can switch back to sd_co_readv/writev now.
213
*/
214
- qemu_coroutine_enter(acb->coroutine);
215
+ aio_co_wake(acb->coroutine);
216
}
217
218
return;
219
@@ -XXX,XX +XXX,XX @@ static void co_read_response(void *opaque)
220
s->co_recv = qemu_coroutine_create(aio_read_response, opaque);
221
}
222
223
- qemu_coroutine_enter(s->co_recv);
224
+ aio_co_wake(s->co_recv);
225
}
226
227
static void co_write_request(void *opaque)
228
{
229
BDRVSheepdogState *s = opaque;
230
231
- qemu_coroutine_enter(s->co_send);
232
+ aio_co_wake(s->co_send);
233
}
234
235
/*
236
diff --git a/block/ssh.c b/block/ssh.c
237
index XXXXXXX..XXXXXXX 100644
238
--- a/block/ssh.c
239
+++ b/block/ssh.c
240
@@ -XXX,XX +XXX,XX @@ static void restart_coroutine(void *opaque)
241
242
DPRINTF("co=%p", co);
243
244
- qemu_coroutine_enter(co);
245
+ aio_co_wake(co);
246
}
247
248
-static coroutine_fn void set_fd_handler(BDRVSSHState *s, BlockDriverState *bs)
249
+/* A non-blocking call returned EAGAIN, so yield, ensuring the
250
+ * handlers are set up so that we'll be rescheduled when there is an
251
+ * interesting event on the socket.
252
+ */
253
+static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
254
{
255
int r;
256
IOHandler *rd_handler = NULL, *wr_handler = NULL;
257
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void set_fd_handler(BDRVSSHState *s, BlockDriverState *bs)
258
259
aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock,
260
false, rd_handler, wr_handler, NULL, co);
261
-}
262
-
263
-static coroutine_fn void clear_fd_handler(BDRVSSHState *s,
264
- BlockDriverState *bs)
265
-{
266
- DPRINTF("s->sock=%d", s->sock);
267
- aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock,
268
- false, NULL, NULL, NULL, NULL);
269
-}
270
-
271
-/* A non-blocking call returned EAGAIN, so yield, ensuring the
272
- * handlers are set up so that we'll be rescheduled when there is an
273
- * interesting event on the socket.
274
- */
275
-static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
276
-{
277
- set_fd_handler(s, bs);
278
qemu_coroutine_yield();
279
- clear_fd_handler(s, bs);
280
+ DPRINTF("s->sock=%d - back", s->sock);
281
+ aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock, false,
282
+ NULL, NULL, NULL, NULL);
283
}
284
285
/* SFTP has a function `libssh2_sftp_seek64' which seeks to a position
286
diff --git a/block/win32-aio.c b/block/win32-aio.c
287
index XXXXXXX..XXXXXXX 100644
288
--- a/block/win32-aio.c
289
+++ b/block/win32-aio.c
290
@@ -XXX,XX +XXX,XX @@ struct QEMUWin32AIOState {
291
HANDLE hIOCP;
292
EventNotifier e;
293
int count;
294
- bool is_aio_context_attached;
295
+ AioContext *aio_ctx;
296
};
297
298
typedef struct QEMUWin32AIOCB {
299
@@ -XXX,XX +XXX,XX @@ static void win32_aio_process_completion(QEMUWin32AIOState *s,
300
}
301
302
303
+ aio_context_acquire(s->aio_ctx);
304
waiocb->common.cb(waiocb->common.opaque, ret);
305
+ aio_context_release(s->aio_ctx);
306
qemu_aio_unref(waiocb);
307
}
308
309
@@ -XXX,XX +XXX,XX @@ void win32_aio_detach_aio_context(QEMUWin32AIOState *aio,
310
AioContext *old_context)
311
{
312
aio_set_event_notifier(old_context, &aio->e, false, NULL, NULL);
313
- aio->is_aio_context_attached = false;
314
+ aio->aio_ctx = NULL;
315
}
316
317
void win32_aio_attach_aio_context(QEMUWin32AIOState *aio,
318
AioContext *new_context)
319
{
320
- aio->is_aio_context_attached = true;
321
+ aio->aio_ctx = new_context;
322
aio_set_event_notifier(new_context, &aio->e, false,
323
win32_aio_completion_cb, NULL);
324
}
325
@@ -XXX,XX +XXX,XX @@ out_free_state:
326
327
void win32_aio_cleanup(QEMUWin32AIOState *aio)
328
{
329
- assert(!aio->is_aio_context_attached);
330
+ assert(!aio->aio_ctx);
331
CloseHandle(aio->hIOCP);
332
event_notifier_cleanup(&aio->e);
333
g_free(aio);
334
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
335
index XXXXXXX..XXXXXXX 100644
336
--- a/hw/block/virtio-blk.c
337
+++ b/hw/block/virtio-blk.c
338
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_ioctl_complete(void *opaque, int status)
339
{
340
VirtIOBlockIoctlReq *ioctl_req = opaque;
341
VirtIOBlockReq *req = ioctl_req->req;
342
- VirtIODevice *vdev = VIRTIO_DEVICE(req->dev);
343
+ VirtIOBlock *s = req->dev;
344
+ VirtIODevice *vdev = VIRTIO_DEVICE(s);
345
struct virtio_scsi_inhdr *scsi;
346
struct sg_io_hdr *hdr;
347
348
@@ -XXX,XX +XXX,XX @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
349
MultiReqBuffer mrb = {};
350
bool progress = false;
351
352
+ aio_context_acquire(blk_get_aio_context(s->blk));
353
blk_io_plug(s->blk);
354
355
do {
356
@@ -XXX,XX +XXX,XX @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)
357
}
358
359
blk_io_unplug(s->blk);
360
+ aio_context_release(blk_get_aio_context(s->blk));
361
return progress;
362
}
363
364
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
365
index XXXXXXX..XXXXXXX 100644
366
--- a/hw/scsi/virtio-scsi.c
367
+++ b/hw/scsi/virtio-scsi.c
368
@@ -XXX,XX +XXX,XX @@ bool virtio_scsi_handle_ctrl_vq(VirtIOSCSI *s, VirtQueue *vq)
369
VirtIOSCSIReq *req;
370
bool progress = false;
371
372
+ virtio_scsi_acquire(s);
373
while ((req = virtio_scsi_pop_req(s, vq))) {
374
progress = true;
375
virtio_scsi_handle_ctrl_req(s, req);
376
}
377
+ virtio_scsi_release(s);
378
return progress;
379
}
380
381
@@ -XXX,XX +XXX,XX @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
382
383
QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs);
384
385
+ virtio_scsi_acquire(s);
386
do {
387
virtio_queue_set_notification(vq, 0);
388
389
@@ -XXX,XX +XXX,XX @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
390
QTAILQ_FOREACH_SAFE(req, &reqs, next, next) {
391
virtio_scsi_handle_cmd_req_submit(s, req);
392
}
393
+ virtio_scsi_release(s);
394
return progress;
395
}
396
397
@@ -XXX,XX +XXX,XX @@ out:
398
399
bool virtio_scsi_handle_event_vq(VirtIOSCSI *s, VirtQueue *vq)
400
{
401
+ virtio_scsi_acquire(s);
402
if (s->events_dropped) {
403
virtio_scsi_push_event(s, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
404
+ virtio_scsi_release(s);
405
return true;
406
}
407
+ virtio_scsi_release(s);
408
return false;
409
}
410
411
diff --git a/util/aio-posix.c b/util/aio-posix.c
412
index XXXXXXX..XXXXXXX 100644
413
--- a/util/aio-posix.c
414
+++ b/util/aio-posix.c
415
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx)
416
(revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) &&
417
aio_node_check(ctx, node->is_external) &&
418
node->io_read) {
419
- aio_context_acquire(ctx);
420
node->io_read(node->opaque);
421
- aio_context_release(ctx);
422
423
/* aio_notify() does not count as progress */
424
if (node->opaque != &ctx->notifier) {
425
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx)
426
(revents & (G_IO_OUT | G_IO_ERR)) &&
427
aio_node_check(ctx, node->is_external) &&
428
node->io_write) {
429
- aio_context_acquire(ctx);
430
node->io_write(node->opaque);
431
- aio_context_release(ctx);
432
progress = true;
433
}
434
435
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
436
start = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
437
}
438
439
- aio_context_acquire(ctx);
440
progress = try_poll_mode(ctx, blocking);
441
- aio_context_release(ctx);
442
-
443
if (!progress) {
444
assert(npfd == 0);
445
446
diff --git a/util/aio-win32.c b/util/aio-win32.c
447
index XXXXXXX..XXXXXXX 100644
448
--- a/util/aio-win32.c
449
+++ b/util/aio-win32.c
450
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event)
451
(revents || event_notifier_get_handle(node->e) == event) &&
452
node->io_notify) {
453
node->pfd.revents = 0;
454
- aio_context_acquire(ctx);
455
node->io_notify(node->e);
456
- aio_context_release(ctx);
457
458
/* aio_notify() does not count as progress */
459
if (node->e != &ctx->notifier) {
460
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event)
461
(node->io_read || node->io_write)) {
462
node->pfd.revents = 0;
463
if ((revents & G_IO_IN) && node->io_read) {
464
- aio_context_acquire(ctx);
465
node->io_read(node->opaque);
466
- aio_context_release(ctx);
467
progress = true;
468
}
469
if ((revents & G_IO_OUT) && node->io_write) {
470
- aio_context_acquire(ctx);
471
node->io_write(node->opaque);
472
- aio_context_release(ctx);
473
progress = true;
474
}
181
475
182
--
476
--
183
2.34.1
477
2.9.3
184
478
185
479
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
The test checks different options. It of course fails if set
3
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
IMGOPTS='compression_type=zstd'. So, let's be explicit in what
4
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
5
compression type we want and independent of IMGOPTS. Test both existing
5
Reviewed-by: Fam Zheng <famz@redhat.com>
6
compression types.
6
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
7
Message-id: 20170213135235.12274-15-pbonzini@redhat.com
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
10
block/archipelago.c | 3 +++
11
block/blkreplay.c | 2 +-
12
block/block-backend.c | 6 ++++++
13
block/curl.c | 26 ++++++++++++++++++--------
14
block/gluster.c | 9 +--------
15
block/io.c | 6 +++++-
16
block/iscsi.c | 6 +++++-
17
block/linux-aio.c | 15 +++++++++------
18
block/nfs.c | 3 ++-
19
block/null.c | 4 ++++
20
block/qed.c | 3 +++
21
block/rbd.c | 4 ++++
22
dma-helpers.c | 2 ++
23
hw/block/virtio-blk.c | 2 ++
24
hw/scsi/scsi-bus.c | 2 ++
25
util/async.c | 4 ++--
26
util/thread-pool.c | 2 ++
27
17 files changed, 71 insertions(+), 28 deletions(-)
7
28
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
29
diff --git a/block/archipelago.c b/block/archipelago.c
9
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
30
index XXXXXXX..XXXXXXX 100644
10
Message-Id: <20211223160144.1097696-9-vsementsov@virtuozzo.com>
31
--- a/block/archipelago.c
11
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
32
+++ b/block/archipelago.c
12
---
33
@@ -XXX,XX +XXX,XX @@ static void qemu_archipelago_complete_aio(void *opaque)
13
tests/qemu-iotests/065 | 16 ++++++++--------
34
{
14
1 file changed, 8 insertions(+), 8 deletions(-)
35
AIORequestData *reqdata = (AIORequestData *) opaque;
15
36
ArchipelagoAIOCB *aio_cb = (ArchipelagoAIOCB *) reqdata->aio_cb;
16
diff --git a/tests/qemu-iotests/065 b/tests/qemu-iotests/065
37
+ AioContext *ctx = bdrv_get_aio_context(aio_cb->common.bs);
38
39
+ aio_context_acquire(ctx);
40
aio_cb->common.cb(aio_cb->common.opaque, aio_cb->ret);
41
+ aio_context_release(ctx);
42
aio_cb->status = 0;
43
44
qemu_aio_unref(aio_cb);
45
diff --git a/block/blkreplay.c b/block/blkreplay.c
17
index XXXXXXX..XXXXXXX 100755
46
index XXXXXXX..XXXXXXX 100755
18
--- a/tests/qemu-iotests/065
47
--- a/block/blkreplay.c
19
+++ b/tests/qemu-iotests/065
48
+++ b/block/blkreplay.c
20
@@ -XXX,XX +XXX,XX @@ class TestQMP(TestImageInfoSpecific):
49
@@ -XXX,XX +XXX,XX @@ static int64_t blkreplay_getlength(BlockDriverState *bs)
21
50
static void blkreplay_bh_cb(void *opaque)
22
class TestQCow2(TestQemuImgInfo):
51
{
23
'''Testing a qcow2 version 2 image'''
52
Request *req = opaque;
24
- img_options = 'compat=0.10'
53
- qemu_coroutine_enter(req->co);
25
+ img_options = 'compat=0.10,compression_type=zlib'
54
+ aio_co_wake(req->co);
26
json_compare = { 'compat': '0.10', 'refcount-bits': 16,
55
qemu_bh_delete(req->bh);
27
'compression-type': 'zlib' }
56
g_free(req);
28
human_compare = [ 'compat: 0.10', 'compression type: zlib',
57
}
29
@@ -XXX,XX +XXX,XX @@ class TestQCow2(TestQemuImgInfo):
58
diff --git a/block/block-backend.c b/block/block-backend.c
30
59
index XXXXXXX..XXXXXXX 100644
31
class TestQCow3NotLazy(TestQemuImgInfo):
60
--- a/block/block-backend.c
32
'''Testing a qcow2 version 3 image with lazy refcounts disabled'''
61
+++ b/block/block-backend.c
33
- img_options = 'compat=1.1,lazy_refcounts=off'
62
@@ -XXX,XX +XXX,XX @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
34
+ img_options = 'compat=1.1,lazy_refcounts=off,compression_type=zstd'
63
static void error_callback_bh(void *opaque)
35
json_compare = { 'compat': '1.1', 'lazy-refcounts': False,
64
{
36
'refcount-bits': 16, 'corrupt': False,
65
struct BlockBackendAIOCB *acb = opaque;
37
- 'compression-type': 'zlib', 'extended-l2': False }
66
+ AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
38
- human_compare = [ 'compat: 1.1', 'compression type: zlib',
67
39
+ 'compression-type': 'zstd', 'extended-l2': False }
68
bdrv_dec_in_flight(acb->common.bs);
40
+ human_compare = [ 'compat: 1.1', 'compression type: zstd',
69
+ aio_context_acquire(ctx);
41
'lazy refcounts: false', 'refcount bits: 16',
70
acb->common.cb(acb->common.opaque, acb->ret);
42
'corrupt: false', 'extended l2: false' ]
71
+ aio_context_release(ctx);
43
72
qemu_aio_unref(acb);
44
class TestQCow3Lazy(TestQemuImgInfo):
73
}
45
'''Testing a qcow2 version 3 image with lazy refcounts enabled'''
74
46
- img_options = 'compat=1.1,lazy_refcounts=on'
75
@@ -XXX,XX +XXX,XX @@ static void blk_aio_complete(BlkAioEmAIOCB *acb)
47
+ img_options = 'compat=1.1,lazy_refcounts=on,compression_type=zlib'
76
static void blk_aio_complete_bh(void *opaque)
48
json_compare = { 'compat': '1.1', 'lazy-refcounts': True,
77
{
49
'refcount-bits': 16, 'corrupt': False,
78
BlkAioEmAIOCB *acb = opaque;
50
'compression-type': 'zlib', 'extended-l2': False }
79
+ AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
51
@@ -XXX,XX +XXX,XX @@ class TestQCow3Lazy(TestQemuImgInfo):
80
52
class TestQCow3NotLazyQMP(TestQMP):
81
assert(acb->has_returned);
53
'''Testing a qcow2 version 3 image with lazy refcounts disabled, opening
82
+ aio_context_acquire(ctx);
54
with lazy refcounts enabled'''
83
blk_aio_complete(acb);
55
- img_options = 'compat=1.1,lazy_refcounts=off'
84
+ aio_context_release(ctx);
56
+ img_options = 'compat=1.1,lazy_refcounts=off,compression_type=zlib'
85
}
57
qemu_options = 'lazy-refcounts=on'
86
58
compare = { 'compat': '1.1', 'lazy-refcounts': False,
87
static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
59
'refcount-bits': 16, 'corrupt': False,
88
diff --git a/block/curl.c b/block/curl.c
60
@@ -XXX,XX +XXX,XX @@ class TestQCow3NotLazyQMP(TestQMP):
89
index XXXXXXX..XXXXXXX 100644
61
class TestQCow3LazyQMP(TestQMP):
90
--- a/block/curl.c
62
'''Testing a qcow2 version 3 image with lazy refcounts enabled, opening
91
+++ b/block/curl.c
63
with lazy refcounts disabled'''
92
@@ -XXX,XX +XXX,XX @@ static void curl_readv_bh_cb(void *p)
64
- img_options = 'compat=1.1,lazy_refcounts=on'
93
{
65
+ img_options = 'compat=1.1,lazy_refcounts=on,compression_type=zstd'
94
CURLState *state;
66
qemu_options = 'lazy-refcounts=off'
95
int running;
67
compare = { 'compat': '1.1', 'lazy-refcounts': True,
96
+ int ret = -EINPROGRESS;
68
'refcount-bits': 16, 'corrupt': False,
97
69
- 'compression-type': 'zlib', 'extended-l2': False }
98
CURLAIOCB *acb = p;
70
+ 'compression-type': 'zstd', 'extended-l2': False }
99
- BDRVCURLState *s = acb->common.bs->opaque;
71
100
+ BlockDriverState *bs = acb->common.bs;
72
TestImageInfoSpecific = None
101
+ BDRVCURLState *s = bs->opaque;
73
TestQemuImgInfo = None
102
+ AioContext *ctx = bdrv_get_aio_context(bs);
103
104
size_t start = acb->sector_num * BDRV_SECTOR_SIZE;
105
size_t end;
106
107
+ aio_context_acquire(ctx);
108
+
109
// In case we have the requested data already (e.g. read-ahead),
110
// we can just call the callback and be done.
111
switch (curl_find_buf(s, start, acb->nb_sectors * BDRV_SECTOR_SIZE, acb)) {
112
@@ -XXX,XX +XXX,XX @@ static void curl_readv_bh_cb(void *p)
113
qemu_aio_unref(acb);
114
// fall through
115
case FIND_RET_WAIT:
116
- return;
117
+ goto out;
118
default:
119
break;
120
}
121
@@ -XXX,XX +XXX,XX @@ static void curl_readv_bh_cb(void *p)
122
// No cache found, so let's start a new request
123
state = curl_init_state(acb->common.bs, s);
124
if (!state) {
125
- acb->common.cb(acb->common.opaque, -EIO);
126
- qemu_aio_unref(acb);
127
- return;
128
+ ret = -EIO;
129
+ goto out;
130
}
131
132
acb->start = 0;
133
@@ -XXX,XX +XXX,XX @@ static void curl_readv_bh_cb(void *p)
134
state->orig_buf = g_try_malloc(state->buf_len);
135
if (state->buf_len && state->orig_buf == NULL) {
136
curl_clean_state(state);
137
- acb->common.cb(acb->common.opaque, -ENOMEM);
138
- qemu_aio_unref(acb);
139
- return;
140
+ ret = -ENOMEM;
141
+ goto out;
142
}
143
state->acb[0] = acb;
144
145
@@ -XXX,XX +XXX,XX @@ static void curl_readv_bh_cb(void *p)
146
147
/* Tell curl it needs to kick things off */
148
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
149
+
150
+out:
151
+ if (ret != -EINPROGRESS) {
152
+ acb->common.cb(acb->common.opaque, ret);
153
+ qemu_aio_unref(acb);
154
+ }
155
+ aio_context_release(ctx);
156
}
157
158
static BlockAIOCB *curl_aio_readv(BlockDriverState *bs,
159
diff --git a/block/gluster.c b/block/gluster.c
160
index XXXXXXX..XXXXXXX 100644
161
--- a/block/gluster.c
162
+++ b/block/gluster.c
163
@@ -XXX,XX +XXX,XX @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
164
return qemu_gluster_glfs_init(gconf, errp);
165
}
166
167
-static void qemu_gluster_complete_aio(void *opaque)
168
-{
169
- GlusterAIOCB *acb = (GlusterAIOCB *)opaque;
170
-
171
- qemu_coroutine_enter(acb->coroutine);
172
-}
173
-
174
/*
175
* AIO callback routine called from GlusterFS thread.
176
*/
177
@@ -XXX,XX +XXX,XX @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
178
acb->ret = -EIO; /* Partial read/write - fail it */
179
}
180
181
- aio_bh_schedule_oneshot(acb->aio_context, qemu_gluster_complete_aio, acb);
182
+ aio_co_schedule(acb->aio_context, acb->coroutine);
183
}
184
185
static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
186
diff --git a/block/io.c b/block/io.c
187
index XXXXXXX..XXXXXXX 100644
188
--- a/block/io.c
189
+++ b/block/io.c
190
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_drain_bh_cb(void *opaque)
191
bdrv_dec_in_flight(bs);
192
bdrv_drained_begin(bs);
193
data->done = true;
194
- qemu_coroutine_enter(co);
195
+ aio_co_wake(co);
196
}
197
198
static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs)
199
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_complete(BlockAIOCBCoroutine *acb)
200
static void bdrv_co_em_bh(void *opaque)
201
{
202
BlockAIOCBCoroutine *acb = opaque;
203
+ BlockDriverState *bs = acb->common.bs;
204
+ AioContext *ctx = bdrv_get_aio_context(bs);
205
206
assert(!acb->need_bh);
207
+ aio_context_acquire(ctx);
208
bdrv_co_complete(acb);
209
+ aio_context_release(ctx);
210
}
211
212
static void bdrv_co_maybe_schedule_bh(BlockAIOCBCoroutine *acb)
213
diff --git a/block/iscsi.c b/block/iscsi.c
214
index XXXXXXX..XXXXXXX 100644
215
--- a/block/iscsi.c
216
+++ b/block/iscsi.c
217
@@ -XXX,XX +XXX,XX @@ static void
218
iscsi_bh_cb(void *p)
219
{
220
IscsiAIOCB *acb = p;
221
+ AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
222
223
qemu_bh_delete(acb->bh);
224
225
g_free(acb->buf);
226
acb->buf = NULL;
227
228
+ aio_context_acquire(ctx);
229
acb->common.cb(acb->common.opaque, acb->status);
230
+ aio_context_release(ctx);
231
232
if (acb->task != NULL) {
233
scsi_free_scsi_task(acb->task);
234
@@ -XXX,XX +XXX,XX @@ iscsi_schedule_bh(IscsiAIOCB *acb)
235
static void iscsi_co_generic_bh_cb(void *opaque)
236
{
237
struct IscsiTask *iTask = opaque;
238
+
239
iTask->complete = 1;
240
- qemu_coroutine_enter(iTask->co);
241
+ aio_co_wake(iTask->co);
242
}
243
244
static void iscsi_retry_timer_expired(void *opaque)
245
diff --git a/block/linux-aio.c b/block/linux-aio.c
246
index XXXXXXX..XXXXXXX 100644
247
--- a/block/linux-aio.c
248
+++ b/block/linux-aio.c
249
@@ -XXX,XX +XXX,XX @@ struct LinuxAioState {
250
io_context_t ctx;
251
EventNotifier e;
252
253
- /* io queue for submit at batch */
254
+ /* io queue for submit at batch. Protected by AioContext lock. */
255
LaioQueue io_q;
256
257
- /* I/O completion processing */
258
+ /* I/O completion processing. Only runs in I/O thread. */
259
QEMUBH *completion_bh;
260
int event_idx;
261
int event_max;
262
@@ -XXX,XX +XXX,XX @@ static inline ssize_t io_event_ret(struct io_event *ev)
263
*/
264
static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
265
{
266
+ LinuxAioState *s = laiocb->ctx;
267
int ret;
268
269
ret = laiocb->ret;
270
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
271
}
272
273
laiocb->ret = ret;
274
+ aio_context_acquire(s->aio_context);
275
if (laiocb->co) {
276
/* If the coroutine is already entered it must be in ioq_submit() and
277
* will notice laio->ret has been filled in when it eventually runs
278
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
279
laiocb->common.cb(laiocb->common.opaque, ret);
280
qemu_aio_unref(laiocb);
281
}
282
+ aio_context_release(s->aio_context);
283
}
284
285
/**
286
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completions(LinuxAioState *s)
287
static void qemu_laio_process_completions_and_submit(LinuxAioState *s)
288
{
289
qemu_laio_process_completions(s);
290
+
291
+ aio_context_acquire(s->aio_context);
292
if (!s->io_q.plugged && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
293
ioq_submit(s);
294
}
295
+ aio_context_release(s->aio_context);
296
}
297
298
static void qemu_laio_completion_bh(void *opaque)
299
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_completion_cb(EventNotifier *e)
300
LinuxAioState *s = container_of(e, LinuxAioState, e);
301
302
if (event_notifier_test_and_clear(&s->e)) {
303
- aio_context_acquire(s->aio_context);
304
qemu_laio_process_completions_and_submit(s);
305
- aio_context_release(s->aio_context);
306
}
307
}
308
309
@@ -XXX,XX +XXX,XX @@ static bool qemu_laio_poll_cb(void *opaque)
310
return false;
311
}
312
313
- aio_context_acquire(s->aio_context);
314
qemu_laio_process_completions_and_submit(s);
315
- aio_context_release(s->aio_context);
316
return true;
317
}
318
319
@@ -XXX,XX +XXX,XX @@ void laio_detach_aio_context(LinuxAioState *s, AioContext *old_context)
320
{
321
aio_set_event_notifier(old_context, &s->e, false, NULL, NULL);
322
qemu_bh_delete(s->completion_bh);
323
+ s->aio_context = NULL;
324
}
325
326
void laio_attach_aio_context(LinuxAioState *s, AioContext *new_context)
327
diff --git a/block/nfs.c b/block/nfs.c
328
index XXXXXXX..XXXXXXX 100644
329
--- a/block/nfs.c
330
+++ b/block/nfs.c
331
@@ -XXX,XX +XXX,XX @@ static void nfs_co_init_task(BlockDriverState *bs, NFSRPC *task)
332
static void nfs_co_generic_bh_cb(void *opaque)
333
{
334
NFSRPC *task = opaque;
335
+
336
task->complete = 1;
337
- qemu_coroutine_enter(task->co);
338
+ aio_co_wake(task->co);
339
}
340
341
static void
342
diff --git a/block/null.c b/block/null.c
343
index XXXXXXX..XXXXXXX 100644
344
--- a/block/null.c
345
+++ b/block/null.c
346
@@ -XXX,XX +XXX,XX @@ static const AIOCBInfo null_aiocb_info = {
347
static void null_bh_cb(void *opaque)
348
{
349
NullAIOCB *acb = opaque;
350
+ AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
351
+
352
+ aio_context_acquire(ctx);
353
acb->common.cb(acb->common.opaque, 0);
354
+ aio_context_release(ctx);
355
qemu_aio_unref(acb);
356
}
357
358
diff --git a/block/qed.c b/block/qed.c
359
index XXXXXXX..XXXXXXX 100644
360
--- a/block/qed.c
361
+++ b/block/qed.c
362
@@ -XXX,XX +XXX,XX @@ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
363
static void qed_aio_complete_bh(void *opaque)
364
{
365
QEDAIOCB *acb = opaque;
366
+ BDRVQEDState *s = acb_to_s(acb);
367
BlockCompletionFunc *cb = acb->common.cb;
368
void *user_opaque = acb->common.opaque;
369
int ret = acb->bh_ret;
370
@@ -XXX,XX +XXX,XX @@ static void qed_aio_complete_bh(void *opaque)
371
qemu_aio_unref(acb);
372
373
/* Invoke callback */
374
+ qed_acquire(s);
375
cb(user_opaque, ret);
376
+ qed_release(s);
377
}
378
379
static void qed_aio_complete(QEDAIOCB *acb, int ret)
380
diff --git a/block/rbd.c b/block/rbd.c
381
index XXXXXXX..XXXXXXX 100644
382
--- a/block/rbd.c
383
+++ b/block/rbd.c
384
@@ -XXX,XX +XXX,XX @@ shutdown:
385
static void qemu_rbd_complete_aio(RADOSCB *rcb)
386
{
387
RBDAIOCB *acb = rcb->acb;
388
+ AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
389
int64_t r;
390
391
r = rcb->ret;
392
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
393
qemu_iovec_from_buf(acb->qiov, 0, acb->bounce, acb->qiov->size);
394
}
395
qemu_vfree(acb->bounce);
396
+
397
+ aio_context_acquire(ctx);
398
acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
399
+ aio_context_release(ctx);
400
401
qemu_aio_unref(acb);
402
}
403
diff --git a/dma-helpers.c b/dma-helpers.c
404
index XXXXXXX..XXXXXXX 100644
405
--- a/dma-helpers.c
406
+++ b/dma-helpers.c
407
@@ -XXX,XX +XXX,XX @@ static void dma_blk_cb(void *opaque, int ret)
408
QEMU_ALIGN_DOWN(dbs->iov.size, dbs->align));
409
}
410
411
+ aio_context_acquire(dbs->ctx);
412
dbs->acb = dbs->io_func(dbs->offset, &dbs->iov,
413
dma_blk_cb, dbs, dbs->io_func_opaque);
414
+ aio_context_release(dbs->ctx);
415
assert(dbs->acb);
416
}
417
418
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
419
index XXXXXXX..XXXXXXX 100644
420
--- a/hw/block/virtio-blk.c
421
+++ b/hw/block/virtio-blk.c
422
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_dma_restart_bh(void *opaque)
423
424
s->rq = NULL;
425
426
+ aio_context_acquire(blk_get_aio_context(s->conf.conf.blk));
427
while (req) {
428
VirtIOBlockReq *next = req->next;
429
if (virtio_blk_handle_request(req, &mrb)) {
430
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_dma_restart_bh(void *opaque)
431
if (mrb.num_reqs) {
432
virtio_blk_submit_multireq(s->blk, &mrb);
433
}
434
+ aio_context_release(blk_get_aio_context(s->conf.conf.blk));
435
}
436
437
static void virtio_blk_dma_restart_cb(void *opaque, int running,
438
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
439
index XXXXXXX..XXXXXXX 100644
440
--- a/hw/scsi/scsi-bus.c
441
+++ b/hw/scsi/scsi-bus.c
442
@@ -XXX,XX +XXX,XX @@ static void scsi_dma_restart_bh(void *opaque)
443
qemu_bh_delete(s->bh);
444
s->bh = NULL;
445
446
+ aio_context_acquire(blk_get_aio_context(s->conf.blk));
447
QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) {
448
scsi_req_ref(req);
449
if (req->retry) {
450
@@ -XXX,XX +XXX,XX @@ static void scsi_dma_restart_bh(void *opaque)
451
}
452
scsi_req_unref(req);
453
}
454
+ aio_context_release(blk_get_aio_context(s->conf.blk));
455
}
456
457
void scsi_req_retry(SCSIRequest *req)
458
diff --git a/util/async.c b/util/async.c
459
index XXXXXXX..XXXXXXX 100644
460
--- a/util/async.c
461
+++ b/util/async.c
462
@@ -XXX,XX +XXX,XX @@ int aio_bh_poll(AioContext *ctx)
463
ret = 1;
464
}
465
bh->idle = 0;
466
- aio_context_acquire(ctx);
467
aio_bh_call(bh);
468
- aio_context_release(ctx);
469
}
470
if (bh->deleted) {
471
deleted = true;
472
@@ -XXX,XX +XXX,XX @@ static void co_schedule_bh_cb(void *opaque)
473
Coroutine *co = QSLIST_FIRST(&straight);
474
QSLIST_REMOVE_HEAD(&straight, co_scheduled_next);
475
trace_aio_co_schedule_bh_cb(ctx, co);
476
+ aio_context_acquire(ctx);
477
qemu_coroutine_enter(co);
478
+ aio_context_release(ctx);
479
}
480
}
481
482
diff --git a/util/thread-pool.c b/util/thread-pool.c
483
index XXXXXXX..XXXXXXX 100644
484
--- a/util/thread-pool.c
485
+++ b/util/thread-pool.c
486
@@ -XXX,XX +XXX,XX @@ static void thread_pool_completion_bh(void *opaque)
487
ThreadPool *pool = opaque;
488
ThreadPoolElement *elem, *next;
489
490
+ aio_context_acquire(pool->ctx);
491
restart:
492
QLIST_FOREACH_SAFE(elem, &pool->head, all, next) {
493
if (elem->state != THREAD_DONE) {
494
@@ -XXX,XX +XXX,XX @@ restart:
495
qemu_aio_unref(elem);
496
}
497
}
498
+ aio_context_release(pool->ctx);
499
}
500
501
static void thread_pool_cancel(BlockAIOCB *acb)
74
--
502
--
75
2.34.1
503
2.9.3
76
504
77
505
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Move the logic to more generic qemu_img_pipe_and_status(). Also behave
3
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
better when we have several -o options. And reuse argument parser of
4
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
5
course.
5
Reviewed-by: Fam Zheng <famz@redhat.com>
6
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
7
Message-id: 20170213135235.12274-16-pbonzini@redhat.com
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
10
block/archipelago.c | 3 ---
11
block/block-backend.c | 7 -------
12
block/curl.c | 2 +-
13
block/io.c | 6 +-----
14
block/iscsi.c | 3 ---
15
block/linux-aio.c | 5 +----
16
block/mirror.c | 12 +++++++++---
17
block/null.c | 8 --------
18
block/qed-cluster.c | 2 ++
19
block/qed-table.c | 12 ++++++++++--
20
block/qed.c | 4 ++--
21
block/rbd.c | 4 ----
22
block/win32-aio.c | 3 ---
23
hw/block/virtio-blk.c | 12 +++++++++++-
24
hw/scsi/scsi-disk.c | 15 +++++++++++++++
25
hw/scsi/scsi-generic.c | 20 +++++++++++++++++---
26
util/thread-pool.c | 4 +++-
27
17 files changed, 72 insertions(+), 50 deletions(-)
6
28
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
29
diff --git a/block/archipelago.c b/block/archipelago.c
8
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
30
index XXXXXXX..XXXXXXX 100644
9
Message-Id: <20211223160144.1097696-7-vsementsov@virtuozzo.com>
31
--- a/block/archipelago.c
10
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
32
+++ b/block/archipelago.c
11
---
33
@@ -XXX,XX +XXX,XX @@ static void qemu_archipelago_complete_aio(void *opaque)
12
tests/qemu-iotests/iotests.py | 36 +++++++++++++++++------------------
34
{
13
1 file changed, 17 insertions(+), 19 deletions(-)
35
AIORequestData *reqdata = (AIORequestData *) opaque;
14
36
ArchipelagoAIOCB *aio_cb = (ArchipelagoAIOCB *) reqdata->aio_cb;
15
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
37
- AioContext *ctx = bdrv_get_aio_context(aio_cb->common.bs);
16
index XXXXXXX..XXXXXXX 100644
38
17
--- a/tests/qemu-iotests/iotests.py
39
- aio_context_acquire(ctx);
18
+++ b/tests/qemu-iotests/iotests.py
40
aio_cb->common.cb(aio_cb->common.opaque, aio_cb->ret);
19
@@ -XXX,XX +XXX,XX @@ def qemu_img_create_prepare_args(args: List[str]) -> List[str]:
41
- aio_context_release(ctx);
20
args = args[1:]
42
aio_cb->status = 0;
21
43
22
p = argparse.ArgumentParser(allow_abbrev=False)
44
qemu_aio_unref(aio_cb);
23
+ # -o option may be specified several times
45
diff --git a/block/block-backend.c b/block/block-backend.c
24
+ p.add_argument('-o', action='append', default=[])
46
index XXXXXXX..XXXXXXX 100644
25
p.add_argument('-f')
47
--- a/block/block-backend.c
26
parsed, remaining = p.parse_known_args(args)
48
+++ b/block/block-backend.c
27
49
@@ -XXX,XX +XXX,XX @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
28
+ opts_list = parsed.o
50
static void error_callback_bh(void *opaque)
29
+
51
{
30
result = ['create']
52
struct BlockBackendAIOCB *acb = opaque;
31
if parsed.f is not None:
53
- AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
32
result += ['-f', parsed.f]
54
33
@@ -XXX,XX +XXX,XX @@ def qemu_img_create_prepare_args(args: List[str]) -> List[str]:
55
bdrv_dec_in_flight(acb->common.bs);
34
# like extended_l2 or compression_type for qcow2. Test may want to create
56
- aio_context_acquire(ctx);
35
# additional images in other formats that doesn't support these options.
57
acb->common.cb(acb->common.opaque, acb->ret);
36
# So, use IMGOPTS only for images created in imgfmt format.
58
- aio_context_release(ctx);
37
- if parsed.f == imgfmt and 'IMGOPTS' in os.environ:
59
qemu_aio_unref(acb);
38
- result += ['-o', os.environ['IMGOPTS']]
60
}
39
+ imgopts = os.environ.get('IMGOPTS')
61
40
+ if imgopts and parsed.f == imgfmt:
62
@@ -XXX,XX +XXX,XX @@ static void blk_aio_complete(BlkAioEmAIOCB *acb)
41
+ opts_list.insert(0, imgopts)
63
static void blk_aio_complete_bh(void *opaque)
42
+
64
{
43
+ # default luks support
65
BlkAioEmAIOCB *acb = opaque;
44
+ if parsed.f == 'luks' and \
66
- AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
45
+ all('key-secret' not in opts for opts in opts_list):
46
+ result += ['--object', luks_default_secret_object]
47
+ opts_list.append(luks_default_key_secret_opt)
48
+
49
+ for opts in opts_list:
50
+ result += ['-o', opts]
51
52
result += remaining
53
54
@@ -XXX,XX +XXX,XX @@ def ordered_qmp(qmsg, conv_keys=True):
55
return qmsg
56
57
def qemu_img_create(*args):
58
- args = list(args)
59
-
67
-
60
- # default luks support
68
assert(acb->has_returned);
61
- if '-f' in args and args[args.index('-f') + 1] == 'luks':
69
- aio_context_acquire(ctx);
62
- if '-o' in args:
70
blk_aio_complete(acb);
63
- i = args.index('-o')
71
- aio_context_release(ctx);
64
- if 'key-secret' not in args[i + 1]:
72
}
65
- args[i + 1].append(luks_default_key_secret_opt)
73
66
- args.insert(i + 2, '--object')
74
static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
67
- args.insert(i + 3, luks_default_secret_object)
75
diff --git a/block/curl.c b/block/curl.c
68
- else:
76
index XXXXXXX..XXXXXXX 100644
69
- args = ['-o', luks_default_key_secret_opt,
77
--- a/block/curl.c
70
- '--object', luks_default_secret_object] + args
78
+++ b/block/curl.c
79
@@ -XXX,XX +XXX,XX @@ static void curl_readv_bh_cb(void *p)
80
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
81
82
out:
83
+ aio_context_release(ctx);
84
if (ret != -EINPROGRESS) {
85
acb->common.cb(acb->common.opaque, ret);
86
qemu_aio_unref(acb);
87
}
88
- aio_context_release(ctx);
89
}
90
91
static BlockAIOCB *curl_aio_readv(BlockDriverState *bs,
92
diff --git a/block/io.c b/block/io.c
93
index XXXXXXX..XXXXXXX 100644
94
--- a/block/io.c
95
+++ b/block/io.c
96
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_io_em_complete(void *opaque, int ret)
97
CoroutineIOCompletion *co = opaque;
98
99
co->ret = ret;
100
- qemu_coroutine_enter(co->coroutine);
101
+ aio_co_wake(co->coroutine);
102
}
103
104
static int coroutine_fn bdrv_driver_preadv(BlockDriverState *bs,
105
@@ -XXX,XX +XXX,XX @@ static void bdrv_co_complete(BlockAIOCBCoroutine *acb)
106
static void bdrv_co_em_bh(void *opaque)
107
{
108
BlockAIOCBCoroutine *acb = opaque;
109
- BlockDriverState *bs = acb->common.bs;
110
- AioContext *ctx = bdrv_get_aio_context(bs);
111
112
assert(!acb->need_bh);
113
- aio_context_acquire(ctx);
114
bdrv_co_complete(acb);
115
- aio_context_release(ctx);
116
}
117
118
static void bdrv_co_maybe_schedule_bh(BlockAIOCBCoroutine *acb)
119
diff --git a/block/iscsi.c b/block/iscsi.c
120
index XXXXXXX..XXXXXXX 100644
121
--- a/block/iscsi.c
122
+++ b/block/iscsi.c
123
@@ -XXX,XX +XXX,XX @@ static void
124
iscsi_bh_cb(void *p)
125
{
126
IscsiAIOCB *acb = p;
127
- AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
128
129
qemu_bh_delete(acb->bh);
130
131
g_free(acb->buf);
132
acb->buf = NULL;
133
134
- aio_context_acquire(ctx);
135
acb->common.cb(acb->common.opaque, acb->status);
136
- aio_context_release(ctx);
137
138
if (acb->task != NULL) {
139
scsi_free_scsi_task(acb->task);
140
diff --git a/block/linux-aio.c b/block/linux-aio.c
141
index XXXXXXX..XXXXXXX 100644
142
--- a/block/linux-aio.c
143
+++ b/block/linux-aio.c
144
@@ -XXX,XX +XXX,XX @@ static inline ssize_t io_event_ret(struct io_event *ev)
145
*/
146
static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
147
{
148
- LinuxAioState *s = laiocb->ctx;
149
int ret;
150
151
ret = laiocb->ret;
152
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
153
}
154
155
laiocb->ret = ret;
156
- aio_context_acquire(s->aio_context);
157
if (laiocb->co) {
158
/* If the coroutine is already entered it must be in ioq_submit() and
159
* will notice laio->ret has been filled in when it eventually runs
160
@@ -XXX,XX +XXX,XX @@ static void qemu_laio_process_completion(struct qemu_laiocb *laiocb)
161
* that!
162
*/
163
if (!qemu_coroutine_entered(laiocb->co)) {
164
- qemu_coroutine_enter(laiocb->co);
165
+ aio_co_wake(laiocb->co);
166
}
167
} else {
168
laiocb->common.cb(laiocb->common.opaque, ret);
169
qemu_aio_unref(laiocb);
170
}
171
- aio_context_release(s->aio_context);
172
}
173
174
/**
175
diff --git a/block/mirror.c b/block/mirror.c
176
index XXXXXXX..XXXXXXX 100644
177
--- a/block/mirror.c
178
+++ b/block/mirror.c
179
@@ -XXX,XX +XXX,XX @@ static void mirror_write_complete(void *opaque, int ret)
180
{
181
MirrorOp *op = opaque;
182
MirrorBlockJob *s = op->s;
183
+
184
+ aio_context_acquire(blk_get_aio_context(s->common.blk));
185
if (ret < 0) {
186
BlockErrorAction action;
187
188
@@ -XXX,XX +XXX,XX @@ static void mirror_write_complete(void *opaque, int ret)
189
}
190
}
191
mirror_iteration_done(op, ret);
192
+ aio_context_release(blk_get_aio_context(s->common.blk));
193
}
194
195
static void mirror_read_complete(void *opaque, int ret)
196
{
197
MirrorOp *op = opaque;
198
MirrorBlockJob *s = op->s;
199
+
200
+ aio_context_acquire(blk_get_aio_context(s->common.blk));
201
if (ret < 0) {
202
BlockErrorAction action;
203
204
@@ -XXX,XX +XXX,XX @@ static void mirror_read_complete(void *opaque, int ret)
205
}
206
207
mirror_iteration_done(op, ret);
208
- return;
209
+ } else {
210
+ blk_aio_pwritev(s->target, op->sector_num * BDRV_SECTOR_SIZE, &op->qiov,
211
+ 0, mirror_write_complete, op);
212
}
213
- blk_aio_pwritev(s->target, op->sector_num * BDRV_SECTOR_SIZE, &op->qiov,
214
- 0, mirror_write_complete, op);
215
+ aio_context_release(blk_get_aio_context(s->common.blk));
216
}
217
218
static inline void mirror_clip_sectors(MirrorBlockJob *s,
219
diff --git a/block/null.c b/block/null.c
220
index XXXXXXX..XXXXXXX 100644
221
--- a/block/null.c
222
+++ b/block/null.c
223
@@ -XXX,XX +XXX,XX @@ static const AIOCBInfo null_aiocb_info = {
224
static void null_bh_cb(void *opaque)
225
{
226
NullAIOCB *acb = opaque;
227
- AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
71
-
228
-
72
- args.insert(0, 'create')
229
- aio_context_acquire(ctx);
230
acb->common.cb(acb->common.opaque, 0);
231
- aio_context_release(ctx);
232
qemu_aio_unref(acb);
233
}
234
235
static void null_timer_cb(void *opaque)
236
{
237
NullAIOCB *acb = opaque;
238
- AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
73
-
239
-
74
- return qemu_img(*args)
240
- aio_context_acquire(ctx);
75
+ return qemu_img('create', *args)
241
acb->common.cb(acb->common.opaque, 0);
76
242
- aio_context_release(ctx);
77
def qemu_img_measure(*args):
243
timer_deinit(&acb->timer);
78
return json.loads(qemu_img_pipe("measure", "--output", "json", *args))
244
qemu_aio_unref(acb);
245
}
246
diff --git a/block/qed-cluster.c b/block/qed-cluster.c
247
index XXXXXXX..XXXXXXX 100644
248
--- a/block/qed-cluster.c
249
+++ b/block/qed-cluster.c
250
@@ -XXX,XX +XXX,XX @@ static void qed_find_cluster_cb(void *opaque, int ret)
251
unsigned int index;
252
unsigned int n;
253
254
+ qed_acquire(s);
255
if (ret) {
256
goto out;
257
}
258
@@ -XXX,XX +XXX,XX @@ static void qed_find_cluster_cb(void *opaque, int ret)
259
260
out:
261
find_cluster_cb->cb(find_cluster_cb->opaque, ret, offset, len);
262
+ qed_release(s);
263
g_free(find_cluster_cb);
264
}
265
266
diff --git a/block/qed-table.c b/block/qed-table.c
267
index XXXXXXX..XXXXXXX 100644
268
--- a/block/qed-table.c
269
+++ b/block/qed-table.c
270
@@ -XXX,XX +XXX,XX @@ static void qed_read_table_cb(void *opaque, int ret)
271
{
272
QEDReadTableCB *read_table_cb = opaque;
273
QEDTable *table = read_table_cb->table;
274
+ BDRVQEDState *s = read_table_cb->s;
275
int noffsets = read_table_cb->qiov.size / sizeof(uint64_t);
276
int i;
277
278
@@ -XXX,XX +XXX,XX @@ static void qed_read_table_cb(void *opaque, int ret)
279
}
280
281
/* Byteswap offsets */
282
+ qed_acquire(s);
283
for (i = 0; i < noffsets; i++) {
284
table->offsets[i] = le64_to_cpu(table->offsets[i]);
285
}
286
+ qed_release(s);
287
288
out:
289
/* Completion */
290
- trace_qed_read_table_cb(read_table_cb->s, read_table_cb->table, ret);
291
+ trace_qed_read_table_cb(s, read_table_cb->table, ret);
292
gencb_complete(&read_table_cb->gencb, ret);
293
}
294
295
@@ -XXX,XX +XXX,XX @@ typedef struct {
296
static void qed_write_table_cb(void *opaque, int ret)
297
{
298
QEDWriteTableCB *write_table_cb = opaque;
299
+ BDRVQEDState *s = write_table_cb->s;
300
301
- trace_qed_write_table_cb(write_table_cb->s,
302
+ trace_qed_write_table_cb(s,
303
write_table_cb->orig_table,
304
write_table_cb->flush,
305
ret);
306
@@ -XXX,XX +XXX,XX @@ static void qed_write_table_cb(void *opaque, int ret)
307
if (write_table_cb->flush) {
308
/* We still need to flush first */
309
write_table_cb->flush = false;
310
+ qed_acquire(s);
311
bdrv_aio_flush(write_table_cb->s->bs, qed_write_table_cb,
312
write_table_cb);
313
+ qed_release(s);
314
return;
315
}
316
317
@@ -XXX,XX +XXX,XX @@ static void qed_read_l2_table_cb(void *opaque, int ret)
318
CachedL2Table *l2_table = request->l2_table;
319
uint64_t l2_offset = read_l2_table_cb->l2_offset;
320
321
+ qed_acquire(s);
322
if (ret) {
323
/* can't trust loaded L2 table anymore */
324
qed_unref_l2_cache_entry(l2_table);
325
@@ -XXX,XX +XXX,XX @@ static void qed_read_l2_table_cb(void *opaque, int ret)
326
request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset);
327
assert(request->l2_table != NULL);
328
}
329
+ qed_release(s);
330
331
gencb_complete(&read_l2_table_cb->gencb, ret);
332
}
333
diff --git a/block/qed.c b/block/qed.c
334
index XXXXXXX..XXXXXXX 100644
335
--- a/block/qed.c
336
+++ b/block/qed.c
337
@@ -XXX,XX +XXX,XX @@ static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t l
338
}
339
340
if (cb->co) {
341
- qemu_coroutine_enter(cb->co);
342
+ aio_co_wake(cb->co);
343
}
344
}
345
346
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn qed_co_pwrite_zeroes_cb(void *opaque, int ret)
347
cb->done = true;
348
cb->ret = ret;
349
if (cb->co) {
350
- qemu_coroutine_enter(cb->co);
351
+ aio_co_wake(cb->co);
352
}
353
}
354
355
diff --git a/block/rbd.c b/block/rbd.c
356
index XXXXXXX..XXXXXXX 100644
357
--- a/block/rbd.c
358
+++ b/block/rbd.c
359
@@ -XXX,XX +XXX,XX @@ shutdown:
360
static void qemu_rbd_complete_aio(RADOSCB *rcb)
361
{
362
RBDAIOCB *acb = rcb->acb;
363
- AioContext *ctx = bdrv_get_aio_context(acb->common.bs);
364
int64_t r;
365
366
r = rcb->ret;
367
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_complete_aio(RADOSCB *rcb)
368
qemu_iovec_from_buf(acb->qiov, 0, acb->bounce, acb->qiov->size);
369
}
370
qemu_vfree(acb->bounce);
371
-
372
- aio_context_acquire(ctx);
373
acb->common.cb(acb->common.opaque, (acb->ret > 0 ? 0 : acb->ret));
374
- aio_context_release(ctx);
375
376
qemu_aio_unref(acb);
377
}
378
diff --git a/block/win32-aio.c b/block/win32-aio.c
379
index XXXXXXX..XXXXXXX 100644
380
--- a/block/win32-aio.c
381
+++ b/block/win32-aio.c
382
@@ -XXX,XX +XXX,XX @@ static void win32_aio_process_completion(QEMUWin32AIOState *s,
383
qemu_vfree(waiocb->buf);
384
}
385
386
-
387
- aio_context_acquire(s->aio_ctx);
388
waiocb->common.cb(waiocb->common.opaque, ret);
389
- aio_context_release(s->aio_ctx);
390
qemu_aio_unref(waiocb);
391
}
392
393
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
394
index XXXXXXX..XXXXXXX 100644
395
--- a/hw/block/virtio-blk.c
396
+++ b/hw/block/virtio-blk.c
397
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
398
static void virtio_blk_rw_complete(void *opaque, int ret)
399
{
400
VirtIOBlockReq *next = opaque;
401
+ VirtIOBlock *s = next->dev;
402
403
+ aio_context_acquire(blk_get_aio_context(s->conf.conf.blk));
404
while (next) {
405
VirtIOBlockReq *req = next;
406
next = req->mr_next;
407
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_rw_complete(void *opaque, int ret)
408
block_acct_done(blk_get_stats(req->dev->blk), &req->acct);
409
virtio_blk_free_request(req);
410
}
411
+ aio_context_release(blk_get_aio_context(s->conf.conf.blk));
412
}
413
414
static void virtio_blk_flush_complete(void *opaque, int ret)
415
{
416
VirtIOBlockReq *req = opaque;
417
+ VirtIOBlock *s = req->dev;
418
419
+ aio_context_acquire(blk_get_aio_context(s->conf.conf.blk));
420
if (ret) {
421
if (virtio_blk_handle_rw_error(req, -ret, 0)) {
422
- return;
423
+ goto out;
424
}
425
}
426
427
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
428
block_acct_done(blk_get_stats(req->dev->blk), &req->acct);
429
virtio_blk_free_request(req);
430
+
431
+out:
432
+ aio_context_release(blk_get_aio_context(s->conf.conf.blk));
433
}
434
435
#ifdef __linux__
436
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_ioctl_complete(void *opaque, int status)
437
virtio_stl_p(vdev, &scsi->data_len, hdr->dxfer_len);
438
439
out:
440
+ aio_context_acquire(blk_get_aio_context(s->conf.conf.blk));
441
virtio_blk_req_complete(req, status);
442
virtio_blk_free_request(req);
443
+ aio_context_release(blk_get_aio_context(s->conf.conf.blk));
444
g_free(ioctl_req);
445
}
446
447
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
448
index XXXXXXX..XXXXXXX 100644
449
--- a/hw/scsi/scsi-disk.c
450
+++ b/hw/scsi/scsi-disk.c
451
@@ -XXX,XX +XXX,XX @@ static void scsi_aio_complete(void *opaque, int ret)
452
453
assert(r->req.aiocb != NULL);
454
r->req.aiocb = NULL;
455
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
456
if (scsi_disk_req_check_error(r, ret, true)) {
457
goto done;
458
}
459
@@ -XXX,XX +XXX,XX @@ static void scsi_aio_complete(void *opaque, int ret)
460
scsi_req_complete(&r->req, GOOD);
461
462
done:
463
+ aio_context_release(blk_get_aio_context(s->qdev.conf.blk));
464
scsi_req_unref(&r->req);
465
}
466
467
@@ -XXX,XX +XXX,XX @@ static void scsi_dma_complete(void *opaque, int ret)
468
assert(r->req.aiocb != NULL);
469
r->req.aiocb = NULL;
470
471
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
472
if (ret < 0) {
473
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
474
} else {
475
block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
476
}
477
scsi_dma_complete_noio(r, ret);
478
+ aio_context_release(blk_get_aio_context(s->qdev.conf.blk));
479
}
480
481
static void scsi_read_complete(void * opaque, int ret)
482
@@ -XXX,XX +XXX,XX @@ static void scsi_read_complete(void * opaque, int ret)
483
484
assert(r->req.aiocb != NULL);
485
r->req.aiocb = NULL;
486
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
487
if (scsi_disk_req_check_error(r, ret, true)) {
488
goto done;
489
}
490
@@ -XXX,XX +XXX,XX @@ static void scsi_read_complete(void * opaque, int ret)
491
492
done:
493
scsi_req_unref(&r->req);
494
+ aio_context_release(blk_get_aio_context(s->qdev.conf.blk));
495
}
496
497
/* Actually issue a read to the block device. */
498
@@ -XXX,XX +XXX,XX @@ static void scsi_do_read_cb(void *opaque, int ret)
499
assert (r->req.aiocb != NULL);
500
r->req.aiocb = NULL;
501
502
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
503
if (ret < 0) {
504
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
505
} else {
506
block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
507
}
508
scsi_do_read(opaque, ret);
509
+ aio_context_release(blk_get_aio_context(s->qdev.conf.blk));
510
}
511
512
/* Read more data from scsi device into buffer. */
513
@@ -XXX,XX +XXX,XX @@ static void scsi_write_complete(void * opaque, int ret)
514
assert (r->req.aiocb != NULL);
515
r->req.aiocb = NULL;
516
517
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
518
if (ret < 0) {
519
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
520
} else {
521
block_acct_done(blk_get_stats(s->qdev.conf.blk), &r->acct);
522
}
523
scsi_write_complete_noio(r, ret);
524
+ aio_context_release(blk_get_aio_context(s->qdev.conf.blk));
525
}
526
527
static void scsi_write_data(SCSIRequest *req)
528
@@ -XXX,XX +XXX,XX @@ static void scsi_unmap_complete(void *opaque, int ret)
529
{
530
UnmapCBData *data = opaque;
531
SCSIDiskReq *r = data->r;
532
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
533
534
assert(r->req.aiocb != NULL);
535
r->req.aiocb = NULL;
536
537
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
538
scsi_unmap_complete_noio(data, ret);
539
+ aio_context_release(blk_get_aio_context(s->qdev.conf.blk));
540
}
541
542
static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf)
543
@@ -XXX,XX +XXX,XX @@ static void scsi_write_same_complete(void *opaque, int ret)
544
545
assert(r->req.aiocb != NULL);
546
r->req.aiocb = NULL;
547
+ aio_context_acquire(blk_get_aio_context(s->qdev.conf.blk));
548
if (scsi_disk_req_check_error(r, ret, true)) {
549
goto done;
550
}
551
@@ -XXX,XX +XXX,XX @@ done:
552
scsi_req_unref(&r->req);
553
qemu_vfree(data->iov.iov_base);
554
g_free(data);
555
+ aio_context_release(blk_get_aio_context(s->qdev.conf.blk));
556
}
557
558
static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf)
559
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
560
index XXXXXXX..XXXXXXX 100644
561
--- a/hw/scsi/scsi-generic.c
562
+++ b/hw/scsi/scsi-generic.c
563
@@ -XXX,XX +XXX,XX @@ done:
564
static void scsi_command_complete(void *opaque, int ret)
565
{
566
SCSIGenericReq *r = (SCSIGenericReq *)opaque;
567
+ SCSIDevice *s = r->req.dev;
568
569
assert(r->req.aiocb != NULL);
570
r->req.aiocb = NULL;
571
+
572
+ aio_context_acquire(blk_get_aio_context(s->conf.blk));
573
scsi_command_complete_noio(r, ret);
574
+ aio_context_release(blk_get_aio_context(s->conf.blk));
575
}
576
577
static int execute_command(BlockBackend *blk,
578
@@ -XXX,XX +XXX,XX @@ static void scsi_read_complete(void * opaque, int ret)
579
assert(r->req.aiocb != NULL);
580
r->req.aiocb = NULL;
581
582
+ aio_context_acquire(blk_get_aio_context(s->conf.blk));
583
+
584
if (ret || r->req.io_canceled) {
585
scsi_command_complete_noio(r, ret);
586
- return;
587
+ goto done;
588
}
589
590
len = r->io_header.dxfer_len - r->io_header.resid;
591
@@ -XXX,XX +XXX,XX @@ static void scsi_read_complete(void * opaque, int ret)
592
r->len = -1;
593
if (len == 0) {
594
scsi_command_complete_noio(r, 0);
595
- return;
596
+ goto done;
597
}
598
599
/* Snoop READ CAPACITY output to set the blocksize. */
600
@@ -XXX,XX +XXX,XX @@ static void scsi_read_complete(void * opaque, int ret)
601
}
602
scsi_req_data(&r->req, len);
603
scsi_req_unref(&r->req);
604
+
605
+done:
606
+ aio_context_release(blk_get_aio_context(s->conf.blk));
607
}
608
609
/* Read more data from scsi device into buffer. */
610
@@ -XXX,XX +XXX,XX @@ static void scsi_write_complete(void * opaque, int ret)
611
assert(r->req.aiocb != NULL);
612
r->req.aiocb = NULL;
613
614
+ aio_context_acquire(blk_get_aio_context(s->conf.blk));
615
+
616
if (ret || r->req.io_canceled) {
617
scsi_command_complete_noio(r, ret);
618
- return;
619
+ goto done;
620
}
621
622
if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
623
@@ -XXX,XX +XXX,XX @@ static void scsi_write_complete(void * opaque, int ret)
624
}
625
626
scsi_command_complete_noio(r, ret);
627
+
628
+done:
629
+ aio_context_release(blk_get_aio_context(s->conf.blk));
630
}
631
632
/* Write data to a scsi device. Returns nonzero on failure.
633
diff --git a/util/thread-pool.c b/util/thread-pool.c
634
index XXXXXXX..XXXXXXX 100644
635
--- a/util/thread-pool.c
636
+++ b/util/thread-pool.c
637
@@ -XXX,XX +XXX,XX @@ restart:
638
*/
639
qemu_bh_schedule(pool->completion_bh);
640
641
+ aio_context_release(pool->ctx);
642
elem->common.cb(elem->common.opaque, elem->ret);
643
+ aio_context_acquire(pool->ctx);
644
qemu_aio_unref(elem);
645
goto restart;
646
} else {
647
@@ -XXX,XX +XXX,XX @@ static void thread_pool_co_cb(void *opaque, int ret)
648
ThreadPoolCo *co = opaque;
649
650
co->ret = ret;
651
- qemu_coroutine_enter(co->co);
652
+ aio_co_wake(co->co);
653
}
654
655
int coroutine_fn thread_pool_submit_co(ThreadPool *pool, ThreadPoolFunc *func,
79
--
656
--
80
2.34.1
657
2.9.3
81
658
82
659
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
We are going to support some addition IMGOPTS in python iotests like
3
This patch prepares for the removal of unnecessary lockcnt inc/dec pairs.
4
in bash iotests. Similarly to bash iotests, we want a way to skip some
4
Extract the dispatching loop for file descriptor handlers into a new
5
tests which can't work with specific IMGOPTS.
5
function aio_dispatch_handlers, and then inline aio_dispatch into
6
aio_poll.
6
7
7
Globally for python iotests we will not support things like
8
aio_dispatch can now become void.
8
'data_file=$TEST_IMG.ext_data_file' in IMGOPTS, so, forbid this
9
globally in iotests.py.
10
9
11
Suggested-by: Hanna Reitz <hreitz@redhat.com>
10
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
13
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
12
Reviewed-by: Fam Zheng <famz@redhat.com>
14
Message-Id: <20211223160144.1097696-3-vsementsov@virtuozzo.com>
13
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
15
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
14
Message-id: 20170213135235.12274-17-pbonzini@redhat.com
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
16
---
16
---
17
tests/qemu-iotests/iotests.py | 15 ++++++++++++++-
17
include/block/aio.h | 6 +-----
18
1 file changed, 14 insertions(+), 1 deletion(-)
18
util/aio-posix.c | 44 ++++++++++++++------------------------------
19
util/aio-win32.c | 13 ++++---------
20
util/async.c | 2 +-
21
4 files changed, 20 insertions(+), 45 deletions(-)
19
22
20
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
23
diff --git a/include/block/aio.h b/include/block/aio.h
21
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
22
--- a/tests/qemu-iotests/iotests.py
25
--- a/include/block/aio.h
23
+++ b/tests/qemu-iotests/iotests.py
26
+++ b/include/block/aio.h
24
@@ -XXX,XX +XXX,XX @@ def _verify_virtio_scsi_pci_or_ccw() -> None:
27
@@ -XXX,XX +XXX,XX @@ bool aio_pending(AioContext *ctx);
25
notrun('Missing virtio-scsi-pci or virtio-scsi-ccw in QEMU binary')
28
/* Dispatch any pending callbacks from the GSource attached to the AioContext.
26
29
*
27
30
* This is used internally in the implementation of the GSource.
28
+def _verify_imgopts(unsupported: Sequence[str] = ()) -> None:
31
- *
29
+ imgopts = os.environ.get('IMGOPTS')
32
- * @dispatch_fds: true to process fds, false to skip them
30
+ # One of usage examples for IMGOPTS is "data_file=$TEST_IMG.ext_data_file"
33
- * (can be used as an optimization by callers that know there
31
+ # but it supported only for bash tests. We don't have a concept of global
34
- * are no fds ready)
32
+ # TEST_IMG in iotests.py, not saying about somehow parsing $variables.
35
*/
33
+ # So, for simplicity let's just not support any IMGOPTS with '$' inside.
36
-bool aio_dispatch(AioContext *ctx, bool dispatch_fds);
34
+ unsup = list(unsupported) + ['$']
37
+void aio_dispatch(AioContext *ctx);
35
+ if imgopts and any(x in imgopts for x in unsup):
38
36
+ notrun(f'not suitable for this imgopts: {imgopts}')
39
/* Progress in completing AIO work to occur. This can issue new pending
40
* aio as a result of executing I/O completion or bh callbacks.
41
diff --git a/util/aio-posix.c b/util/aio-posix.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/util/aio-posix.c
44
+++ b/util/aio-posix.c
45
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx)
46
AioHandler *node, *tmp;
47
bool progress = false;
48
49
- /*
50
- * We have to walk very carefully in case aio_set_fd_handler is
51
- * called while we're walking.
52
- */
53
- qemu_lockcnt_inc(&ctx->list_lock);
54
-
55
QLIST_FOREACH_SAFE_RCU(node, &ctx->aio_handlers, node, tmp) {
56
int revents;
57
58
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx)
59
}
60
}
61
62
- qemu_lockcnt_dec(&ctx->list_lock);
63
return progress;
64
}
65
66
-/*
67
- * Note that dispatch_fds == false has the side-effect of post-poning the
68
- * freeing of deleted handlers.
69
- */
70
-bool aio_dispatch(AioContext *ctx, bool dispatch_fds)
71
+void aio_dispatch(AioContext *ctx)
72
{
73
- bool progress;
74
+ aio_bh_poll(ctx);
75
76
- /*
77
- * If there are callbacks left that have been queued, we need to call them.
78
- * Do not call select in this case, because it is possible that the caller
79
- * does not need a complete flush (as is the case for aio_poll loops).
80
- */
81
- progress = aio_bh_poll(ctx);
82
+ qemu_lockcnt_inc(&ctx->list_lock);
83
+ aio_dispatch_handlers(ctx);
84
+ qemu_lockcnt_dec(&ctx->list_lock);
85
86
- if (dispatch_fds) {
87
- progress |= aio_dispatch_handlers(ctx);
88
- }
89
-
90
- /* Run our timers */
91
- progress |= timerlistgroup_run_timers(&ctx->tlg);
92
-
93
- return progress;
94
+ timerlistgroup_run_timers(&ctx->tlg);
95
}
96
97
/* These thread-local variables are used only in a small part of aio_poll
98
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
99
npfd = 0;
100
qemu_lockcnt_dec(&ctx->list_lock);
101
102
- /* Run dispatch even if there were no readable fds to run timers */
103
- if (aio_dispatch(ctx, ret > 0)) {
104
- progress = true;
105
+ progress |= aio_bh_poll(ctx);
37
+
106
+
107
+ if (ret > 0) {
108
+ qemu_lockcnt_inc(&ctx->list_lock);
109
+ progress |= aio_dispatch_handlers(ctx);
110
+ qemu_lockcnt_dec(&ctx->list_lock);
111
}
112
113
+ progress |= timerlistgroup_run_timers(&ctx->tlg);
38
+
114
+
39
def supports_quorum():
115
return progress;
40
return 'quorum' in qemu_img_pipe('--help')
116
}
41
117
42
@@ -XXX,XX +XXX,XX @@ def execute_setup_common(supported_fmts: Sequence[str] = (),
118
diff --git a/util/aio-win32.c b/util/aio-win32.c
43
unsupported_fmts: Sequence[str] = (),
119
index XXXXXXX..XXXXXXX 100644
44
supported_protocols: Sequence[str] = (),
120
--- a/util/aio-win32.c
45
unsupported_protocols: Sequence[str] = (),
121
+++ b/util/aio-win32.c
46
- required_fmts: Sequence[str] = ()) -> bool:
122
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event)
47
+ required_fmts: Sequence[str] = (),
123
return progress;
48
+ unsupported_imgopts: Sequence[str] = ()) -> bool:
124
}
49
"""
125
50
Perform necessary setup for either script-style or unittest-style tests.
126
-bool aio_dispatch(AioContext *ctx, bool dispatch_fds)
51
127
+void aio_dispatch(AioContext *ctx)
52
@@ -XXX,XX +XXX,XX @@ def execute_setup_common(supported_fmts: Sequence[str] = (),
128
{
53
_verify_aio_mode(supported_aio_modes)
129
- bool progress;
54
_verify_formats(required_fmts)
130
-
55
_verify_virtio_blk()
131
- progress = aio_bh_poll(ctx);
56
+ _verify_imgopts(unsupported_imgopts)
132
- if (dispatch_fds) {
57
133
- progress |= aio_dispatch_handlers(ctx, INVALID_HANDLE_VALUE);
58
return debug
134
- }
135
- progress |= timerlistgroup_run_timers(&ctx->tlg);
136
- return progress;
137
+ aio_bh_poll(ctx);
138
+ aio_dispatch_handlers(ctx, INVALID_HANDLE_VALUE);
139
+ timerlistgroup_run_timers(&ctx->tlg);
140
}
141
142
bool aio_poll(AioContext *ctx, bool blocking)
143
diff --git a/util/async.c b/util/async.c
144
index XXXXXXX..XXXXXXX 100644
145
--- a/util/async.c
146
+++ b/util/async.c
147
@@ -XXX,XX +XXX,XX @@ aio_ctx_dispatch(GSource *source,
148
AioContext *ctx = (AioContext *) source;
149
150
assert(callback == NULL);
151
- aio_dispatch(ctx, true);
152
+ aio_dispatch(ctx);
153
return true;
154
}
59
155
60
--
156
--
61
2.34.1
157
2.9.3
62
158
63
159
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
If image doesn't have any compressed cluster we can easily switch to
3
Pull the increment/decrement pair out of aio_bh_poll and into the
4
zlib compression, which may allow to downgrade the image.
4
callers.
5
5
6
That's mostly needed to support IMGOPTS='compression_type=zstd' in some
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
iotests which do qcow2 downgrade.
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Reviewed-by: Fam Zheng <famz@redhat.com>
9
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
10
Message-id: 20170213135235.12274-18-pbonzini@redhat.com
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
13
util/aio-posix.c | 8 +++-----
14
util/aio-win32.c | 8 ++++----
15
util/async.c | 12 ++++++------
16
3 files changed, 13 insertions(+), 15 deletions(-)
8
17
9
While being here also fix checkpatch complain against '#' in printf
18
diff --git a/util/aio-posix.c b/util/aio-posix.c
10
formatting.
11
12
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
14
Message-Id: <20211223160144.1097696-13-vsementsov@virtuozzo.com>
15
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
16
---
17
block/qcow2.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++--
18
1 file changed, 56 insertions(+), 2 deletions(-)
19
20
diff --git a/block/qcow2.c b/block/qcow2.c
21
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
22
--- a/block/qcow2.c
20
--- a/util/aio-posix.c
23
+++ b/block/qcow2.c
21
+++ b/util/aio-posix.c
24
@@ -XXX,XX +XXX,XX @@ static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
22
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx)
25
return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0);
23
24
void aio_dispatch(AioContext *ctx)
25
{
26
+ qemu_lockcnt_inc(&ctx->list_lock);
27
aio_bh_poll(ctx);
28
-
29
- qemu_lockcnt_inc(&ctx->list_lock);
30
aio_dispatch_handlers(ctx);
31
qemu_lockcnt_dec(&ctx->list_lock);
32
33
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
34
}
35
36
npfd = 0;
37
- qemu_lockcnt_dec(&ctx->list_lock);
38
39
progress |= aio_bh_poll(ctx);
40
41
if (ret > 0) {
42
- qemu_lockcnt_inc(&ctx->list_lock);
43
progress |= aio_dispatch_handlers(ctx);
44
- qemu_lockcnt_dec(&ctx->list_lock);
45
}
46
47
+ qemu_lockcnt_dec(&ctx->list_lock);
48
+
49
progress |= timerlistgroup_run_timers(&ctx->tlg);
50
51
return progress;
52
diff --git a/util/aio-win32.c b/util/aio-win32.c
53
index XXXXXXX..XXXXXXX 100644
54
--- a/util/aio-win32.c
55
+++ b/util/aio-win32.c
56
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event)
57
bool progress = false;
58
AioHandler *tmp;
59
60
- qemu_lockcnt_inc(&ctx->list_lock);
61
-
62
/*
63
* We have to walk very carefully in case aio_set_fd_handler is
64
* called while we're walking.
65
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handlers(AioContext *ctx, HANDLE event)
66
}
67
}
68
69
- qemu_lockcnt_dec(&ctx->list_lock);
70
return progress;
26
}
71
}
27
72
28
+static int qcow2_has_compressed_clusters(BlockDriverState *bs)
73
void aio_dispatch(AioContext *ctx)
29
+{
74
{
30
+ int64_t offset = 0;
75
+ qemu_lockcnt_inc(&ctx->list_lock);
31
+ int64_t bytes = bdrv_getlength(bs);
76
aio_bh_poll(ctx);
77
aio_dispatch_handlers(ctx, INVALID_HANDLE_VALUE);
78
+ qemu_lockcnt_dec(&ctx->list_lock);
79
timerlistgroup_run_timers(&ctx->tlg);
80
}
81
82
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
83
}
84
}
85
86
- qemu_lockcnt_dec(&ctx->list_lock);
87
first = true;
88
89
/* ctx->notifier is always registered. */
90
@@ -XXX,XX +XXX,XX @@ bool aio_poll(AioContext *ctx, bool blocking)
91
progress |= aio_dispatch_handlers(ctx, event);
92
} while (count > 0);
93
94
+ qemu_lockcnt_dec(&ctx->list_lock);
32
+
95
+
33
+ if (bytes < 0) {
96
progress |= timerlistgroup_run_timers(&ctx->tlg);
34
+ return bytes;
97
return progress;
35
+ }
98
}
36
+
99
diff --git a/util/async.c b/util/async.c
37
+ while (bytes != 0) {
100
index XXXXXXX..XXXXXXX 100644
38
+ int ret;
101
--- a/util/async.c
39
+ QCow2SubclusterType type;
102
+++ b/util/async.c
40
+ unsigned int cur_bytes = MIN(INT_MAX, bytes);
103
@@ -XXX,XX +XXX,XX @@ void aio_bh_call(QEMUBH *bh)
41
+ uint64_t host_offset;
104
bh->cb(bh->opaque);
42
+
105
}
43
+ ret = qcow2_get_host_offset(bs, offset, &cur_bytes, &host_offset,
106
44
+ &type);
107
-/* Multiple occurrences of aio_bh_poll cannot be called concurrently */
45
+ if (ret < 0) {
108
+/* Multiple occurrences of aio_bh_poll cannot be called concurrently.
46
+ return ret;
109
+ * The count in ctx->list_lock is incremented before the call, and is
47
+ }
110
+ * not affected by the call.
48
+
111
+ */
49
+ if (type == QCOW2_SUBCLUSTER_COMPRESSED) {
112
int aio_bh_poll(AioContext *ctx)
50
+ return 1;
113
{
51
+ }
114
QEMUBH *bh, **bhp, *next;
52
+
115
int ret;
53
+ offset += cur_bytes;
116
bool deleted = false;
54
+ bytes -= cur_bytes;
117
55
+ }
118
- qemu_lockcnt_inc(&ctx->list_lock);
56
+
119
-
57
+ return 0;
120
ret = 0;
58
+}
121
for (bh = atomic_rcu_read(&ctx->first_bh); bh; bh = next) {
59
+
122
next = atomic_rcu_read(&bh->next);
60
/*
123
@@ -XXX,XX +XXX,XX @@ int aio_bh_poll(AioContext *ctx)
61
* Downgrades an image's version. To achieve this, any incompatible features
124
62
* have to be removed.
125
/* remove deleted bhs */
63
@@ -XXX,XX +XXX,XX @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
126
if (!deleted) {
64
* the first place; if that happens nonetheless, returning -ENOTSUP is the
127
- qemu_lockcnt_dec(&ctx->list_lock);
65
* best thing to do anyway */
66
67
- if (s->incompatible_features) {
68
+ if (s->incompatible_features & ~QCOW2_INCOMPAT_COMPRESSION) {
69
error_setg(errp, "Cannot downgrade an image with incompatible features "
70
- "%#" PRIx64 " set", s->incompatible_features);
71
+ "0x%" PRIx64 " set",
72
+ s->incompatible_features & ~QCOW2_INCOMPAT_COMPRESSION);
73
return -ENOTSUP;
74
}
75
76
@@ -XXX,XX +XXX,XX @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
77
return ret;
128
return ret;
78
}
129
}
79
130
80
+ if (s->incompatible_features & QCOW2_INCOMPAT_COMPRESSION) {
131
- if (qemu_lockcnt_dec_and_lock(&ctx->list_lock)) {
81
+ ret = qcow2_has_compressed_clusters(bs);
132
+ if (qemu_lockcnt_dec_if_lock(&ctx->list_lock)) {
82
+ if (ret < 0) {
133
bhp = &ctx->first_bh;
83
+ error_setg(errp, "Failed to check block status");
134
while (*bhp) {
84
+ return -EINVAL;
135
bh = *bhp;
85
+ }
136
@@ -XXX,XX +XXX,XX @@ int aio_bh_poll(AioContext *ctx)
86
+ if (ret) {
137
bhp = &bh->next;
87
+ error_setg(errp, "Cannot downgrade an image with zstd compression "
138
}
88
+ "type and existing compressed clusters");
139
}
89
+ return -ENOTSUP;
140
- qemu_lockcnt_unlock(&ctx->list_lock);
90
+ }
141
+ qemu_lockcnt_inc_and_unlock(&ctx->list_lock);
91
+ /*
142
}
92
+ * No compressed clusters for now, so just chose default zlib
143
return ret;
93
+ * compression.
144
}
94
+ */
95
+ s->incompatible_features &= ~QCOW2_INCOMPAT_COMPRESSION;
96
+ s->compression_type = QCOW2_COMPRESSION_TYPE_ZLIB;
97
+ }
98
+
99
+ assert(s->incompatible_features == 0);
100
+
101
s->qcow_version = target_version;
102
ret = qcow2_update_header(bs);
103
if (ret < 0) {
104
--
145
--
105
2.34.1
146
2.9.3
106
147
107
148
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Adding support of IMGOPTS (like in bash tests) allows user to pass a
3
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
lot of different options. Still, some may require additional logic.
4
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
5
Reviewed-by: Fam Zheng <famz@redhat.com>
6
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
7
Message-id: 20170213135235.12274-19-pbonzini@redhat.com
8
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
10
include/block/block_int.h | 64 +++++++++++++++++++++++++-----------------
11
include/sysemu/block-backend.h | 14 ++++++---
12
2 files changed, 49 insertions(+), 29 deletions(-)
5
13
6
Now we want compression_type option, so add some smart logic around it:
14
diff --git a/include/block/block_int.h b/include/block/block_int.h
7
ignore compression_type=zstd in IMGOPTS, if test want qcow2 in
8
compatibility mode. As well, ignore compression_type for non-qcow2
9
formats.
10
11
Note that we may instead add support only to qemu_img_create(), but
12
that works bad:
13
14
1. We'll have to update a lot of tests to use qemu_img_create instead
15
of qemu_img('create'). (still, we may want do it anyway, but no
16
reason to create a dependancy between task of supporting IMGOPTS and
17
updating a lot of tests)
18
19
2. Some tests use qemu_img_pipe('create', ..) - even more work on
20
updating
21
22
3. Even if we update all tests to go through qemu_img_create, we'll
23
need a way to avoid creating new tests using qemu_img*('create') -
24
add assertions.. That doesn't seem good.
25
26
So, let's add support of IMGOPTS to most generic
27
qemu_img_pipe_and_status().
28
29
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
30
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
31
Message-Id: <20211223160144.1097696-5-vsementsov@virtuozzo.com>
32
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
33
---
34
tests/qemu-iotests/iotests.py | 27 ++++++++++++++++++++++++++-
35
1 file changed, 26 insertions(+), 1 deletion(-)
36
37
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
38
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
39
--- a/tests/qemu-iotests/iotests.py
16
--- a/include/block/block_int.h
40
+++ b/tests/qemu-iotests/iotests.py
17
+++ b/include/block/block_int.h
41
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ struct BdrvChild {
42
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
* copied as well.
43
#
20
*/
44
21
struct BlockDriverState {
45
+import argparse
22
- int64_t total_sectors; /* if we are reading a disk image, give its
46
import atexit
23
- size in sectors */
47
import bz2
24
+ /* Protected by big QEMU lock or read-only after opening. No special
48
from collections import OrderedDict
25
+ * locking needed during I/O...
49
@@ -XXX,XX +XXX,XX @@ def qemu_tool_pipe_and_status(tool: str, args: Sequence[str],
26
+ */
50
{-subp.returncode}: {cmd}\n')
27
int open_flags; /* flags used to open the file, re-used for re-open */
51
return (output, subp.returncode)
28
bool read_only; /* if true, the media is read only */
52
29
bool encrypted; /* if true, the media is encrypted */
53
+def qemu_img_create_prepare_args(args: List[str]) -> List[str]:
30
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
54
+ if not args or args[0] != 'create':
31
bool sg; /* if true, the device is a /dev/sg* */
55
+ return list(args)
32
bool probed; /* if true, format was probed rather than specified */
56
+ args = args[1:]
33
34
- int copy_on_read; /* if nonzero, copy read backing sectors into image.
35
- note this is a reference count */
36
-
37
- CoQueue flush_queue; /* Serializing flush queue */
38
- bool active_flush_req; /* Flush request in flight? */
39
- unsigned int write_gen; /* Current data generation */
40
- unsigned int flushed_gen; /* Flushed write generation */
41
-
42
BlockDriver *drv; /* NULL means no media */
43
void *opaque;
44
45
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
46
BdrvChild *backing;
47
BdrvChild *file;
48
49
- /* Callback before write request is processed */
50
- NotifierWithReturnList before_write_notifiers;
51
-
52
- /* number of in-flight requests; overall and serialising */
53
- unsigned int in_flight;
54
- unsigned int serialising_in_flight;
55
-
56
- bool wakeup;
57
-
58
- /* Offset after the highest byte written to */
59
- uint64_t wr_highest_offset;
60
-
61
/* I/O Limits */
62
BlockLimits bl;
63
64
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
65
QTAILQ_ENTRY(BlockDriverState) bs_list;
66
/* element of the list of monitor-owned BDS */
67
QTAILQ_ENTRY(BlockDriverState) monitor_list;
68
- QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps;
69
int refcnt;
70
71
- QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
72
-
73
/* operation blockers */
74
QLIST_HEAD(, BdrvOpBlocker) op_blockers[BLOCK_OP_TYPE_MAX];
75
76
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
77
/* The error object in use for blocking operations on backing_hd */
78
Error *backing_blocker;
79
80
+ /* Protected by AioContext lock */
57
+
81
+
58
+ p = argparse.ArgumentParser(allow_abbrev=False)
82
+ /* If true, copy read backing sectors into image. Can be >1 if more
59
+ p.add_argument('-f')
83
+ * than one client has requested copy-on-read.
60
+ parsed, remaining = p.parse_known_args(args)
84
+ */
85
+ int copy_on_read;
61
+
86
+
62
+ result = ['create']
87
+ /* If we are reading a disk image, give its size in sectors.
63
+ if parsed.f is not None:
88
+ * Generally read-only; it is written to by load_vmstate and save_vmstate,
64
+ result += ['-f', parsed.f]
89
+ * but the block layer is quiescent during those.
90
+ */
91
+ int64_t total_sectors;
65
+
92
+
66
+ # IMGOPTS most probably contain options specific for the selected format,
93
+ /* Callback before write request is processed */
67
+ # like extended_l2 or compression_type for qcow2. Test may want to create
94
+ NotifierWithReturnList before_write_notifiers;
68
+ # additional images in other formats that doesn't support these options.
69
+ # So, use IMGOPTS only for images created in imgfmt format.
70
+ if parsed.f == imgfmt and 'IMGOPTS' in os.environ:
71
+ result += ['-o', os.environ['IMGOPTS']]
72
+
95
+
73
+ result += remaining
96
+ /* number of in-flight requests; overall and serialising */
97
+ unsigned int in_flight;
98
+ unsigned int serialising_in_flight;
74
+
99
+
75
+ return result
100
+ bool wakeup;
76
+
101
+
77
def qemu_img_pipe_and_status(*args: str) -> Tuple[str, int]:
102
+ /* Offset after the highest byte written to */
78
"""
103
+ uint64_t wr_highest_offset;
79
Run qemu-img and return both its output and its exit code
104
+
80
"""
105
/* threshold limit for writes, in bytes. "High water mark". */
81
- full_args = qemu_img_args + list(args)
106
uint64_t write_threshold_offset;
82
+ full_args = qemu_img_args + qemu_img_create_prepare_args(list(args))
107
NotifierWithReturn write_threshold_notifier;
83
return qemu_tool_pipe_and_status('qemu-img', full_args)
108
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
84
109
/* counter for nested bdrv_io_plug */
85
def qemu_img(*args: str) -> int:
110
unsigned io_plugged;
111
112
+ QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
113
+ CoQueue flush_queue; /* Serializing flush queue */
114
+ bool active_flush_req; /* Flush request in flight? */
115
+ unsigned int write_gen; /* Current data generation */
116
+ unsigned int flushed_gen; /* Flushed write generation */
117
+
118
+ QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps;
119
+
120
+ /* do we need to tell the quest if we have a volatile write cache? */
121
+ int enable_write_cache;
122
+
123
int quiesce_counter;
124
};
125
126
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
127
index XXXXXXX..XXXXXXX 100644
128
--- a/include/sysemu/block-backend.h
129
+++ b/include/sysemu/block-backend.h
130
@@ -XXX,XX +XXX,XX @@ typedef struct BlockDevOps {
131
* fields that must be public. This is in particular for QLIST_ENTRY() and
132
* friends so that BlockBackends can be kept in lists outside block-backend.c */
133
typedef struct BlockBackendPublic {
134
- /* I/O throttling.
135
- * throttle_state tells us if this BlockBackend has I/O limits configured.
136
- * io_limits_disabled tells us if they are currently being enforced */
137
+ /* I/O throttling has its own locking, but also some fields are
138
+ * protected by the AioContext lock.
139
+ */
140
+
141
+ /* Protected by AioContext lock. */
142
CoQueue throttled_reqs[2];
143
+
144
+ /* Nonzero if the I/O limits are currently being ignored; generally
145
+ * it is zero. */
146
unsigned int io_limits_disabled;
147
148
/* The following fields are protected by the ThrottleGroup lock.
149
- * See the ThrottleGroup documentation for details. */
150
+ * See the ThrottleGroup documentation for details.
151
+ * throttle_state tells us if I/O limits are configured. */
152
ThrottleState *throttle_state;
153
ThrottleTimers throttle_timers;
154
unsigned pending_reqs[2];
86
--
155
--
87
2.34.1
156
2.9.3
88
157
89
158
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
We are going to support IMGOPTS for python iotests. Still some iotests
3
This uses the lock-free mutex described in the paper '"Blocking without
4
will not work with common IMGOPTS used with bash iotests like
4
Locking", or LFTHREADS: A lock-free thread library' by Gidenstam and
5
specifying refcount_bits and compat qcow2 options. So we
5
Papatriantafilou. The same technique is used in OSv, and in fact
6
should define corresponding unsupported_imgopts for now.
6
the code is essentially a conversion to C of OSv's code.
7
7
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
[Added missing coroutine_fn in tests/test-aio-multithread.c.
9
Message-Id: <20211223160144.1097696-4-vsementsov@virtuozzo.com>
9
--Stefan]
10
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
10
11
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
12
Reviewed-by: Fam Zheng <famz@redhat.com>
13
Message-id: 20170213181244.16297-2-pbonzini@redhat.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
15
---
12
tests/qemu-iotests/044 | 3 ++-
16
include/qemu/coroutine.h | 17 ++++-
13
tests/qemu-iotests/065 | 3 ++-
17
tests/test-aio-multithread.c | 86 ++++++++++++++++++++++++
14
tests/qemu-iotests/163 | 3 ++-
18
util/qemu-coroutine-lock.c | 155 ++++++++++++++++++++++++++++++++++++++++---
15
tests/qemu-iotests/165 | 3 ++-
19
util/trace-events | 1 +
16
tests/qemu-iotests/196 | 3 ++-
20
4 files changed, 246 insertions(+), 13 deletions(-)
17
tests/qemu-iotests/242 | 3 ++-
21
18
tests/qemu-iotests/246 | 3 ++-
22
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
19
tests/qemu-iotests/254 | 3 ++-
23
index XXXXXXX..XXXXXXX 100644
20
tests/qemu-iotests/260 | 3 ++-
24
--- a/include/qemu/coroutine.h
21
tests/qemu-iotests/274 | 3 ++-
25
+++ b/include/qemu/coroutine.h
22
tests/qemu-iotests/281 | 3 ++-
26
@@ -XXX,XX +XXX,XX @@ bool qemu_co_queue_empty(CoQueue *queue);
23
tests/qemu-iotests/303 | 3 ++-
27
/**
24
tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test | 3 ++-
28
* Provides a mutex that can be used to synchronise coroutines
25
tests/qemu-iotests/tests/migrate-bitmaps-test | 3 ++-
29
*/
26
tests/qemu-iotests/tests/remove-bitmap-from-backing | 3 ++-
30
+struct CoWaitRecord;
27
15 files changed, 30 insertions(+), 15 deletions(-)
31
typedef struct CoMutex {
28
32
- bool locked;
29
diff --git a/tests/qemu-iotests/044 b/tests/qemu-iotests/044
33
+ /* Count of pending lockers; 0 for a free mutex, 1 for an
30
index XXXXXXX..XXXXXXX 100755
34
+ * uncontended mutex.
31
--- a/tests/qemu-iotests/044
35
+ */
32
+++ b/tests/qemu-iotests/044
36
+ unsigned locked;
33
@@ -XXX,XX +XXX,XX @@ class TestRefcountTableGrowth(iotests.QMPTestCase):
37
+
34
38
+ /* A queue of waiters. Elements are added atomically in front of
35
if __name__ == '__main__':
39
+ * from_push. to_pop is only populated, and popped from, by whoever
36
iotests.main(supported_fmts=['qcow2'],
40
+ * is in charge of the next wakeup. This can be an unlocker or,
37
- supported_protocols=['file'])
41
+ * through the handoff protocol, a locker that is about to go to sleep.
38
+ supported_protocols=['file'],
42
+ */
39
+ unsupported_imgopts=['refcount_bits'])
43
+ QSLIST_HEAD(, CoWaitRecord) from_push, to_pop;
40
diff --git a/tests/qemu-iotests/065 b/tests/qemu-iotests/065
44
+
41
index XXXXXXX..XXXXXXX 100755
45
+ unsigned handoff, sequence;
42
--- a/tests/qemu-iotests/065
46
+
43
+++ b/tests/qemu-iotests/065
47
Coroutine *holder;
44
@@ -XXX,XX +XXX,XX @@ TestQMP = None
48
- CoQueue queue;
45
49
} CoMutex;
46
if __name__ == '__main__':
50
47
iotests.main(supported_fmts=['qcow2'],
51
/**
48
- supported_protocols=['file'])
52
diff --git a/tests/test-aio-multithread.c b/tests/test-aio-multithread.c
49
+ supported_protocols=['file'],
53
index XXXXXXX..XXXXXXX 100644
50
+ unsupported_imgopts=['refcount_bits'])
54
--- a/tests/test-aio-multithread.c
51
diff --git a/tests/qemu-iotests/163 b/tests/qemu-iotests/163
55
+++ b/tests/test-aio-multithread.c
52
index XXXXXXX..XXXXXXX 100755
56
@@ -XXX,XX +XXX,XX @@ static void test_multi_co_schedule_10(void)
53
--- a/tests/qemu-iotests/163
57
test_multi_co_schedule(10);
54
+++ b/tests/qemu-iotests/163
58
}
55
@@ -XXX,XX +XXX,XX @@ ShrinkBaseClass = None
59
56
60
+/* CoMutex thread-safety. */
57
if __name__ == '__main__':
61
+
58
iotests.main(supported_fmts=['raw', 'qcow2'],
62
+static uint32_t atomic_counter;
59
- supported_protocols=['file'])
63
+static uint32_t running;
60
+ supported_protocols=['file'],
64
+static uint32_t counter;
61
+ unsupported_imgopts=['compat'])
65
+static CoMutex comutex;
62
diff --git a/tests/qemu-iotests/165 b/tests/qemu-iotests/165
66
+
63
index XXXXXXX..XXXXXXX 100755
67
+static void coroutine_fn test_multi_co_mutex_entry(void *opaque)
64
--- a/tests/qemu-iotests/165
68
+{
65
+++ b/tests/qemu-iotests/165
69
+ while (!atomic_mb_read(&now_stopping)) {
66
@@ -XXX,XX +XXX,XX @@ class TestPersistentDirtyBitmap(iotests.QMPTestCase):
70
+ qemu_co_mutex_lock(&comutex);
67
71
+ counter++;
68
if __name__ == '__main__':
72
+ qemu_co_mutex_unlock(&comutex);
69
iotests.main(supported_fmts=['qcow2'],
73
+
70
- supported_protocols=['file'])
74
+ /* Increase atomic_counter *after* releasing the mutex. Otherwise
71
+ supported_protocols=['file'],
75
+ * there is a chance (it happens about 1 in 3 runs) that the iothread
72
+ unsupported_imgopts=['compat'])
76
+ * exits before the coroutine is woken up, causing a spurious
73
diff --git a/tests/qemu-iotests/196 b/tests/qemu-iotests/196
77
+ * assertion failure.
74
index XXXXXXX..XXXXXXX 100755
78
+ */
75
--- a/tests/qemu-iotests/196
79
+ atomic_inc(&atomic_counter);
76
+++ b/tests/qemu-iotests/196
80
+ }
77
@@ -XXX,XX +XXX,XX @@ class TestInvalidateAutoclear(iotests.QMPTestCase):
81
+ atomic_dec(&running);
78
82
+}
79
if __name__ == '__main__':
83
+
80
iotests.main(supported_fmts=['qcow2'],
84
+static void test_multi_co_mutex(int threads, int seconds)
81
- supported_protocols=['file'])
85
+{
82
+ supported_protocols=['file'],
86
+ int i;
83
+ unsupported_imgopts=['compat'])
87
+
84
diff --git a/tests/qemu-iotests/242 b/tests/qemu-iotests/242
88
+ qemu_co_mutex_init(&comutex);
85
index XXXXXXX..XXXXXXX 100755
89
+ counter = 0;
86
--- a/tests/qemu-iotests/242
90
+ atomic_counter = 0;
87
+++ b/tests/qemu-iotests/242
91
+ now_stopping = false;
88
@@ -XXX,XX +XXX,XX @@ from iotests import qemu_img_create, qemu_io, qemu_img_pipe, \
92
+
89
file_path, img_info_log, log, filter_qemu_io
93
+ create_aio_contexts();
90
94
+ assert(threads <= NUM_CONTEXTS);
91
iotests.script_initialize(supported_fmts=['qcow2'],
95
+ running = threads;
92
- supported_protocols=['file'])
96
+ for (i = 0; i < threads; i++) {
93
+ supported_protocols=['file'],
97
+ Coroutine *co1 = qemu_coroutine_create(test_multi_co_mutex_entry, NULL);
94
+ unsupported_imgopts=['refcount_bits', 'compat'])
98
+ aio_co_schedule(ctx[i], co1);
95
99
+ }
96
disk = file_path('disk')
100
+
97
chunk = 256 * 1024
101
+ g_usleep(seconds * 1000000);
98
diff --git a/tests/qemu-iotests/246 b/tests/qemu-iotests/246
102
+
99
index XXXXXXX..XXXXXXX 100755
103
+ atomic_mb_set(&now_stopping, true);
100
--- a/tests/qemu-iotests/246
104
+ while (running > 0) {
101
+++ b/tests/qemu-iotests/246
105
+ g_usleep(100000);
106
+ }
107
+
108
+ join_aio_contexts();
109
+ g_test_message("%d iterations/second\n", counter / seconds);
110
+ g_assert_cmpint(counter, ==, atomic_counter);
111
+}
112
+
113
+/* Testing with NUM_CONTEXTS threads focuses on the queue. The mutex however
114
+ * is too contended (and the threads spend too much time in aio_poll)
115
+ * to actually stress the handoff protocol.
116
+ */
117
+static void test_multi_co_mutex_1(void)
118
+{
119
+ test_multi_co_mutex(NUM_CONTEXTS, 1);
120
+}
121
+
122
+static void test_multi_co_mutex_10(void)
123
+{
124
+ test_multi_co_mutex(NUM_CONTEXTS, 10);
125
+}
126
+
127
+/* Testing with fewer threads stresses the handoff protocol too. Still, the
128
+ * case where the locker _can_ pick up a handoff is very rare, happening
129
+ * about 10 times in 1 million, so increase the runtime a bit compared to
130
+ * other "quick" testcases that only run for 1 second.
131
+ */
132
+static void test_multi_co_mutex_2_3(void)
133
+{
134
+ test_multi_co_mutex(2, 3);
135
+}
136
+
137
+static void test_multi_co_mutex_2_30(void)
138
+{
139
+ test_multi_co_mutex(2, 30);
140
+}
141
+
142
/* End of tests. */
143
144
int main(int argc, char **argv)
145
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
146
g_test_add_func("/aio/multi/lifecycle", test_lifecycle);
147
if (g_test_quick()) {
148
g_test_add_func("/aio/multi/schedule", test_multi_co_schedule_1);
149
+ g_test_add_func("/aio/multi/mutex/contended", test_multi_co_mutex_1);
150
+ g_test_add_func("/aio/multi/mutex/handoff", test_multi_co_mutex_2_3);
151
} else {
152
g_test_add_func("/aio/multi/schedule", test_multi_co_schedule_10);
153
+ g_test_add_func("/aio/multi/mutex/contended", test_multi_co_mutex_10);
154
+ g_test_add_func("/aio/multi/mutex/handoff", test_multi_co_mutex_2_30);
155
}
156
return g_test_run();
157
}
158
diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c
159
index XXXXXXX..XXXXXXX 100644
160
--- a/util/qemu-coroutine-lock.c
161
+++ b/util/qemu-coroutine-lock.c
102
@@ -XXX,XX +XXX,XX @@
162
@@ -XXX,XX +XXX,XX @@
103
import iotests
163
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
104
from iotests import log
164
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
105
165
* THE SOFTWARE.
106
-iotests.script_initialize(supported_fmts=['qcow2'])
166
+ *
107
+iotests.script_initialize(supported_fmts=['qcow2'],
167
+ * The lock-free mutex implementation is based on OSv
108
+ unsupported_imgopts=['compat'])
168
+ * (core/lfmutex.cc, include/lockfree/mutex.hh).
109
size = 64 * 1024 * 1024 * 1024
169
+ * Copyright (C) 2013 Cloudius Systems, Ltd.
110
gran_small = 32 * 1024
170
*/
111
gran_large = 128 * 1024
171
112
diff --git a/tests/qemu-iotests/254 b/tests/qemu-iotests/254
172
#include "qemu/osdep.h"
113
index XXXXXXX..XXXXXXX 100755
173
@@ -XXX,XX +XXX,XX @@ bool qemu_co_queue_empty(CoQueue *queue)
114
--- a/tests/qemu-iotests/254
174
return QSIMPLEQ_FIRST(&queue->entries) == NULL;
115
+++ b/tests/qemu-iotests/254
175
}
116
@@ -XXX,XX +XXX,XX @@
176
117
import iotests
177
+/* The wait records are handled with a multiple-producer, single-consumer
118
from iotests import qemu_img_create, file_path, log
178
+ * lock-free queue. There cannot be two concurrent pop_waiter() calls
119
179
+ * because pop_waiter() can only be called while mutex->handoff is zero.
120
-iotests.script_initialize(supported_fmts=['qcow2'])
180
+ * This can happen in three cases:
121
+iotests.script_initialize(supported_fmts=['qcow2'],
181
+ * - in qemu_co_mutex_unlock, before the hand-off protocol has started.
122
+ unsupported_imgopts=['compat'])
182
+ * In this case, qemu_co_mutex_lock will see mutex->handoff == 0 and
123
183
+ * not take part in the handoff.
124
disk, top = file_path('disk', 'top')
184
+ * - in qemu_co_mutex_lock, if it steals the hand-off responsibility from
125
size = 1024 * 1024
185
+ * qemu_co_mutex_unlock. In this case, qemu_co_mutex_unlock will fail
126
diff --git a/tests/qemu-iotests/260 b/tests/qemu-iotests/260
186
+ * the cmpxchg (it will see either 0 or the next sequence value) and
127
index XXXXXXX..XXXXXXX 100755
187
+ * exit. The next hand-off cannot begin until qemu_co_mutex_lock has
128
--- a/tests/qemu-iotests/260
188
+ * woken up someone.
129
+++ b/tests/qemu-iotests/260
189
+ * - in qemu_co_mutex_unlock, if it takes the hand-off token itself.
130
@@ -XXX,XX +XXX,XX @@ import iotests
190
+ * In this case another iteration starts with mutex->handoff == 0;
131
from iotests import qemu_img_create, file_path, log, filter_qmp_event
191
+ * a concurrent qemu_co_mutex_lock will fail the cmpxchg, and
132
192
+ * qemu_co_mutex_unlock will go back to case (1).
133
iotests.script_initialize(
193
+ *
134
- supported_fmts=['qcow2']
194
+ * The following functions manage this queue.
135
+ supported_fmts=['qcow2'],
195
+ */
136
+ unsupported_imgopts=['compat']
196
+typedef struct CoWaitRecord {
137
)
197
+ Coroutine *co;
138
198
+ QSLIST_ENTRY(CoWaitRecord) next;
139
base, top = file_path('base', 'top')
199
+} CoWaitRecord;
140
diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274
200
+
141
index XXXXXXX..XXXXXXX 100755
201
+static void push_waiter(CoMutex *mutex, CoWaitRecord *w)
142
--- a/tests/qemu-iotests/274
202
+{
143
+++ b/tests/qemu-iotests/274
203
+ w->co = qemu_coroutine_self();
144
@@ -XXX,XX +XXX,XX @@
204
+ QSLIST_INSERT_HEAD_ATOMIC(&mutex->from_push, w, next);
145
import iotests
205
+}
146
206
+
147
iotests.script_initialize(supported_fmts=['qcow2'],
207
+static void move_waiters(CoMutex *mutex)
148
- supported_platforms=['linux'])
208
+{
149
+ supported_platforms=['linux'],
209
+ QSLIST_HEAD(, CoWaitRecord) reversed;
150
+ unsupported_imgopts=['refcount_bits', 'compat'])
210
+ QSLIST_MOVE_ATOMIC(&reversed, &mutex->from_push);
151
211
+ while (!QSLIST_EMPTY(&reversed)) {
152
size_short = 1 * 1024 * 1024
212
+ CoWaitRecord *w = QSLIST_FIRST(&reversed);
153
size_long = 2 * 1024 * 1024
213
+ QSLIST_REMOVE_HEAD(&reversed, next);
154
diff --git a/tests/qemu-iotests/281 b/tests/qemu-iotests/281
214
+ QSLIST_INSERT_HEAD(&mutex->to_pop, w, next);
155
index XXXXXXX..XXXXXXX 100755
215
+ }
156
--- a/tests/qemu-iotests/281
216
+}
157
+++ b/tests/qemu-iotests/281
217
+
158
@@ -XXX,XX +XXX,XX @@ class TestBlockdevBackupAbort(iotests.QMPTestCase):
218
+static CoWaitRecord *pop_waiter(CoMutex *mutex)
159
219
+{
160
if __name__ == '__main__':
220
+ CoWaitRecord *w;
161
iotests.main(supported_fmts=['qcow2'],
221
+
162
- supported_protocols=['file'])
222
+ if (QSLIST_EMPTY(&mutex->to_pop)) {
163
+ supported_protocols=['file'],
223
+ move_waiters(mutex);
164
+ unsupported_imgopts=['compat'])
224
+ if (QSLIST_EMPTY(&mutex->to_pop)) {
165
diff --git a/tests/qemu-iotests/303 b/tests/qemu-iotests/303
225
+ return NULL;
166
index XXXXXXX..XXXXXXX 100755
226
+ }
167
--- a/tests/qemu-iotests/303
227
+ }
168
+++ b/tests/qemu-iotests/303
228
+ w = QSLIST_FIRST(&mutex->to_pop);
169
@@ -XXX,XX +XXX,XX @@ import iotests
229
+ QSLIST_REMOVE_HEAD(&mutex->to_pop, next);
170
import subprocess
230
+ return w;
171
from iotests import qemu_img_create, qemu_io, file_path, log, filter_qemu_io
231
+}
172
232
+
173
-iotests.script_initialize(supported_fmts=['qcow2'])
233
+static bool has_waiters(CoMutex *mutex)
174
+iotests.script_initialize(supported_fmts=['qcow2'],
234
+{
175
+ unsupported_imgopts=['refcount_bits', 'compat'])
235
+ return QSLIST_EMPTY(&mutex->to_pop) || QSLIST_EMPTY(&mutex->from_push);
176
236
+}
177
disk = file_path('disk')
237
+
178
chunk = 1024 * 1024
238
void qemu_co_mutex_init(CoMutex *mutex)
179
diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test
239
{
180
index XXXXXXX..XXXXXXX 100755
240
memset(mutex, 0, sizeof(*mutex));
181
--- a/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test
241
- qemu_co_queue_init(&mutex->queue);
182
+++ b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test
242
}
183
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase):
243
184
244
-void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex)
185
245
+static void coroutine_fn qemu_co_mutex_lock_slowpath(CoMutex *mutex)
186
if __name__ == '__main__':
246
{
187
- iotests.main(supported_fmts=['qcow2'])
247
Coroutine *self = qemu_coroutine_self();
188
+ iotests.main(supported_fmts=['qcow2'],
248
+ CoWaitRecord w;
189
+ unsupported_imgopts=['compat'])
249
+ unsigned old_handoff;
190
diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-test b/tests/qemu-iotests/tests/migrate-bitmaps-test
250
191
index XXXXXXX..XXXXXXX 100755
251
trace_qemu_co_mutex_lock_entry(mutex, self);
192
--- a/tests/qemu-iotests/tests/migrate-bitmaps-test
252
+ w.co = self;
193
+++ b/tests/qemu-iotests/tests/migrate-bitmaps-test
253
+ push_waiter(mutex, &w);
194
@@ -XXX,XX +XXX,XX @@ def main() -> None:
254
195
255
- while (mutex->locked) {
196
iotests.main(
256
- qemu_co_queue_wait(&mutex->queue);
197
supported_fmts=['qcow2'],
257
+ /* This is the "Responsibility Hand-Off" protocol; a lock() picks from
198
- supported_protocols=['file']
258
+ * a concurrent unlock() the responsibility of waking somebody up.
199
+ supported_protocols=['file'],
259
+ */
200
+ unsupported_imgopts=['compat']
260
+ old_handoff = atomic_mb_read(&mutex->handoff);
201
)
261
+ if (old_handoff &&
202
262
+ has_waiters(mutex) &&
203
263
+ atomic_cmpxchg(&mutex->handoff, old_handoff, 0) == old_handoff) {
204
diff --git a/tests/qemu-iotests/tests/remove-bitmap-from-backing b/tests/qemu-iotests/tests/remove-bitmap-from-backing
264
+ /* There can be no concurrent pops, because there can be only
205
index XXXXXXX..XXXXXXX 100755
265
+ * one active handoff at a time.
206
--- a/tests/qemu-iotests/tests/remove-bitmap-from-backing
266
+ */
207
+++ b/tests/qemu-iotests/tests/remove-bitmap-from-backing
267
+ CoWaitRecord *to_wake = pop_waiter(mutex);
208
@@ -XXX,XX +XXX,XX @@
268
+ Coroutine *co = to_wake->co;
209
import iotests
269
+ if (co == self) {
210
from iotests import log, qemu_img_create, qemu_img, qemu_img_pipe
270
+ /* We got the lock ourselves! */
211
271
+ assert(to_wake == &w);
212
-iotests.script_initialize(supported_fmts=['qcow2'])
272
+ return;
213
+iotests.script_initialize(supported_fmts=['qcow2'],
273
+ }
214
+ unsupported_imgopts=['compat'])
274
+
215
275
+ aio_co_wake(co);
216
top, base = iotests.file_path('top', 'base')
276
}
217
size = '1M'
277
278
- mutex->locked = true;
279
- mutex->holder = self;
280
- self->locks_held++;
281
-
282
+ qemu_coroutine_yield();
283
trace_qemu_co_mutex_lock_return(mutex, self);
284
}
285
286
+void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex)
287
+{
288
+ Coroutine *self = qemu_coroutine_self();
289
+
290
+ if (atomic_fetch_inc(&mutex->locked) == 0) {
291
+ /* Uncontended. */
292
+ trace_qemu_co_mutex_lock_uncontended(mutex, self);
293
+ } else {
294
+ qemu_co_mutex_lock_slowpath(mutex);
295
+ }
296
+ mutex->holder = self;
297
+ self->locks_held++;
298
+}
299
+
300
void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex)
301
{
302
Coroutine *self = qemu_coroutine_self();
303
304
trace_qemu_co_mutex_unlock_entry(mutex, self);
305
306
- assert(mutex->locked == true);
307
+ assert(mutex->locked);
308
assert(mutex->holder == self);
309
assert(qemu_in_coroutine());
310
311
- mutex->locked = false;
312
mutex->holder = NULL;
313
self->locks_held--;
314
- qemu_co_queue_next(&mutex->queue);
315
+ if (atomic_fetch_dec(&mutex->locked) == 1) {
316
+ /* No waiting qemu_co_mutex_lock(). Pfew, that was easy! */
317
+ return;
318
+ }
319
+
320
+ for (;;) {
321
+ CoWaitRecord *to_wake = pop_waiter(mutex);
322
+ unsigned our_handoff;
323
+
324
+ if (to_wake) {
325
+ Coroutine *co = to_wake->co;
326
+ aio_co_wake(co);
327
+ break;
328
+ }
329
+
330
+ /* Some concurrent lock() is in progress (we know this because
331
+ * mutex->locked was >1) but it hasn't yet put itself on the wait
332
+ * queue. Pick a sequence number for the handoff protocol (not 0).
333
+ */
334
+ if (++mutex->sequence == 0) {
335
+ mutex->sequence = 1;
336
+ }
337
+
338
+ our_handoff = mutex->sequence;
339
+ atomic_mb_set(&mutex->handoff, our_handoff);
340
+ if (!has_waiters(mutex)) {
341
+ /* The concurrent lock has not added itself yet, so it
342
+ * will be able to pick our handoff.
343
+ */
344
+ break;
345
+ }
346
+
347
+ /* Try to do the handoff protocol ourselves; if somebody else has
348
+ * already taken it, however, we're done and they're responsible.
349
+ */
350
+ if (atomic_cmpxchg(&mutex->handoff, our_handoff, 0) != our_handoff) {
351
+ break;
352
+ }
353
+ }
354
355
trace_qemu_co_mutex_unlock_return(mutex, self);
356
}
357
diff --git a/util/trace-events b/util/trace-events
358
index XXXXXXX..XXXXXXX 100644
359
--- a/util/trace-events
360
+++ b/util/trace-events
361
@@ -XXX,XX +XXX,XX @@ qemu_coroutine_terminate(void *co) "self %p"
362
363
# util/qemu-coroutine-lock.c
364
qemu_co_queue_run_restart(void *co) "co %p"
365
+qemu_co_mutex_lock_uncontended(void *mutex, void *self) "mutex %p self %p"
366
qemu_co_mutex_lock_entry(void *mutex, void *self) "mutex %p self %p"
367
qemu_co_mutex_lock_return(void *mutex, void *self) "mutex %p self %p"
368
qemu_co_mutex_unlock_entry(void *mutex, void *self) "mutex %p self %p"
218
--
369
--
219
2.34.1
370
2.9.3
220
371
221
372
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
We'll use it in tests instead of explicit qcow2.py. Then we are going
3
Running a very small critical section on pthread_mutex_t and CoMutex
4
to add some filtering in _qcow2_dump_header.
4
shows that pthread_mutex_t is much faster because it doesn't actually
5
go to sleep. What happens is that the critical section is shorter
6
than the latency of entering the kernel and thus FUTEX_WAIT always
7
fails. With CoMutex there is no such latency but you still want to
8
avoid wait and wakeup. So introduce it artificially.
5
9
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
This only works with one waiters; because CoMutex is fair, it will
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
always have more waits and wakeups than a pthread_mutex_t.
8
Message-Id: <20211223160144.1097696-14-vsementsov@virtuozzo.com>
12
9
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
13
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
14
Reviewed-by: Fam Zheng <famz@redhat.com>
15
Message-id: 20170213181244.16297-3-pbonzini@redhat.com
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
17
---
11
tests/qemu-iotests/common.rc | 10 ++++++++++
18
include/qemu/coroutine.h | 5 +++++
12
1 file changed, 10 insertions(+)
19
util/qemu-coroutine-lock.c | 51 ++++++++++++++++++++++++++++++++++++++++------
20
util/qemu-coroutine.c | 2 +-
21
3 files changed, 51 insertions(+), 7 deletions(-)
13
22
14
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
23
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
15
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/common.rc
25
--- a/include/qemu/coroutine.h
17
+++ b/tests/qemu-iotests/common.rc
26
+++ b/include/qemu/coroutine.h
18
@@ -XXX,XX +XXX,XX @@ _require_one_device_of()
27
@@ -XXX,XX +XXX,XX @@ typedef struct CoMutex {
19
_notrun "$* not available"
28
*/
29
unsigned locked;
30
31
+ /* Context that is holding the lock. Useful to avoid spinning
32
+ * when two coroutines on the same AioContext try to get the lock. :)
33
+ */
34
+ AioContext *ctx;
35
+
36
/* A queue of waiters. Elements are added atomically in front of
37
* from_push. to_pop is only populated, and popped from, by whoever
38
* is in charge of the next wakeup. This can be an unlocker or,
39
diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/util/qemu-coroutine-lock.c
42
+++ b/util/qemu-coroutine-lock.c
43
@@ -XXX,XX +XXX,XX @@
44
#include "qemu-common.h"
45
#include "qemu/coroutine.h"
46
#include "qemu/coroutine_int.h"
47
+#include "qemu/processor.h"
48
#include "qemu/queue.h"
49
#include "block/aio.h"
50
#include "trace.h"
51
@@ -XXX,XX +XXX,XX @@ void qemu_co_mutex_init(CoMutex *mutex)
52
memset(mutex, 0, sizeof(*mutex));
20
}
53
}
21
54
22
+_qcow2_dump_header()
55
-static void coroutine_fn qemu_co_mutex_lock_slowpath(CoMutex *mutex)
56
+static void coroutine_fn qemu_co_mutex_wake(CoMutex *mutex, Coroutine *co)
23
+{
57
+{
24
+ img="$1"
58
+ /* Read co before co->ctx; pairs with smp_wmb() in
25
+ if [ -z "$img" ]; then
59
+ * qemu_coroutine_enter().
26
+ img="$TEST_IMG"
60
+ */
27
+ fi
61
+ smp_read_barrier_depends();
28
+
62
+ mutex->ctx = co->ctx;
29
+ $PYTHON qcow2.py "$img" dump-header
63
+ aio_co_wake(co);
30
+}
64
+}
31
+
65
+
32
# make sure this script returns success
66
+static void coroutine_fn qemu_co_mutex_lock_slowpath(AioContext *ctx,
33
true
67
+ CoMutex *mutex)
68
{
69
Coroutine *self = qemu_coroutine_self();
70
CoWaitRecord w;
71
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn qemu_co_mutex_lock_slowpath(CoMutex *mutex)
72
if (co == self) {
73
/* We got the lock ourselves! */
74
assert(to_wake == &w);
75
+ mutex->ctx = ctx;
76
return;
77
}
78
79
- aio_co_wake(co);
80
+ qemu_co_mutex_wake(mutex, co);
81
}
82
83
qemu_coroutine_yield();
84
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn qemu_co_mutex_lock_slowpath(CoMutex *mutex)
85
86
void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex)
87
{
88
+ AioContext *ctx = qemu_get_current_aio_context();
89
Coroutine *self = qemu_coroutine_self();
90
+ int waiters, i;
91
92
- if (atomic_fetch_inc(&mutex->locked) == 0) {
93
+ /* Running a very small critical section on pthread_mutex_t and CoMutex
94
+ * shows that pthread_mutex_t is much faster because it doesn't actually
95
+ * go to sleep. What happens is that the critical section is shorter
96
+ * than the latency of entering the kernel and thus FUTEX_WAIT always
97
+ * fails. With CoMutex there is no such latency but you still want to
98
+ * avoid wait and wakeup. So introduce it artificially.
99
+ */
100
+ i = 0;
101
+retry_fast_path:
102
+ waiters = atomic_cmpxchg(&mutex->locked, 0, 1);
103
+ if (waiters != 0) {
104
+ while (waiters == 1 && ++i < 1000) {
105
+ if (atomic_read(&mutex->ctx) == ctx) {
106
+ break;
107
+ }
108
+ if (atomic_read(&mutex->locked) == 0) {
109
+ goto retry_fast_path;
110
+ }
111
+ cpu_relax();
112
+ }
113
+ waiters = atomic_fetch_inc(&mutex->locked);
114
+ }
115
+
116
+ if (waiters == 0) {
117
/* Uncontended. */
118
trace_qemu_co_mutex_lock_uncontended(mutex, self);
119
+ mutex->ctx = ctx;
120
} else {
121
- qemu_co_mutex_lock_slowpath(mutex);
122
+ qemu_co_mutex_lock_slowpath(ctx, mutex);
123
}
124
mutex->holder = self;
125
self->locks_held++;
126
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex)
127
assert(mutex->holder == self);
128
assert(qemu_in_coroutine());
129
130
+ mutex->ctx = NULL;
131
mutex->holder = NULL;
132
self->locks_held--;
133
if (atomic_fetch_dec(&mutex->locked) == 1) {
134
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex)
135
unsigned our_handoff;
136
137
if (to_wake) {
138
- Coroutine *co = to_wake->co;
139
- aio_co_wake(co);
140
+ qemu_co_mutex_wake(mutex, to_wake->co);
141
break;
142
}
143
144
diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c
145
index XXXXXXX..XXXXXXX 100644
146
--- a/util/qemu-coroutine.c
147
+++ b/util/qemu-coroutine.c
148
@@ -XXX,XX +XXX,XX @@ void qemu_coroutine_enter(Coroutine *co)
149
co->ctx = qemu_get_current_aio_context();
150
151
/* Store co->ctx before anything that stores co. Matches
152
- * barrier in aio_co_wake.
153
+ * barrier in aio_co_wake and qemu_co_mutex_wake.
154
*/
155
smp_wmb();
156
34
--
157
--
35
2.34.1
158
2.9.3
36
159
37
160
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
We are going to support IMGOPTS environment variable like in bash
3
Add two implementations of the same benchmark as the previous patch,
4
tests. Corresponding global variable in iotests.py should be called
4
but using pthreads. One uses a normal QemuMutex, the other is Linux
5
imgopts. So to not interfere with function argument, rename it in
5
only and implements a fair mutex based on MCS locks and futexes.
6
advance.
6
This shows that the slower performance of the 5-thread case is due to
7
7
the fairness of CoMutex, rather than to coroutines. If fairness does
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
not matter, as is the case with two threads, CoMutex can actually be
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
faster than pthreads.
10
Message-Id: <20211223160144.1097696-2-vsementsov@virtuozzo.com>
10
11
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
11
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
12
Reviewed-by: Fam Zheng <famz@redhat.com>
13
Message-id: 20170213181244.16297-4-pbonzini@redhat.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
15
---
13
tests/qemu-iotests/210 | 8 ++++----
16
tests/test-aio-multithread.c | 164 +++++++++++++++++++++++++++++++++++++++++++
14
tests/qemu-iotests/iotests.py | 5 +++--
17
1 file changed, 164 insertions(+)
15
2 files changed, 7 insertions(+), 6 deletions(-)
18
16
19
diff --git a/tests/test-aio-multithread.c b/tests/test-aio-multithread.c
17
diff --git a/tests/qemu-iotests/210 b/tests/qemu-iotests/210
18
index XXXXXXX..XXXXXXX 100755
19
--- a/tests/qemu-iotests/210
20
+++ b/tests/qemu-iotests/210
21
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.luks') as disk_path, \
22
'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
23
filter_path=disk_path,
24
extra_args=['--object', 'secret,id=keysec0,data=foo'],
25
- imgopts=True)
26
+ use_image_opts=True)
27
28
#
29
# Successful image creation (with non-default options)
30
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.luks') as disk_path, \
31
'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
32
filter_path=disk_path,
33
extra_args=['--object', 'secret,id=keysec0,data=foo'],
34
- imgopts=True)
35
+ use_image_opts=True)
36
37
#
38
# Invalid BlockdevRef
39
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.luks') as disk_path, \
40
'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
41
filter_path=disk_path,
42
extra_args=['--object', 'secret,id=keysec0,data=foo'],
43
- imgopts=True)
44
+ use_image_opts=True)
45
46
#
47
# Invalid sizes
48
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('t.luks') as disk_path, \
49
'driver=luks,file.driver=file,file.filename=%s,key-secret=keysec0' % (disk_path),
50
filter_path=disk_path,
51
extra_args=['--object', 'secret,id=keysec0,data=foo'],
52
- imgopts=True)
53
+ use_image_opts=True)
54
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
55
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
56
--- a/tests/qemu-iotests/iotests.py
21
--- a/tests/test-aio-multithread.c
57
+++ b/tests/qemu-iotests/iotests.py
22
+++ b/tests/test-aio-multithread.c
58
@@ -XXX,XX +XXX,XX @@ def qemu_img_log(*args):
23
@@ -XXX,XX +XXX,XX @@ static void test_multi_co_mutex_2_30(void)
59
log(result, filters=[filter_testfiles])
24
test_multi_co_mutex(2, 30);
60
return result
25
}
61
26
62
-def img_info_log(filename, filter_path=None, imgopts=False, extra_args=()):
27
+/* Same test with fair mutexes, for performance comparison. */
63
+def img_info_log(filename, filter_path=None, use_image_opts=False,
28
+
64
+ extra_args=()):
29
+#ifdef CONFIG_LINUX
65
args = ['info']
30
+#include "qemu/futex.h"
66
- if imgopts:
31
+
67
+ if use_image_opts:
32
+/* The nodes for the mutex reside in this structure (on which we try to avoid
68
args.append('--image-opts')
33
+ * false sharing). The head of the mutex is in the "mutex_head" variable.
69
else:
34
+ */
70
args += ['-f', imgfmt]
35
+static struct {
36
+ int next, locked;
37
+ int padding[14];
38
+} nodes[NUM_CONTEXTS] __attribute__((__aligned__(64)));
39
+
40
+static int mutex_head = -1;
41
+
42
+static void mcs_mutex_lock(void)
43
+{
44
+ int prev;
45
+
46
+ nodes[id].next = -1;
47
+ nodes[id].locked = 1;
48
+ prev = atomic_xchg(&mutex_head, id);
49
+ if (prev != -1) {
50
+ atomic_set(&nodes[prev].next, id);
51
+ qemu_futex_wait(&nodes[id].locked, 1);
52
+ }
53
+}
54
+
55
+static void mcs_mutex_unlock(void)
56
+{
57
+ int next;
58
+ if (nodes[id].next == -1) {
59
+ if (atomic_read(&mutex_head) == id &&
60
+ atomic_cmpxchg(&mutex_head, id, -1) == id) {
61
+ /* Last item in the list, exit. */
62
+ return;
63
+ }
64
+ while (atomic_read(&nodes[id].next) == -1) {
65
+ /* mcs_mutex_lock did the xchg, but has not updated
66
+ * nodes[prev].next yet.
67
+ */
68
+ }
69
+ }
70
+
71
+ /* Wake up the next in line. */
72
+ next = nodes[id].next;
73
+ nodes[next].locked = 0;
74
+ qemu_futex_wake(&nodes[next].locked, 1);
75
+}
76
+
77
+static void test_multi_fair_mutex_entry(void *opaque)
78
+{
79
+ while (!atomic_mb_read(&now_stopping)) {
80
+ mcs_mutex_lock();
81
+ counter++;
82
+ mcs_mutex_unlock();
83
+ atomic_inc(&atomic_counter);
84
+ }
85
+ atomic_dec(&running);
86
+}
87
+
88
+static void test_multi_fair_mutex(int threads, int seconds)
89
+{
90
+ int i;
91
+
92
+ assert(mutex_head == -1);
93
+ counter = 0;
94
+ atomic_counter = 0;
95
+ now_stopping = false;
96
+
97
+ create_aio_contexts();
98
+ assert(threads <= NUM_CONTEXTS);
99
+ running = threads;
100
+ for (i = 0; i < threads; i++) {
101
+ Coroutine *co1 = qemu_coroutine_create(test_multi_fair_mutex_entry, NULL);
102
+ aio_co_schedule(ctx[i], co1);
103
+ }
104
+
105
+ g_usleep(seconds * 1000000);
106
+
107
+ atomic_mb_set(&now_stopping, true);
108
+ while (running > 0) {
109
+ g_usleep(100000);
110
+ }
111
+
112
+ join_aio_contexts();
113
+ g_test_message("%d iterations/second\n", counter / seconds);
114
+ g_assert_cmpint(counter, ==, atomic_counter);
115
+}
116
+
117
+static void test_multi_fair_mutex_1(void)
118
+{
119
+ test_multi_fair_mutex(NUM_CONTEXTS, 1);
120
+}
121
+
122
+static void test_multi_fair_mutex_10(void)
123
+{
124
+ test_multi_fair_mutex(NUM_CONTEXTS, 10);
125
+}
126
+#endif
127
+
128
+/* Same test with pthread mutexes, for performance comparison and
129
+ * portability. */
130
+
131
+static QemuMutex mutex;
132
+
133
+static void test_multi_mutex_entry(void *opaque)
134
+{
135
+ while (!atomic_mb_read(&now_stopping)) {
136
+ qemu_mutex_lock(&mutex);
137
+ counter++;
138
+ qemu_mutex_unlock(&mutex);
139
+ atomic_inc(&atomic_counter);
140
+ }
141
+ atomic_dec(&running);
142
+}
143
+
144
+static void test_multi_mutex(int threads, int seconds)
145
+{
146
+ int i;
147
+
148
+ qemu_mutex_init(&mutex);
149
+ counter = 0;
150
+ atomic_counter = 0;
151
+ now_stopping = false;
152
+
153
+ create_aio_contexts();
154
+ assert(threads <= NUM_CONTEXTS);
155
+ running = threads;
156
+ for (i = 0; i < threads; i++) {
157
+ Coroutine *co1 = qemu_coroutine_create(test_multi_mutex_entry, NULL);
158
+ aio_co_schedule(ctx[i], co1);
159
+ }
160
+
161
+ g_usleep(seconds * 1000000);
162
+
163
+ atomic_mb_set(&now_stopping, true);
164
+ while (running > 0) {
165
+ g_usleep(100000);
166
+ }
167
+
168
+ join_aio_contexts();
169
+ g_test_message("%d iterations/second\n", counter / seconds);
170
+ g_assert_cmpint(counter, ==, atomic_counter);
171
+}
172
+
173
+static void test_multi_mutex_1(void)
174
+{
175
+ test_multi_mutex(NUM_CONTEXTS, 1);
176
+}
177
+
178
+static void test_multi_mutex_10(void)
179
+{
180
+ test_multi_mutex(NUM_CONTEXTS, 10);
181
+}
182
+
183
/* End of tests. */
184
185
int main(int argc, char **argv)
186
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
187
g_test_add_func("/aio/multi/schedule", test_multi_co_schedule_1);
188
g_test_add_func("/aio/multi/mutex/contended", test_multi_co_mutex_1);
189
g_test_add_func("/aio/multi/mutex/handoff", test_multi_co_mutex_2_3);
190
+#ifdef CONFIG_LINUX
191
+ g_test_add_func("/aio/multi/mutex/mcs", test_multi_fair_mutex_1);
192
+#endif
193
+ g_test_add_func("/aio/multi/mutex/pthread", test_multi_mutex_1);
194
} else {
195
g_test_add_func("/aio/multi/schedule", test_multi_co_schedule_10);
196
g_test_add_func("/aio/multi/mutex/contended", test_multi_co_mutex_10);
197
g_test_add_func("/aio/multi/mutex/handoff", test_multi_co_mutex_2_30);
198
+#ifdef CONFIG_LINUX
199
+ g_test_add_func("/aio/multi/mutex/mcs", test_multi_fair_mutex_10);
200
+#endif
201
+ g_test_add_func("/aio/multi/mutex/pthread", test_multi_mutex_10);
202
}
203
return g_test_run();
204
}
71
--
205
--
72
2.34.1
206
2.9.3
73
207
74
208
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
The test prints qcow2 header fields which depends on chosen compression
3
This will avoid forward references in the next patch. It is also
4
type. So, let's be explicit in what compression type we want and
4
more logical because CoQueue is not anymore the basic primitive.
5
independent of IMGOPTS. Test both existing compression types.
6
5
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Fam Zheng <famz@redhat.com>
9
Message-Id: <20211223160144.1097696-8-vsementsov@virtuozzo.com>
8
Message-id: 20170213181244.16297-5-pbonzini@redhat.com
10
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
10
---
12
tests/qemu-iotests/303 | 25 ++++++++++++++++---------
11
include/qemu/coroutine.h | 89 ++++++++++++++++++++++++------------------------
13
tests/qemu-iotests/303.out | 30 +++++++++++++++++++++++++++++-
12
1 file changed, 44 insertions(+), 45 deletions(-)
14
2 files changed, 45 insertions(+), 10 deletions(-)
15
13
16
diff --git a/tests/qemu-iotests/303 b/tests/qemu-iotests/303
14
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
17
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/qemu-iotests/303
16
--- a/include/qemu/coroutine.h
19
+++ b/tests/qemu-iotests/303
17
+++ b/include/qemu/coroutine.h
20
@@ -XXX,XX +XXX,XX @@ def add_bitmap(num, begin, end, disabled):
18
@@ -XXX,XX +XXX,XX @@ bool qemu_in_coroutine(void);
21
log('')
19
*/
22
20
bool qemu_coroutine_entered(Coroutine *co);
23
21
24
-qemu_img_create('-f', iotests.imgfmt, disk, '10M')
25
-
22
-
26
-add_bitmap(1, 0, 6, False)
23
-/**
27
-add_bitmap(2, 6, 8, True)
24
- * CoQueues are a mechanism to queue coroutines in order to continue executing
28
-dump = ['./qcow2.py', disk, 'dump-header']
25
- * them later. They provide the fundamental primitives on which coroutine locks
29
-subprocess.run(dump)
26
- * are built.
30
-# Dump the metadata in JSON format
27
- */
31
-dump.append('-j')
28
-typedef struct CoQueue {
32
-subprocess.run(dump)
29
- QSIMPLEQ_HEAD(, Coroutine) entries;
33
+def test(compression_type: str, json_output: bool) -> None:
30
-} CoQueue;
34
+ qemu_img_create('-f', iotests.imgfmt,
31
-
35
+ '-o', f'compression_type={compression_type}',
32
-/**
36
+ disk, '10M')
33
- * Initialise a CoQueue. This must be called before any other operation is used
37
+ add_bitmap(1, 0, 6, False)
34
- * on the CoQueue.
38
+ add_bitmap(2, 6, 8, True)
35
- */
36
-void qemu_co_queue_init(CoQueue *queue);
37
-
38
-/**
39
- * Adds the current coroutine to the CoQueue and transfers control to the
40
- * caller of the coroutine.
41
- */
42
-void coroutine_fn qemu_co_queue_wait(CoQueue *queue);
43
-
44
-/**
45
- * Restarts the next coroutine in the CoQueue and removes it from the queue.
46
- *
47
- * Returns true if a coroutine was restarted, false if the queue is empty.
48
- */
49
-bool coroutine_fn qemu_co_queue_next(CoQueue *queue);
50
-
51
-/**
52
- * Restarts all coroutines in the CoQueue and leaves the queue empty.
53
- */
54
-void coroutine_fn qemu_co_queue_restart_all(CoQueue *queue);
55
-
56
-/**
57
- * Enter the next coroutine in the queue
58
- */
59
-bool qemu_co_enter_next(CoQueue *queue);
60
-
61
-/**
62
- * Checks if the CoQueue is empty.
63
- */
64
-bool qemu_co_queue_empty(CoQueue *queue);
65
-
66
-
67
/**
68
* Provides a mutex that can be used to synchronise coroutines
69
*/
70
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_mutex_lock(CoMutex *mutex);
71
*/
72
void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex);
73
39
+
74
+
40
+ cmd = ['./qcow2.py', disk, 'dump-header']
75
+/**
41
+ if json_output:
76
+ * CoQueues are a mechanism to queue coroutines in order to continue executing
42
+ cmd.append('-j')
77
+ * them later.
78
+ */
79
+typedef struct CoQueue {
80
+ QSIMPLEQ_HEAD(, Coroutine) entries;
81
+} CoQueue;
43
+
82
+
44
+ subprocess.run(cmd)
83
+/**
84
+ * Initialise a CoQueue. This must be called before any other operation is used
85
+ * on the CoQueue.
86
+ */
87
+void qemu_co_queue_init(CoQueue *queue);
88
+
89
+/**
90
+ * Adds the current coroutine to the CoQueue and transfers control to the
91
+ * caller of the coroutine.
92
+ */
93
+void coroutine_fn qemu_co_queue_wait(CoQueue *queue);
94
+
95
+/**
96
+ * Restarts the next coroutine in the CoQueue and removes it from the queue.
97
+ *
98
+ * Returns true if a coroutine was restarted, false if the queue is empty.
99
+ */
100
+bool coroutine_fn qemu_co_queue_next(CoQueue *queue);
101
+
102
+/**
103
+ * Restarts all coroutines in the CoQueue and leaves the queue empty.
104
+ */
105
+void coroutine_fn qemu_co_queue_restart_all(CoQueue *queue);
106
+
107
+/**
108
+ * Enter the next coroutine in the queue
109
+ */
110
+bool qemu_co_enter_next(CoQueue *queue);
111
+
112
+/**
113
+ * Checks if the CoQueue is empty.
114
+ */
115
+bool qemu_co_queue_empty(CoQueue *queue);
45
+
116
+
46
+
117
+
47
+test('zlib', False)
118
typedef struct CoRwlock {
48
+test('zstd', True)
119
bool writer;
49
diff --git a/tests/qemu-iotests/303.out b/tests/qemu-iotests/303.out
120
int reader;
50
index XXXXXXX..XXXXXXX 100644
51
--- a/tests/qemu-iotests/303.out
52
+++ b/tests/qemu-iotests/303.out
53
@@ -XXX,XX +XXX,XX @@ extra_data_size 0
54
Bitmap table type size offset
55
0 all-zeroes 0 0
56
57
+Add bitmap 1
58
+wrote 1048576/1048576 bytes at offset 0
59
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
60
+
61
+wrote 1048576/1048576 bytes at offset 1048576
62
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
63
+
64
+wrote 1048576/1048576 bytes at offset 2097152
65
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
66
+
67
+wrote 1048576/1048576 bytes at offset 3145728
68
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
69
+
70
+wrote 1048576/1048576 bytes at offset 4194304
71
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
72
+
73
+wrote 1048576/1048576 bytes at offset 5242880
74
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
75
+
76
+
77
+Add bitmap 2
78
+wrote 1048576/1048576 bytes at offset 6291456
79
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
80
+
81
+wrote 1048576/1048576 bytes at offset 7340032
82
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
83
+
84
+
85
{
86
"magic": 1363560955,
87
"version": 3,
88
@@ -XXX,XX +XXX,XX @@ Bitmap table type size offset
89
"refcount_table_clusters": 1,
90
"nb_snapshots": 0,
91
"snapshot_offset": 0,
92
- "incompatible_features": 0,
93
+ "incompatible_features": 8,
94
"compatible_features": 0,
95
"autoclear_features": 1,
96
"refcount_order": 4,
97
--
121
--
98
2.34.1
122
2.9.3
99
123
100
124
diff view generated by jsdifflib
1
This test assumes that mirror flushes the source when entering the READY
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
state, and that the format level will pass that flush on to the protocol
2
3
level (where we intercept it with blkdebug).
3
All that CoQueue needs in order to become thread-safe is help
4
4
from an external mutex. Add this to the API.
5
However, apparently that does not happen when using a VMDK image with
5
6
zeroed_grain=on, which actually is the default set by testenv.py. Right
6
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
now, Python tests ignore IMGOPTS, though, so this has no effect; but
7
Reviewed-by: Fam Zheng <famz@redhat.com>
8
Vladimir has a series that will change this, so we need to fix this test
8
Message-id: 20170213181244.16297-6-pbonzini@redhat.com
9
before that series lands.
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
11
We can fix it by writing data to the source before we start the mirror
12
job; apparently that makes the (VMDK) format layer change its mind and
13
pass on the pre-READY flush to the protocol level, so the test passes
14
again. (I presume, without any data written, mirror just does a 64M
15
zero write on the target, which VMDK with zeroed_grain=on basically just
16
ignores.)
17
18
Without this, we do not get a flush, and so blkdebug only sees a single
19
flush at the end of the job instead of two, and therefore does not
20
inject an error, which makes the block job complete instead of raising
21
an error.
22
23
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
24
Message-Id: <20211223165308.103793-1-hreitz@redhat.com>
25
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
26
---
10
---
27
tests/qemu-iotests/tests/mirror-ready-cancel-error | 7 ++++++-
11
include/qemu/coroutine.h | 8 +++++---
28
1 file changed, 6 insertions(+), 1 deletion(-)
12
block/backup.c | 2 +-
29
13
block/io.c | 4 ++--
30
diff --git a/tests/qemu-iotests/tests/mirror-ready-cancel-error b/tests/qemu-iotests/tests/mirror-ready-cancel-error
14
block/nbd-client.c | 2 +-
31
index XXXXXXX..XXXXXXX 100755
15
block/qcow2-cluster.c | 4 +---
32
--- a/tests/qemu-iotests/tests/mirror-ready-cancel-error
16
block/sheepdog.c | 2 +-
33
+++ b/tests/qemu-iotests/tests/mirror-ready-cancel-error
17
block/throttle-groups.c | 2 +-
34
@@ -XXX,XX +XXX,XX @@ class TestMirrorReadyCancelError(iotests.QMPTestCase):
18
hw/9pfs/9p.c | 2 +-
35
assert iotests.qemu_img_create('-f', iotests.imgfmt, target,
19
util/qemu-coroutine-lock.c | 24 +++++++++++++++++++++---
36
str(image_size)) == 0
20
9 files changed, 34 insertions(+), 16 deletions(-)
37
21
38
+ # Ensure that mirror will copy something before READY so the
22
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
39
+ # target format layer will forward the pre-READY flush to its
23
index XXXXXXX..XXXXXXX 100644
40
+ # file child
24
--- a/include/qemu/coroutine.h
41
+ assert iotests.qemu_io_silent('-c', 'write -P 1 0 64k', source) == 0
25
+++ b/include/qemu/coroutine.h
26
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_mutex_unlock(CoMutex *mutex);
27
28
/**
29
* CoQueues are a mechanism to queue coroutines in order to continue executing
30
- * them later.
31
+ * them later. They are similar to condition variables, but they need help
32
+ * from an external mutex in order to maintain thread-safety.
33
*/
34
typedef struct CoQueue {
35
QSIMPLEQ_HEAD(, Coroutine) entries;
36
@@ -XXX,XX +XXX,XX @@ void qemu_co_queue_init(CoQueue *queue);
37
38
/**
39
* Adds the current coroutine to the CoQueue and transfers control to the
40
- * caller of the coroutine.
41
+ * caller of the coroutine. The mutex is unlocked during the wait and
42
+ * locked again afterwards.
43
*/
44
-void coroutine_fn qemu_co_queue_wait(CoQueue *queue);
45
+void coroutine_fn qemu_co_queue_wait(CoQueue *queue, CoMutex *mutex);
46
47
/**
48
* Restarts the next coroutine in the CoQueue and removes it from the queue.
49
diff --git a/block/backup.c b/block/backup.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/block/backup.c
52
+++ b/block/backup.c
53
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn wait_for_overlapping_requests(BackupBlockJob *job,
54
retry = false;
55
QLIST_FOREACH(req, &job->inflight_reqs, list) {
56
if (end > req->start && start < req->end) {
57
- qemu_co_queue_wait(&req->wait_queue);
58
+ qemu_co_queue_wait(&req->wait_queue, NULL);
59
retry = true;
60
break;
61
}
62
diff --git a/block/io.c b/block/io.c
63
index XXXXXXX..XXXXXXX 100644
64
--- a/block/io.c
65
+++ b/block/io.c
66
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self)
67
* (instead of producing a deadlock in the former case). */
68
if (!req->waiting_for) {
69
self->waiting_for = req;
70
- qemu_co_queue_wait(&req->wait_queue);
71
+ qemu_co_queue_wait(&req->wait_queue, NULL);
72
self->waiting_for = NULL;
73
retry = true;
74
waited = true;
75
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
76
77
/* Wait until any previous flushes are completed */
78
while (bs->active_flush_req) {
79
- qemu_co_queue_wait(&bs->flush_queue);
80
+ qemu_co_queue_wait(&bs->flush_queue, NULL);
81
}
82
83
bs->active_flush_req = true;
84
diff --git a/block/nbd-client.c b/block/nbd-client.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/block/nbd-client.c
87
+++ b/block/nbd-client.c
88
@@ -XXX,XX +XXX,XX @@ static void nbd_coroutine_start(NBDClientSession *s,
89
/* Poor man semaphore. The free_sema is locked when no other request
90
* can be accepted, and unlocked after receiving one reply. */
91
if (s->in_flight == MAX_NBD_REQUESTS) {
92
- qemu_co_queue_wait(&s->free_sema);
93
+ qemu_co_queue_wait(&s->free_sema, NULL);
94
assert(s->in_flight < MAX_NBD_REQUESTS);
95
}
96
s->in_flight++;
97
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
98
index XXXXXXX..XXXXXXX 100644
99
--- a/block/qcow2-cluster.c
100
+++ b/block/qcow2-cluster.c
101
@@ -XXX,XX +XXX,XX @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
102
if (bytes == 0) {
103
/* Wait for the dependency to complete. We need to recheck
104
* the free/allocated clusters when we continue. */
105
- qemu_co_mutex_unlock(&s->lock);
106
- qemu_co_queue_wait(&old_alloc->dependent_requests);
107
- qemu_co_mutex_lock(&s->lock);
108
+ qemu_co_queue_wait(&old_alloc->dependent_requests, &s->lock);
109
return -EAGAIN;
110
}
111
}
112
diff --git a/block/sheepdog.c b/block/sheepdog.c
113
index XXXXXXX..XXXXXXX 100644
114
--- a/block/sheepdog.c
115
+++ b/block/sheepdog.c
116
@@ -XXX,XX +XXX,XX @@ static void wait_for_overlapping_aiocb(BDRVSheepdogState *s, SheepdogAIOCB *acb)
117
retry:
118
QLIST_FOREACH(cb, &s->inflight_aiocb_head, aiocb_siblings) {
119
if (AIOCBOverlapping(acb, cb)) {
120
- qemu_co_queue_wait(&s->overlapping_queue);
121
+ qemu_co_queue_wait(&s->overlapping_queue, NULL);
122
goto retry;
123
}
124
}
125
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
126
index XXXXXXX..XXXXXXX 100644
127
--- a/block/throttle-groups.c
128
+++ b/block/throttle-groups.c
129
@@ -XXX,XX +XXX,XX @@ void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
130
if (must_wait || blkp->pending_reqs[is_write]) {
131
blkp->pending_reqs[is_write]++;
132
qemu_mutex_unlock(&tg->lock);
133
- qemu_co_queue_wait(&blkp->throttled_reqs[is_write]);
134
+ qemu_co_queue_wait(&blkp->throttled_reqs[is_write], NULL);
135
qemu_mutex_lock(&tg->lock);
136
blkp->pending_reqs[is_write]--;
137
}
138
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
139
index XXXXXXX..XXXXXXX 100644
140
--- a/hw/9pfs/9p.c
141
+++ b/hw/9pfs/9p.c
142
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn v9fs_flush(void *opaque)
143
/*
144
* Wait for pdu to complete.
145
*/
146
- qemu_co_queue_wait(&cancel_pdu->complete);
147
+ qemu_co_queue_wait(&cancel_pdu->complete, NULL);
148
cancel_pdu->cancelled = 0;
149
pdu_free(cancel_pdu);
150
}
151
diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c
152
index XXXXXXX..XXXXXXX 100644
153
--- a/util/qemu-coroutine-lock.c
154
+++ b/util/qemu-coroutine-lock.c
155
@@ -XXX,XX +XXX,XX @@ void qemu_co_queue_init(CoQueue *queue)
156
QSIMPLEQ_INIT(&queue->entries);
157
}
158
159
-void coroutine_fn qemu_co_queue_wait(CoQueue *queue)
160
+void coroutine_fn qemu_co_queue_wait(CoQueue *queue, CoMutex *mutex)
161
{
162
Coroutine *self = qemu_coroutine_self();
163
QSIMPLEQ_INSERT_TAIL(&queue->entries, self, co_queue_next);
42
+
164
+
43
self.vm = iotests.VM()
165
+ if (mutex) {
44
self.vm.launch()
166
+ qemu_co_mutex_unlock(mutex);
45
167
+ }
46
@@ -XXX,XX +XXX,XX @@ class TestMirrorReadyCancelError(iotests.QMPTestCase):
168
+
47
# Write something so will not leave the job immediately, but
169
+ /* There is no race condition here. Other threads will call
48
# flush first (which will fail, thanks to blkdebug)
170
+ * aio_co_schedule on our AioContext, which can reenter this
49
res = self.vm.qmp('human-monitor-command',
171
+ * coroutine but only after this yield and after the main loop
50
- command_line='qemu-io mirror-top "write 0 64k"')
172
+ * has gone through the next iteration.
51
+ command_line='qemu-io mirror-top "write -P 2 0 64k"')
173
+ */
52
self.assert_qmp(res, 'return', '')
174
qemu_coroutine_yield();
53
175
assert(qemu_in_coroutine());
54
# Drain status change events
176
+
177
+ /* TODO: OSv implements wait morphing here, where the wakeup
178
+ * primitive automatically places the woken coroutine on the
179
+ * mutex's queue. This avoids the thundering herd effect.
180
+ */
181
+ if (mutex) {
182
+ qemu_co_mutex_lock(mutex);
183
+ }
184
}
185
186
/**
187
@@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_rdlock(CoRwlock *lock)
188
Coroutine *self = qemu_coroutine_self();
189
190
while (lock->writer) {
191
- qemu_co_queue_wait(&lock->queue);
192
+ qemu_co_queue_wait(&lock->queue, NULL);
193
}
194
lock->reader++;
195
self->locks_held++;
196
@@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_wrlock(CoRwlock *lock)
197
Coroutine *self = qemu_coroutine_self();
198
199
while (lock->writer || lock->reader) {
200
- qemu_co_queue_wait(&lock->queue);
201
+ qemu_co_queue_wait(&lock->queue, NULL);
202
}
203
lock->writer = true;
204
self->locks_held++;
55
--
205
--
56
2.34.1
206
2.9.3
57
207
58
208
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
The lsi53c895a SCSI adaptor might not be enabled in each and every
3
This adds a CoMutex around the existing CoQueue. Because the write-side
4
x86 QEMU binary, e.g. it's disabled in the RHEL/CentOS build.
4
can just take CoMutex, the old "writer" field is not necessary anymore.
5
Thus let's add a check to the 051 test so that it does not fail if
5
Instead of removing it altogether, count the number of pending writers
6
this device is not available.
6
during a read-side critical section and forbid further readers from
7
entering.
7
8
8
Signed-off-by: Thomas Huth <thuth@redhat.com>
9
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Message-Id: <20211206143404.247032-1-thuth@redhat.com>
10
Reviewed-by: Fam Zheng <famz@redhat.com>
10
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
11
Message-id: 20170213181244.16297-7-pbonzini@redhat.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
---
13
---
12
tests/qemu-iotests/051 | 4 ++++
14
include/qemu/coroutine.h | 3 ++-
13
1 file changed, 4 insertions(+)
15
util/qemu-coroutine-lock.c | 35 ++++++++++++++++++++++++-----------
16
2 files changed, 26 insertions(+), 12 deletions(-)
14
17
15
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
18
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
16
index XXXXXXX..XXXXXXX 100755
19
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/qemu-iotests/051
20
--- a/include/qemu/coroutine.h
18
+++ b/tests/qemu-iotests/051
21
+++ b/include/qemu/coroutine.h
19
@@ -XXX,XX +XXX,XX @@ _supported_proto file
22
@@ -XXX,XX +XXX,XX @@ bool qemu_co_queue_empty(CoQueue *queue);
20
_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)' data_file
23
21
_require_drivers nbd
24
22
25
typedef struct CoRwlock {
23
+if [ "$QEMU_DEFAULT_MACHINE" = "pc" ]; then
26
- bool writer;
24
+ _require_devices lsi53c895a
27
+ int pending_writer;
25
+fi
28
int reader;
29
+ CoMutex mutex;
30
CoQueue queue;
31
} CoRwlock;
32
33
diff --git a/util/qemu-coroutine-lock.c b/util/qemu-coroutine-lock.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/util/qemu-coroutine-lock.c
36
+++ b/util/qemu-coroutine-lock.c
37
@@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_init(CoRwlock *lock)
38
{
39
memset(lock, 0, sizeof(*lock));
40
qemu_co_queue_init(&lock->queue);
41
+ qemu_co_mutex_init(&lock->mutex);
42
}
43
44
void qemu_co_rwlock_rdlock(CoRwlock *lock)
45
{
46
Coroutine *self = qemu_coroutine_self();
47
48
- while (lock->writer) {
49
- qemu_co_queue_wait(&lock->queue, NULL);
50
+ qemu_co_mutex_lock(&lock->mutex);
51
+ /* For fairness, wait if a writer is in line. */
52
+ while (lock->pending_writer) {
53
+ qemu_co_queue_wait(&lock->queue, &lock->mutex);
54
}
55
lock->reader++;
56
+ qemu_co_mutex_unlock(&lock->mutex);
26
+
57
+
27
do_run_qemu()
58
+ /* The rest of the read-side critical section is run without the mutex. */
59
self->locks_held++;
60
}
61
62
@@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_unlock(CoRwlock *lock)
63
Coroutine *self = qemu_coroutine_self();
64
65
assert(qemu_in_coroutine());
66
- if (lock->writer) {
67
- lock->writer = false;
68
+ if (!lock->reader) {
69
+ /* The critical section started in qemu_co_rwlock_wrlock. */
70
qemu_co_queue_restart_all(&lock->queue);
71
} else {
72
+ self->locks_held--;
73
+
74
+ qemu_co_mutex_lock(&lock->mutex);
75
lock->reader--;
76
assert(lock->reader >= 0);
77
/* Wakeup only one waiting writer */
78
@@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_unlock(CoRwlock *lock)
79
qemu_co_queue_next(&lock->queue);
80
}
81
}
82
- self->locks_held--;
83
+ qemu_co_mutex_unlock(&lock->mutex);
84
}
85
86
void qemu_co_rwlock_wrlock(CoRwlock *lock)
28
{
87
{
29
echo Testing: "$@"
88
- Coroutine *self = qemu_coroutine_self();
89
-
90
- while (lock->writer || lock->reader) {
91
- qemu_co_queue_wait(&lock->queue, NULL);
92
+ qemu_co_mutex_lock(&lock->mutex);
93
+ lock->pending_writer++;
94
+ while (lock->reader) {
95
+ qemu_co_queue_wait(&lock->queue, &lock->mutex);
96
}
97
- lock->writer = true;
98
- self->locks_held++;
99
+ lock->pending_writer--;
100
+
101
+ /* The rest of the write-side critical section is run with
102
+ * the mutex taken, so that lock->reader remains zero.
103
+ * There is no need to update self->locks_held.
104
+ */
105
}
30
--
106
--
31
2.34.1
107
2.9.3
32
108
33
109
diff view generated by jsdifflib