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 |