1
The following changes since commit b4fbe1f65a4769c09e6bf2d79fc84360f840f40e:
1
The following changes since commit 6c769690ac845fa62642a5f93b4e4bd906adab95:
2
2
3
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190129' into staging (2019-01-29 12:00:19 +0000)
3
Merge remote-tracking branch 'remotes/vsementsov/tags/pull-simplebench-2021-05-04' into staging (2021-05-21 12:02:34 +0100)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://git.xanclic.moe/XanClic/qemu.git tags/pull-block-2019-01-31
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to 908b30164bbffad7430d551b2a03a8fbcaa631ef:
9
for you to fetch changes up to 0a6f0c76a030710780ce10d6347a70f098024d21:
10
10
11
iotests: Allow 147 to be run concurrently (2019-01-31 00:44:55 +0100)
11
coroutine-sleep: introduce qemu_co_sleep (2021-05-21 18:22:33 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
14
Pull request
15
- New debugging QMP command to explore block graphs
15
16
- Converted DPRINTF()s to trace events
16
(Resent due to an email preparation mistake.)
17
- Fixed qemu-io's use of getopt() for systems with optreset
18
- Minor NVMe emulation fixes
19
- An iotest fix
20
17
21
----------------------------------------------------------------
18
----------------------------------------------------------------
22
Laurent Vivier (4):
23
block/ssh: Convert from DPRINTF() macro to trace events
24
block/curl: Convert from DPRINTF() macro to trace events
25
block/file-posix: Convert from DPRINTF() macro to trace events
26
block/sheepdog: Convert from DPRINTF() macro to trace events
27
19
28
Li Qiang (3):
20
Paolo Bonzini (6):
29
nvme: use TYPE_NVME instead of constant string
21
coroutine-sleep: use a stack-allocated timer
30
nvme: ensure the num_queues is not zero
22
coroutine-sleep: disallow NULL QemuCoSleepState** argument
31
nvme: use pci_dev directly in nvme_realize
23
coroutine-sleep: allow qemu_co_sleep_wake that wakes nothing
24
coroutine-sleep: move timer out of QemuCoSleepState
25
coroutine-sleep: replace QemuCoSleepState pointer with struct in the
26
API
27
coroutine-sleep: introduce qemu_co_sleep
32
28
33
Max Reitz (3):
29
Philippe Mathieu-Daudé (1):
34
iotests.py: Add qemu_nbd_pipe()
30
bitops.h: Improve find_xxx_bit() documentation
35
iotests: Bind qemu-nbd to localhost in 147
36
iotests: Allow 147 to be run concurrently
37
31
38
Richard W.M. Jones (1):
32
Zenghui Yu (1):
39
qemu-io: Add generic function for reinitializing optind.
33
multi-process: Initialize variables declared with g_auto*
40
34
41
Vladimir Sementsov-Ogievskiy (2):
35
include/qemu/bitops.h | 15 ++++++--
42
qapi: add x-debug-query-block-graph
36
include/qemu/coroutine.h | 27 ++++++++-----
43
scripts: add render_block_graph function for QEMUMachine
37
block/block-copy.c | 10 ++---
44
38
block/nbd.c | 14 +++----
45
configure | 14 ++++
39
hw/remote/memory.c | 5 +--
46
qapi/block-core.json | 108 ++++++++++++++++++++++++
40
hw/remote/proxy.c | 3 +-
47
include/block/block.h | 1 +
41
util/qemu-coroutine-sleep.c | 75 +++++++++++++++++++------------------
48
include/qemu/osdep.h | 16 ++++
42
7 files changed, 79 insertions(+), 70 deletions(-)
49
include/sysemu/block-backend.h | 2 +
50
block.c | 148 +++++++++++++++++++++++++++++++++
51
block/block-backend.c | 5 ++
52
block/curl.c | 29 ++-----
53
block/file-posix.c | 25 ++----
54
block/sheepdog.c | 47 ++++-------
55
block/ssh.c | 46 ++++------
56
blockdev.c | 5 ++
57
hw/block/nvme.c | 15 ++--
58
qemu-img.c | 2 +-
59
qemu-io-cmds.c | 2 +-
60
block/trace-events | 47 +++++++++++
61
scripts/render_block_graph.py | 120 ++++++++++++++++++++++++++
62
tests/qemu-iotests/147 | 98 +++++++++++++++-------
63
tests/qemu-iotests/iotests.py | 14 ++++
64
19 files changed, 608 insertions(+), 136 deletions(-)
65
create mode 100755 scripts/render_block_graph.py
66
43
67
--
44
--
68
2.20.1
45
2.31.1
69
46
70
diff view generated by jsdifflib
1
To do this, we need to allow creating the NBD server on various ports
1
From: Zenghui Yu <yuzenghui@huawei.com>
2
instead of a single one (which may not even work if you run just one
3
instance, because something entirely else might be using that port).
4
2
5
So we just pick a random port in [32768, 32768 + 1024) and try to create
3
Quote docs/devel/style.rst (section "Automatic memory deallocation"):
6
a server there. If that fails, we just retry until something sticks.
7
4
8
For the IPv6 test, we need a different range, though (just above that
5
* Variables declared with g_auto* MUST always be initialized,
9
one). This is because "localhost" resolves to both 127.0.0.1 and ::1.
6
otherwise the cleanup function will use uninitialized stack memory
10
This means that if you bind to it, it will bind to both, if possible, or
11
just one if the other is already in use. Therefore, if the IPv6 test
12
has already taken [::1]:some_port and we then try to take
13
localhost:some_port, that will work -- only the second server will be
14
bound to 127.0.0.1:some_port alone and not [::1]:some_port in addition.
15
So we have two different servers on the same port, one for IPv4 and one
16
for IPv6.
17
7
18
But when we then try to connect to the server through
8
Initialize @name properly to get rid of the compilation error (using
19
localhost:some_port, we will always end up at the IPv6 one (as long as
9
gcc-7.3.0 on CentOS):
20
it is up), and this may not be the one we want.
21
10
22
Thus, we must make sure not to create an IPv6-only NBD server on the
11
../hw/remote/proxy.c: In function 'pci_proxy_dev_realize':
23
same port as a normal "dual-stack" NBD server -- which is done by using
12
/usr/include/glib-2.0/glib/glib-autocleanups.h:28:3: error: 'name' may be used uninitialized in this function [-Werror=maybe-uninitialized]
24
distinct port ranges, as explained above.
13
g_free (*pp);
14
^~~~~~~~~~~~
15
../hw/remote/proxy.c:350:30: note: 'name' was declared here
16
g_autofree char *name;
17
^~~~
25
18
26
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
Signed-off-by: Zenghui Yu <yuzenghui@huawei.com>
27
Message-id: 20181221234750.23577-4-mreitz@redhat.com
20
Reviewed-by: Jagannathan Raman <jag.raman@oracle.com>
28
Reviewed-by: John Snow <jsnow@redhat.com>
21
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
29
Signed-off-by: Max Reitz <mreitz@redhat.com>
22
Reviewed-by: Miroslav Rezanina <mrezanin@redhat.com>
23
Message-id: 20210312112143.1369-1-yuzenghui@huawei.com
24
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
30
---
25
---
31
tests/qemu-iotests/147 | 98 +++++++++++++++++++++++++++++-------------
26
hw/remote/memory.c | 5 ++---
32
1 file changed, 68 insertions(+), 30 deletions(-)
27
hw/remote/proxy.c | 3 +--
28
2 files changed, 3 insertions(+), 5 deletions(-)
33
29
34
diff --git a/tests/qemu-iotests/147 b/tests/qemu-iotests/147
30
diff --git a/hw/remote/memory.c b/hw/remote/memory.c
35
index XXXXXXX..XXXXXXX 100755
31
index XXXXXXX..XXXXXXX 100644
36
--- a/tests/qemu-iotests/147
32
--- a/hw/remote/memory.c
37
+++ b/tests/qemu-iotests/147
33
+++ b/hw/remote/memory.c
38
@@ -XXX,XX +XXX,XX @@
34
@@ -XXX,XX +XXX,XX @@ void remote_sysmem_reconfig(MPQemuMsg *msg, Error **errp)
39
#
35
40
36
remote_sysmem_reset();
41
import os
37
42
+import random
38
- for (region = 0; region < msg->num_fds; region++) {
43
import socket
39
- g_autofree char *name;
44
import stat
40
+ for (region = 0; region < msg->num_fds; region++, suffix++) {
45
import time
41
+ g_autofree char *name = g_strdup_printf("remote-mem-%u", suffix);
46
import iotests
42
subregion = g_new(MemoryRegion, 1);
47
-from iotests import cachemode, imgfmt, qemu_img, qemu_nbd
43
- name = g_strdup_printf("remote-mem-%u", suffix++);
48
+from iotests import cachemode, imgfmt, qemu_img, qemu_nbd, qemu_nbd_pipe
44
memory_region_init_ram_from_fd(subregion, NULL,
49
45
name, sysmem_info->sizes[region],
50
-NBD_PORT = 10811
46
true, msg->fds[region],
51
+NBD_PORT_START = 32768
47
diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c
52
+NBD_PORT_END = NBD_PORT_START + 1024
48
index XXXXXXX..XXXXXXX 100644
53
+NBD_IPV6_PORT_START = NBD_PORT_END
49
--- a/hw/remote/proxy.c
54
+NBD_IPV6_PORT_END = NBD_IPV6_PORT_START + 1024
50
+++ b/hw/remote/proxy.c
55
51
@@ -XXX,XX +XXX,XX @@ static void probe_pci_info(PCIDevice *dev, Error **errp)
56
test_img = os.path.join(iotests.test_dir, 'test.img')
52
PCI_BASE_ADDRESS_SPACE_IO : PCI_BASE_ADDRESS_SPACE_MEMORY;
57
unix_socket = os.path.join(iotests.test_dir, 'nbd.socket')
53
58
@@ -XXX,XX +XXX,XX @@ class QemuNBD(NBDBlockdevAddBase):
54
if (size) {
59
except OSError:
55
- g_autofree char *name;
60
pass
56
+ g_autofree char *name = g_strdup_printf("bar-region-%d", i);
61
57
pdev->region[i].dev = pdev;
62
+ def _try_server_up(self, *args):
58
pdev->region[i].present = true;
63
+ status, msg = qemu_nbd_pipe('-f', imgfmt, test_img, *args)
59
if (type == PCI_BASE_ADDRESS_SPACE_MEMORY) {
64
+ if status == 0:
60
pdev->region[i].memory = true;
65
+ return True
61
}
66
+ if 'Address already in use' in msg:
62
- name = g_strdup_printf("bar-region-%d", i);
67
+ return False
63
memory_region_init_io(&pdev->region[i].mr, OBJECT(pdev),
68
+ self.fail(msg)
64
&proxy_mr_ops, &pdev->region[i],
69
+
65
name, size);
70
def _server_up(self, *args):
71
- self.assertEqual(qemu_nbd('-f', imgfmt, test_img, *args), 0)
72
+ self.assertTrue(self._try_server_up(*args))
73
74
def test_inet(self):
75
- self._server_up('-b', 'localhost', '-p', str(NBD_PORT))
76
+ while True:
77
+ nbd_port = random.randrange(NBD_PORT_START, NBD_PORT_END)
78
+ if self._try_server_up('-b', 'localhost', '-p', str(nbd_port)):
79
+ break
80
+
81
address = { 'type': 'inet',
82
'data': {
83
'host': 'localhost',
84
- 'port': str(NBD_PORT)
85
+ 'port': str(nbd_port)
86
} }
87
- self.client_test('nbd://localhost:%i' % NBD_PORT,
88
+ self.client_test('nbd://localhost:%i' % nbd_port,
89
flatten_sock_addr(address))
90
91
def test_unix(self):
92
@@ -XXX,XX +XXX,XX @@ class BuiltinNBD(NBDBlockdevAddBase):
93
except OSError:
94
pass
95
96
- def _server_up(self, address, export_name=None, export_name2=None):
97
+ # Returns False on EADDRINUSE; fails an assertion on other errors.
98
+ # Returns True on success.
99
+ def _try_server_up(self, address, export_name=None, export_name2=None):
100
result = self.server.qmp('nbd-server-start', addr=address)
101
+ if 'error' in result and \
102
+ 'Address already in use' in result['error']['desc']:
103
+ return False
104
self.assert_qmp(result, 'return', {})
105
106
if export_name is None:
107
@@ -XXX,XX +XXX,XX @@ class BuiltinNBD(NBDBlockdevAddBase):
108
name=export_name2)
109
self.assert_qmp(result, 'return', {})
110
111
+ return True
112
+
113
+ def _server_up(self, address, export_name=None, export_name2=None):
114
+ self.assertTrue(self._try_server_up(address, export_name, export_name2))
115
116
def _server_down(self):
117
result = self.server.qmp('nbd-server-stop')
118
self.assert_qmp(result, 'return', {})
119
120
def do_test_inet(self, export_name=None):
121
- address = { 'type': 'inet',
122
- 'data': {
123
- 'host': 'localhost',
124
- 'port': str(NBD_PORT)
125
- } }
126
- self._server_up(address, export_name)
127
+ while True:
128
+ nbd_port = random.randrange(NBD_PORT_START, NBD_PORT_END)
129
+ address = { 'type': 'inet',
130
+ 'data': {
131
+ 'host': 'localhost',
132
+ 'port': str(nbd_port)
133
+ } }
134
+ if self._try_server_up(address, export_name):
135
+ break
136
+
137
export_name = export_name or 'nbd-export'
138
- self.client_test('nbd://localhost:%i/%s' % (NBD_PORT, export_name),
139
+ self.client_test('nbd://localhost:%i/%s' % (nbd_port, export_name),
140
flatten_sock_addr(address), export_name)
141
self._server_down()
142
143
@@ -XXX,XX +XXX,XX @@ class BuiltinNBD(NBDBlockdevAddBase):
144
self.do_test_inet('shadow')
145
146
def test_inet_two_exports(self):
147
- address = { 'type': 'inet',
148
- 'data': {
149
- 'host': 'localhost',
150
- 'port': str(NBD_PORT)
151
- } }
152
- self._server_up(address, 'exp1', 'exp2')
153
- self.client_test('nbd://localhost:%i/%s' % (NBD_PORT, 'exp1'),
154
+ while True:
155
+ nbd_port = random.randrange(NBD_PORT_START, NBD_PORT_END)
156
+ address = { 'type': 'inet',
157
+ 'data': {
158
+ 'host': 'localhost',
159
+ 'port': str(nbd_port)
160
+ } }
161
+ if self._try_server_up(address, 'exp1', 'exp2'):
162
+ break
163
+
164
+ self.client_test('nbd://localhost:%i/%s' % (nbd_port, 'exp1'),
165
flatten_sock_addr(address), 'exp1', 'node1', False)
166
- self.client_test('nbd://localhost:%i/%s' % (NBD_PORT, 'exp2'),
167
+ self.client_test('nbd://localhost:%i/%s' % (nbd_port, 'exp2'),
168
flatten_sock_addr(address), 'exp2', 'node2', False)
169
result = self.vm.qmp('blockdev-del', node_name='node1')
170
self.assert_qmp(result, 'return', {})
171
@@ -XXX,XX +XXX,XX @@ class BuiltinNBD(NBDBlockdevAddBase):
172
except socket.gaierror:
173
# IPv6 not available, skip
174
return
175
- address = { 'type': 'inet',
176
- 'data': {
177
- 'host': '::1',
178
- 'port': str(NBD_PORT),
179
- 'ipv4': False,
180
- 'ipv6': True
181
- } }
182
+
183
+ while True:
184
+ nbd_port = random.randrange(NBD_IPV6_PORT_START, NBD_IPV6_PORT_END)
185
+ address = { 'type': 'inet',
186
+ 'data': {
187
+ 'host': '::1',
188
+ 'port': str(nbd_port),
189
+ 'ipv4': False,
190
+ 'ipv6': True
191
+ } }
192
+ if self._try_server_up(address):
193
+ break
194
+
195
filename = { 'driver': 'raw',
196
'file': {
197
'driver': 'nbd',
198
'export': 'nbd-export',
199
'server': flatten_sock_addr(address)
200
} }
201
- self._server_up(address)
202
self.client_test(filename, flatten_sock_addr(address), 'nbd-export')
203
self._server_down()
204
205
--
66
--
206
2.20.1
67
2.31.1
207
68
208
diff view generated by jsdifflib
1
By default, qemu-nbd binds to 0.0.0.0. However, we then proceed to
1
From: Philippe Mathieu-Daudé <philmd@redhat.com>
2
connect to "localhost". Usually, this works out fine; but if this test
3
is run concurrently, some other test function may have bound a different
4
server to ::1 (on the same port -- you can bind different serves to the
5
same port, as long as one is on IPv4 and the other on IPv6).
6
2
7
So running qemu-nbd works, it can bind to 0.0.0.0:NBD_PORT. But
3
Document the following functions return the bitmap size
8
potentially a concurrent test has successfully taken [::1]:NBD_PORT. In
4
if no matching bit is found:
9
this case, trying to connect to "localhost" will lead us to the IPv6
10
instance, where we do not want to end up.
11
5
12
Fix this by just binding to "localhost". This will make qemu-nbd error
6
- find_first_bit
13
out immediately and not give us cryptic errors later.
7
- find_next_bit
8
- find_last_bit
9
- find_first_zero_bit
10
- find_next_zero_bit
14
11
15
(Also, it will allow us to just try a different port as of a future
12
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
16
patch.)
13
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Message-id: 20210510200758.2623154-2-philmd@redhat.com
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
17
---
18
include/qemu/bitops.h | 15 ++++++++++++---
19
1 file changed, 12 insertions(+), 3 deletions(-)
17
20
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
21
diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
19
Message-id: 20181221234750.23577-3-mreitz@redhat.com
22
index XXXXXXX..XXXXXXX 100644
20
Reviewed-by: John Snow <jsnow@redhat.com>
23
--- a/include/qemu/bitops.h
21
Reviewed-by: Eric Blake <eblake@redhat.com>
24
+++ b/include/qemu/bitops.h
22
Signed-off-by: Max Reitz <mreitz@redhat.com>
25
@@ -XXX,XX +XXX,XX @@ static inline int test_bit(long nr, const unsigned long *addr)
23
---
26
* @addr: The address to start the search at
24
tests/qemu-iotests/147 | 2 +-
27
* @size: The maximum size to search
25
1 file changed, 1 insertion(+), 1 deletion(-)
28
*
29
- * Returns the bit number of the first set bit, or size.
30
+ * Returns the bit number of the last set bit,
31
+ * or @size if there is no set bit in the bitmap.
32
*/
33
unsigned long find_last_bit(const unsigned long *addr,
34
unsigned long size);
35
@@ -XXX,XX +XXX,XX @@ unsigned long find_last_bit(const unsigned long *addr,
36
* @addr: The address to base the search on
37
* @offset: The bitnumber to start searching at
38
* @size: The bitmap size in bits
39
+ *
40
+ * Returns the bit number of the next set bit,
41
+ * or @size if there are no further set bits in the bitmap.
42
*/
43
unsigned long find_next_bit(const unsigned long *addr,
44
unsigned long size,
45
@@ -XXX,XX +XXX,XX @@ unsigned long find_next_bit(const unsigned long *addr,
46
* @addr: The address to base the search on
47
* @offset: The bitnumber to start searching at
48
* @size: The bitmap size in bits
49
+ *
50
+ * Returns the bit number of the next cleared bit,
51
+ * or @size if there are no further clear bits in the bitmap.
52
*/
53
54
unsigned long find_next_zero_bit(const unsigned long *addr,
55
@@ -XXX,XX +XXX,XX @@ unsigned long find_next_zero_bit(const unsigned long *addr,
56
* @addr: The address to start the search at
57
* @size: The maximum size to search
58
*
59
- * Returns the bit number of the first set bit.
60
+ * Returns the bit number of the first set bit,
61
+ * or @size if there is no set bit in the bitmap.
62
*/
63
static inline unsigned long find_first_bit(const unsigned long *addr,
64
unsigned long size)
65
@@ -XXX,XX +XXX,XX @@ static inline unsigned long find_first_bit(const unsigned long *addr,
66
* @addr: The address to start the search at
67
* @size: The maximum size to search
68
*
69
- * Returns the bit number of the first cleared bit.
70
+ * Returns the bit number of the first cleared bit,
71
+ * or @size if there is no clear bit in the bitmap.
72
*/
73
static inline unsigned long find_first_zero_bit(const unsigned long *addr,
74
unsigned long size)
75
--
76
2.31.1
26
77
27
diff --git a/tests/qemu-iotests/147 b/tests/qemu-iotests/147
28
index XXXXXXX..XXXXXXX 100755
29
--- a/tests/qemu-iotests/147
30
+++ b/tests/qemu-iotests/147
31
@@ -XXX,XX +XXX,XX @@ class QemuNBD(NBDBlockdevAddBase):
32
self.assertEqual(qemu_nbd('-f', imgfmt, test_img, *args), 0)
33
34
def test_inet(self):
35
- self._server_up('-p', str(NBD_PORT))
36
+ self._server_up('-b', 'localhost', '-p', str(NBD_PORT))
37
address = { 'type': 'inet',
38
'data': {
39
'host': 'localhost',
40
--
41
2.20.1
42
43
diff view generated by jsdifflib
1
From: Li Qiang <liq3ea@163.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Signed-off-by: Li Qiang <liq3ea@163.com>
3
The lifetime of the timer is well-known (it cannot outlive
4
Reviewed-by: Max Reitz <mreitz@redhat.com>
4
qemu_co_sleep_ns_wakeable, because it's deleted by the time the
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
5
coroutine resumes), so it is not necessary to place it on the heap.
6
Message-id: 20190120055558.32984-2-liq3ea@163.com
6
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Message-id: 20210517100548.28806-2-pbonzini@redhat.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
---
11
---
9
hw/block/nvme.c | 2 +-
12
util/qemu-coroutine-sleep.c | 9 ++++-----
10
1 file changed, 1 insertion(+), 1 deletion(-)
13
1 file changed, 4 insertions(+), 5 deletions(-)
11
14
12
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
15
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
13
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/block/nvme.c
17
--- a/util/qemu-coroutine-sleep.c
15
+++ b/hw/block/nvme.c
18
+++ b/util/qemu-coroutine-sleep.c
16
@@ -XXX,XX +XXX,XX @@ static void nvme_instance_init(Object *obj)
19
@@ -XXX,XX +XXX,XX @@ static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
20
21
struct QemuCoSleepState {
22
Coroutine *co;
23
- QEMUTimer *ts;
24
+ QEMUTimer ts;
25
QemuCoSleepState **user_state_pointer;
26
};
27
28
@@ -XXX,XX +XXX,XX @@ void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
29
if (sleep_state->user_state_pointer) {
30
*sleep_state->user_state_pointer = NULL;
31
}
32
- timer_del(sleep_state->ts);
33
+ timer_del(&sleep_state->ts);
34
aio_co_wake(sleep_state->co);
17
}
35
}
18
36
19
static const TypeInfo nvme_info = {
37
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
20
- .name = "nvme",
38
AioContext *ctx = qemu_get_current_aio_context();
21
+ .name = TYPE_NVME,
39
QemuCoSleepState state = {
22
.parent = TYPE_PCI_DEVICE,
40
.co = qemu_coroutine_self(),
23
.instance_size = sizeof(NvmeCtrl),
41
- .ts = aio_timer_new(ctx, type, SCALE_NS, co_sleep_cb, &state),
24
.class_init = nvme_class_init,
42
.user_state_pointer = sleep_state,
43
};
44
45
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
46
abort();
47
}
48
49
+ aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, &state);
50
if (sleep_state) {
51
*sleep_state = &state;
52
}
53
- timer_mod(state.ts, qemu_clock_get_ns(type) + ns);
54
+ timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
55
qemu_coroutine_yield();
56
if (sleep_state) {
57
/*
58
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
59
*/
60
assert(*sleep_state == NULL);
61
}
62
- timer_free(state.ts);
63
}
25
--
64
--
26
2.20.1
65
2.31.1
27
66
28
diff view generated by jsdifflib
1
From: Laurent Vivier <lvivier@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
3
Simplify the code by removing conditionals. qemu_co_sleep_ns
4
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
4
can simply point the argument to an on-stack temporary.
5
Message-id: 20181213162727.17438-5-lvivier@redhat.com
5
6
[mreitz: Fixed sheepdog_snapshot_create_inode's format string to use
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
PRIx32 for uint32_ts]
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Message-id: 20210517100548.28806-3-pbonzini@redhat.com
9
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
---
10
---
10
block/sheepdog.c | 47 +++++++++++++++++-----------------------------
11
include/qemu/coroutine.h | 5 +++--
11
block/trace-events | 14 ++++++++++++++
12
util/qemu-coroutine-sleep.c | 18 +++++-------------
12
2 files changed, 31 insertions(+), 30 deletions(-)
13
2 files changed, 8 insertions(+), 15 deletions(-)
13
14
14
diff --git a/block/sheepdog.c b/block/sheepdog.c
15
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/block/sheepdog.c
17
--- a/include/qemu/coroutine.h
17
+++ b/block/sheepdog.c
18
+++ b/include/qemu/coroutine.h
18
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@ typedef struct QemuCoSleepState QemuCoSleepState;
19
#include "sysemu/block-backend.h"
20
20
#include "qemu/bitops.h"
21
/**
21
#include "qemu/cutils.h"
22
* Yield the coroutine for a given duration. During this yield, @sleep_state
22
+#include "trace.h"
23
- * (if not NULL) is set to an opaque pointer, which may be used for
23
24
+ * is set to an opaque pointer, which may be used for
24
#define SD_PROTO_VER 0x01
25
* qemu_co_sleep_wake(). Be careful, the pointer is set back to zero when the
25
26
* timer fires. Don't save the obtained value to other variables and don't call
26
@@ -XXX,XX +XXX,XX @@ static inline size_t count_data_objs(const struct SheepdogInode *inode)
27
* qemu_co_sleep_wake from another aio context.
27
(1UL << inode->block_size_shift));
28
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
29
QemuCoSleepState **sleep_state);
30
static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
31
{
32
- qemu_co_sleep_ns_wakeable(type, ns, NULL);
33
+ QemuCoSleepState *unused = NULL;
34
+ qemu_co_sleep_ns_wakeable(type, ns, &unused);
28
}
35
}
29
36
30
-#undef DPRINTF
37
/**
31
-#ifdef DEBUG_SDOG
38
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
32
-#define DEBUG_SDOG_PRINT 1
39
index XXXXXXX..XXXXXXX 100644
33
-#else
40
--- a/util/qemu-coroutine-sleep.c
34
-#define DEBUG_SDOG_PRINT 0
41
+++ b/util/qemu-coroutine-sleep.c
35
-#endif
42
@@ -XXX,XX +XXX,XX @@ void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
36
-#define DPRINTF(fmt, args...) \
43
qemu_co_sleep_ns__scheduled, NULL);
37
- do { \
44
38
- if (DEBUG_SDOG_PRINT) { \
45
assert(scheduled == qemu_co_sleep_ns__scheduled);
39
- fprintf(stderr, "%s %d: " fmt, __func__, __LINE__, ##args); \
46
- if (sleep_state->user_state_pointer) {
40
- } \
47
- *sleep_state->user_state_pointer = NULL;
41
- } while (0)
48
- }
42
-
49
+ *sleep_state->user_state_pointer = NULL;
43
typedef struct SheepdogAIOCB SheepdogAIOCB;
50
timer_del(&sleep_state->ts);
44
typedef struct BDRVSheepdogState BDRVSheepdogState;
51
aio_co_wake(sleep_state->co);
45
52
}
46
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void reconnect_to_sdog(void *opaque)
53
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
47
Error *local_err = NULL;
48
s->fd = get_sheep_fd(s, &local_err);
49
if (s->fd < 0) {
50
- DPRINTF("Wait for connection to be established\n");
51
+ trace_sheepdog_reconnect_to_sdog();
52
error_report_err(local_err);
53
qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000000ULL);
54
}
55
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn aio_read_response(void *opaque)
56
break;
57
case AIOCB_FLUSH_CACHE:
58
if (rsp.result == SD_RES_INVALID_PARMS) {
59
- DPRINTF("disable cache since the server doesn't support it\n");
60
+ trace_sheepdog_aio_read_response();
61
s->cache_flags = SD_FLAG_CMD_DIRECT;
62
rsp.result = SD_RES_SUCCESS;
63
}
64
@@ -XXX,XX +XXX,XX @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
65
s->discard_supported = true;
66
67
if (snap_id || tag[0]) {
68
- DPRINTF("%" PRIx32 " snapshot inode was open.\n", vid);
69
+ trace_sheepdog_open(vid);
70
s->is_snapshot = true;
71
}
54
}
72
55
73
@@ -XXX,XX +XXX,XX @@ static void sd_close(BlockDriverState *bs)
56
aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, &state);
74
unsigned int wlen, rlen = 0;
57
- if (sleep_state) {
75
int fd, ret;
58
- *sleep_state = &state;
76
59
- }
77
- DPRINTF("%s\n", s->name);
60
+ *sleep_state = &state;
78
+ trace_sheepdog_close(s->name);
61
timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
79
62
qemu_coroutine_yield();
80
fd = connect_to_sdog(s, &local_err);
63
- if (sleep_state) {
81
if (fd < 0) {
64
- /*
82
@@ -XXX,XX +XXX,XX @@ static int sd_create_branch(BDRVSheepdogState *s)
65
- * Note that *sleep_state is cleared during qemu_co_sleep_wake
83
char *buf;
66
- * before resuming this coroutine.
84
bool deleted;
67
- */
85
68
- assert(*sleep_state == NULL);
86
- DPRINTF("%" PRIx32 " is snapshot.\n", s->inode.vdi_id);
69
- }
87
+ trace_sheepdog_create_branch_snapshot(s->inode.vdi_id);
88
89
buf = g_malloc(SD_INODE_SIZE);
90
91
@@ -XXX,XX +XXX,XX @@ static int sd_create_branch(BDRVSheepdogState *s)
92
goto out;
93
}
94
95
- DPRINTF("%" PRIx32 " is created.\n", vid);
96
+ trace_sheepdog_create_branch_created(vid);
97
98
fd = connect_to_sdog(s, &local_err);
99
if (fd < 0) {
100
@@ -XXX,XX +XXX,XX @@ static int sd_create_branch(BDRVSheepdogState *s)
101
102
s->is_snapshot = false;
103
ret = 0;
104
- DPRINTF("%" PRIx32 " was newly created.\n", s->inode.vdi_id);
105
+ trace_sheepdog_create_branch_new(s->inode.vdi_id);
106
107
out:
108
g_free(buf);
109
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn sd_co_rw_vector(SheepdogAIOCB *acb)
110
}
111
112
if (create) {
113
- DPRINTF("update ino (%" PRIu32 ") %" PRIu64 " %" PRIu64 " %ld\n",
114
- inode->vdi_id, oid,
115
- vid_to_data_oid(inode->data_vdi_id[idx], idx), idx);
116
+ trace_sheepdog_co_rw_vector_update(inode->vdi_id, oid,
117
+ vid_to_data_oid(inode->data_vdi_id[idx], idx),
118
+ idx);
119
oid = vid_to_data_oid(inode->vdi_id, idx);
120
- DPRINTF("new oid %" PRIx64 "\n", oid);
121
+ trace_sheepdog_co_rw_vector_new(oid);
122
}
123
124
aio_req = alloc_aio_req(s, acb, oid, len, offset, flags, create,
125
@@ -XXX,XX +XXX,XX @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
126
SheepdogInode *inode;
127
unsigned int datalen;
128
129
- DPRINTF("sn_info: name %s id_str %s s: name %s vm_state_size %" PRId64 " "
130
- "is_snapshot %d\n", sn_info->name, sn_info->id_str,
131
- s->name, sn_info->vm_state_size, s->is_snapshot);
132
+ trace_sheepdog_snapshot_create_info(sn_info->name, sn_info->id_str, s->name,
133
+ sn_info->vm_state_size, s->is_snapshot);
134
135
if (s->is_snapshot) {
136
error_report("You can't create a snapshot of a snapshot VDI, "
137
@@ -XXX,XX +XXX,XX @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
138
return -EINVAL;
139
}
140
141
- DPRINTF("%s %s\n", sn_info->name, sn_info->id_str);
142
+ trace_sheepdog_snapshot_create(sn_info->name, sn_info->id_str);
143
144
s->inode.vm_state_size = sn_info->vm_state_size;
145
s->inode.vm_clock_nsec = sn_info->vm_clock_nsec;
146
@@ -XXX,XX +XXX,XX @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
147
}
148
149
memcpy(&s->inode, inode, datalen);
150
- DPRINTF("s->inode: name %s snap_id %x oid %x\n",
151
- s->inode.name, s->inode.snap_id, s->inode.vdi_id);
152
+ trace_sheepdog_snapshot_create_inode(s->inode.name, s->inode.snap_id,
153
+ s->inode.vdi_id);
154
155
cleanup:
156
g_free(inode);
157
diff --git a/block/trace-events b/block/trace-events
158
index XXXXXXX..XXXXXXX 100644
159
--- a/block/trace-events
160
+++ b/block/trace-events
161
@@ -XXX,XX +XXX,XX @@ file_xfs_discard(const char *error) "cannot punch hole (%s)"
162
file_FindEjectableOpticalMedia(const char *media) "Matching using %s"
163
file_setup_cdrom(const char *partition) "Using %s as optical disc"
164
file_hdev_is_sg(int type, int version) "SG device found: type=%d, version=%d"
165
+
70
+
166
+# block/sheepdog.c
71
+ /* qemu_co_sleep_wake clears *sleep_state before resuming this coroutine. */
167
+sheepdog_reconnect_to_sdog(void) "Wait for connection to be established"
72
+ assert(*sleep_state == NULL);
168
+sheepdog_aio_read_response(void) "disable cache since the server doesn't support it"
73
}
169
+sheepdog_open(uint32_t vid) "0x%" PRIx32 " snapshot inode was open"
170
+sheepdog_close(const char *name) "%s"
171
+sheepdog_create_branch_snapshot(uint32_t vdi) "0x%" PRIx32 " is snapshot"
172
+sheepdog_create_branch_created(uint32_t vdi) "0x%" PRIx32 " is created"
173
+sheepdog_create_branch_new(uint32_t vdi) "0x%" PRIx32 " was newly created"
174
+sheepdog_co_rw_vector_update(uint32_t vdi, uint64_t oid, uint64_t data, long idx) "update ino (%" PRIu32 ") %" PRIu64 " %" PRIu64 " %ld"
175
+sheepdog_co_rw_vector_new(uint64_t oid) "new oid 0x%" PRIx64
176
+sheepdog_snapshot_create_info(const char *sn_name, const char *id, const char *name, int64_t size, int is_snapshot) "sn_info: name %s id_str %s s: name %s vm_state_size %" PRId64 " " "is_snapshot %d"
177
+sheepdog_snapshot_create(const char *sn_name, const char *id) "%s %s"
178
+sheepdog_snapshot_create_inode(const char *name, uint32_t snap, uint32_t vdi) "s->inode: name %s snap_id 0x%" PRIx32 " vdi 0x%" PRIx32
179
--
74
--
180
2.20.1
75
2.31.1
181
76
182
diff view generated by jsdifflib
1
From: Laurent Vivier <lvivier@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
3
All callers of qemu_co_sleep_wake are checking whether they are passing
4
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
4
a NULL argument inside the pointer-to-pointer: do the check in
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
5
qemu_co_sleep_wake itself.
6
Message-id: 20181213162727.17438-2-lvivier@redhat.com
6
7
[mreitz: Fixed type of ssh_{read,write}_return's parameter to be ssize_t
7
As a side effect, qemu_co_sleep_wake can be called more than once and
8
instead of size_t]
8
it will only wake the coroutine once; after the first time, the argument
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
will be set to NULL via *sleep_state->user_state_pointer. However, this
10
would not be safe unless co_sleep_cb keeps using the QemuCoSleepState*
11
directly, so make it go through the pointer-to-pointer instead.
12
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
15
Message-id: 20210517100548.28806-4-pbonzini@redhat.com
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
17
---
11
block/ssh.c | 46 +++++++++++++++++-----------------------------
18
block/block-copy.c | 4 +---
12
block/trace-events | 17 +++++++++++++++++
19
block/nbd.c | 8 ++------
13
2 files changed, 34 insertions(+), 29 deletions(-)
20
util/qemu-coroutine-sleep.c | 21 ++++++++++++---------
21
3 files changed, 15 insertions(+), 18 deletions(-)
14
22
15
diff --git a/block/ssh.c b/block/ssh.c
23
diff --git a/block/block-copy.c b/block/block-copy.c
16
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
17
--- a/block/ssh.c
25
--- a/block/block-copy.c
18
+++ b/block/ssh.c
26
+++ b/block/block-copy.c
19
@@ -XXX,XX +XXX,XX @@
27
@@ -XXX,XX +XXX,XX @@ out:
20
#include "qapi/qmp/qstring.h"
28
21
#include "qapi/qobject-input-visitor.h"
29
void block_copy_kick(BlockCopyCallState *call_state)
22
#include "qapi/qobject-output-visitor.h"
30
{
23
+#include "trace.h"
31
- if (call_state->sleep_state) {
24
32
- qemu_co_sleep_wake(call_state->sleep_state);
25
-/* DEBUG_SSH=1 enables the DPRINTF (debugging printf) statements in
33
- }
26
- * this block driver code.
34
+ qemu_co_sleep_wake(call_state->sleep_state);
27
- *
35
}
28
+/*
36
29
* TRACE_LIBSSH2=<bitmask> enables tracing in libssh2 itself. Note
37
/*
30
* that this requires that libssh2 was specially compiled with the
38
diff --git a/block/nbd.c b/block/nbd.c
31
* `./configure --enable-debug' option, so most likely you will have
39
index XXXXXXX..XXXXXXX 100644
32
* to compile it yourself. The meaning of <bitmask> is described
40
--- a/block/nbd.c
33
* here: http://www.libssh2.org/libssh2_trace.html
41
+++ b/block/nbd.c
34
*/
42
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn nbd_client_co_drain_begin(BlockDriverState *bs)
35
-#define DEBUG_SSH 0
43
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
36
#define TRACE_LIBSSH2 0 /* or try: LIBSSH2_TRACE_SFTP */
44
37
45
s->drained = true;
38
-#define DPRINTF(fmt, ...) \
46
- if (s->connection_co_sleep_ns_state) {
39
- do { \
47
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
40
- if (DEBUG_SSH) { \
48
- }
41
- fprintf(stderr, "ssh: %-15s " fmt "\n", \
49
+ qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
42
- __func__, ##__VA_ARGS__); \
50
43
- } \
51
nbd_co_establish_connection_cancel(bs, false);
44
- } while (0)
52
45
-
53
@@ -XXX,XX +XXX,XX @@ static void nbd_teardown_connection(BlockDriverState *bs)
46
typedef struct BDRVSSHState {
54
47
/* Coroutine. */
55
s->state = NBD_CLIENT_QUIT;
48
CoMutex lock;
56
if (s->connection_co) {
49
@@ -XXX,XX +XXX,XX @@ static int check_host_key_knownhosts(BDRVSSHState *s,
57
- if (s->connection_co_sleep_ns_state) {
50
switch (r) {
58
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
51
case LIBSSH2_KNOWNHOST_CHECK_MATCH:
59
- }
52
/* OK */
60
+ qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
53
- DPRINTF("host key OK: %s", found->key);
61
nbd_co_establish_connection_cancel(bs, true);
54
+ trace_ssh_check_host_key_knownhosts(found->key);
55
break;
56
case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
57
ret = -EINVAL;
58
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
59
}
62
}
60
63
if (qemu_in_coroutine()) {
61
/* Open the remote file. */
64
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
62
- DPRINTF("opening file %s flags=0x%x creat_mode=0%o",
65
index XXXXXXX..XXXXXXX 100644
63
- opts->path, ssh_flags, creat_mode);
66
--- a/util/qemu-coroutine-sleep.c
64
+ trace_ssh_connect_to_ssh(opts->path, ssh_flags, creat_mode);
67
+++ b/util/qemu-coroutine-sleep.c
65
s->sftp_handle = libssh2_sftp_open(s->sftp, opts->path, ssh_flags,
68
@@ -XXX,XX +XXX,XX @@ struct QemuCoSleepState {
66
creat_mode);
69
67
if (!s->sftp_handle) {
70
void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
68
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn ssh_co_create_opts(const char *filename, QemuOpts *opts,
71
{
69
/* Get desired file size. */
72
- /* Write of schedule protected by barrier write in aio_co_schedule */
70
ssh_opts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
73
- const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled,
71
BDRV_SECTOR_SIZE);
74
- qemu_co_sleep_ns__scheduled, NULL);
72
- DPRINTF("total_size=%" PRIi64, ssh_opts->size);
75
+ if (sleep_state) {
73
+ trace_ssh_co_create_opts(ssh_opts->size);
76
+ /* Write of schedule protected by barrier write in aio_co_schedule */
74
77
+ const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled,
75
uri_options = qdict_new();
78
+ qemu_co_sleep_ns__scheduled, NULL);
76
ret = parse_uri(filename, uri_options, errp);
79
77
@@ -XXX,XX +XXX,XX @@ static void restart_coroutine(void *opaque)
80
- assert(scheduled == qemu_co_sleep_ns__scheduled);
78
BDRVSSHState *s = bs->opaque;
81
- *sleep_state->user_state_pointer = NULL;
79
AioContext *ctx = bdrv_get_aio_context(bs);
82
- timer_del(&sleep_state->ts);
80
83
- aio_co_wake(sleep_state->co);
81
- DPRINTF("co=%p", restart->co);
84
+ assert(scheduled == qemu_co_sleep_ns__scheduled);
82
+ trace_ssh_restart_coroutine(restart->co);
85
+ *sleep_state->user_state_pointer = NULL;
83
aio_set_fd_handler(ctx, s->sock, false, NULL, NULL, NULL, NULL);
86
+ timer_del(&sleep_state->ts);
84
87
+ aio_co_wake(sleep_state->co);
85
aio_co_wake(restart->co);
88
+ }
86
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
89
}
87
wr_handler = restart_coroutine;
90
91
static void co_sleep_cb(void *opaque)
92
{
93
- qemu_co_sleep_wake(opaque);
94
+ QemuCoSleepState **sleep_state = opaque;
95
+ qemu_co_sleep_wake(*sleep_state);
96
}
97
98
void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
99
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
100
abort();
88
}
101
}
89
102
90
- DPRINTF("s->sock=%d rd_handler=%p wr_handler=%p", s->sock,
103
- aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, &state);
91
- rd_handler, wr_handler);
104
+ aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, sleep_state);
92
+ trace_ssh_co_yield(s->sock, rd_handler, wr_handler);
105
*sleep_state = &state;
93
106
timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
94
aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock,
95
false, rd_handler, wr_handler, NULL, &restart);
96
qemu_coroutine_yield();
107
qemu_coroutine_yield();
97
- DPRINTF("s->sock=%d - back", s->sock);
98
+ trace_ssh_co_yield_back(s->sock);
99
}
100
101
/* SFTP has a function `libssh2_sftp_seek64' which seeks to a position
102
@@ -XXX,XX +XXX,XX @@ static void ssh_seek(BDRVSSHState *s, int64_t offset, int flags)
103
bool force = (flags & SSH_SEEK_FORCE) != 0;
104
105
if (force || op_read != s->offset_op_read || offset != s->offset) {
106
- DPRINTF("seeking to offset=%" PRIi64, offset);
107
+ trace_ssh_seek(offset);
108
libssh2_sftp_seek64(s->sftp_handle, offset);
109
s->offset = offset;
110
s->offset_op_read = op_read;
111
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
112
char *buf, *end_of_vec;
113
struct iovec *i;
114
115
- DPRINTF("offset=%" PRIi64 " size=%zu", offset, size);
116
+ trace_ssh_read(offset, size);
117
118
ssh_seek(s, offset, SSH_SEEK_READ);
119
120
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
121
*/
122
for (got = 0; got < size; ) {
123
again:
124
- DPRINTF("sftp_read buf=%p size=%zu", buf, end_of_vec - buf);
125
+ trace_ssh_read_buf(buf, end_of_vec - buf);
126
r = libssh2_sftp_read(s->sftp_handle, buf, end_of_vec - buf);
127
- DPRINTF("sftp_read returned %zd", r);
128
+ trace_ssh_read_return(r);
129
130
if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
131
co_yield(s, bs);
132
@@ -XXX,XX +XXX,XX @@ static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
133
char *buf, *end_of_vec;
134
struct iovec *i;
135
136
- DPRINTF("offset=%" PRIi64 " size=%zu", offset, size);
137
+ trace_ssh_write(offset, size);
138
139
ssh_seek(s, offset, SSH_SEEK_WRITE);
140
141
@@ -XXX,XX +XXX,XX @@ static int ssh_write(BDRVSSHState *s, BlockDriverState *bs,
142
143
for (written = 0; written < size; ) {
144
again:
145
- DPRINTF("sftp_write buf=%p size=%zu", buf, end_of_vec - buf);
146
+ trace_ssh_write_buf(buf, end_of_vec - buf);
147
r = libssh2_sftp_write(s->sftp_handle, buf, end_of_vec - buf);
148
- DPRINTF("sftp_write returned %zd", r);
149
+ trace_ssh_write_return(r);
150
151
if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
152
co_yield(s, bs);
153
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_flush(BDRVSSHState *s, BlockDriverState *bs)
154
{
155
int r;
156
157
- DPRINTF("fsync");
158
+ trace_ssh_flush();
159
again:
160
r = libssh2_sftp_fsync(s->sftp_handle);
161
if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
162
@@ -XXX,XX +XXX,XX @@ static int64_t ssh_getlength(BlockDriverState *bs)
163
164
/* Note we cannot make a libssh2 call here. */
165
length = (int64_t) s->attrs.filesize;
166
- DPRINTF("length=%" PRIi64, length);
167
+ trace_ssh_getlength(length);
168
169
return length;
170
}
171
diff --git a/block/trace-events b/block/trace-events
172
index XXXXXXX..XXXXXXX 100644
173
--- a/block/trace-events
174
+++ b/block/trace-events
175
@@ -XXX,XX +XXX,XX @@ iscsi_xcopy(void *src_lun, uint64_t src_off, void *dst_lun, uint64_t dst_off, ui
176
# block/nbd-client.c
177
nbd_read_reply_entry_fail(int ret, const char *err) "ret = %d, err: %s"
178
nbd_co_request_fail(uint64_t from, uint32_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name, int ret, const char *err) "Request failed { .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) } ret = %d, err: %s"
179
+
180
+# block/ssh.c
181
+ssh_restart_coroutine(void *co) "co=%p"
182
+ssh_flush(void) "fsync"
183
+ssh_check_host_key_knownhosts(const char *key) "host key OK: %s"
184
+ssh_connect_to_ssh(char *path, int flags, int mode) "opening file %s flags=0x%x creat_mode=0%o"
185
+ssh_co_yield(int sock, void *rd_handler, void *wr_handler) "s->sock=%d rd_handler=%p wr_handler=%p"
186
+ssh_co_yield_back(int sock) "s->sock=%d - back"
187
+ssh_getlength(int64_t length) "length=%" PRIi64
188
+ssh_co_create_opts(uint64_t size) "total_size=%" PRIu64
189
+ssh_read(int64_t offset, size_t size) "offset=%" PRIi64 " size=%zu"
190
+ssh_read_buf(void *buf, size_t size) "sftp_read buf=%p size=%zu"
191
+ssh_read_return(ssize_t ret) "sftp_read returned %zd"
192
+ssh_write(int64_t offset, size_t size) "offset=%" PRIi64 " size=%zu"
193
+ssh_write_buf(void *buf, size_t size) "sftp_write buf=%p size=%zu"
194
+ssh_write_return(ssize_t ret) "sftp_write returned %zd"
195
+ssh_seek(int64_t offset) "seeking to offset=%" PRIi64
196
--
108
--
197
2.20.1
109
2.31.1
198
110
199
diff view generated by jsdifflib
1
From: Li Qiang <liq3ea@163.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
There is no need to make another reference.
3
This simplification is enabled by the previous patch. Now aio_co_wake
4
will only be called once, therefore we do not care about a spurious
5
firing of the timer after a qemu_co_sleep_wake.
4
6
5
Signed-off-by: Li Qiang <liq3ea@163.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Message-id: 20210517100548.28806-5-pbonzini@redhat.com
8
Message-id: 20190120055558.32984-4-liq3ea@163.com
10
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
---
11
hw/block/nvme.c | 8 ++++----
12
util/qemu-coroutine-sleep.c | 8 ++++----
12
1 file changed, 4 insertions(+), 4 deletions(-)
13
1 file changed, 4 insertions(+), 4 deletions(-)
13
14
14
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
15
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/block/nvme.c
17
--- a/util/qemu-coroutine-sleep.c
17
+++ b/hw/block/nvme.c
18
+++ b/util/qemu-coroutine-sleep.c
18
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
19
@@ -XXX,XX +XXX,XX @@ static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
19
pci_conf[PCI_INTERRUPT_PIN] = 1;
20
20
pci_config_set_prog_interface(pci_dev->config, 0x2);
21
struct QemuCoSleepState {
21
pci_config_set_class(pci_dev->config, PCI_CLASS_STORAGE_EXPRESS);
22
Coroutine *co;
22
- pcie_endpoint_cap_init(&n->parent_obj, 0x80);
23
- QEMUTimer ts;
23
+ pcie_endpoint_cap_init(pci_dev, 0x80);
24
QemuCoSleepState **user_state_pointer;
24
25
};
25
n->num_namespaces = 1;
26
26
n->reg_size = pow2ceil(0x1004 + 2 * (n->num_queues + 1) * 4);
27
@@ -XXX,XX +XXX,XX @@ void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
27
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
28
28
29
assert(scheduled == qemu_co_sleep_ns__scheduled);
29
memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n,
30
*sleep_state->user_state_pointer = NULL;
30
"nvme", n->reg_size);
31
- timer_del(&sleep_state->ts);
31
- pci_register_bar(&n->parent_obj, 0,
32
aio_co_wake(sleep_state->co);
32
+ pci_register_bar(pci_dev, 0,
33
}
33
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64,
34
}
34
&n->iomem);
35
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
35
- msix_init_exclusive_bar(&n->parent_obj, n->num_queues, 4, NULL);
36
QemuCoSleepState **sleep_state)
36
+ msix_init_exclusive_bar(pci_dev, n->num_queues, 4, NULL);
37
{
37
38
AioContext *ctx = qemu_get_current_aio_context();
38
id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
39
+ QEMUTimer ts;
39
id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID));
40
QemuCoSleepState state = {
40
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
41
.co = qemu_coroutine_self(),
41
n->cmbuf = g_malloc0(NVME_CMBSZ_GETSIZE(n->bar.cmbsz));
42
.user_state_pointer = sleep_state,
42
memory_region_init_io(&n->ctrl_mem, OBJECT(n), &nvme_cmb_ops, n,
43
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
43
"nvme-cmb", NVME_CMBSZ_GETSIZE(n->bar.cmbsz));
44
abort();
44
- pci_register_bar(&n->parent_obj, NVME_CMBLOC_BIR(n->bar.cmbloc),
45
}
45
+ pci_register_bar(pci_dev, NVME_CMBLOC_BIR(n->bar.cmbloc),
46
46
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
47
- aio_timer_init(ctx, &state.ts, type, SCALE_NS, co_sleep_cb, sleep_state);
47
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem);
48
+ aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, sleep_state);
48
49
*sleep_state = &state;
50
- timer_mod(&state.ts, qemu_clock_get_ns(type) + ns);
51
+ timer_mod(&ts, qemu_clock_get_ns(type) + ns);
52
qemu_coroutine_yield();
53
+ timer_del(&ts);
54
55
/* qemu_co_sleep_wake clears *sleep_state before resuming this coroutine. */
56
assert(*sleep_state == NULL);
49
--
57
--
50
2.20.1
58
2.31.1
51
59
52
diff view generated by jsdifflib
1
From: "Richard W.M. Jones" <rjones@redhat.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
On FreeBSD 11.2:
3
Right now, users of qemu_co_sleep_ns_wakeable are simply passing
4
4
a pointer to QemuCoSleepState by reference to the function. But
5
$ nbdkit memory size=1M --run './qemu-io -f raw -c "aio_write 0 512" $nbd'
5
QemuCoSleepState really is just a Coroutine*; making the
6
Parsing error: non-numeric argument, or extraneous/unrecognized suffix -- aio_write
6
content of the struct public is just as efficient and lets us
7
7
skip the user_state_pointer indirection.
8
After main option parsing, we reinitialize optind so we can parse each
8
9
command. However reinitializing optind to 0 does not work on FreeBSD.
9
Since the usage is changed, take the occasion to rename the
10
What happens when you do this is optind remains 0 after the option
10
struct to QemuCoSleep.
11
parsing loop, and the result is we try to parse argv[optind] ==
11
12
argv[0] == "aio_write" as if it was the first parameter.
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
13
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
14
The FreeBSD manual page says:
14
Message-id: 20210517100548.28806-6-pbonzini@redhat.com
15
15
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
16
In order to use getopt() to evaluate multiple sets of arguments, or to
17
evaluate a single set of arguments multiple times, the variable optreset
18
must be set to 1 before the second and each additional set of calls to
19
getopt(), and the variable optind must be reinitialized.
20
21
(From the rest of the man page it is clear that optind must be
22
reinitialized to 1).
23
24
The glibc man page says:
25
26
A program that scans multiple argument vectors, or rescans the same
27
vector more than once, and wants to make use of GNU extensions such as
28
'+' and '-' at the start of optstring, or changes the value of
29
POSIXLY_CORRECT between scans, must reinitialize getopt() by resetting
30
optind to 0, rather than the traditional value of 1. (Resetting to 0
31
forces the invocation of an internal initialization routine that
32
rechecks POSIXLY_CORRECT and checks for GNU extensions in optstring.)
33
34
This commit introduces an OS-portability function called
35
qemu_reset_optind which provides a way of resetting optind that works
36
on FreeBSD and platforms that use optreset, while keeping it the same
37
as now on other platforms.
38
39
Note that the qemu codebase sets optind in many other places, but in
40
those other places it's setting a local variable and not using getopt.
41
This change is only needed in places where we are using getopt and the
42
associated global variable optind.
43
44
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
45
Message-id: 20190118101114.11759-2-rjones@redhat.com
46
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
47
Reviewed-by: Eric Blake <eblake@redhat.com>
48
Signed-off-by: Max Reitz <mreitz@redhat.com>
49
---
16
---
50
configure | 14 ++++++++++++++
17
include/qemu/coroutine.h | 23 +++++++++++----------
51
include/qemu/osdep.h | 16 ++++++++++++++++
18
block/block-copy.c | 8 ++++----
52
qemu-img.c | 2 +-
19
block/nbd.c | 10 ++++-----
53
qemu-io-cmds.c | 2 +-
20
util/qemu-coroutine-sleep.c | 41 ++++++++++++++++---------------------
54
4 files changed, 32 insertions(+), 2 deletions(-)
21
4 files changed, 39 insertions(+), 43 deletions(-)
55
22
56
diff --git a/configure b/configure
23
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
57
index XXXXXXX..XXXXXXX 100755
24
index XXXXXXX..XXXXXXX 100644
58
--- a/configure
25
--- a/include/qemu/coroutine.h
59
+++ b/configure
26
+++ b/include/qemu/coroutine.h
60
@@ -XXX,XX +XXX,XX @@ if compile_prog "" "" ; then
27
@@ -XXX,XX +XXX,XX @@ void qemu_co_rwlock_wrlock(CoRwlock *lock);
61
signalfd=yes
28
*/
62
fi
29
void qemu_co_rwlock_unlock(CoRwlock *lock);
63
30
64
+# check if optreset global is declared by <getopt.h>
31
-typedef struct QemuCoSleepState QemuCoSleepState;
65
+optreset="no"
32
+typedef struct QemuCoSleep {
66
+cat > $TMPC << EOF
33
+ Coroutine *to_wake;
67
+#include <getopt.h>
34
+} QemuCoSleep;
68
+int main(void) { return optreset; }
35
69
+EOF
36
/**
37
- * Yield the coroutine for a given duration. During this yield, @sleep_state
38
- * is set to an opaque pointer, which may be used for
39
- * qemu_co_sleep_wake(). Be careful, the pointer is set back to zero when the
40
- * timer fires. Don't save the obtained value to other variables and don't call
41
- * qemu_co_sleep_wake from another aio context.
42
+ * Yield the coroutine for a given duration. Initializes @w so that,
43
+ * during this yield, it can be passed to qemu_co_sleep_wake() to
44
+ * terminate the sleep.
45
*/
46
-void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
47
- QemuCoSleepState **sleep_state);
48
+void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
49
+ QEMUClockType type, int64_t ns);
70
+
50
+
71
+if compile_prog "" "" ; then
51
static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
72
+ optreset=yes
52
{
73
+fi
53
- QemuCoSleepState *unused = NULL;
74
+
54
- qemu_co_sleep_ns_wakeable(type, ns, &unused);
75
# check if eventfd is supported
55
+ QemuCoSleep w = { 0 };
76
eventfd=no
56
+ qemu_co_sleep_ns_wakeable(&w, type, ns);
77
cat > $TMPC << EOF
57
}
78
@@ -XXX,XX +XXX,XX @@ fi
58
79
if test "$signalfd" = "yes" ; then
59
/**
80
echo "CONFIG_SIGNALFD=y" >> $config_host_mak
60
@@ -XXX,XX +XXX,XX @@ static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
81
fi
61
* qemu_co_sleep_ns() and should be checked to be non-NULL before calling
82
+if test "$optreset" = "yes" ; then
62
* qemu_co_sleep_wake().
83
+ echo "HAVE_OPTRESET=y" >> $config_host_mak
63
*/
84
+fi
64
-void qemu_co_sleep_wake(QemuCoSleepState *sleep_state);
85
if test "$tcg" = "yes"; then
65
+void qemu_co_sleep_wake(QemuCoSleep *w);
86
echo "CONFIG_TCG=y" >> $config_host_mak
66
87
if test "$tcg_interpreter" = "yes" ; then
67
/**
88
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
68
* Yield until a file descriptor becomes readable
89
index XXXXXXX..XXXXXXX 100644
69
diff --git a/block/block-copy.c b/block/block-copy.c
90
--- a/include/qemu/osdep.h
70
index XXXXXXX..XXXXXXX 100644
91
+++ b/include/qemu/osdep.h
71
--- a/block/block-copy.c
92
@@ -XXX,XX +XXX,XX @@ extern int daemon(int, int);
72
+++ b/block/block-copy.c
93
#include <ctype.h>
73
@@ -XXX,XX +XXX,XX @@ typedef struct BlockCopyCallState {
94
#include <errno.h>
74
/* State */
95
#include <fcntl.h>
75
int ret;
96
+#include <getopt.h>
76
bool finished;
97
#include <sys/stat.h>
77
- QemuCoSleepState *sleep_state;
98
#include <sys/time.h>
78
+ QemuCoSleep sleep;
99
#include <assert.h>
79
bool cancelled;
100
@@ -XXX,XX +XXX,XX @@ extern int qemu_icache_linesize_log;
80
101
extern int qemu_dcache_linesize;
81
/* OUT parameters */
102
extern int qemu_dcache_linesize_log;
82
@@ -XXX,XX +XXX,XX @@ block_copy_dirty_clusters(BlockCopyCallState *call_state)
103
83
if (ns > 0) {
104
+/*
84
block_copy_task_end(task, -EAGAIN);
105
+ * After using getopt or getopt_long, if you need to parse another set
85
g_free(task);
106
+ * of options, then you must reset optind. Unfortunately the way to
86
- qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, ns,
107
+ * do this varies between implementations of getopt.
87
- &call_state->sleep_state);
108
+ */
88
+ qemu_co_sleep_ns_wakeable(&call_state->sleep,
109
+static inline void qemu_reset_optind(void)
89
+ QEMU_CLOCK_REALTIME, ns);
90
continue;
91
}
92
}
93
@@ -XXX,XX +XXX,XX @@ out:
94
95
void block_copy_kick(BlockCopyCallState *call_state)
96
{
97
- qemu_co_sleep_wake(call_state->sleep_state);
98
+ qemu_co_sleep_wake(&call_state->sleep);
99
}
100
101
/*
102
diff --git a/block/nbd.c b/block/nbd.c
103
index XXXXXXX..XXXXXXX 100644
104
--- a/block/nbd.c
105
+++ b/block/nbd.c
106
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVNBDState {
107
CoQueue free_sema;
108
Coroutine *connection_co;
109
Coroutine *teardown_co;
110
- QemuCoSleepState *connection_co_sleep_ns_state;
111
+ QemuCoSleep reconnect_sleep;
112
bool drained;
113
bool wait_drained_end;
114
int in_flight;
115
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn nbd_client_co_drain_begin(BlockDriverState *bs)
116
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
117
118
s->drained = true;
119
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
120
+ qemu_co_sleep_wake(&s->reconnect_sleep);
121
122
nbd_co_establish_connection_cancel(bs, false);
123
124
@@ -XXX,XX +XXX,XX @@ static void nbd_teardown_connection(BlockDriverState *bs)
125
126
s->state = NBD_CLIENT_QUIT;
127
if (s->connection_co) {
128
- qemu_co_sleep_wake(s->connection_co_sleep_ns_state);
129
+ qemu_co_sleep_wake(&s->reconnect_sleep);
130
nbd_co_establish_connection_cancel(bs, true);
131
}
132
if (qemu_in_coroutine()) {
133
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s)
134
}
135
bdrv_inc_in_flight(s->bs);
136
} else {
137
- qemu_co_sleep_ns_wakeable(QEMU_CLOCK_REALTIME, timeout,
138
- &s->connection_co_sleep_ns_state);
139
+ qemu_co_sleep_ns_wakeable(&s->reconnect_sleep,
140
+ QEMU_CLOCK_REALTIME, timeout);
141
if (s->drained) {
142
continue;
143
}
144
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
145
index XXXXXXX..XXXXXXX 100644
146
--- a/util/qemu-coroutine-sleep.c
147
+++ b/util/qemu-coroutine-sleep.c
148
@@ -XXX,XX +XXX,XX @@
149
150
static const char *qemu_co_sleep_ns__scheduled = "qemu_co_sleep_ns";
151
152
-struct QemuCoSleepState {
153
+void qemu_co_sleep_wake(QemuCoSleep *w)
110
+{
154
+{
111
+#ifdef HAVE_OPTRESET
155
Coroutine *co;
112
+ optind = 1;
156
- QemuCoSleepState **user_state_pointer;
113
+ optreset = 1;
157
-};
114
+#else
158
115
+ optind = 0;
159
-void qemu_co_sleep_wake(QemuCoSleepState *sleep_state)
116
+#endif
160
-{
117
+}
161
- if (sleep_state) {
118
+
162
+ co = w->to_wake;
119
#endif
163
+ w->to_wake = NULL;
120
diff --git a/qemu-img.c b/qemu-img.c
164
+ if (co) {
121
index XXXXXXX..XXXXXXX 100644
165
/* Write of schedule protected by barrier write in aio_co_schedule */
122
--- a/qemu-img.c
166
- const char *scheduled = qatomic_cmpxchg(&sleep_state->co->scheduled,
123
+++ b/qemu-img.c
167
+ const char *scheduled = qatomic_cmpxchg(&co->scheduled,
124
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
168
qemu_co_sleep_ns__scheduled, NULL);
125
return 0;
169
170
assert(scheduled == qemu_co_sleep_ns__scheduled);
171
- *sleep_state->user_state_pointer = NULL;
172
- aio_co_wake(sleep_state->co);
173
+ aio_co_wake(co);
126
}
174
}
127
argv += optind;
175
}
128
- optind = 0;
176
129
+ qemu_reset_optind();
177
static void co_sleep_cb(void *opaque)
130
178
{
131
if (!trace_init_backends()) {
179
- QemuCoSleepState **sleep_state = opaque;
132
exit(1);
180
- qemu_co_sleep_wake(*sleep_state);
133
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
181
+ QemuCoSleep *w = opaque;
134
index XXXXXXX..XXXXXXX 100644
182
+ qemu_co_sleep_wake(w);
135
--- a/qemu-io-cmds.c
183
}
136
+++ b/qemu-io-cmds.c
184
137
@@ -XXX,XX +XXX,XX @@ static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc,
185
-void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
138
}
186
- QemuCoSleepState **sleep_state)
187
+void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
188
+ QEMUClockType type, int64_t ns)
189
{
190
+ Coroutine *co = qemu_coroutine_self();
191
AioContext *ctx = qemu_get_current_aio_context();
192
QEMUTimer ts;
193
- QemuCoSleepState state = {
194
- .co = qemu_coroutine_self(),
195
- .user_state_pointer = sleep_state,
196
- };
197
198
- const char *scheduled = qatomic_cmpxchg(&state.co->scheduled, NULL,
199
- qemu_co_sleep_ns__scheduled);
200
+ const char *scheduled = qatomic_cmpxchg(&co->scheduled, NULL,
201
+ qemu_co_sleep_ns__scheduled);
202
if (scheduled) {
203
fprintf(stderr,
204
"%s: Co-routine was already scheduled in '%s'\n",
205
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QEMUClockType type, int64_t ns,
206
abort();
139
}
207
}
140
208
141
- optind = 0;
209
- aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, sleep_state);
142
+ qemu_reset_optind();
210
- *sleep_state = &state;
143
return ct->cfunc(blk, argc, argv);
211
+ w->to_wake = co;
144
}
212
+ aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w),
145
213
timer_mod(&ts, qemu_clock_get_ns(type) + ns);
214
qemu_coroutine_yield();
215
timer_del(&ts);
216
217
- /* qemu_co_sleep_wake clears *sleep_state before resuming this coroutine. */
218
- assert(*sleep_state == NULL);
219
+ /* w->to_wake is cleared before resuming this coroutine. */
220
+ assert(w->to_wake == NULL);
221
}
146
--
222
--
147
2.20.1
223
2.31.1
148
224
149
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Add a new command, returning block nodes (and their users) graph.
3
Allow using QemuCoSleep to sleep forever until woken by qemu_co_sleep_wake.
4
This makes the logic of qemu_co_sleep_ns_wakeable easy to understand.
4
5
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
In the future we will introduce an API that can work even if the
6
Message-id: 20181221170909.25584-2-vsementsov@virtuozzo.com
7
sleep and wake happen from different threads. For now, initializing
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
w->to_wake after timer_mod is fine because the timer can only fire in
9
the same AioContext.
10
11
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
13
Message-id: 20210517100548.28806-7-pbonzini@redhat.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
---
15
---
9
qapi/block-core.json | 108 ++++++++++++++++++++++++
16
include/qemu/coroutine.h | 5 +++++
10
include/block/block.h | 1 +
17
util/qemu-coroutine-sleep.c | 26 +++++++++++++++++++-------
11
include/sysemu/block-backend.h | 2 +
18
2 files changed, 24 insertions(+), 7 deletions(-)
12
block.c | 148 +++++++++++++++++++++++++++++++++
13
block/block-backend.c | 5 ++
14
blockdev.c | 5 ++
15
6 files changed, 269 insertions(+)
16
19
17
diff --git a/qapi/block-core.json b/qapi/block-core.json
20
diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h
18
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
19
--- a/qapi/block-core.json
22
--- a/include/qemu/coroutine.h
20
+++ b/qapi/block-core.json
23
+++ b/include/qemu/coroutine.h
21
@@ -XXX,XX +XXX,XX @@
24
@@ -XXX,XX +XXX,XX @@ typedef struct QemuCoSleep {
22
##
25
void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
23
{ 'command': 'query-named-block-nodes', 'returns': [ 'BlockDeviceInfo' ] }
26
QEMUClockType type, int64_t ns);
24
27
25
+##
28
+/**
26
+# @XDbgBlockGraphNodeType:
29
+ * Yield the coroutine until the next call to qemu_co_sleep_wake.
27
+#
30
+ */
28
+# @block-backend: corresponds to BlockBackend
31
+void coroutine_fn qemu_co_sleep(QemuCoSleep *w);
29
+#
30
+# @block-job: corresonds to BlockJob
31
+#
32
+# @block-driver: corresponds to BlockDriverState
33
+#
34
+# Since: 4.0
35
+##
36
+{ 'enum': 'XDbgBlockGraphNodeType',
37
+ 'data': [ 'block-backend', 'block-job', 'block-driver' ] }
38
+
32
+
39
+##
33
static inline void coroutine_fn qemu_co_sleep_ns(QEMUClockType type, int64_t ns)
40
+# @XDbgBlockGraphNode:
34
{
41
+#
35
QemuCoSleep w = { 0 };
42
+# @id: Block graph node identifier. This @id is generated only for
36
diff --git a/util/qemu-coroutine-sleep.c b/util/qemu-coroutine-sleep.c
43
+# x-debug-query-block-graph and does not relate to any other identifiers in
37
index XXXXXXX..XXXXXXX 100644
44
+# Qemu.
38
--- a/util/qemu-coroutine-sleep.c
45
+#
39
+++ b/util/qemu-coroutine-sleep.c
46
+# @type: Type of graph node. Can be one of block-backend, block-job or
40
@@ -XXX,XX +XXX,XX @@ static void co_sleep_cb(void *opaque)
47
+# block-driver-state.
41
qemu_co_sleep_wake(w);
48
+#
42
}
49
+# @name: Human readable name of the node. Corresponds to node-name for
43
50
+# block-driver-state nodes; is not guaranteed to be unique in the whole
44
-void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
51
+# graph (with block-jobs and block-backends).
45
- QEMUClockType type, int64_t ns)
52
+#
46
+void coroutine_fn qemu_co_sleep(QemuCoSleep *w)
53
+# Since: 4.0
47
{
54
+##
48
Coroutine *co = qemu_coroutine_self();
55
+{ 'struct': 'XDbgBlockGraphNode',
49
- AioContext *ctx = qemu_get_current_aio_context();
56
+ 'data': { 'id': 'uint64', 'type': 'XDbgBlockGraphNodeType', 'name': 'str' } }
50
- QEMUTimer ts;
51
52
const char *scheduled = qatomic_cmpxchg(&co->scheduled, NULL,
53
qemu_co_sleep_ns__scheduled);
54
@@ -XXX,XX +XXX,XX @@ void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
55
}
56
57
w->to_wake = co;
58
- aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w),
59
- timer_mod(&ts, qemu_clock_get_ns(type) + ns);
60
qemu_coroutine_yield();
61
- timer_del(&ts);
62
63
/* w->to_wake is cleared before resuming this coroutine. */
64
assert(w->to_wake == NULL);
65
}
57
+
66
+
58
+##
67
+void coroutine_fn qemu_co_sleep_ns_wakeable(QemuCoSleep *w,
59
+# @BlockPermission:
68
+ QEMUClockType type, int64_t ns)
60
+#
69
+{
61
+# Enum of base block permissions.
70
+ AioContext *ctx = qemu_get_current_aio_context();
62
+#
71
+ QEMUTimer ts;
63
+# @consistent-read: A user that has the "permission" of consistent reads is
64
+# guaranteed that their view of the contents of the block
65
+# device is complete and self-consistent, representing the
66
+# contents of a disk at a specific point.
67
+# For most block devices (including their backing files) this
68
+# is true, but the property cannot be maintained in a few
69
+# situations like for intermediate nodes of a commit block
70
+# job.
71
+#
72
+# @write: This permission is required to change the visible disk contents.
73
+#
74
+# @write-unchanged: This permission (which is weaker than BLK_PERM_WRITE) is
75
+# both enough and required for writes to the block node when
76
+# the caller promises that the visible disk content doesn't
77
+# change.
78
+# As the BLK_PERM_WRITE permission is strictly stronger,
79
+# either is sufficient to perform an unchanging write.
80
+#
81
+# @resize: This permission is required to change the size of a block node.
82
+#
83
+# @graph-mod: This permission is required to change the node that this
84
+# BdrvChild points to.
85
+#
86
+# Since: 4.0
87
+##
88
+ { 'enum': 'BlockPermission',
89
+ 'data': [ 'consistent-read', 'write', 'write-unchanged', 'resize',
90
+ 'graph-mod' ] }
91
+##
92
+# @XDbgBlockGraphEdge:
93
+#
94
+# Block Graph edge description for x-debug-query-block-graph.
95
+#
96
+# @parent: parent id
97
+#
98
+# @child: child id
99
+#
100
+# @name: name of the relation (examples are 'file' and 'backing')
101
+#
102
+# @perm: granted permissions for the parent operating on the child
103
+#
104
+# @shared-perm: permissions that can still be granted to other users of the
105
+# child while it is still attached to this parent
106
+#
107
+# Since: 4.0
108
+##
109
+{ 'struct': 'XDbgBlockGraphEdge',
110
+ 'data': { 'parent': 'uint64', 'child': 'uint64',
111
+ 'name': 'str', 'perm': [ 'BlockPermission' ],
112
+ 'shared-perm': [ 'BlockPermission' ] } }
113
+
72
+
114
+##
73
+ aio_timer_init(ctx, &ts, type, SCALE_NS, co_sleep_cb, w);
115
+# @XDbgBlockGraph:
74
+ timer_mod(&ts, qemu_clock_get_ns(type) + ns);
116
+#
117
+# Block Graph - list of nodes and list of edges.
118
+#
119
+# Since: 4.0
120
+##
121
+{ 'struct': 'XDbgBlockGraph',
122
+ 'data': { 'nodes': ['XDbgBlockGraphNode'], 'edges': ['XDbgBlockGraphEdge'] } }
123
+
124
+##
125
+# @x-debug-query-block-graph:
126
+#
127
+# Get the block graph.
128
+#
129
+# Since: 4.0
130
+##
131
+{ 'command': 'x-debug-query-block-graph', 'returns': 'XDbgBlockGraph' }
132
+
133
##
134
# @drive-mirror:
135
#
136
diff --git a/include/block/block.h b/include/block/block.h
137
index XXXXXXX..XXXXXXX 100644
138
--- a/include/block/block.h
139
+++ b/include/block/block.h
140
@@ -XXX,XX +XXX,XX @@ void bdrv_eject(BlockDriverState *bs, bool eject_flag);
141
const char *bdrv_get_format_name(BlockDriverState *bs);
142
BlockDriverState *bdrv_find_node(const char *node_name);
143
BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp);
144
+XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp);
145
BlockDriverState *bdrv_lookup_bs(const char *device,
146
const char *node_name,
147
Error **errp);
148
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
149
index XXXXXXX..XXXXXXX 100644
150
--- a/include/sysemu/block-backend.h
151
+++ b/include/sysemu/block-backend.h
152
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
153
int bytes, BdrvRequestFlags read_flags,
154
BdrvRequestFlags write_flags);
155
156
+const BdrvChild *blk_root(BlockBackend *blk);
157
+
158
#endif
159
diff --git a/block.c b/block.c
160
index XXXXXXX..XXXXXXX 100644
161
--- a/block.c
162
+++ b/block.c
163
@@ -XXX,XX +XXX,XX @@ BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp)
164
return list;
165
}
166
167
+#define QAPI_LIST_ADD(list, element) do { \
168
+ typeof(list) _tmp = g_new(typeof(*(list)), 1); \
169
+ _tmp->value = (element); \
170
+ _tmp->next = (list); \
171
+ (list) = _tmp; \
172
+} while (0)
173
+
174
+typedef struct XDbgBlockGraphConstructor {
175
+ XDbgBlockGraph *graph;
176
+ GHashTable *graph_nodes;
177
+} XDbgBlockGraphConstructor;
178
+
179
+static XDbgBlockGraphConstructor *xdbg_graph_new(void)
180
+{
181
+ XDbgBlockGraphConstructor *gr = g_new(XDbgBlockGraphConstructor, 1);
182
+
183
+ gr->graph = g_new0(XDbgBlockGraph, 1);
184
+ gr->graph_nodes = g_hash_table_new(NULL, NULL);
185
+
186
+ return gr;
187
+}
188
+
189
+static XDbgBlockGraph *xdbg_graph_finalize(XDbgBlockGraphConstructor *gr)
190
+{
191
+ XDbgBlockGraph *graph = gr->graph;
192
+
193
+ g_hash_table_destroy(gr->graph_nodes);
194
+ g_free(gr);
195
+
196
+ return graph;
197
+}
198
+
199
+static uintptr_t xdbg_graph_node_num(XDbgBlockGraphConstructor *gr, void *node)
200
+{
201
+ uintptr_t ret = (uintptr_t)g_hash_table_lookup(gr->graph_nodes, node);
202
+
203
+ if (ret != 0) {
204
+ return ret;
205
+ }
206
+
75
+
207
+ /*
76
+ /*
208
+ * Start counting from 1, not 0, because 0 interferes with not-found (NULL)
77
+ * The timer will fire in the current AiOContext, so the callback
209
+ * answer of g_hash_table_lookup.
78
+ * must happen after qemu_co_sleep yields and there is no race
79
+ * between timer_mod and qemu_co_sleep.
210
+ */
80
+ */
211
+ ret = g_hash_table_size(gr->graph_nodes) + 1;
81
+ qemu_co_sleep(w);
212
+ g_hash_table_insert(gr->graph_nodes, node, (void *)ret);
82
+ timer_del(&ts);
213
+
214
+ return ret;
215
+}
83
+}
216
+
217
+static void xdbg_graph_add_node(XDbgBlockGraphConstructor *gr, void *node,
218
+ XDbgBlockGraphNodeType type, const char *name)
219
+{
220
+ XDbgBlockGraphNode *n;
221
+
222
+ n = g_new0(XDbgBlockGraphNode, 1);
223
+
224
+ n->id = xdbg_graph_node_num(gr, node);
225
+ n->type = type;
226
+ n->name = g_strdup(name);
227
+
228
+ QAPI_LIST_ADD(gr->graph->nodes, n);
229
+}
230
+
231
+static void xdbg_graph_add_edge(XDbgBlockGraphConstructor *gr, void *parent,
232
+ const BdrvChild *child)
233
+{
234
+ typedef struct {
235
+ unsigned int flag;
236
+ BlockPermission num;
237
+ } PermissionMap;
238
+
239
+ static const PermissionMap permissions[] = {
240
+ { BLK_PERM_CONSISTENT_READ, BLOCK_PERMISSION_CONSISTENT_READ },
241
+ { BLK_PERM_WRITE, BLOCK_PERMISSION_WRITE },
242
+ { BLK_PERM_WRITE_UNCHANGED, BLOCK_PERMISSION_WRITE_UNCHANGED },
243
+ { BLK_PERM_RESIZE, BLOCK_PERMISSION_RESIZE },
244
+ { BLK_PERM_GRAPH_MOD, BLOCK_PERMISSION_GRAPH_MOD },
245
+ { 0, 0 }
246
+ };
247
+ const PermissionMap *p;
248
+ XDbgBlockGraphEdge *edge;
249
+
250
+ QEMU_BUILD_BUG_ON(1UL << (ARRAY_SIZE(permissions) - 1) != BLK_PERM_ALL + 1);
251
+
252
+ edge = g_new0(XDbgBlockGraphEdge, 1);
253
+
254
+ edge->parent = xdbg_graph_node_num(gr, parent);
255
+ edge->child = xdbg_graph_node_num(gr, child->bs);
256
+ edge->name = g_strdup(child->name);
257
+
258
+ for (p = permissions; p->flag; p++) {
259
+ if (p->flag & child->perm) {
260
+ QAPI_LIST_ADD(edge->perm, p->num);
261
+ }
262
+ if (p->flag & child->shared_perm) {
263
+ QAPI_LIST_ADD(edge->shared_perm, p->num);
264
+ }
265
+ }
266
+
267
+ QAPI_LIST_ADD(gr->graph->edges, edge);
268
+}
269
+
270
+
271
+XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp)
272
+{
273
+ BlockBackend *blk;
274
+ BlockJob *job;
275
+ BlockDriverState *bs;
276
+ BdrvChild *child;
277
+ XDbgBlockGraphConstructor *gr = xdbg_graph_new();
278
+
279
+ for (blk = blk_all_next(NULL); blk; blk = blk_all_next(blk)) {
280
+ char *allocated_name = NULL;
281
+ const char *name = blk_name(blk);
282
+
283
+ if (!*name) {
284
+ name = allocated_name = blk_get_attached_dev_id(blk);
285
+ }
286
+ xdbg_graph_add_node(gr, blk, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_BACKEND,
287
+ name);
288
+ g_free(allocated_name);
289
+ if (blk_root(blk)) {
290
+ xdbg_graph_add_edge(gr, blk, blk_root(blk));
291
+ }
292
+ }
293
+
294
+ for (job = block_job_next(NULL); job; job = block_job_next(job)) {
295
+ GSList *el;
296
+
297
+ xdbg_graph_add_node(gr, job, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_JOB,
298
+ job->job.id);
299
+ for (el = job->nodes; el; el = el->next) {
300
+ xdbg_graph_add_edge(gr, job, (BdrvChild *)el->data);
301
+ }
302
+ }
303
+
304
+ QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) {
305
+ xdbg_graph_add_node(gr, bs, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_DRIVER,
306
+ bs->node_name);
307
+ QLIST_FOREACH(child, &bs->children, next) {
308
+ xdbg_graph_add_edge(gr, bs, child);
309
+ }
310
+ }
311
+
312
+ return xdbg_graph_finalize(gr);
313
+}
314
+
315
BlockDriverState *bdrv_lookup_bs(const char *device,
316
const char *node_name,
317
Error **errp)
318
diff --git a/block/block-backend.c b/block/block-backend.c
319
index XXXXXXX..XXXXXXX 100644
320
--- a/block/block-backend.c
321
+++ b/block/block-backend.c
322
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
323
blk_out->root, off_out,
324
bytes, read_flags, write_flags);
325
}
326
+
327
+const BdrvChild *blk_root(BlockBackend *blk)
328
+{
329
+ return blk->root;
330
+}
331
diff --git a/blockdev.c b/blockdev.c
332
index XXXXXXX..XXXXXXX 100644
333
--- a/blockdev.c
334
+++ b/blockdev.c
335
@@ -XXX,XX +XXX,XX @@ BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp)
336
return bdrv_named_nodes_list(errp);
337
}
338
339
+XDbgBlockGraph *qmp_x_debug_query_block_graph(Error **errp)
340
+{
341
+ return bdrv_get_xdbg_block_graph(errp);
342
+}
343
+
344
BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
345
Error **errp)
346
{
347
--
84
--
348
2.20.1
85
2.31.1
349
86
350
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
Render block nodes graph with help of graphviz. This new function is
4
for debugging, so there is no sense to put it into qemu.py as a method
5
of QEMUMachine. Let's instead put it separately.
6
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Acked-by: Eduardo Habkost <ehabkost@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 20181221170909.25584-3-vsementsov@virtuozzo.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
scripts/render_block_graph.py | 120 ++++++++++++++++++++++++++++++++++
14
1 file changed, 120 insertions(+)
15
create mode 100755 scripts/render_block_graph.py
16
17
diff --git a/scripts/render_block_graph.py b/scripts/render_block_graph.py
18
new file mode 100755
19
index XXXXXXX..XXXXXXX
20
--- /dev/null
21
+++ b/scripts/render_block_graph.py
22
@@ -XXX,XX +XXX,XX @@
23
+#!/usr/bin/env python
24
+#
25
+# Render Qemu Block Graph
26
+#
27
+# Copyright (c) 2018 Virtuozzo International GmbH. All rights reserved.
28
+#
29
+# This program is free software; you can redistribute it and/or modify
30
+# it under the terms of the GNU General Public License as published by
31
+# the Free Software Foundation; either version 2 of the License, or
32
+# (at your option) any later version.
33
+#
34
+# This program is distributed in the hope that it will be useful,
35
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
36
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37
+# GNU General Public License for more details.
38
+#
39
+# You should have received a copy of the GNU General Public License
40
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
41
+#
42
+
43
+import os
44
+import sys
45
+import subprocess
46
+import json
47
+from graphviz import Digraph
48
+from qemu import MonitorResponseError
49
+
50
+
51
+def perm(arr):
52
+ s = 'w' if 'write' in arr else '_'
53
+ s += 'r' if 'consistent-read' in arr else '_'
54
+ s += 'u' if 'write-unchanged' in arr else '_'
55
+ s += 'g' if 'graph-mod' in arr else '_'
56
+ s += 's' if 'resize' in arr else '_'
57
+ return s
58
+
59
+
60
+def render_block_graph(qmp, filename, format='png'):
61
+ '''
62
+ Render graph in text (dot) representation into "@filename" and
63
+ representation in @format into "@filename.@format"
64
+ '''
65
+
66
+ bds_nodes = qmp.command('query-named-block-nodes')
67
+ bds_nodes = {n['node-name']: n for n in bds_nodes}
68
+
69
+ job_nodes = qmp.command('query-block-jobs')
70
+ job_nodes = {n['device']: n for n in job_nodes}
71
+
72
+ block_graph = qmp.command('x-debug-query-block-graph')
73
+
74
+ graph = Digraph(comment='Block Nodes Graph')
75
+ graph.format = format
76
+ graph.node('permission symbols:\l'
77
+ ' w - Write\l'
78
+ ' r - consistent-Read\l'
79
+ ' u - write - Unchanged\l'
80
+ ' g - Graph-mod\l'
81
+ ' s - reSize\l'
82
+ 'edge label scheme:\l'
83
+ ' <child type>\l'
84
+ ' <perm>\l'
85
+ ' <shared_perm>\l', shape='none')
86
+
87
+ for n in block_graph['nodes']:
88
+ if n['type'] == 'block-driver':
89
+ info = bds_nodes[n['name']]
90
+ label = n['name'] + ' [' + info['drv'] + ']'
91
+ if info['drv'] == 'file':
92
+ label += '\n' + os.path.basename(info['file'])
93
+ shape = 'ellipse'
94
+ elif n['type'] == 'block-job':
95
+ info = job_nodes[n['name']]
96
+ label = info['type'] + ' job (' + n['name'] + ')'
97
+ shape = 'box'
98
+ else:
99
+ assert n['type'] == 'block-backend'
100
+ label = n['name'] if n['name'] else 'unnamed blk'
101
+ shape = 'box'
102
+
103
+ graph.node(str(n['id']), label, shape=shape)
104
+
105
+ for e in block_graph['edges']:
106
+ label = '%s\l%s\l%s\l' % (e['name'], perm(e['perm']),
107
+ perm(e['shared-perm']))
108
+ graph.edge(str(e['parent']), str(e['child']), label=label)
109
+
110
+ graph.render(filename)
111
+
112
+
113
+class LibvirtGuest():
114
+ def __init__(self, name):
115
+ self.name = name
116
+
117
+ def command(self, cmd):
118
+ # only supports qmp commands without parameters
119
+ m = {'execute': cmd}
120
+ ar = ['virsh', 'qemu-monitor-command', self.name, json.dumps(m)]
121
+
122
+ reply = json.loads(subprocess.check_output(ar))
123
+
124
+ if 'error' in reply:
125
+ raise MonitorResponseError(reply)
126
+
127
+ return reply['return']
128
+
129
+
130
+if __name__ == '__main__':
131
+ obj = sys.argv[1]
132
+ out = sys.argv[2]
133
+
134
+ if os.path.exists(obj):
135
+ # assume unix socket
136
+ qmp = QEMUMonitorProtocol(obj)
137
+ qmp.connect()
138
+ else:
139
+ # assume libvirt guest name
140
+ qmp = LibvirtGuest(obj)
141
+
142
+ render_block_graph(qmp, out)
143
--
144
2.20.1
145
146
diff view generated by jsdifflib
Deleted patch
1
From: Laurent Vivier <lvivier@redhat.com>
2
1
3
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
4
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
6
Message-id: 20181213162727.17438-3-lvivier@redhat.com
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
9
block/curl.c | 29 ++++++++---------------------
10
block/trace-events | 9 +++++++++
11
2 files changed, 17 insertions(+), 21 deletions(-)
12
13
diff --git a/block/curl.c b/block/curl.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/curl.c
16
+++ b/block/curl.c
17
@@ -XXX,XX +XXX,XX @@
18
#include "crypto/secret.h"
19
#include <curl/curl.h>
20
#include "qemu/cutils.h"
21
+#include "trace.h"
22
23
-// #define DEBUG_CURL
24
// #define DEBUG_VERBOSE
25
26
-#ifdef DEBUG_CURL
27
-#define DEBUG_CURL_PRINT 1
28
-#else
29
-#define DEBUG_CURL_PRINT 0
30
-#endif
31
-#define DPRINTF(fmt, ...) \
32
- do { \
33
- if (DEBUG_CURL_PRINT) { \
34
- fprintf(stderr, fmt, ## __VA_ARGS__); \
35
- } \
36
- } while (0)
37
-
38
#if LIBCURL_VERSION_NUM >= 0x071000
39
/* The multi interface timer callback was introduced in 7.16.0 */
40
#define NEED_CURL_TIMER_CALLBACK
41
@@ -XXX,XX +XXX,XX @@ static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
42
{
43
BDRVCURLState *s = opaque;
44
45
- DPRINTF("CURL: timer callback timeout_ms %ld\n", timeout_ms);
46
+ trace_curl_timer_cb(timeout_ms);
47
if (timeout_ms == -1) {
48
timer_del(&s->timer);
49
} else {
50
@@ -XXX,XX +XXX,XX @@ static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
51
}
52
socket = NULL;
53
54
- DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, (int)fd);
55
+ trace_curl_sock_cb(action, (int)fd);
56
switch (action) {
57
case CURL_POLL_IN:
58
aio_set_fd_handler(s->aio_context, fd, false,
59
@@ -XXX,XX +XXX,XX @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
60
size_t realsize = size * nmemb;
61
int i;
62
63
- DPRINTF("CURL: Just reading %zd bytes\n", realsize);
64
+ trace_curl_read_cb(realsize);
65
66
if (!s || !s->orig_buf) {
67
goto read_end;
68
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
69
}
70
}
71
72
- DPRINTF("CURL: Opening %s\n", file);
73
+ trace_curl_open(file);
74
qemu_co_queue_init(&s->free_state_waitq);
75
s->aio_context = bdrv_get_aio_context(bs);
76
s->url = g_strdup(file);
77
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
78
"Server does not support 'range' (byte ranges).");
79
goto out;
80
}
81
- DPRINTF("CURL: Size = %" PRIu64 "\n", s->len);
82
+ trace_curl_open_size(s->len);
83
84
qemu_mutex_lock(&s->mutex);
85
curl_clean_state(state);
86
@@ -XXX,XX +XXX,XX @@ static void curl_setup_preadv(BlockDriverState *bs, CURLAIOCB *acb)
87
state->acb[0] = acb;
88
89
snprintf(state->range, 127, "%" PRIu64 "-%" PRIu64, start, end);
90
- DPRINTF("CURL (AIO): Reading %" PRIu64 " at %" PRIu64 " (%s)\n",
91
- acb->bytes, start, state->range);
92
+ trace_curl_setup_preadv(acb->bytes, start, state->range);
93
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
94
95
curl_multi_add_handle(s->multi, state->curl);
96
@@ -XXX,XX +XXX,XX @@ static void curl_close(BlockDriverState *bs)
97
{
98
BDRVCURLState *s = bs->opaque;
99
100
- DPRINTF("CURL: Close\n");
101
+ trace_curl_close();
102
curl_detach_aio_context(bs);
103
qemu_mutex_destroy(&s->mutex);
104
105
diff --git a/block/trace-events b/block/trace-events
106
index XXXXXXX..XXXXXXX 100644
107
--- a/block/trace-events
108
+++ b/block/trace-events
109
@@ -XXX,XX +XXX,XX @@ ssh_write(int64_t offset, size_t size) "offset=%" PRIi64 " size=%zu"
110
ssh_write_buf(void *buf, size_t size) "sftp_write buf=%p size=%zu"
111
ssh_write_return(ssize_t ret) "sftp_write returned %zd"
112
ssh_seek(int64_t offset) "seeking to offset=%" PRIi64
113
+
114
+# block/curl.c
115
+curl_timer_cb(long timeout_ms) "timer callback timeout_ms %ld"
116
+curl_sock_cb(int action, int fd) "sock action %d on fd %d"
117
+curl_read_cb(size_t realsize) "just reading %zu bytes"
118
+curl_open(const char *file) "opening %s"
119
+curl_open_size(uint64_t size) "size = %" PRIu64
120
+curl_setup_preadv(uint64_t bytes, uint64_t start, const char *range) "reading %" PRIu64 " at %" PRIu64 " (%s)"
121
+curl_close(void) "close"
122
--
123
2.20.1
124
125
diff view generated by jsdifflib
Deleted patch
1
From: Laurent Vivier <lvivier@redhat.com>
2
1
3
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
4
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
5
Message-id: 20181213162727.17438-4-lvivier@redhat.com
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
8
block/file-posix.c | 25 ++++++-------------------
9
block/trace-events | 7 +++++++
10
2 files changed, 13 insertions(+), 19 deletions(-)
11
12
diff --git a/block/file-posix.c b/block/file-posix.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block/file-posix.c
15
+++ b/block/file-posix.c
16
@@ -XXX,XX +XXX,XX @@
17
#include <xfs/xfs.h>
18
#endif
19
20
-//#define DEBUG_BLOCK
21
-
22
-#ifdef DEBUG_BLOCK
23
-# define DEBUG_BLOCK_PRINT 1
24
-#else
25
-# define DEBUG_BLOCK_PRINT 0
26
-#endif
27
-#define DPRINTF(fmt, ...) \
28
-do { \
29
- if (DEBUG_BLOCK_PRINT) { \
30
- printf(fmt, ## __VA_ARGS__); \
31
- } \
32
-} while (0)
33
+#include "trace.h"
34
35
/* OS X does not have O_DSYNC */
36
#ifndef O_DSYNC
37
@@ -XXX,XX +XXX,XX @@ static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
38
39
if (xfsctl(NULL, s->fd, XFS_IOC_ZERO_RANGE, &fl) < 0) {
40
err = errno;
41
- DPRINTF("cannot write zero range (%s)\n", strerror(errno));
42
+ trace_file_xfs_write_zeroes(strerror(errno));
43
return -err;
44
}
45
46
@@ -XXX,XX +XXX,XX @@ static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
47
48
if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) {
49
err = errno;
50
- DPRINTF("cannot punch hole (%s)\n", strerror(errno));
51
+ trace_file_xfs_discard(strerror(errno));
52
return -err;
53
}
54
55
@@ -XXX,XX +XXX,XX @@ static char *FindEjectableOpticalMedia(io_iterator_t *mediaIterator)
56
57
/* If a match was found, leave the loop */
58
if (*mediaIterator != 0) {
59
- DPRINTF("Matching using %s\n", matching_array[index]);
60
+ trace_file_FindEjectableOpticalMedia(matching_array[index]);
61
mediaType = g_strdup(matching_array[index]);
62
break;
63
}
64
@@ -XXX,XX +XXX,XX @@ static bool setup_cdrom(char *bsd_path, Error **errp)
65
if (partition_found == false) {
66
error_setg(errp, "Failed to find a working partition on disc");
67
} else {
68
- DPRINTF("Using %s as optical disc\n", test_partition);
69
+ trace_file_setup_cdrom(test_partition);
70
pstrcpy(bsd_path, MAXPATHLEN, test_partition);
71
}
72
return partition_found;
73
@@ -XXX,XX +XXX,XX @@ static bool hdev_is_sg(BlockDriverState *bs)
74
75
ret = ioctl(s->fd, SG_GET_SCSI_ID, &scsiid);
76
if (ret >= 0) {
77
- DPRINTF("SG device found: type=%d, version=%d\n",
78
- scsiid.scsi_type, sg_version);
79
+ trace_file_hdev_is_sg(scsiid.scsi_type, sg_version);
80
return true;
81
}
82
83
diff --git a/block/trace-events b/block/trace-events
84
index XXXXXXX..XXXXXXX 100644
85
--- a/block/trace-events
86
+++ b/block/trace-events
87
@@ -XXX,XX +XXX,XX @@ curl_open(const char *file) "opening %s"
88
curl_open_size(uint64_t size) "size = %" PRIu64
89
curl_setup_preadv(uint64_t bytes, uint64_t start, const char *range) "reading %" PRIu64 " at %" PRIu64 " (%s)"
90
curl_close(void) "close"
91
+
92
+# block/file-posix.c
93
+file_xfs_write_zeroes(const char *error) "cannot write zero range (%s)"
94
+file_xfs_discard(const char *error) "cannot punch hole (%s)"
95
+file_FindEjectableOpticalMedia(const char *media) "Matching using %s"
96
+file_setup_cdrom(const char *partition) "Using %s as optical disc"
97
+file_hdev_is_sg(int type, int version) "SG device found: type=%d, version=%d"
98
--
99
2.20.1
100
101
diff view generated by jsdifflib
Deleted patch
1
From: Li Qiang <liq3ea@163.com>
2
1
3
When it is zero, it causes segv.
4
Using following command:
5
6
"-drive file=//home/test/test1.img,if=none,id=id0
7
-device nvme,drive=id0,serial=test,num_queues=0"
8
causes following Backtrack:
9
10
Thread 4 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
11
[Switching to Thread 0x7fffe9735700 (LWP 30952)]
12
0x0000555555a7a77c in nvme_start_ctrl (n=0x5555577473f0) at hw/block/nvme.c:825
13
825     if (unlikely(n->cq[0])) {
14
(gdb) bt
15
0 0x0000555555a7a77c in nvme_start_ctrl (n=0x5555577473f0)
16
at hw/block/nvme.c:825
17
1 0x0000555555a7af7f in nvme_write_bar (n=0x5555577473f0, offset=20,
18
data=4587521, size=4) at hw/block/nvme.c:969
19
2 0x0000555555a7b81a in nvme_mmio_write (opaque=0x5555577473f0, addr=20,
20
data=4587521, size=4) at hw/block/nvme.c:1163
21
3 0x0000555555869236 in memory_region_write_accessor (mr=0x555557747cd0,
22
addr=20, value=0x7fffe97320f8, size=4, shift=0, mask=4294967295, attrs=...)
23
at /home/test/qemu1/qemu/memory.c:502
24
4 0x0000555555869446 in access_with_adjusted_size (addr=20,
25
value=0x7fffe97320f8, size=4, access_size_min=2, access_size_max=8,
26
access_fn=0x55555586914d <memory_region_write_accessor>,
27
mr=0x555557747cd0, attrs=...) at /home/test/qemu1/qemu/memory.c:568
28
5 0x000055555586c479 in memory_region_dispatch_write (mr=0x555557747cd0,
29
addr=20, data=4587521, size=4, attrs=...)
30
at /home/test/qemu1/qemu/memory.c:1499
31
6 0x00005555558030af in flatview_write_continue (fv=0x7fffe0061130,
32
addr=4273930260, attrs=..., buf=0x7ffff7ff0028 "\001", len=4, addr1=20,
33
l=4, mr=0x555557747cd0) at /home/test/qemu1/qemu/exec.c:3234
34
7 0x00005555558031f9 in flatview_write (fv=0x7fffe0061130, addr=4273930260,
35
attrs=..., buf=0x7ffff7ff0028 "\001", len=4)
36
at /home/test/qemu1/qemu/exec.c:3273
37
8 0x00005555558034ff in address_space_write (
38
---Type <return> to continue, or q <return> to quit---
39
as=0x555556758480 <address_space_memory>, addr=4273930260, attrs=...,
40
buf=0x7ffff7ff0028 "\001", len=4) at /home/test/qemu1/qemu/exec.c:3363
41
9 0x0000555555803550 in address_space_rw (
42
as=0x555556758480 <address_space_memory>, addr=4273930260, attrs=...,
43
buf=0x7ffff7ff0028 "\001", len=4, is_write=true)
44
at /home/test/qemu1/qemu/exec.c:3374
45
10 0x00005555558884a1 in kvm_cpu_exec (cpu=0x555556920e40)
46
at /home/test/qemu1/qemu/accel/kvm/kvm-all.c:2031
47
11 0x000055555584cd9d in qemu_kvm_cpu_thread_fn (arg=0x555556920e40)
48
at /home/test/qemu1/qemu/cpus.c:1281
49
12 0x0000555555dbaf6d in qemu_thread_start (args=0x5555569438a0)
50
at util/qemu-thread-posix.c:502
51
13 0x00007ffff5dc86db in start_thread (arg=0x7fffe9735700)
52
at pthread_create.c:463
53
14 0x00007ffff5af188f in clone ()
54
at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
55
56
Signed-off-by: Li Qiang <liq3ea@163.com>
57
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
58
Message-id: 20190120055558.32984-3-liq3ea@163.com
59
Signed-off-by: Max Reitz <mreitz@redhat.com>
60
---
61
hw/block/nvme.c | 5 +++++
62
1 file changed, 5 insertions(+)
63
64
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/hw/block/nvme.c
67
+++ b/hw/block/nvme.c
68
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
69
int64_t bs_size;
70
uint8_t *pci_conf;
71
72
+ if (!n->num_queues) {
73
+ error_setg(errp, "num_queues can't be zero");
74
+ return;
75
+ }
76
+
77
if (!n->conf.blk) {
78
error_setg(errp, "drive property not set");
79
return;
80
--
81
2.20.1
82
83
diff view generated by jsdifflib
Deleted patch
1
In some cases, we may want to deal with qemu-nbd errors (e.g. by
2
launching it in a different configuration until it no longer throws
3
any). In that case, we do not want its output ending up in the test
4
output.
5
1
6
It may still be useful for handling the error, though, so add a new
7
function that works basically like qemu_nbd(), only that it returns the
8
qemu-nbd output instead of making it end up in the log. In contrast to
9
qemu_img_pipe(), it does still return the exit code as well, though,
10
because that is even more important for error handling.
11
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
Message-id: 20181221234750.23577-2-mreitz@redhat.com
14
Reviewed-by: John Snow <jsnow@redhat.com>
15
Reviewed-by: Eric Blake <eblake@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
tests/qemu-iotests/iotests.py | 14 ++++++++++++++
19
1 file changed, 14 insertions(+)
20
21
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
22
index XXXXXXX..XXXXXXX 100644
23
--- a/tests/qemu-iotests/iotests.py
24
+++ b/tests/qemu-iotests/iotests.py
25
@@ -XXX,XX +XXX,XX @@ def qemu_nbd(*args):
26
'''Run qemu-nbd in daemon mode and return the parent's exit code'''
27
return subprocess.call(qemu_nbd_args + ['--fork'] + list(args))
28
29
+def qemu_nbd_pipe(*args):
30
+ '''Run qemu-nbd in daemon mode and return both the parent's exit code
31
+ and its output'''
32
+ subp = subprocess.Popen(qemu_nbd_args + ['--fork'] + list(args),
33
+ stdout=subprocess.PIPE,
34
+ stderr=subprocess.STDOUT,
35
+ universal_newlines=True)
36
+ exitcode = subp.wait()
37
+ if exitcode < 0:
38
+ sys.stderr.write('qemu-nbd received signal %i: %s\n' %
39
+ (-exitcode,
40
+ ' '.join(qemu_nbd_args + ['--fork'] + list(args))))
41
+ return exitcode, subp.communicate()[0]
42
+
43
def compare_images(img1, img2, fmt1=imgfmt, fmt2=imgfmt):
44
'''Return True if two image files are identical'''
45
return qemu_img('compare', '-f', fmt1,
46
--
47
2.20.1
48
49
diff view generated by jsdifflib