1
The following changes since commit b4fbe1f65a4769c09e6bf2d79fc84360f840f40e:
1
The following changes since commit 9cf289af47bcfae5c75de37d8e5d6fd23705322c:
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 tag 'qga-pull-request' of gitlab.com:marcandre.lureau/qemu into staging (2022-05-04 03:42:49 -0700)
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 bef2e050d6a7feb865854c65570c496ac5a8cf53:
10
10
11
iotests: Allow 147 to be run concurrently (2019-01-31 00:44:55 +0100)
11
util/event-loop-base: Introduce options to set the thread pool size (2022-05-04 17:02:19 +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
Add new thread-pool-min/thread-pool-max parameters to control the thread pool
17
- Fixed qemu-io's use of getopt() for systems with optreset
17
used for async I/O.
18
- Minor NVMe emulation fixes
19
- An iotest fix
20
18
21
----------------------------------------------------------------
19
----------------------------------------------------------------
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
20
28
Li Qiang (3):
21
Nicolas Saenz Julienne (3):
29
nvme: use TYPE_NVME instead of constant string
22
Introduce event-loop-base abstract class
30
nvme: ensure the num_queues is not zero
23
util/main-loop: Introduce the main loop into QOM
31
nvme: use pci_dev directly in nvme_realize
24
util/event-loop-base: Introduce options to set the thread pool size
32
25
33
Max Reitz (3):
26
qapi/qom.json | 43 ++++++++--
34
iotests.py: Add qemu_nbd_pipe()
27
meson.build | 26 +++---
35
iotests: Bind qemu-nbd to localhost in 147
28
include/block/aio.h | 10 +++
36
iotests: Allow 147 to be run concurrently
29
include/block/thread-pool.h | 3 +
37
30
include/qemu/main-loop.h | 10 +++
38
Richard W.M. Jones (1):
31
include/sysemu/event-loop-base.h | 41 +++++++++
39
qemu-io: Add generic function for reinitializing optind.
32
include/sysemu/iothread.h | 6 +-
40
33
event-loop-base.c | 140 +++++++++++++++++++++++++++++++
41
Vladimir Sementsov-Ogievskiy (2):
34
iothread.c | 68 +++++----------
42
qapi: add x-debug-query-block-graph
35
util/aio-posix.c | 1 +
43
scripts: add render_block_graph function for QEMUMachine
36
util/async.c | 20 +++++
44
37
util/main-loop.c | 65 ++++++++++++++
45
configure | 14 ++++
38
util/thread-pool.c | 55 +++++++++++-
46
qapi/block-core.json | 108 ++++++++++++++++++++++++
39
13 files changed, 419 insertions(+), 69 deletions(-)
47
include/block/block.h | 1 +
40
create mode 100644 include/sysemu/event-loop-base.h
48
include/qemu/osdep.h | 16 ++++
41
create mode 100644 event-loop-base.c
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
42
67
--
43
--
68
2.20.1
44
2.35.1
69
70
diff view generated by jsdifflib
1
From: Laurent Vivier <lvivier@redhat.com>
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
2
3
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
3
Introduce the 'event-loop-base' abstract class, it'll hold the
4
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
4
properties common to all event loops and provide the necessary hooks for
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
5
their creation and maintenance. Then have iothread inherit from it.
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
EventLoopBaseClass is defined as user creatable and provides a hook for
8
instead of size_t]
8
its children to attach themselves to the user creatable class 'complete'
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
function. It also provides an update_params() callback to propagate
10
property changes onto its children.
11
12
The new 'event-loop-base' class will live in the root directory. It is
13
built on its own using the 'link_whole' option (there are no direct
14
function dependencies between the class and its children, it all happens
15
trough 'constructor' magic). And also imposes new compilation
16
dependencies:
17
18
qom <- event-loop-base <- blockdev (iothread.c)
19
20
And in subsequent patches:
21
22
qom <- event-loop-base <- qemuutil (util/main-loop.c)
23
24
All this forced some amount of reordering in meson.build:
25
26
- Moved qom build definition before qemuutil. Doing it the other way
27
around (i.e. moving qemuutil after qom) isn't possible as a lot of
28
core libraries that live in between the two depend on it.
29
30
- Process the 'hw' subdir earlier, as it introduces files into the
31
'qom' source set.
32
33
No functional changes intended.
34
35
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
36
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
37
Acked-by: Markus Armbruster <armbru@redhat.com>
38
Message-id: 20220425075723.20019-2-nsaenzju@redhat.com
39
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
10
---
40
---
11
block/ssh.c | 46 +++++++++++++++++-----------------------------
41
qapi/qom.json | 22 +++++--
12
block/trace-events | 17 +++++++++++++++++
42
meson.build | 23 ++++---
13
2 files changed, 34 insertions(+), 29 deletions(-)
43
include/sysemu/event-loop-base.h | 36 +++++++++++
14
44
include/sysemu/iothread.h | 6 +-
15
diff --git a/block/ssh.c b/block/ssh.c
45
event-loop-base.c | 104 +++++++++++++++++++++++++++++++
46
iothread.c | 65 ++++++-------------
47
6 files changed, 192 insertions(+), 64 deletions(-)
48
create mode 100644 include/sysemu/event-loop-base.h
49
create mode 100644 event-loop-base.c
50
51
diff --git a/qapi/qom.json b/qapi/qom.json
16
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
17
--- a/block/ssh.c
53
--- a/qapi/qom.json
18
+++ b/block/ssh.c
54
+++ b/qapi/qom.json
19
@@ -XXX,XX +XXX,XX @@
55
@@ -XXX,XX +XXX,XX @@
20
#include "qapi/qmp/qstring.h"
56
'*repeat': 'bool',
21
#include "qapi/qobject-input-visitor.h"
57
'*grab-toggle': 'GrabToggleKeys' } }
22
#include "qapi/qobject-output-visitor.h"
58
23
+#include "trace.h"
59
+##
24
60
+# @EventLoopBaseProperties:
25
-/* DEBUG_SSH=1 enables the DPRINTF (debugging printf) statements in
61
+#
26
- * this block driver code.
62
+# Common properties for event loops
27
- *
63
+#
64
+# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
65
+# 0 means that the engine will use its default.
66
+# (default: 0)
67
+#
68
+# Since: 7.1
69
+##
70
+{ 'struct': 'EventLoopBaseProperties',
71
+ 'data': { '*aio-max-batch': 'int' } }
72
+
73
##
74
# @IothreadProperties:
75
#
76
@@ -XXX,XX +XXX,XX @@
77
# algorithm detects it is spending too long polling without
78
# encountering events. 0 selects a default behaviour (default: 0)
79
#
80
-# @aio-max-batch: maximum number of requests in a batch for the AIO engine,
81
-# 0 means that the engine will use its default
82
-# (default:0, since 6.1)
83
+# The @aio-max-batch option is available since 6.1.
84
#
85
# Since: 2.0
86
##
87
{ 'struct': 'IothreadProperties',
88
+ 'base': 'EventLoopBaseProperties',
89
'data': { '*poll-max-ns': 'int',
90
'*poll-grow': 'int',
91
- '*poll-shrink': 'int',
92
- '*aio-max-batch': 'int' } }
93
+ '*poll-shrink': 'int' } }
94
95
##
96
# @MemoryBackendProperties:
97
diff --git a/meson.build b/meson.build
98
index XXXXXXX..XXXXXXX 100644
99
--- a/meson.build
100
+++ b/meson.build
101
@@ -XXX,XX +XXX,XX @@ subdir('qom')
102
subdir('authz')
103
subdir('crypto')
104
subdir('ui')
105
+subdir('hw')
106
107
108
if enable_modules
109
@@ -XXX,XX +XXX,XX @@ if enable_modules
110
modulecommon = declare_dependency(link_whole: libmodulecommon, compile_args: '-DBUILD_DSO')
111
endif
112
113
+qom_ss = qom_ss.apply(config_host, strict: false)
114
+libqom = static_library('qom', qom_ss.sources() + genh,
115
+ dependencies: [qom_ss.dependencies()],
116
+ name_suffix: 'fa')
117
+qom = declare_dependency(link_whole: libqom)
118
+
119
+event_loop_base = files('event-loop-base.c')
120
+event_loop_base = static_library('event-loop-base', sources: event_loop_base + genh,
121
+ build_by_default: true)
122
+event_loop_base = declare_dependency(link_whole: event_loop_base,
123
+ dependencies: [qom])
124
+
125
stub_ss = stub_ss.apply(config_all, strict: false)
126
127
util_ss.add_all(trace_ss)
128
@@ -XXX,XX +XXX,XX @@ subdir('monitor')
129
subdir('net')
130
subdir('replay')
131
subdir('semihosting')
132
-subdir('hw')
133
subdir('tcg')
134
subdir('fpu')
135
subdir('accel')
136
@@ -XXX,XX +XXX,XX @@ qemu_syms = custom_target('qemu.syms', output: 'qemu.syms',
137
capture: true,
138
command: [undefsym, nm, '@INPUT@'])
139
140
-qom_ss = qom_ss.apply(config_host, strict: false)
141
-libqom = static_library('qom', qom_ss.sources() + genh,
142
- dependencies: [qom_ss.dependencies()],
143
- name_suffix: 'fa')
144
-
145
-qom = declare_dependency(link_whole: libqom)
146
-
147
authz_ss = authz_ss.apply(config_host, strict: false)
148
libauthz = static_library('authz', authz_ss.sources() + genh,
149
dependencies: [authz_ss.dependencies()],
150
@@ -XXX,XX +XXX,XX @@ libblockdev = static_library('blockdev', blockdev_ss.sources() + genh,
151
build_by_default: false)
152
153
blockdev = declare_dependency(link_whole: [libblockdev],
154
- dependencies: [block])
155
+ dependencies: [block, event_loop_base])
156
157
qmp_ss = qmp_ss.apply(config_host, strict: false)
158
libqmp = static_library('qmp', qmp_ss.sources() + genh,
159
diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h
160
new file mode 100644
161
index XXXXXXX..XXXXXXX
162
--- /dev/null
163
+++ b/include/sysemu/event-loop-base.h
164
@@ -XXX,XX +XXX,XX @@
28
+/*
165
+/*
29
* TRACE_LIBSSH2=<bitmask> enables tracing in libssh2 itself. Note
166
+ * QEMU event-loop backend
30
* that this requires that libssh2 was specially compiled with the
167
+ *
31
* `./configure --enable-debug' option, so most likely you will have
168
+ * Copyright (C) 2022 Red Hat Inc
32
* to compile it yourself. The meaning of <bitmask> is described
169
+ *
33
* here: http://www.libssh2.org/libssh2_trace.html
170
+ * Authors:
34
*/
171
+ * Nicolas Saenz Julienne <nsaenzju@redhat.com>
35
-#define DEBUG_SSH 0
172
+ *
36
#define TRACE_LIBSSH2 0 /* or try: LIBSSH2_TRACE_SFTP */
173
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
37
174
+ * See the COPYING file in the top-level directory.
38
-#define DPRINTF(fmt, ...) \
175
+ */
39
- do { \
176
+#ifndef QEMU_EVENT_LOOP_BASE_H
40
- if (DEBUG_SSH) { \
177
+#define QEMU_EVENT_LOOP_BASE_H
41
- fprintf(stderr, "ssh: %-15s " fmt "\n", \
178
+
42
- __func__, ##__VA_ARGS__); \
179
+#include "qom/object.h"
43
- } \
180
+#include "block/aio.h"
44
- } while (0)
181
+#include "qemu/typedefs.h"
45
-
182
+
46
typedef struct BDRVSSHState {
183
+#define TYPE_EVENT_LOOP_BASE "event-loop-base"
47
/* Coroutine. */
184
+OBJECT_DECLARE_TYPE(EventLoopBase, EventLoopBaseClass,
48
CoMutex lock;
185
+ EVENT_LOOP_BASE)
49
@@ -XXX,XX +XXX,XX @@ static int check_host_key_knownhosts(BDRVSSHState *s,
186
+
50
switch (r) {
187
+struct EventLoopBaseClass {
51
case LIBSSH2_KNOWNHOST_CHECK_MATCH:
188
+ ObjectClass parent_class;
52
/* OK */
189
+
53
- DPRINTF("host key OK: %s", found->key);
190
+ void (*init)(EventLoopBase *base, Error **errp);
54
+ trace_ssh_check_host_key_knownhosts(found->key);
191
+ void (*update_params)(EventLoopBase *base, Error **errp);
55
break;
192
+};
56
case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
193
+
57
ret = -EINVAL;
194
+struct EventLoopBase {
58
@@ -XXX,XX +XXX,XX @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts,
195
+ Object parent;
196
+
197
+ /* AioContext AIO engine parameters */
198
+ int64_t aio_max_batch;
199
+};
200
+#endif
201
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
202
index XXXXXXX..XXXXXXX 100644
203
--- a/include/sysemu/iothread.h
204
+++ b/include/sysemu/iothread.h
205
@@ -XXX,XX +XXX,XX @@
206
#include "block/aio.h"
207
#include "qemu/thread.h"
208
#include "qom/object.h"
209
+#include "sysemu/event-loop-base.h"
210
211
#define TYPE_IOTHREAD "iothread"
212
213
struct IOThread {
214
- Object parent_obj;
215
+ EventLoopBase parent_obj;
216
217
QemuThread thread;
218
AioContext *ctx;
219
@@ -XXX,XX +XXX,XX @@ struct IOThread {
220
int64_t poll_max_ns;
221
int64_t poll_grow;
222
int64_t poll_shrink;
223
-
224
- /* AioContext AIO engine parameters */
225
- int64_t aio_max_batch;
226
};
227
typedef struct IOThread IOThread;
228
229
diff --git a/event-loop-base.c b/event-loop-base.c
230
new file mode 100644
231
index XXXXXXX..XXXXXXX
232
--- /dev/null
233
+++ b/event-loop-base.c
234
@@ -XXX,XX +XXX,XX @@
235
+/*
236
+ * QEMU event-loop base
237
+ *
238
+ * Copyright (C) 2022 Red Hat Inc
239
+ *
240
+ * Authors:
241
+ * Stefan Hajnoczi <stefanha@redhat.com>
242
+ * Nicolas Saenz Julienne <nsaenzju@redhat.com>
243
+ *
244
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
245
+ * See the COPYING file in the top-level directory.
246
+ */
247
+
248
+#include "qemu/osdep.h"
249
+#include "qom/object_interfaces.h"
250
+#include "qapi/error.h"
251
+#include "sysemu/event-loop-base.h"
252
+
253
+typedef struct {
254
+ const char *name;
255
+ ptrdiff_t offset; /* field's byte offset in EventLoopBase struct */
256
+} EventLoopBaseParamInfo;
257
+
258
+static EventLoopBaseParamInfo aio_max_batch_info = {
259
+ "aio-max-batch", offsetof(EventLoopBase, aio_max_batch),
260
+};
261
+
262
+static void event_loop_base_get_param(Object *obj, Visitor *v,
263
+ const char *name, void *opaque, Error **errp)
264
+{
265
+ EventLoopBase *event_loop_base = EVENT_LOOP_BASE(obj);
266
+ EventLoopBaseParamInfo *info = opaque;
267
+ int64_t *field = (void *)event_loop_base + info->offset;
268
+
269
+ visit_type_int64(v, name, field, errp);
270
+}
271
+
272
+static void event_loop_base_set_param(Object *obj, Visitor *v,
273
+ const char *name, void *opaque, Error **errp)
274
+{
275
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(obj);
276
+ EventLoopBase *base = EVENT_LOOP_BASE(obj);
277
+ EventLoopBaseParamInfo *info = opaque;
278
+ int64_t *field = (void *)base + info->offset;
279
+ int64_t value;
280
+
281
+ if (!visit_type_int64(v, name, &value, errp)) {
282
+ return;
283
+ }
284
+
285
+ if (value < 0) {
286
+ error_setg(errp, "%s value must be in range [0, %" PRId64 "]",
287
+ info->name, INT64_MAX);
288
+ return;
289
+ }
290
+
291
+ *field = value;
292
+
293
+ if (bc->update_params) {
294
+ bc->update_params(base, errp);
295
+ }
296
+
297
+ return;
298
+}
299
+
300
+static void event_loop_base_complete(UserCreatable *uc, Error **errp)
301
+{
302
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc);
303
+ EventLoopBase *base = EVENT_LOOP_BASE(uc);
304
+
305
+ if (bc->init) {
306
+ bc->init(base, errp);
307
+ }
308
+}
309
+
310
+static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
311
+{
312
+ UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
313
+ ucc->complete = event_loop_base_complete;
314
+
315
+ object_class_property_add(klass, "aio-max-batch", "int",
316
+ event_loop_base_get_param,
317
+ event_loop_base_set_param,
318
+ NULL, &aio_max_batch_info);
319
+}
320
+
321
+static const TypeInfo event_loop_base_info = {
322
+ .name = TYPE_EVENT_LOOP_BASE,
323
+ .parent = TYPE_OBJECT,
324
+ .instance_size = sizeof(EventLoopBase),
325
+ .class_size = sizeof(EventLoopBaseClass),
326
+ .class_init = event_loop_base_class_init,
327
+ .abstract = true,
328
+ .interfaces = (InterfaceInfo[]) {
329
+ { TYPE_USER_CREATABLE },
330
+ { }
331
+ }
332
+};
333
+
334
+static void register_types(void)
335
+{
336
+ type_register_static(&event_loop_base_info);
337
+}
338
+type_init(register_types);
339
diff --git a/iothread.c b/iothread.c
340
index XXXXXXX..XXXXXXX 100644
341
--- a/iothread.c
342
+++ b/iothread.c
343
@@ -XXX,XX +XXX,XX @@
344
#include "qemu/module.h"
345
#include "block/aio.h"
346
#include "block/block.h"
347
+#include "sysemu/event-loop-base.h"
348
#include "sysemu/iothread.h"
349
#include "qapi/error.h"
350
#include "qapi/qapi-commands-misc.h"
351
@@ -XXX,XX +XXX,XX @@ static void iothread_init_gcontext(IOThread *iothread)
352
iothread->main_loop = g_main_loop_new(iothread->worker_context, TRUE);
353
}
354
355
-static void iothread_set_aio_context_params(IOThread *iothread, Error **errp)
356
+static void iothread_set_aio_context_params(EventLoopBase *base, Error **errp)
357
{
358
+ IOThread *iothread = IOTHREAD(base);
359
ERRP_GUARD();
360
361
+ if (!iothread->ctx) {
362
+ return;
363
+ }
364
+
365
aio_context_set_poll_params(iothread->ctx,
366
iothread->poll_max_ns,
367
iothread->poll_grow,
368
@@ -XXX,XX +XXX,XX @@ static void iothread_set_aio_context_params(IOThread *iothread, Error **errp)
59
}
369
}
60
370
61
/* Open the remote file. */
371
aio_context_set_aio_params(iothread->ctx,
62
- DPRINTF("opening file %s flags=0x%x creat_mode=0%o",
372
- iothread->aio_max_batch,
63
- opts->path, ssh_flags, creat_mode);
373
+ iothread->parent_obj.aio_max_batch,
64
+ trace_ssh_connect_to_ssh(opts->path, ssh_flags, creat_mode);
374
errp);
65
s->sftp_handle = libssh2_sftp_open(s->sftp, opts->path, ssh_flags,
375
}
66
creat_mode);
376
67
if (!s->sftp_handle) {
377
-static void iothread_complete(UserCreatable *obj, Error **errp)
68
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn ssh_co_create_opts(const char *filename, QemuOpts *opts,
378
+
69
/* Get desired file size. */
379
+static void iothread_init(EventLoopBase *base, Error **errp)
70
ssh_opts->size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
380
{
71
BDRV_SECTOR_SIZE);
381
Error *local_error = NULL;
72
- DPRINTF("total_size=%" PRIi64, ssh_opts->size);
382
- IOThread *iothread = IOTHREAD(obj);
73
+ trace_ssh_co_create_opts(ssh_opts->size);
383
+ IOThread *iothread = IOTHREAD(base);
74
384
char *thread_name;
75
uri_options = qdict_new();
385
76
ret = parse_uri(filename, uri_options, errp);
386
iothread->stopping = false;
77
@@ -XXX,XX +XXX,XX @@ static void restart_coroutine(void *opaque)
387
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
78
BDRVSSHState *s = bs->opaque;
388
*/
79
AioContext *ctx = bdrv_get_aio_context(bs);
389
iothread_init_gcontext(iothread);
80
390
81
- DPRINTF("co=%p", restart->co);
391
- iothread_set_aio_context_params(iothread, &local_error);
82
+ trace_ssh_restart_coroutine(restart->co);
392
+ iothread_set_aio_context_params(base, &local_error);
83
aio_set_fd_handler(ctx, s->sock, false, NULL, NULL, NULL, NULL);
393
if (local_error) {
84
394
error_propagate(errp, local_error);
85
aio_co_wake(restart->co);
395
aio_context_unref(iothread->ctx);
86
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void co_yield(BDRVSSHState *s, BlockDriverState *bs)
396
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
87
wr_handler = restart_coroutine;
397
* to inherit.
398
*/
399
thread_name = g_strdup_printf("IO %s",
400
- object_get_canonical_path_component(OBJECT(obj)));
401
+ object_get_canonical_path_component(OBJECT(base)));
402
qemu_thread_create(&iothread->thread, thread_name, iothread_run,
403
iothread, QEMU_THREAD_JOINABLE);
404
g_free(thread_name);
405
@@ -XXX,XX +XXX,XX @@ static IOThreadParamInfo poll_grow_info = {
406
static IOThreadParamInfo poll_shrink_info = {
407
"poll-shrink", offsetof(IOThread, poll_shrink),
408
};
409
-static IOThreadParamInfo aio_max_batch_info = {
410
- "aio-max-batch", offsetof(IOThread, aio_max_batch),
411
-};
412
413
static void iothread_get_param(Object *obj, Visitor *v,
414
const char *name, IOThreadParamInfo *info, Error **errp)
415
@@ -XXX,XX +XXX,XX @@ static void iothread_set_poll_param(Object *obj, Visitor *v,
88
}
416
}
89
90
- DPRINTF("s->sock=%d rd_handler=%p wr_handler=%p", s->sock,
91
- rd_handler, wr_handler);
92
+ trace_ssh_co_yield(s->sock, rd_handler, wr_handler);
93
94
aio_set_fd_handler(bdrv_get_aio_context(bs), s->sock,
95
false, rd_handler, wr_handler, NULL, &restart);
96
qemu_coroutine_yield();
97
- DPRINTF("s->sock=%d - back", s->sock);
98
+ trace_ssh_co_yield_back(s->sock);
99
}
417
}
100
418
101
/* SFTP has a function `libssh2_sftp_seek64' which seeks to a position
419
-static void iothread_get_aio_param(Object *obj, Visitor *v,
102
@@ -XXX,XX +XXX,XX @@ static void ssh_seek(BDRVSSHState *s, int64_t offset, int flags)
420
- const char *name, void *opaque, Error **errp)
103
bool force = (flags & SSH_SEEK_FORCE) != 0;
421
-{
104
422
- IOThreadParamInfo *info = opaque;
105
if (force || op_read != s->offset_op_read || offset != s->offset) {
423
-
106
- DPRINTF("seeking to offset=%" PRIi64, offset);
424
- iothread_get_param(obj, v, name, info, errp);
107
+ trace_ssh_seek(offset);
425
-}
108
libssh2_sftp_seek64(s->sftp_handle, offset);
426
-
109
s->offset = offset;
427
-static void iothread_set_aio_param(Object *obj, Visitor *v,
110
s->offset_op_read = op_read;
428
- const char *name, void *opaque, Error **errp)
111
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
429
-{
112
char *buf, *end_of_vec;
430
- IOThread *iothread = IOTHREAD(obj);
113
struct iovec *i;
431
- IOThreadParamInfo *info = opaque;
114
432
-
115
- DPRINTF("offset=%" PRIi64 " size=%zu", offset, size);
433
- if (!iothread_set_param(obj, v, name, info, errp)) {
116
+ trace_ssh_read(offset, size);
434
- return;
117
435
- }
118
ssh_seek(s, offset, SSH_SEEK_READ);
436
-
119
437
- if (iothread->ctx) {
120
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int ssh_read(BDRVSSHState *s, BlockDriverState *bs,
438
- aio_context_set_aio_params(iothread->ctx,
121
*/
439
- iothread->aio_max_batch,
122
for (got = 0; got < size; ) {
440
- errp);
123
again:
441
- }
124
- DPRINTF("sftp_read buf=%p size=%zu", buf, end_of_vec - buf);
442
-}
125
+ trace_ssh_read_buf(buf, end_of_vec - buf);
443
-
126
r = libssh2_sftp_read(s->sftp_handle, buf, end_of_vec - buf);
444
static void iothread_class_init(ObjectClass *klass, void *class_data)
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
{
445
{
155
int r;
446
- UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
156
447
- ucc->complete = iothread_complete;
157
- DPRINTF("fsync");
448
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(klass);
158
+ trace_ssh_flush();
449
+
159
again:
450
+ bc->init = iothread_init;
160
r = libssh2_sftp_fsync(s->sftp_handle);
451
+ bc->update_params = iothread_set_aio_context_params;
161
if (r == LIBSSH2_ERROR_EAGAIN || r == LIBSSH2_ERROR_TIMEOUT) {
452
162
@@ -XXX,XX +XXX,XX @@ static int64_t ssh_getlength(BlockDriverState *bs)
453
object_class_property_add(klass, "poll-max-ns", "int",
163
454
iothread_get_poll_param,
164
/* Note we cannot make a libssh2 call here. */
455
@@ -XXX,XX +XXX,XX @@ static void iothread_class_init(ObjectClass *klass, void *class_data)
165
length = (int64_t) s->attrs.filesize;
456
iothread_get_poll_param,
166
- DPRINTF("length=%" PRIi64, length);
457
iothread_set_poll_param,
167
+ trace_ssh_getlength(length);
458
NULL, &poll_shrink_info);
168
459
- object_class_property_add(klass, "aio-max-batch", "int",
169
return length;
460
- iothread_get_aio_param,
461
- iothread_set_aio_param,
462
- NULL, &aio_max_batch_info);
170
}
463
}
171
diff --git a/block/trace-events b/block/trace-events
464
172
index XXXXXXX..XXXXXXX 100644
465
static const TypeInfo iothread_info = {
173
--- a/block/trace-events
466
.name = TYPE_IOTHREAD,
174
+++ b/block/trace-events
467
- .parent = TYPE_OBJECT,
175
@@ -XXX,XX +XXX,XX @@ iscsi_xcopy(void *src_lun, uint64_t src_off, void *dst_lun, uint64_t dst_off, ui
468
+ .parent = TYPE_EVENT_LOOP_BASE,
176
# block/nbd-client.c
469
.class_init = iothread_class_init,
177
nbd_read_reply_entry_fail(int ret, const char *err) "ret = %d, err: %s"
470
.instance_size = sizeof(IOThread),
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"
471
.instance_init = iothread_instance_init,
179
+
472
.instance_finalize = iothread_instance_finalize,
180
+# block/ssh.c
473
- .interfaces = (InterfaceInfo[]) {
181
+ssh_restart_coroutine(void *co) "co=%p"
474
- {TYPE_USER_CREATABLE},
182
+ssh_flush(void) "fsync"
475
- {}
183
+ssh_check_host_key_knownhosts(const char *key) "host key OK: %s"
476
- },
184
+ssh_connect_to_ssh(char *path, int flags, int mode) "opening file %s flags=0x%x creat_mode=0%o"
477
};
185
+ssh_co_yield(int sock, void *rd_handler, void *wr_handler) "s->sock=%d rd_handler=%p wr_handler=%p"
478
186
+ssh_co_yield_back(int sock) "s->sock=%d - back"
479
static void iothread_register_types(void)
187
+ssh_getlength(int64_t length) "length=%" PRIi64
480
@@ -XXX,XX +XXX,XX @@ static int query_one_iothread(Object *object, void *opaque)
188
+ssh_co_create_opts(uint64_t size) "total_size=%" PRIu64
481
info->poll_max_ns = iothread->poll_max_ns;
189
+ssh_read(int64_t offset, size_t size) "offset=%" PRIi64 " size=%zu"
482
info->poll_grow = iothread->poll_grow;
190
+ssh_read_buf(void *buf, size_t size) "sftp_read buf=%p size=%zu"
483
info->poll_shrink = iothread->poll_shrink;
191
+ssh_read_return(ssize_t ret) "sftp_read returned %zd"
484
- info->aio_max_batch = iothread->aio_max_batch;
192
+ssh_write(int64_t offset, size_t size) "offset=%" PRIi64 " size=%zu"
485
+ info->aio_max_batch = iothread->parent_obj.aio_max_batch;
193
+ssh_write_buf(void *buf, size_t size) "sftp_write buf=%p size=%zu"
486
194
+ssh_write_return(ssize_t ret) "sftp_write returned %zd"
487
QAPI_LIST_APPEND(*tail, info);
195
+ssh_seek(int64_t offset) "seeking to offset=%" PRIi64
488
return 0;
196
--
489
--
197
2.20.1
490
2.35.1
198
199
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
2
3
Add a new command, returning block nodes (and their users) graph.
3
'event-loop-base' provides basic property handling for all 'AioContext'
4
4
based event loops. So let's define a new 'MainLoopClass' that inherits
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
from it. This will permit tweaking the main loop's properties through
6
Message-id: 20181221170909.25584-2-vsementsov@virtuozzo.com
6
qapi as well as through the command line using the '-object' keyword[1].
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Only one instance of 'MainLoopClass' might be created at any time.
8
9
'EventLoopBaseClass' learns a new callback, 'can_be_deleted()' so as to
10
mark 'MainLoop' as non-deletable.
11
12
[1] For example:
13
-object main-loop,id=main-loop,aio-max-batch=<value>
14
15
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
17
Acked-by: Markus Armbruster <armbru@redhat.com>
18
Message-id: 20220425075723.20019-3-nsaenzju@redhat.com
19
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
8
---
20
---
9
qapi/block-core.json | 108 ++++++++++++++++++++++++
21
qapi/qom.json | 13 ++++++++
10
include/block/block.h | 1 +
22
meson.build | 3 +-
11
include/sysemu/block-backend.h | 2 +
23
include/qemu/main-loop.h | 10 ++++++
12
block.c | 148 +++++++++++++++++++++++++++++++++
24
include/sysemu/event-loop-base.h | 1 +
13
block/block-backend.c | 5 ++
25
event-loop-base.c | 13 ++++++++
14
blockdev.c | 5 ++
26
util/main-loop.c | 56 ++++++++++++++++++++++++++++++++
15
6 files changed, 269 insertions(+)
27
6 files changed, 95 insertions(+), 1 deletion(-)
16
28
17
diff --git a/qapi/block-core.json b/qapi/block-core.json
29
diff --git a/qapi/qom.json b/qapi/qom.json
18
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
19
--- a/qapi/block-core.json
31
--- a/qapi/qom.json
20
+++ b/qapi/block-core.json
32
+++ b/qapi/qom.json
21
@@ -XXX,XX +XXX,XX @@
33
@@ -XXX,XX +XXX,XX @@
34
'*poll-grow': 'int',
35
'*poll-shrink': 'int' } }
36
37
+##
38
+# @MainLoopProperties:
39
+#
40
+# Properties for the main-loop object.
41
+#
42
+# Since: 7.1
43
+##
44
+{ 'struct': 'MainLoopProperties',
45
+ 'base': 'EventLoopBaseProperties',
46
+ 'data': {} }
47
+
22
##
48
##
23
{ 'command': 'query-named-block-nodes', 'returns': [ 'BlockDeviceInfo' ] }
49
# @MemoryBackendProperties:
24
25
+##
26
+# @XDbgBlockGraphNodeType:
27
+#
28
+# @block-backend: corresponds to BlockBackend
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
+
39
+##
40
+# @XDbgBlockGraphNode:
41
+#
42
+# @id: Block graph node identifier. This @id is generated only for
43
+# x-debug-query-block-graph and does not relate to any other identifiers in
44
+# Qemu.
45
+#
46
+# @type: Type of graph node. Can be one of block-backend, block-job or
47
+# block-driver-state.
48
+#
49
+# @name: Human readable name of the node. Corresponds to node-name for
50
+# block-driver-state nodes; is not guaranteed to be unique in the whole
51
+# graph (with block-jobs and block-backends).
52
+#
53
+# Since: 4.0
54
+##
55
+{ 'struct': 'XDbgBlockGraphNode',
56
+ 'data': { 'id': 'uint64', 'type': 'XDbgBlockGraphNodeType', 'name': 'str' } }
57
+
58
+##
59
+# @BlockPermission:
60
+#
61
+# Enum of base block permissions.
62
+#
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
+
114
+##
115
+# @XDbgBlockGraph:
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
#
50
#
136
diff --git a/include/block/block.h b/include/block/block.h
51
@@ -XXX,XX +XXX,XX @@
137
index XXXXXXX..XXXXXXX 100644
52
{ 'name': 'input-linux',
138
--- a/include/block/block.h
53
'if': 'CONFIG_LINUX' },
139
+++ b/include/block/block.h
54
'iothread',
140
@@ -XXX,XX +XXX,XX @@ void bdrv_eject(BlockDriverState *bs, bool eject_flag);
55
+ 'main-loop',
141
const char *bdrv_get_format_name(BlockDriverState *bs);
56
{ 'name': 'memory-backend-epc',
142
BlockDriverState *bdrv_find_node(const char *node_name);
57
'if': 'CONFIG_LINUX' },
143
BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp);
58
'memory-backend-file',
144
+XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp);
59
@@ -XXX,XX +XXX,XX @@
145
BlockDriverState *bdrv_lookup_bs(const char *device,
60
'input-linux': { 'type': 'InputLinuxProperties',
146
const char *node_name,
61
'if': 'CONFIG_LINUX' },
147
Error **errp);
62
'iothread': 'IothreadProperties',
148
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
63
+ 'main-loop': 'MainLoopProperties',
149
index XXXXXXX..XXXXXXX 100644
64
'memory-backend-epc': { 'type': 'MemoryBackendEpcProperties',
150
--- a/include/sysemu/block-backend.h
65
'if': 'CONFIG_LINUX' },
151
+++ b/include/sysemu/block-backend.h
66
'memory-backend-file': 'MemoryBackendFileProperties',
152
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
67
diff --git a/meson.build b/meson.build
153
int bytes, BdrvRequestFlags read_flags,
68
index XXXXXXX..XXXXXXX 100644
154
BdrvRequestFlags write_flags);
69
--- a/meson.build
155
70
+++ b/meson.build
156
+const BdrvChild *blk_root(BlockBackend *blk);
71
@@ -XXX,XX +XXX,XX @@ libqemuutil = static_library('qemuutil',
157
+
72
sources: util_ss.sources() + stub_ss.sources() + genh,
158
#endif
73
dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman])
159
diff --git a/block.c b/block.c
74
qemuutil = declare_dependency(link_with: libqemuutil,
160
index XXXXXXX..XXXXXXX 100644
75
- sources: genh + version_res)
161
--- a/block.c
76
+ sources: genh + version_res,
162
+++ b/block.c
77
+ dependencies: [event_loop_base])
163
@@ -XXX,XX +XXX,XX @@ BlockDeviceInfoList *bdrv_named_nodes_list(Error **errp)
78
164
return list;
79
if have_system or have_user
80
decodetree = generator(find_program('scripts/decodetree.py'),
81
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
82
index XXXXXXX..XXXXXXX 100644
83
--- a/include/qemu/main-loop.h
84
+++ b/include/qemu/main-loop.h
85
@@ -XXX,XX +XXX,XX @@
86
#define QEMU_MAIN_LOOP_H
87
88
#include "block/aio.h"
89
+#include "qom/object.h"
90
+#include "sysemu/event-loop-base.h"
91
92
#define SIG_IPI SIGUSR1
93
94
+#define TYPE_MAIN_LOOP "main-loop"
95
+OBJECT_DECLARE_TYPE(MainLoop, MainLoopClass, MAIN_LOOP)
96
+
97
+struct MainLoop {
98
+ EventLoopBase parent_obj;
99
+};
100
+typedef struct MainLoop MainLoop;
101
+
102
/**
103
* qemu_init_main_loop: Set up the process so that it can run the main loop.
104
*
105
diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h
106
index XXXXXXX..XXXXXXX 100644
107
--- a/include/sysemu/event-loop-base.h
108
+++ b/include/sysemu/event-loop-base.h
109
@@ -XXX,XX +XXX,XX @@ struct EventLoopBaseClass {
110
111
void (*init)(EventLoopBase *base, Error **errp);
112
void (*update_params)(EventLoopBase *base, Error **errp);
113
+ bool (*can_be_deleted)(EventLoopBase *base);
114
};
115
116
struct EventLoopBase {
117
diff --git a/event-loop-base.c b/event-loop-base.c
118
index XXXXXXX..XXXXXXX 100644
119
--- a/event-loop-base.c
120
+++ b/event-loop-base.c
121
@@ -XXX,XX +XXX,XX @@ static void event_loop_base_complete(UserCreatable *uc, Error **errp)
122
}
165
}
123
}
166
124
167
+#define QAPI_LIST_ADD(list, element) do { \
125
+static bool event_loop_base_can_be_deleted(UserCreatable *uc)
168
+ typeof(list) _tmp = g_new(typeof(*(list)), 1); \
126
+{
169
+ _tmp->value = (element); \
127
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc);
170
+ _tmp->next = (list); \
128
+ EventLoopBase *backend = EVENT_LOOP_BASE(uc);
171
+ (list) = _tmp; \
129
+
172
+} while (0)
130
+ if (bc->can_be_deleted) {
173
+
131
+ return bc->can_be_deleted(backend);
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
+ }
132
+ }
206
+
133
+
207
+ /*
134
+ return true;
208
+ * Start counting from 1, not 0, because 0 interferes with not-found (NULL)
135
+}
209
+ * answer of g_hash_table_lookup.
136
+
210
+ */
137
static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
211
+ ret = g_hash_table_size(gr->graph_nodes) + 1;
138
{
212
+ g_hash_table_insert(gr->graph_nodes, node, (void *)ret);
139
UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
213
+
140
ucc->complete = event_loop_base_complete;
214
+ return ret;
141
+ ucc->can_be_deleted = event_loop_base_can_be_deleted;
215
+}
142
216
+
143
object_class_property_add(klass, "aio-max-batch", "int",
217
+static void xdbg_graph_add_node(XDbgBlockGraphConstructor *gr, void *node,
144
event_loop_base_get_param,
218
+ XDbgBlockGraphNodeType type, const char *name)
145
diff --git a/util/main-loop.c b/util/main-loop.c
219
+{
146
index XXXXXXX..XXXXXXX 100644
220
+ XDbgBlockGraphNode *n;
147
--- a/util/main-loop.c
221
+
148
+++ b/util/main-loop.c
222
+ n = g_new0(XDbgBlockGraphNode, 1);
149
@@ -XXX,XX +XXX,XX @@
223
+
150
#include "qemu/error-report.h"
224
+ n->id = xdbg_graph_node_num(gr, node);
151
#include "qemu/queue.h"
225
+ n->type = type;
152
#include "qemu/compiler.h"
226
+ n->name = g_strdup(name);
153
+#include "qom/object.h"
227
+
154
228
+ QAPI_LIST_ADD(gr->graph->nodes, n);
155
#ifndef _WIN32
229
+}
156
#include <sys/wait.h>
230
+
157
@@ -XXX,XX +XXX,XX @@ int qemu_init_main_loop(Error **errp)
231
+static void xdbg_graph_add_edge(XDbgBlockGraphConstructor *gr, void *parent,
158
return 0;
232
+ const BdrvChild *child)
159
}
233
+{
160
234
+ typedef struct {
161
+static void main_loop_update_params(EventLoopBase *base, Error **errp)
235
+ unsigned int flag;
162
+{
236
+ BlockPermission num;
163
+ if (!qemu_aio_context) {
237
+ } PermissionMap;
164
+ error_setg(errp, "qemu aio context not ready");
238
+
165
+ return;
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
+ }
166
+ }
266
+
167
+
267
+ QAPI_LIST_ADD(gr->graph->edges, edge);
168
+ aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
268
+}
169
+}
269
+
170
+
270
+
171
+MainLoop *mloop;
271
+XDbgBlockGraph *bdrv_get_xdbg_block_graph(Error **errp)
172
+
272
+{
173
+static void main_loop_init(EventLoopBase *base, Error **errp)
273
+ BlockBackend *blk;
174
+{
274
+ BlockJob *job;
175
+ MainLoop *m = MAIN_LOOP(base);
275
+ BlockDriverState *bs;
176
+
276
+ BdrvChild *child;
177
+ if (mloop) {
277
+ XDbgBlockGraphConstructor *gr = xdbg_graph_new();
178
+ error_setg(errp, "only one main-loop instance allowed");
278
+
179
+ return;
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
+ }
180
+ }
293
+
181
+
294
+ for (job = block_job_next(NULL); job; job = block_job_next(job)) {
182
+ main_loop_update_params(base, errp);
295
+ GSList *el;
183
+
296
+
184
+ mloop = m;
297
+ xdbg_graph_add_node(gr, job, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_JOB,
185
+ return;
298
+ job->job.id);
186
+}
299
+ for (el = job->nodes; el; el = el->next) {
187
+
300
+ xdbg_graph_add_edge(gr, job, (BdrvChild *)el->data);
188
+static bool main_loop_can_be_deleted(EventLoopBase *base)
301
+ }
189
+{
302
+ }
190
+ return false;
303
+
191
+}
304
+ QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) {
192
+
305
+ xdbg_graph_add_node(gr, bs, X_DBG_BLOCK_GRAPH_NODE_TYPE_BLOCK_DRIVER,
193
+static void main_loop_class_init(ObjectClass *oc, void *class_data)
306
+ bs->node_name);
194
+{
307
+ QLIST_FOREACH(child, &bs->children, next) {
195
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(oc);
308
+ xdbg_graph_add_edge(gr, bs, child);
196
+
309
+ }
197
+ bc->init = main_loop_init;
310
+ }
198
+ bc->update_params = main_loop_update_params;
311
+
199
+ bc->can_be_deleted = main_loop_can_be_deleted;
312
+ return xdbg_graph_finalize(gr);
200
+}
313
+}
201
+
314
+
202
+static const TypeInfo main_loop_info = {
315
BlockDriverState *bdrv_lookup_bs(const char *device,
203
+ .name = TYPE_MAIN_LOOP,
316
const char *node_name,
204
+ .parent = TYPE_EVENT_LOOP_BASE,
317
Error **errp)
205
+ .class_init = main_loop_class_init,
318
diff --git a/block/block-backend.c b/block/block-backend.c
206
+ .instance_size = sizeof(MainLoop),
319
index XXXXXXX..XXXXXXX 100644
207
+};
320
--- a/block/block-backend.c
208
+
321
+++ b/block/block-backend.c
209
+static void main_loop_register_types(void)
322
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
210
+{
323
blk_out->root, off_out,
211
+ type_register_static(&main_loop_info);
324
bytes, read_flags, write_flags);
212
+}
325
}
213
+
326
+
214
+type_init(main_loop_register_types)
327
+const BdrvChild *blk_root(BlockBackend *blk)
215
+
328
+{
216
static int max_priority;
329
+ return blk->root;
217
330
+}
218
#ifndef _WIN32
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
--
219
--
348
2.20.1
220
2.35.1
349
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
1
From: Laurent Vivier <lvivier@redhat.com>
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
2
3
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
3
The thread pool regulates itself: when idle, it kills threads until
4
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
4
empty, when in demand, it creates new threads until full. This behaviour
5
Message-id: 20181213162727.17438-4-lvivier@redhat.com
5
doesn't play well with latency sensitive workloads where the price of
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
creating a new thread is too high. For example, when paired with qemu's
7
'-mlock', or using safety features like SafeStack, creating a new thread
8
has been measured take multiple milliseconds.
9
10
In order to mitigate this let's introduce a new 'EventLoopBase'
11
property to set the thread pool size. The threads will be created during
12
the pool's initialization or upon updating the property's value, remain
13
available during its lifetime regardless of demand, and destroyed upon
14
freeing it. A properly characterized workload will then be able to
15
configure the pool to avoid any latency spikes.
16
17
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
19
Acked-by: Markus Armbruster <armbru@redhat.com>
20
Message-id: 20220425075723.20019-4-nsaenzju@redhat.com
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7
---
22
---
8
block/file-posix.c | 25 ++++++-------------------
23
qapi/qom.json | 10 +++++-
9
block/trace-events | 7 +++++++
24
include/block/aio.h | 10 ++++++
10
2 files changed, 13 insertions(+), 19 deletions(-)
25
include/block/thread-pool.h | 3 ++
26
include/sysemu/event-loop-base.h | 4 +++
27
event-loop-base.c | 23 +++++++++++++
28
iothread.c | 3 ++
29
util/aio-posix.c | 1 +
30
util/async.c | 20 ++++++++++++
31
util/main-loop.c | 9 ++++++
32
util/thread-pool.c | 55 +++++++++++++++++++++++++++++---
33
10 files changed, 133 insertions(+), 5 deletions(-)
11
34
12
diff --git a/block/file-posix.c b/block/file-posix.c
35
diff --git a/qapi/qom.json b/qapi/qom.json
13
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
14
--- a/block/file-posix.c
37
--- a/qapi/qom.json
15
+++ b/block/file-posix.c
38
+++ b/qapi/qom.json
16
@@ -XXX,XX +XXX,XX @@
39
@@ -XXX,XX +XXX,XX @@
17
#include <xfs/xfs.h>
40
# 0 means that the engine will use its default.
41
# (default: 0)
42
#
43
+# @thread-pool-min: minimum number of threads reserved in the thread pool
44
+# (default:0)
45
+#
46
+# @thread-pool-max: maximum number of threads the thread pool can contain
47
+# (default:64)
48
+#
49
# Since: 7.1
50
##
51
{ 'struct': 'EventLoopBaseProperties',
52
- 'data': { '*aio-max-batch': 'int' } }
53
+ 'data': { '*aio-max-batch': 'int',
54
+ '*thread-pool-min': 'int',
55
+ '*thread-pool-max': 'int' } }
56
57
##
58
# @IothreadProperties:
59
diff --git a/include/block/aio.h b/include/block/aio.h
60
index XXXXXXX..XXXXXXX 100644
61
--- a/include/block/aio.h
62
+++ b/include/block/aio.h
63
@@ -XXX,XX +XXX,XX @@ struct AioContext {
64
QSLIST_HEAD(, Coroutine) scheduled_coroutines;
65
QEMUBH *co_schedule_bh;
66
67
+ int thread_pool_min;
68
+ int thread_pool_max;
69
/* Thread pool for performing work and receiving completion callbacks.
70
* Has its own locking.
71
*/
72
@@ -XXX,XX +XXX,XX @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
73
void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch,
74
Error **errp);
75
76
+/**
77
+ * aio_context_set_thread_pool_params:
78
+ * @ctx: the aio context
79
+ * @min: min number of threads to have readily available in the thread pool
80
+ * @min: max number of threads the thread pool can contain
81
+ */
82
+void aio_context_set_thread_pool_params(AioContext *ctx, int64_t min,
83
+ int64_t max, Error **errp);
18
#endif
84
#endif
19
85
diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h
20
-//#define DEBUG_BLOCK
86
index XXXXXXX..XXXXXXX 100644
21
-
87
--- a/include/block/thread-pool.h
22
-#ifdef DEBUG_BLOCK
88
+++ b/include/block/thread-pool.h
23
-# define DEBUG_BLOCK_PRINT 1
89
@@ -XXX,XX +XXX,XX @@
24
-#else
90
25
-# define DEBUG_BLOCK_PRINT 0
91
#include "block/block.h"
26
-#endif
92
27
-#define DPRINTF(fmt, ...) \
93
+#define THREAD_POOL_MAX_THREADS_DEFAULT 64
28
-do { \
94
+
29
- if (DEBUG_BLOCK_PRINT) { \
95
typedef int ThreadPoolFunc(void *opaque);
30
- printf(fmt, ## __VA_ARGS__); \
96
31
- } \
97
typedef struct ThreadPool ThreadPool;
32
-} while (0)
98
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool,
33
+#include "trace.h"
99
int coroutine_fn thread_pool_submit_co(ThreadPool *pool,
34
100
ThreadPoolFunc *func, void *arg);
35
/* OS X does not have O_DSYNC */
101
void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg);
36
#ifndef O_DSYNC
102
+void thread_pool_update_params(ThreadPool *pool, struct AioContext *ctx);
37
@@ -XXX,XX +XXX,XX @@ static int xfs_write_zeroes(BDRVRawState *s, int64_t offset, uint64_t bytes)
103
38
104
#endif
39
if (xfsctl(NULL, s->fd, XFS_IOC_ZERO_RANGE, &fl) < 0) {
105
diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h
40
err = errno;
106
index XXXXXXX..XXXXXXX 100644
41
- DPRINTF("cannot write zero range (%s)\n", strerror(errno));
107
--- a/include/sysemu/event-loop-base.h
42
+ trace_file_xfs_write_zeroes(strerror(errno));
108
+++ b/include/sysemu/event-loop-base.h
43
return -err;
109
@@ -XXX,XX +XXX,XX @@ struct EventLoopBase {
110
111
/* AioContext AIO engine parameters */
112
int64_t aio_max_batch;
113
+
114
+ /* AioContext thread pool parameters */
115
+ int64_t thread_pool_min;
116
+ int64_t thread_pool_max;
117
};
118
#endif
119
diff --git a/event-loop-base.c b/event-loop-base.c
120
index XXXXXXX..XXXXXXX 100644
121
--- a/event-loop-base.c
122
+++ b/event-loop-base.c
123
@@ -XXX,XX +XXX,XX @@
124
#include "qemu/osdep.h"
125
#include "qom/object_interfaces.h"
126
#include "qapi/error.h"
127
+#include "block/thread-pool.h"
128
#include "sysemu/event-loop-base.h"
129
130
typedef struct {
131
@@ -XXX,XX +XXX,XX @@ typedef struct {
132
ptrdiff_t offset; /* field's byte offset in EventLoopBase struct */
133
} EventLoopBaseParamInfo;
134
135
+static void event_loop_base_instance_init(Object *obj)
136
+{
137
+ EventLoopBase *base = EVENT_LOOP_BASE(obj);
138
+
139
+ base->thread_pool_max = THREAD_POOL_MAX_THREADS_DEFAULT;
140
+}
141
+
142
static EventLoopBaseParamInfo aio_max_batch_info = {
143
"aio-max-batch", offsetof(EventLoopBase, aio_max_batch),
144
};
145
+static EventLoopBaseParamInfo thread_pool_min_info = {
146
+ "thread-pool-min", offsetof(EventLoopBase, thread_pool_min),
147
+};
148
+static EventLoopBaseParamInfo thread_pool_max_info = {
149
+ "thread-pool-max", offsetof(EventLoopBase, thread_pool_max),
150
+};
151
152
static void event_loop_base_get_param(Object *obj, Visitor *v,
153
const char *name, void *opaque, Error **errp)
154
@@ -XXX,XX +XXX,XX @@ static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
155
event_loop_base_get_param,
156
event_loop_base_set_param,
157
NULL, &aio_max_batch_info);
158
+ object_class_property_add(klass, "thread-pool-min", "int",
159
+ event_loop_base_get_param,
160
+ event_loop_base_set_param,
161
+ NULL, &thread_pool_min_info);
162
+ object_class_property_add(klass, "thread-pool-max", "int",
163
+ event_loop_base_get_param,
164
+ event_loop_base_set_param,
165
+ NULL, &thread_pool_max_info);
166
}
167
168
static const TypeInfo event_loop_base_info = {
169
.name = TYPE_EVENT_LOOP_BASE,
170
.parent = TYPE_OBJECT,
171
.instance_size = sizeof(EventLoopBase),
172
+ .instance_init = event_loop_base_instance_init,
173
.class_size = sizeof(EventLoopBaseClass),
174
.class_init = event_loop_base_class_init,
175
.abstract = true,
176
diff --git a/iothread.c b/iothread.c
177
index XXXXXXX..XXXXXXX 100644
178
--- a/iothread.c
179
+++ b/iothread.c
180
@@ -XXX,XX +XXX,XX @@ static void iothread_set_aio_context_params(EventLoopBase *base, Error **errp)
181
aio_context_set_aio_params(iothread->ctx,
182
iothread->parent_obj.aio_max_batch,
183
errp);
184
+
185
+ aio_context_set_thread_pool_params(iothread->ctx, base->thread_pool_min,
186
+ base->thread_pool_max, errp);
187
}
188
189
190
diff --git a/util/aio-posix.c b/util/aio-posix.c
191
index XXXXXXX..XXXXXXX 100644
192
--- a/util/aio-posix.c
193
+++ b/util/aio-posix.c
194
@@ -XXX,XX +XXX,XX @@
195
196
#include "qemu/osdep.h"
197
#include "block/block.h"
198
+#include "block/thread-pool.h"
199
#include "qemu/main-loop.h"
200
#include "qemu/rcu.h"
201
#include "qemu/rcu_queue.h"
202
diff --git a/util/async.c b/util/async.c
203
index XXXXXXX..XXXXXXX 100644
204
--- a/util/async.c
205
+++ b/util/async.c
206
@@ -XXX,XX +XXX,XX @@ AioContext *aio_context_new(Error **errp)
207
208
ctx->aio_max_batch = 0;
209
210
+ ctx->thread_pool_min = 0;
211
+ ctx->thread_pool_max = THREAD_POOL_MAX_THREADS_DEFAULT;
212
+
213
return ctx;
214
fail:
215
g_source_destroy(&ctx->source);
216
@@ -XXX,XX +XXX,XX @@ void qemu_set_current_aio_context(AioContext *ctx)
217
assert(!get_my_aiocontext());
218
set_my_aiocontext(ctx);
219
}
220
+
221
+void aio_context_set_thread_pool_params(AioContext *ctx, int64_t min,
222
+ int64_t max, Error **errp)
223
+{
224
+
225
+ if (min > max || !max || min > INT_MAX || max > INT_MAX) {
226
+ error_setg(errp, "bad thread-pool-min/thread-pool-max values");
227
+ return;
228
+ }
229
+
230
+ ctx->thread_pool_min = min;
231
+ ctx->thread_pool_max = max;
232
+
233
+ if (ctx->thread_pool) {
234
+ thread_pool_update_params(ctx->thread_pool, ctx);
235
+ }
236
+}
237
diff --git a/util/main-loop.c b/util/main-loop.c
238
index XXXXXXX..XXXXXXX 100644
239
--- a/util/main-loop.c
240
+++ b/util/main-loop.c
241
@@ -XXX,XX +XXX,XX @@
242
#include "sysemu/replay.h"
243
#include "qemu/main-loop.h"
244
#include "block/aio.h"
245
+#include "block/thread-pool.h"
246
#include "qemu/error-report.h"
247
#include "qemu/queue.h"
248
#include "qemu/compiler.h"
249
@@ -XXX,XX +XXX,XX @@ int qemu_init_main_loop(Error **errp)
250
251
static void main_loop_update_params(EventLoopBase *base, Error **errp)
252
{
253
+ ERRP_GUARD();
254
+
255
if (!qemu_aio_context) {
256
error_setg(errp, "qemu aio context not ready");
257
return;
44
}
258
}
45
259
46
@@ -XXX,XX +XXX,XX @@ static int xfs_discard(BDRVRawState *s, int64_t offset, uint64_t bytes)
260
aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
47
261
+ if (*errp) {
48
if (xfsctl(NULL, s->fd, XFS_IOC_UNRESVSP64, &fl) < 0) {
262
+ return;
49
err = errno;
263
+ }
50
- DPRINTF("cannot punch hole (%s)\n", strerror(errno));
264
+
51
+ trace_file_xfs_discard(strerror(errno));
265
+ aio_context_set_thread_pool_params(qemu_aio_context, base->thread_pool_min,
52
return -err;
266
+ base->thread_pool_max, errp);
53
}
267
}
54
268
55
@@ -XXX,XX +XXX,XX @@ static char *FindEjectableOpticalMedia(io_iterator_t *mediaIterator)
269
MainLoop *mloop;
56
270
diff --git a/util/thread-pool.c b/util/thread-pool.c
57
/* If a match was found, leave the loop */
271
index XXXXXXX..XXXXXXX 100644
58
if (*mediaIterator != 0) {
272
--- a/util/thread-pool.c
59
- DPRINTF("Matching using %s\n", matching_array[index]);
273
+++ b/util/thread-pool.c
60
+ trace_file_FindEjectableOpticalMedia(matching_array[index]);
274
@@ -XXX,XX +XXX,XX @@ struct ThreadPool {
61
mediaType = g_strdup(matching_array[index]);
275
QemuMutex lock;
276
QemuCond worker_stopped;
277
QemuSemaphore sem;
278
- int max_threads;
279
QEMUBH *new_thread_bh;
280
281
/* The following variables are only accessed from one AioContext. */
282
@@ -XXX,XX +XXX,XX @@ struct ThreadPool {
283
int new_threads; /* backlog of threads we need to create */
284
int pending_threads; /* threads created but not running yet */
285
bool stopping;
286
+ int min_threads;
287
+ int max_threads;
288
};
289
290
+static inline bool back_to_sleep(ThreadPool *pool, int ret)
291
+{
292
+ /*
293
+ * The semaphore timed out, we should exit the loop except when:
294
+ * - There is work to do, we raced with the signal.
295
+ * - The max threads threshold just changed, we raced with the signal.
296
+ * - The thread pool forces a minimum number of readily available threads.
297
+ */
298
+ if (ret == -1 && (!QTAILQ_EMPTY(&pool->request_list) ||
299
+ pool->cur_threads > pool->max_threads ||
300
+ pool->cur_threads <= pool->min_threads)) {
301
+ return true;
302
+ }
303
+
304
+ return false;
305
+}
306
+
307
static void *worker_thread(void *opaque)
308
{
309
ThreadPool *pool = opaque;
310
@@ -XXX,XX +XXX,XX @@ static void *worker_thread(void *opaque)
311
ret = qemu_sem_timedwait(&pool->sem, 10000);
312
qemu_mutex_lock(&pool->lock);
313
pool->idle_threads--;
314
- } while (ret == -1 && !QTAILQ_EMPTY(&pool->request_list));
315
- if (ret == -1 || pool->stopping) {
316
+ } while (back_to_sleep(pool, ret));
317
+ if (ret == -1 || pool->stopping ||
318
+ pool->cur_threads > pool->max_threads) {
62
break;
319
break;
63
}
320
}
64
@@ -XXX,XX +XXX,XX @@ static bool setup_cdrom(char *bsd_path, Error **errp)
321
65
if (partition_found == false) {
322
@@ -XXX,XX +XXX,XX @@ void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg)
66
error_setg(errp, "Failed to find a working partition on disc");
323
thread_pool_submit_aio(pool, func, arg, NULL, NULL);
67
} else {
324
}
68
- DPRINTF("Using %s as optical disc\n", test_partition);
325
69
+ trace_file_setup_cdrom(test_partition);
326
+void thread_pool_update_params(ThreadPool *pool, AioContext *ctx)
70
pstrcpy(bsd_path, MAXPATHLEN, test_partition);
327
+{
71
}
328
+ qemu_mutex_lock(&pool->lock);
72
return partition_found;
329
+
73
@@ -XXX,XX +XXX,XX @@ static bool hdev_is_sg(BlockDriverState *bs)
330
+ pool->min_threads = ctx->thread_pool_min;
74
331
+ pool->max_threads = ctx->thread_pool_max;
75
ret = ioctl(s->fd, SG_GET_SCSI_ID, &scsiid);
332
+
76
if (ret >= 0) {
333
+ /*
77
- DPRINTF("SG device found: type=%d, version=%d\n",
334
+ * We either have to:
78
- scsiid.scsi_type, sg_version);
335
+ * - Increase the number available of threads until over the min_threads
79
+ trace_file_hdev_is_sg(scsiid.scsi_type, sg_version);
336
+ * threshold.
80
return true;
337
+ * - Decrease the number of available threads until under the max_threads
81
}
338
+ * threshold.
82
339
+ * - Do nothing. The current number of threads fall in between the min and
83
diff --git a/block/trace-events b/block/trace-events
340
+ * max thresholds. We'll let the pool manage itself.
84
index XXXXXXX..XXXXXXX 100644
341
+ */
85
--- a/block/trace-events
342
+ for (int i = pool->cur_threads; i < pool->min_threads; i++) {
86
+++ b/block/trace-events
343
+ spawn_thread(pool);
87
@@ -XXX,XX +XXX,XX @@ curl_open(const char *file) "opening %s"
344
+ }
88
curl_open_size(uint64_t size) "size = %" PRIu64
345
+
89
curl_setup_preadv(uint64_t bytes, uint64_t start, const char *range) "reading %" PRIu64 " at %" PRIu64 " (%s)"
346
+ for (int i = pool->cur_threads; i > pool->max_threads; i--) {
90
curl_close(void) "close"
347
+ qemu_sem_post(&pool->sem);
91
+
348
+ }
92
+# block/file-posix.c
349
+
93
+file_xfs_write_zeroes(const char *error) "cannot write zero range (%s)"
350
+ qemu_mutex_unlock(&pool->lock);
94
+file_xfs_discard(const char *error) "cannot punch hole (%s)"
351
+}
95
+file_FindEjectableOpticalMedia(const char *media) "Matching using %s"
352
+
96
+file_setup_cdrom(const char *partition) "Using %s as optical disc"
353
static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
97
+file_hdev_is_sg(int type, int version) "SG device found: type=%d, version=%d"
354
{
355
if (!ctx) {
356
@@ -XXX,XX +XXX,XX @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
357
qemu_mutex_init(&pool->lock);
358
qemu_cond_init(&pool->worker_stopped);
359
qemu_sem_init(&pool->sem, 0);
360
- pool->max_threads = 64;
361
pool->new_thread_bh = aio_bh_new(ctx, spawn_thread_bh_fn, pool);
362
363
QLIST_INIT(&pool->head);
364
QTAILQ_INIT(&pool->request_list);
365
+
366
+ thread_pool_update_params(pool, ctx);
367
}
368
369
ThreadPool *thread_pool_new(AioContext *ctx)
98
--
370
--
99
2.20.1
371
2.35.1
100
101
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-5-lvivier@redhat.com
6
[mreitz: Fixed sheepdog_snapshot_create_inode's format string to use
7
PRIx32 for uint32_ts]
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
block/sheepdog.c | 47 +++++++++++++++++-----------------------------
11
block/trace-events | 14 ++++++++++++++
12
2 files changed, 31 insertions(+), 30 deletions(-)
13
14
diff --git a/block/sheepdog.c b/block/sheepdog.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/sheepdog.c
17
+++ b/block/sheepdog.c
18
@@ -XXX,XX +XXX,XX @@
19
#include "sysemu/block-backend.h"
20
#include "qemu/bitops.h"
21
#include "qemu/cutils.h"
22
+#include "trace.h"
23
24
#define SD_PROTO_VER 0x01
25
26
@@ -XXX,XX +XXX,XX @@ static inline size_t count_data_objs(const struct SheepdogInode *inode)
27
(1UL << inode->block_size_shift));
28
}
29
30
-#undef DPRINTF
31
-#ifdef DEBUG_SDOG
32
-#define DEBUG_SDOG_PRINT 1
33
-#else
34
-#define DEBUG_SDOG_PRINT 0
35
-#endif
36
-#define DPRINTF(fmt, args...) \
37
- do { \
38
- if (DEBUG_SDOG_PRINT) { \
39
- fprintf(stderr, "%s %d: " fmt, __func__, __LINE__, ##args); \
40
- } \
41
- } while (0)
42
-
43
typedef struct SheepdogAIOCB SheepdogAIOCB;
44
typedef struct BDRVSheepdogState BDRVSheepdogState;
45
46
@@ -XXX,XX +XXX,XX @@ static coroutine_fn void reconnect_to_sdog(void *opaque)
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
}
72
73
@@ -XXX,XX +XXX,XX @@ static void sd_close(BlockDriverState *bs)
74
unsigned int wlen, rlen = 0;
75
int fd, ret;
76
77
- DPRINTF("%s\n", s->name);
78
+ trace_sheepdog_close(s->name);
79
80
fd = connect_to_sdog(s, &local_err);
81
if (fd < 0) {
82
@@ -XXX,XX +XXX,XX @@ static int sd_create_branch(BDRVSheepdogState *s)
83
char *buf;
84
bool deleted;
85
86
- DPRINTF("%" PRIx32 " is snapshot.\n", s->inode.vdi_id);
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
+
166
+# block/sheepdog.c
167
+sheepdog_reconnect_to_sdog(void) "Wait for connection to be established"
168
+sheepdog_aio_read_response(void) "disable cache since the server doesn't support it"
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
--
180
2.20.1
181
182
diff view generated by jsdifflib
Deleted patch
1
From: "Richard W.M. Jones" <rjones@redhat.com>
2
1
3
On FreeBSD 11.2:
4
5
$ nbdkit memory size=1M --run './qemu-io -f raw -c "aio_write 0 512" $nbd'
6
Parsing error: non-numeric argument, or extraneous/unrecognized suffix -- aio_write
7
8
After main option parsing, we reinitialize optind so we can parse each
9
command. However reinitializing optind to 0 does not work on FreeBSD.
10
What happens when you do this is optind remains 0 after the option
11
parsing loop, and the result is we try to parse argv[optind] ==
12
argv[0] == "aio_write" as if it was the first parameter.
13
14
The FreeBSD manual page says:
15
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
---
50
configure | 14 ++++++++++++++
51
include/qemu/osdep.h | 16 ++++++++++++++++
52
qemu-img.c | 2 +-
53
qemu-io-cmds.c | 2 +-
54
4 files changed, 32 insertions(+), 2 deletions(-)
55
56
diff --git a/configure b/configure
57
index XXXXXXX..XXXXXXX 100755
58
--- a/configure
59
+++ b/configure
60
@@ -XXX,XX +XXX,XX @@ if compile_prog "" "" ; then
61
signalfd=yes
62
fi
63
64
+# check if optreset global is declared by <getopt.h>
65
+optreset="no"
66
+cat > $TMPC << EOF
67
+#include <getopt.h>
68
+int main(void) { return optreset; }
69
+EOF
70
+
71
+if compile_prog "" "" ; then
72
+ optreset=yes
73
+fi
74
+
75
# check if eventfd is supported
76
eventfd=no
77
cat > $TMPC << EOF
78
@@ -XXX,XX +XXX,XX @@ fi
79
if test "$signalfd" = "yes" ; then
80
echo "CONFIG_SIGNALFD=y" >> $config_host_mak
81
fi
82
+if test "$optreset" = "yes" ; then
83
+ echo "HAVE_OPTRESET=y" >> $config_host_mak
84
+fi
85
if test "$tcg" = "yes"; then
86
echo "CONFIG_TCG=y" >> $config_host_mak
87
if test "$tcg_interpreter" = "yes" ; then
88
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
89
index XXXXXXX..XXXXXXX 100644
90
--- a/include/qemu/osdep.h
91
+++ b/include/qemu/osdep.h
92
@@ -XXX,XX +XXX,XX @@ extern int daemon(int, int);
93
#include <ctype.h>
94
#include <errno.h>
95
#include <fcntl.h>
96
+#include <getopt.h>
97
#include <sys/stat.h>
98
#include <sys/time.h>
99
#include <assert.h>
100
@@ -XXX,XX +XXX,XX @@ extern int qemu_icache_linesize_log;
101
extern int qemu_dcache_linesize;
102
extern int qemu_dcache_linesize_log;
103
104
+/*
105
+ * After using getopt or getopt_long, if you need to parse another set
106
+ * of options, then you must reset optind. Unfortunately the way to
107
+ * do this varies between implementations of getopt.
108
+ */
109
+static inline void qemu_reset_optind(void)
110
+{
111
+#ifdef HAVE_OPTRESET
112
+ optind = 1;
113
+ optreset = 1;
114
+#else
115
+ optind = 0;
116
+#endif
117
+}
118
+
119
#endif
120
diff --git a/qemu-img.c b/qemu-img.c
121
index XXXXXXX..XXXXXXX 100644
122
--- a/qemu-img.c
123
+++ b/qemu-img.c
124
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
125
return 0;
126
}
127
argv += optind;
128
- optind = 0;
129
+ qemu_reset_optind();
130
131
if (!trace_init_backends()) {
132
exit(1);
133
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
134
index XXXXXXX..XXXXXXX 100644
135
--- a/qemu-io-cmds.c
136
+++ b/qemu-io-cmds.c
137
@@ -XXX,XX +XXX,XX @@ static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc,
138
}
139
}
140
141
- optind = 0;
142
+ qemu_reset_optind();
143
return ct->cfunc(blk, argc, argv);
144
}
145
146
--
147
2.20.1
148
149
diff view generated by jsdifflib
Deleted patch
1
From: Li Qiang <liq3ea@163.com>
2
1
3
Signed-off-by: Li Qiang <liq3ea@163.com>
4
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
6
Message-id: 20190120055558.32984-2-liq3ea@163.com
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
9
hw/block/nvme.c | 2 +-
10
1 file changed, 1 insertion(+), 1 deletion(-)
11
12
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/block/nvme.c
15
+++ b/hw/block/nvme.c
16
@@ -XXX,XX +XXX,XX @@ static void nvme_instance_init(Object *obj)
17
}
18
19
static const TypeInfo nvme_info = {
20
- .name = "nvme",
21
+ .name = TYPE_NVME,
22
.parent = TYPE_PCI_DEVICE,
23
.instance_size = sizeof(NvmeCtrl),
24
.class_init = nvme_class_init,
25
--
26
2.20.1
27
28
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
From: Li Qiang <liq3ea@163.com>
2
1
3
There is no need to make another reference.
4
5
Signed-off-by: Li Qiang <liq3ea@163.com>
6
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Message-id: 20190120055558.32984-4-liq3ea@163.com
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
hw/block/nvme.c | 8 ++++----
12
1 file changed, 4 insertions(+), 4 deletions(-)
13
14
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/block/nvme.c
17
+++ b/hw/block/nvme.c
18
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
19
pci_conf[PCI_INTERRUPT_PIN] = 1;
20
pci_config_set_prog_interface(pci_dev->config, 0x2);
21
pci_config_set_class(pci_dev->config, PCI_CLASS_STORAGE_EXPRESS);
22
- pcie_endpoint_cap_init(&n->parent_obj, 0x80);
23
+ pcie_endpoint_cap_init(pci_dev, 0x80);
24
25
n->num_namespaces = 1;
26
n->reg_size = pow2ceil(0x1004 + 2 * (n->num_queues + 1) * 4);
27
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
28
29
memory_region_init_io(&n->iomem, OBJECT(n), &nvme_mmio_ops, n,
30
"nvme", n->reg_size);
31
- pci_register_bar(&n->parent_obj, 0,
32
+ pci_register_bar(pci_dev, 0,
33
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64,
34
&n->iomem);
35
- msix_init_exclusive_bar(&n->parent_obj, n->num_queues, 4, NULL);
36
+ msix_init_exclusive_bar(pci_dev, n->num_queues, 4, NULL);
37
38
id->vid = cpu_to_le16(pci_get_word(pci_conf + PCI_VENDOR_ID));
39
id->ssvid = cpu_to_le16(pci_get_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID));
40
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
41
n->cmbuf = g_malloc0(NVME_CMBSZ_GETSIZE(n->bar.cmbsz));
42
memory_region_init_io(&n->ctrl_mem, OBJECT(n), &nvme_cmb_ops, n,
43
"nvme-cmb", NVME_CMBSZ_GETSIZE(n->bar.cmbsz));
44
- pci_register_bar(&n->parent_obj, NVME_CMBLOC_BIR(n->bar.cmbloc),
45
+ pci_register_bar(pci_dev, NVME_CMBLOC_BIR(n->bar.cmbloc),
46
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
47
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem);
48
49
--
50
2.20.1
51
52
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
Deleted patch
1
By default, qemu-nbd binds to 0.0.0.0. However, we then proceed to
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
1
7
So running qemu-nbd works, it can bind to 0.0.0.0:NBD_PORT. But
8
potentially a concurrent test has successfully taken [::1]:NBD_PORT. In
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
12
Fix this by just binding to "localhost". This will make qemu-nbd error
13
out immediately and not give us cryptic errors later.
14
15
(Also, it will allow us to just try a different port as of a future
16
patch.)
17
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
Message-id: 20181221234750.23577-3-mreitz@redhat.com
20
Reviewed-by: John Snow <jsnow@redhat.com>
21
Reviewed-by: Eric Blake <eblake@redhat.com>
22
Signed-off-by: Max Reitz <mreitz@redhat.com>
23
---
24
tests/qemu-iotests/147 | 2 +-
25
1 file changed, 1 insertion(+), 1 deletion(-)
26
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
Deleted patch
1
To do this, we need to allow creating the NBD server on various ports
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
1
5
So we just pick a random port in [32768, 32768 + 1024) and try to create
6
a server there. If that fails, we just retry until something sticks.
7
8
For the IPv6 test, we need a different range, though (just above that
9
one). This is because "localhost" resolves to both 127.0.0.1 and ::1.
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
18
But when we then try to connect to the server through
19
localhost:some_port, we will always end up at the IPv6 one (as long as
20
it is up), and this may not be the one we want.
21
22
Thus, we must make sure not to create an IPv6-only NBD server on the
23
same port as a normal "dual-stack" NBD server -- which is done by using
24
distinct port ranges, as explained above.
25
26
Signed-off-by: Max Reitz <mreitz@redhat.com>
27
Message-id: 20181221234750.23577-4-mreitz@redhat.com
28
Reviewed-by: John Snow <jsnow@redhat.com>
29
Signed-off-by: Max Reitz <mreitz@redhat.com>
30
---
31
tests/qemu-iotests/147 | 98 +++++++++++++++++++++++++++++-------------
32
1 file changed, 68 insertions(+), 30 deletions(-)
33
34
diff --git a/tests/qemu-iotests/147 b/tests/qemu-iotests/147
35
index XXXXXXX..XXXXXXX 100755
36
--- a/tests/qemu-iotests/147
37
+++ b/tests/qemu-iotests/147
38
@@ -XXX,XX +XXX,XX @@
39
#
40
41
import os
42
+import random
43
import socket
44
import stat
45
import time
46
import iotests
47
-from iotests import cachemode, imgfmt, qemu_img, qemu_nbd
48
+from iotests import cachemode, imgfmt, qemu_img, qemu_nbd, qemu_nbd_pipe
49
50
-NBD_PORT = 10811
51
+NBD_PORT_START = 32768
52
+NBD_PORT_END = NBD_PORT_START + 1024
53
+NBD_IPV6_PORT_START = NBD_PORT_END
54
+NBD_IPV6_PORT_END = NBD_IPV6_PORT_START + 1024
55
56
test_img = os.path.join(iotests.test_dir, 'test.img')
57
unix_socket = os.path.join(iotests.test_dir, 'nbd.socket')
58
@@ -XXX,XX +XXX,XX @@ class QemuNBD(NBDBlockdevAddBase):
59
except OSError:
60
pass
61
62
+ def _try_server_up(self, *args):
63
+ status, msg = qemu_nbd_pipe('-f', imgfmt, test_img, *args)
64
+ if status == 0:
65
+ return True
66
+ if 'Address already in use' in msg:
67
+ return False
68
+ self.fail(msg)
69
+
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
--
206
2.20.1
207
208
diff view generated by jsdifflib