1
The following changes since commit a1cf5fac2b929ffa2abd1285401f2535ff8c6fea:
1
The following changes since commit 9cf289af47bcfae5c75de37d8e5d6fd23705322c:
2
2
3
Merge remote-tracking branch 'remotes/armbru/tags/pull-block-2017-02-21' into staging (2017-02-21 13:58:50 +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
git@github.com:codyprime/qemu-kvm-jtc.git tags/block-pull-request
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to 6135c5e12606b8413708384e3e7d43f6010c5941:
9
for you to fetch changes up to bef2e050d6a7feb865854c65570c496ac5a8cf53:
10
10
11
qemu-options: Fix broken sheepdog URL (2017-02-21 10:38:09 -0500)
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
16
Add new thread-pool-min/thread-pool-max parameters to control the thread pool
17
used for async I/O.
18
15
----------------------------------------------------------------
19
----------------------------------------------------------------
16
20
17
Anton Nefedov (1):
21
Nicolas Saenz Julienne (3):
18
mirror: do not increase offset during initial zero_or_discard phase
22
Introduce event-loop-base abstract class
23
util/main-loop: Introduce the main loop into QOM
24
util/event-loop-base: Introduce options to set the thread pool size
19
25
20
Jeff Cody (1):
26
qapi/qom.json | 43 ++++++++--
21
QAPI: Fix blockdev-add example documentation
27
meson.build | 26 +++---
22
28
include/block/aio.h | 10 +++
23
Kevin Wolf (6):
29
include/block/thread-pool.h | 3 +
24
iscsi: Split URL into individual options
30
include/qemu/main-loop.h | 10 +++
25
iscsi: Handle -iscsi user/password in bdrv_parse_filename()
31
include/sysemu/event-loop-base.h | 41 +++++++++
26
iscsi: Add initiator-name option
32
include/sysemu/iothread.h | 6 +-
27
iscsi: Add header-digest option
33
event-loop-base.c | 140 +++++++++++++++++++++++++++++++
28
iscsi: Add timeout option
34
iothread.c | 68 +++++----------
29
iscsi: Add blockdev-add support
35
util/aio-posix.c | 1 +
30
36
util/async.c | 20 +++++
31
Thomas Huth (1):
37
util/main-loop.c | 65 ++++++++++++++
32
qemu-options: Fix broken sheepdog URL
38
util/thread-pool.c | 55 +++++++++++-
33
39
13 files changed, 419 insertions(+), 69 deletions(-)
34
block/iscsi.c | 353 +++++++++++++++++++++++++++++++--------------------
40
create mode 100644 include/sysemu/event-loop-base.h
35
block/mirror.c | 9 +-
41
create mode 100644 event-loop-base.c
36
qapi/block-core.json | 125 +++++++++++++-----
37
qemu-options.hx | 2 +-
38
4 files changed, 317 insertions(+), 172 deletions(-)
39
42
40
--
43
--
41
2.9.3
44
2.35.1
42
43
diff view generated by jsdifflib
1
From: Kevin Wolf <kwolf@redhat.com>
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
2
3
This was previously only available with -iscsi. Again, after this patch,
3
Introduce the 'event-loop-base' abstract class, it'll hold the
4
the -iscsi option only takes effect if an URL is given. New users are
4
properties common to all event loops and provide the necessary hooks for
5
supposed to use the new driver-specific option.
5
their creation and maintenance. Then have iothread inherit from it.
6
6
7
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
7
EventLoopBaseClass is defined as user creatable and provides a hook for
8
Reviewed-by: Fam Zheng <famz@redhat.com>
8
its children to attach themselves to the user creatable class 'complete'
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
function. It also provides an update_params() callback to propagate
10
Signed-off-by: Jeff Cody <jcody@redhat.com>
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>
11
---
40
---
12
block/iscsi.c | 39 +++++++++++++++------------------------
41
qapi/qom.json | 22 +++++--
13
1 file changed, 15 insertions(+), 24 deletions(-)
42
meson.build | 23 ++++---
14
43
include/sysemu/event-loop-base.h | 36 +++++++++++
15
diff --git a/block/iscsi.c b/block/iscsi.c
44
include/sysemu/iothread.h | 6 +-
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/iscsi.c
53
--- a/qapi/qom.json
18
+++ b/block/iscsi.c
54
+++ b/qapi/qom.json
19
@@ -XXX,XX +XXX,XX @@ static void apply_chap(struct iscsi_context *iscsi, QemuOpts *opts,
55
@@ -XXX,XX +XXX,XX @@
20
g_free(secret);
56
'*repeat': 'bool',
57
'*grab-toggle': 'GrabToggleKeys' } }
58
59
+##
60
+# @EventLoopBaseProperties:
61
+#
62
+# Common properties for event loops
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 @@
165
+/*
166
+ * QEMU event-loop backend
167
+ *
168
+ * Copyright (C) 2022 Red Hat Inc
169
+ *
170
+ * Authors:
171
+ * Nicolas Saenz Julienne <nsaenzju@redhat.com>
172
+ *
173
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
174
+ * See the COPYING file in the top-level directory.
175
+ */
176
+#ifndef QEMU_EVENT_LOOP_BASE_H
177
+#define QEMU_EVENT_LOOP_BASE_H
178
+
179
+#include "qom/object.h"
180
+#include "block/aio.h"
181
+#include "qemu/typedefs.h"
182
+
183
+#define TYPE_EVENT_LOOP_BASE "event-loop-base"
184
+OBJECT_DECLARE_TYPE(EventLoopBase, EventLoopBaseClass,
185
+ EVENT_LOOP_BASE)
186
+
187
+struct EventLoopBaseClass {
188
+ ObjectClass parent_class;
189
+
190
+ void (*init)(EventLoopBase *base, Error **errp);
191
+ void (*update_params)(EventLoopBase *base, Error **errp);
192
+};
193
+
194
+struct EventLoopBase {
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);
21
}
353
}
22
354
23
-static void parse_header_digest(struct iscsi_context *iscsi, const char *target,
355
-static void iothread_set_aio_context_params(IOThread *iothread, Error **errp)
24
+static void apply_header_digest(struct iscsi_context *iscsi, QemuOpts *opts,
356
+static void iothread_set_aio_context_params(EventLoopBase *base, Error **errp)
25
Error **errp)
26
{
357
{
27
- QemuOptsList *list;
358
+ IOThread *iothread = IOTHREAD(base);
28
- QemuOpts *opts;
359
ERRP_GUARD();
29
const char *digest = NULL;
360
30
361
+ if (!iothread->ctx) {
31
- list = qemu_find_opts("iscsi");
362
+ return;
32
- if (!list) {
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)
369
}
370
371
aio_context_set_aio_params(iothread->ctx,
372
- iothread->aio_max_batch,
373
+ iothread->parent_obj.aio_max_batch,
374
errp);
375
}
376
377
-static void iothread_complete(UserCreatable *obj, Error **errp)
378
+
379
+static void iothread_init(EventLoopBase *base, Error **errp)
380
{
381
Error *local_error = NULL;
382
- IOThread *iothread = IOTHREAD(obj);
383
+ IOThread *iothread = IOTHREAD(base);
384
char *thread_name;
385
386
iothread->stopping = false;
387
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
388
*/
389
iothread_init_gcontext(iothread);
390
391
- iothread_set_aio_context_params(iothread, &local_error);
392
+ iothread_set_aio_context_params(base, &local_error);
393
if (local_error) {
394
error_propagate(errp, local_error);
395
aio_context_unref(iothread->ctx);
396
@@ -XXX,XX +XXX,XX @@ static void iothread_complete(UserCreatable *obj, Error **errp)
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,
416
}
417
}
418
419
-static void iothread_get_aio_param(Object *obj, Visitor *v,
420
- const char *name, void *opaque, Error **errp)
421
-{
422
- IOThreadParamInfo *info = opaque;
423
-
424
- iothread_get_param(obj, v, name, info, errp);
425
-}
426
-
427
-static void iothread_set_aio_param(Object *obj, Visitor *v,
428
- const char *name, void *opaque, Error **errp)
429
-{
430
- IOThread *iothread = IOTHREAD(obj);
431
- IOThreadParamInfo *info = opaque;
432
-
433
- if (!iothread_set_param(obj, v, name, info, errp)) {
33
- return;
434
- return;
34
- }
435
- }
35
-
436
-
36
- opts = qemu_opts_find(list, target);
437
- if (iothread->ctx) {
37
- if (opts == NULL) {
438
- aio_context_set_aio_params(iothread->ctx,
38
- opts = QTAILQ_FIRST(&list->head);
439
- iothread->aio_max_batch,
39
- if (!opts) {
440
- errp);
40
- return;
41
- }
42
- }
441
- }
43
-
442
-}
44
digest = qemu_opt_get(opts, "header-digest");
443
-
45
if (!digest) {
444
static void iothread_class_init(ObjectClass *klass, void *class_data)
46
- return;
47
- }
48
-
49
- if (!strcmp(digest, "CRC32C")) {
50
+ iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
51
+ } else if (!strcmp(digest, "CRC32C")) {
52
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C);
53
} else if (!strcmp(digest, "NONE")) {
54
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE);
55
@@ -XXX,XX +XXX,XX @@ static void iscsi_parse_iscsi_option(const char *target, QDict *options)
56
{
445
{
57
QemuOptsList *list;
446
- UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
58
QemuOpts *opts;
447
- ucc->complete = iothread_complete;
59
- const char *user, *password, *password_secret, *initiator_name;
448
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(klass);
60
+ const char *user, *password, *password_secret, *initiator_name,
449
+
61
+ *header_digest;
450
+ bc->init = iothread_init;
62
451
+ bc->update_params = iothread_set_aio_context_params;
63
list = qemu_find_opts("iscsi");
452
64
if (!list) {
453
object_class_property_add(klass, "poll-max-ns", "int",
65
@@ -XXX,XX +XXX,XX @@ static void iscsi_parse_iscsi_option(const char *target, QDict *options)
454
iothread_get_poll_param,
66
if (initiator_name) {
455
@@ -XXX,XX +XXX,XX @@ static void iothread_class_init(ObjectClass *klass, void *class_data)
67
qdict_set_default_str(options, "initiator-name", initiator_name);
456
iothread_get_poll_param,
68
}
457
iothread_set_poll_param,
69
+
458
NULL, &poll_shrink_info);
70
+ header_digest = qemu_opt_get(opts, "header-digest");
459
- object_class_property_add(klass, "aio-max-batch", "int",
71
+ if (header_digest) {
460
- iothread_get_aio_param,
72
+ qdict_set_default_str(options, "header-digest", header_digest);
461
- iothread_set_aio_param,
73
+ }
462
- NULL, &aio_max_batch_info);
74
}
463
}
75
464
76
/*
465
static const TypeInfo iothread_info = {
77
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
466
.name = TYPE_IOTHREAD,
78
.name = "initiator-name",
467
- .parent = TYPE_OBJECT,
79
.type = QEMU_OPT_STRING,
468
+ .parent = TYPE_EVENT_LOOP_BASE,
80
},
469
.class_init = iothread_class_init,
81
+ {
470
.instance_size = sizeof(IOThread),
82
+ .name = "header-digest",
471
.instance_init = iothread_instance_init,
83
+ .type = QEMU_OPT_STRING,
472
.instance_finalize = iothread_instance_finalize,
84
+ },
473
- .interfaces = (InterfaceInfo[]) {
85
{ /* end of list */ }
474
- {TYPE_USER_CREATABLE},
86
},
475
- {}
476
- },
87
};
477
};
88
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
478
89
goto out;
479
static void iothread_register_types(void)
90
}
480
@@ -XXX,XX +XXX,XX @@ static int query_one_iothread(Object *object, void *opaque)
91
481
info->poll_max_ns = iothread->poll_max_ns;
92
- iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
482
info->poll_grow = iothread->poll_grow;
93
-
483
info->poll_shrink = iothread->poll_shrink;
94
/* check if we got HEADER_DIGEST via the options */
484
- info->aio_max_batch = iothread->aio_max_batch;
95
- parse_header_digest(iscsi, target, &local_err);
485
+ info->aio_max_batch = iothread->parent_obj.aio_max_batch;
96
+ apply_header_digest(iscsi, opts, &local_err);
486
97
if (local_err != NULL) {
487
QAPI_LIST_APPEND(*tail, info);
98
error_propagate(errp, local_err);
488
return 0;
99
ret = -EINVAL;
100
--
489
--
101
2.9.3
490
2.35.1
102
103
diff view generated by jsdifflib
1
From: Kevin Wolf <kwolf@redhat.com>
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
2
3
This introduces a .bdrv_parse_filename handler for iscsi which parses an
3
'event-loop-base' provides basic property handling for all 'AioContext'
4
URL if given and translates it to individual options.
4
based event loops. So let's define a new 'MainLoopClass' that inherits
5
5
from it. This will permit tweaking the main loop's properties through
6
Reviewed-by: Fam Zheng <famz@redhat.com>
6
qapi as well as through the command line using the '-object' keyword[1].
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Only one instance of 'MainLoopClass' might be created at any time.
8
Signed-off-by: Jeff Cody <jcody@redhat.com>
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>
9
---
20
---
10
block/iscsi.c | 193 ++++++++++++++++++++++++++++++++++++++++++----------------
21
qapi/qom.json | 13 ++++++++
11
1 file changed, 140 insertions(+), 53 deletions(-)
22
meson.build | 3 +-
12
23
include/qemu/main-loop.h | 10 ++++++
13
diff --git a/block/iscsi.c b/block/iscsi.c
24
include/sysemu/event-loop-base.h | 1 +
14
index XXXXXXX..XXXXXXX 100644
25
event-loop-base.c | 13 ++++++++
15
--- a/block/iscsi.c
26
util/main-loop.c | 56 ++++++++++++++++++++++++++++++++
16
+++ b/block/iscsi.c
27
6 files changed, 95 insertions(+), 1 deletion(-)
17
@@ -XXX,XX +XXX,XX @@ static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
28
29
diff --git a/qapi/qom.json b/qapi/qom.json
30
index XXXXXXX..XXXXXXX 100644
31
--- a/qapi/qom.json
32
+++ b/qapi/qom.json
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
+
48
##
49
# @MemoryBackendProperties:
50
#
51
@@ -XXX,XX +XXX,XX @@
52
{ 'name': 'input-linux',
53
'if': 'CONFIG_LINUX' },
54
'iothread',
55
+ 'main-loop',
56
{ 'name': 'memory-backend-epc',
57
'if': 'CONFIG_LINUX' },
58
'memory-backend-file',
59
@@ -XXX,XX +XXX,XX @@
60
'input-linux': { 'type': 'InputLinuxProperties',
61
'if': 'CONFIG_LINUX' },
62
'iothread': 'IothreadProperties',
63
+ 'main-loop': 'MainLoopProperties',
64
'memory-backend-epc': { 'type': 'MemoryBackendEpcProperties',
65
'if': 'CONFIG_LINUX' },
66
'memory-backend-file': 'MemoryBackendFileProperties',
67
diff --git a/meson.build b/meson.build
68
index XXXXXXX..XXXXXXX 100644
69
--- a/meson.build
70
+++ b/meson.build
71
@@ -XXX,XX +XXX,XX @@ libqemuutil = static_library('qemuutil',
72
sources: util_ss.sources() + stub_ss.sources() + genh,
73
dependencies: [util_ss.dependencies(), libm, threads, glib, socket, malloc, pixman])
74
qemuutil = declare_dependency(link_with: libqemuutil,
75
- sources: genh + version_res)
76
+ sources: genh + version_res,
77
+ dependencies: [event_loop_base])
78
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)
18
}
122
}
19
}
123
}
20
124
21
-/* TODO Convert to fine grained options */
125
+static bool event_loop_base_can_be_deleted(UserCreatable *uc)
22
-static QemuOptsList runtime_opts = {
126
+{
23
- .name = "iscsi",
127
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc);
24
- .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
128
+ EventLoopBase *backend = EVENT_LOOP_BASE(uc);
25
- .desc = {
129
+
26
- {
130
+ if (bc->can_be_deleted) {
27
- .name = "filename",
131
+ return bc->can_be_deleted(backend);
28
- .type = QEMU_OPT_STRING,
132
+ }
29
- .help = "URL to the iscsi image",
133
+
30
- },
134
+ return true;
31
- { /* end of list */ }
135
+}
32
- },
136
+
33
-};
137
static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
34
-
35
static struct scsi_task *iscsi_do_inquiry(struct iscsi_context *iscsi, int lun,
36
int evpd, int pc, void **inq, Error **errp)
37
{
138
{
38
@@ -XXX,XX +XXX,XX @@ out:
139
UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
39
* We support iscsi url's on the form
140
ucc->complete = event_loop_base_complete;
40
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
141
+ ucc->can_be_deleted = event_loop_base_can_be_deleted;
41
*/
142
42
+static void iscsi_parse_filename(const char *filename, QDict *options,
143
object_class_property_add(klass, "aio-max-batch", "int",
43
+ Error **errp)
144
event_loop_base_get_param,
44
+{
145
diff --git a/util/main-loop.c b/util/main-loop.c
45
+ struct iscsi_url *iscsi_url;
146
index XXXXXXX..XXXXXXX 100644
46
+ const char *transport_name;
147
--- a/util/main-loop.c
47
+ char *lun_str;
148
+++ b/util/main-loop.c
48
+
149
@@ -XXX,XX +XXX,XX @@
49
+ iscsi_url = iscsi_parse_full_url(NULL, filename);
150
#include "qemu/error-report.h"
50
+ if (iscsi_url == NULL) {
151
#include "qemu/queue.h"
51
+ error_setg(errp, "Failed to parse URL : %s", filename);
152
#include "qemu/compiler.h"
153
+#include "qom/object.h"
154
155
#ifndef _WIN32
156
#include <sys/wait.h>
157
@@ -XXX,XX +XXX,XX @@ int qemu_init_main_loop(Error **errp)
158
return 0;
159
}
160
161
+static void main_loop_update_params(EventLoopBase *base, Error **errp)
162
+{
163
+ if (!qemu_aio_context) {
164
+ error_setg(errp, "qemu aio context not ready");
52
+ return;
165
+ return;
53
+ }
166
+ }
54
+
167
+
55
+#if LIBISCSI_API_VERSION >= (20160603)
168
+ aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
56
+ switch (iscsi_url->transport) {
169
+}
57
+ case TCP_TRANSPORT:
170
+
58
+ transport_name = "tcp";
171
+MainLoop *mloop;
59
+ break;
172
+
60
+ case ISER_TRANSPORT:
173
+static void main_loop_init(EventLoopBase *base, Error **errp)
61
+ transport_name = "iser";
174
+{
62
+ break;
175
+ MainLoop *m = MAIN_LOOP(base);
63
+ default:
176
+
64
+ error_setg(errp, "Unknown transport type (%d)",
177
+ if (mloop) {
65
+ iscsi_url->transport);
178
+ error_setg(errp, "only one main-loop instance allowed");
66
+ return;
179
+ return;
67
+ }
180
+ }
68
+#else
181
+
69
+ transport_name = "tcp";
182
+ main_loop_update_params(base, errp);
70
+#endif
183
+
71
+
184
+ mloop = m;
72
+ qdict_set_default_str(options, "transport", transport_name);
185
+ return;
73
+ qdict_set_default_str(options, "portal", iscsi_url->portal);
186
+}
74
+ qdict_set_default_str(options, "target", iscsi_url->target);
187
+
75
+
188
+static bool main_loop_can_be_deleted(EventLoopBase *base)
76
+ lun_str = g_strdup_printf("%d", iscsi_url->lun);
189
+{
77
+ qdict_set_default_str(options, "lun", lun_str);
190
+ return false;
78
+ g_free(lun_str);
191
+}
79
+
192
+
80
+ if (iscsi_url->user[0] != '\0') {
193
+static void main_loop_class_init(ObjectClass *oc, void *class_data)
81
+ qdict_set_default_str(options, "user", iscsi_url->user);
194
+{
82
+ qdict_set_default_str(options, "password", iscsi_url->passwd);
195
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(oc);
83
+ }
196
+
84
+
197
+ bc->init = main_loop_init;
85
+ iscsi_destroy_url(iscsi_url);
198
+ bc->update_params = main_loop_update_params;
86
+}
199
+ bc->can_be_deleted = main_loop_can_be_deleted;
87
+
200
+}
88
+/* TODO Add -iscsi options */
201
+
89
+static QemuOptsList runtime_opts = {
202
+static const TypeInfo main_loop_info = {
90
+ .name = "iscsi",
203
+ .name = TYPE_MAIN_LOOP,
91
+ .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
204
+ .parent = TYPE_EVENT_LOOP_BASE,
92
+ .desc = {
205
+ .class_init = main_loop_class_init,
93
+ {
206
+ .instance_size = sizeof(MainLoop),
94
+ .name = "transport",
95
+ .type = QEMU_OPT_STRING,
96
+ },
97
+ {
98
+ .name = "portal",
99
+ .type = QEMU_OPT_STRING,
100
+ },
101
+ {
102
+ .name = "target",
103
+ .type = QEMU_OPT_STRING,
104
+ },
105
+ {
106
+ .name = "user",
107
+ .type = QEMU_OPT_STRING,
108
+ },
109
+ {
110
+ .name = "password",
111
+ .type = QEMU_OPT_STRING,
112
+ },
113
+ {
114
+ .name = "lun",
115
+ .type = QEMU_OPT_NUMBER,
116
+ },
117
+ { /* end of list */ }
118
+ },
119
+};
207
+};
120
+
208
+
121
static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
209
+static void main_loop_register_types(void)
122
Error **errp)
210
+{
123
{
211
+ type_register_static(&main_loop_info);
124
IscsiLun *iscsilun = bs->opaque;
212
+}
125
struct iscsi_context *iscsi = NULL;
213
+
126
- struct iscsi_url *iscsi_url = NULL;
214
+type_init(main_loop_register_types)
127
struct scsi_task *task = NULL;
215
+
128
struct scsi_inquiry_standard *inq = NULL;
216
static int max_priority;
129
struct scsi_inquiry_supported_pages *inq_vpd;
217
130
char *initiator_name = NULL;
218
#ifndef _WIN32
131
QemuOpts *opts;
132
Error *local_err = NULL;
133
- const char *filename;
134
- int i, ret = 0, timeout = 0;
135
+ const char *transport_name, *portal, *target;
136
+ const char *user, *password;
137
+#if LIBISCSI_API_VERSION >= (20160603)
138
+ enum iscsi_transport_type transport;
139
+#endif
140
+ int i, ret = 0, timeout = 0, lun;
141
142
opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
143
qemu_opts_absorb_qdict(opts, options, &local_err);
144
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
145
goto out;
146
}
147
148
- filename = qemu_opt_get(opts, "filename");
149
+ transport_name = qemu_opt_get(opts, "transport");
150
+ portal = qemu_opt_get(opts, "portal");
151
+ target = qemu_opt_get(opts, "target");
152
+ user = qemu_opt_get(opts, "user");
153
+ password = qemu_opt_get(opts, "password");
154
+ lun = qemu_opt_get_number(opts, "lun", 0);
155
156
- iscsi_url = iscsi_parse_full_url(iscsi, filename);
157
- if (iscsi_url == NULL) {
158
- error_setg(errp, "Failed to parse URL : %s", filename);
159
+ if (!transport_name || !portal || !target) {
160
+ error_setg(errp, "Need all of transport, portal and target options");
161
+ ret = -EINVAL;
162
+ goto out;
163
+ }
164
+ if (user && !password) {
165
+ error_setg(errp, "If a user name is given, a password is required");
166
+ ret = -EINVAL;
167
+ goto out;
168
+ }
169
+
170
+ if (!strcmp(transport_name, "tcp")) {
171
+#if LIBISCSI_API_VERSION >= (20160603)
172
+ transport = TCP_TRANSPORT;
173
+ } else if (!strcmp(transport_name, "iser")) {
174
+ transport = ISER_TRANSPORT;
175
+#else
176
+ /* TCP is what older libiscsi versions always use */
177
+#endif
178
+ } else {
179
+ error_setg(errp, "Unknown transport: %s", transport_name);
180
ret = -EINVAL;
181
goto out;
182
}
183
184
memset(iscsilun, 0, sizeof(IscsiLun));
185
186
- initiator_name = parse_initiator_name(iscsi_url->target);
187
+ initiator_name = parse_initiator_name(target);
188
189
iscsi = iscsi_create_context(initiator_name);
190
if (iscsi == NULL) {
191
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
192
goto out;
193
}
194
#if LIBISCSI_API_VERSION >= (20160603)
195
- if (iscsi_init_transport(iscsi, iscsi_url->transport)) {
196
+ if (iscsi_init_transport(iscsi, transport)) {
197
error_setg(errp, ("Error initializing transport."));
198
ret = -EINVAL;
199
goto out;
200
}
201
#endif
202
- if (iscsi_set_targetname(iscsi, iscsi_url->target)) {
203
+ if (iscsi_set_targetname(iscsi, target)) {
204
error_setg(errp, "iSCSI: Failed to set target name.");
205
ret = -EINVAL;
206
goto out;
207
}
208
209
- if (iscsi_url->user[0] != '\0') {
210
- ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user,
211
- iscsi_url->passwd);
212
+ if (user) {
213
+ ret = iscsi_set_initiator_username_pwd(iscsi, user, password);
214
if (ret != 0) {
215
error_setg(errp, "Failed to set initiator username and password");
216
ret = -EINVAL;
217
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
218
}
219
220
/* check if we got CHAP username/password via the options */
221
- parse_chap(iscsi, iscsi_url->target, &local_err);
222
+ parse_chap(iscsi, target, &local_err);
223
if (local_err != NULL) {
224
error_propagate(errp, local_err);
225
ret = -EINVAL;
226
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
227
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
228
229
/* check if we got HEADER_DIGEST via the options */
230
- parse_header_digest(iscsi, iscsi_url->target, &local_err);
231
+ parse_header_digest(iscsi, target, &local_err);
232
if (local_err != NULL) {
233
error_propagate(errp, local_err);
234
ret = -EINVAL;
235
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
236
}
237
238
/* timeout handling is broken in libiscsi before 1.15.0 */
239
- timeout = parse_timeout(iscsi_url->target);
240
+ timeout = parse_timeout(target);
241
#if LIBISCSI_API_VERSION >= 20150621
242
iscsi_set_timeout(iscsi, timeout);
243
#else
244
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
245
}
246
#endif
247
248
- if (iscsi_full_connect_sync(iscsi, iscsi_url->portal, iscsi_url->lun) != 0) {
249
+ if (iscsi_full_connect_sync(iscsi, portal, lun) != 0) {
250
error_setg(errp, "iSCSI: Failed to connect to LUN : %s",
251
iscsi_get_error(iscsi));
252
ret = -EINVAL;
253
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
254
255
iscsilun->iscsi = iscsi;
256
iscsilun->aio_context = bdrv_get_aio_context(bs);
257
- iscsilun->lun = iscsi_url->lun;
258
+ iscsilun->lun = lun;
259
iscsilun->has_write_same = true;
260
261
task = iscsi_do_inquiry(iscsilun->iscsi, iscsilun->lun, 0, 0,
262
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
263
out:
264
qemu_opts_del(opts);
265
g_free(initiator_name);
266
- if (iscsi_url != NULL) {
267
- iscsi_destroy_url(iscsi_url);
268
- }
269
if (task != NULL) {
270
scsi_free_scsi_task(task);
271
}
272
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iscsi = {
273
.format_name = "iscsi",
274
.protocol_name = "iscsi",
275
276
- .instance_size = sizeof(IscsiLun),
277
- .bdrv_needs_filename = true,
278
- .bdrv_file_open = iscsi_open,
279
- .bdrv_close = iscsi_close,
280
- .bdrv_create = iscsi_create,
281
- .create_opts = &iscsi_create_opts,
282
- .bdrv_reopen_prepare = iscsi_reopen_prepare,
283
- .bdrv_reopen_commit = iscsi_reopen_commit,
284
- .bdrv_invalidate_cache = iscsi_invalidate_cache,
285
+ .instance_size = sizeof(IscsiLun),
286
+ .bdrv_parse_filename = iscsi_parse_filename,
287
+ .bdrv_file_open = iscsi_open,
288
+ .bdrv_close = iscsi_close,
289
+ .bdrv_create = iscsi_create,
290
+ .create_opts = &iscsi_create_opts,
291
+ .bdrv_reopen_prepare = iscsi_reopen_prepare,
292
+ .bdrv_reopen_commit = iscsi_reopen_commit,
293
+ .bdrv_invalidate_cache = iscsi_invalidate_cache,
294
295
.bdrv_getlength = iscsi_getlength,
296
.bdrv_get_info = iscsi_get_info,
297
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_iser = {
298
.format_name = "iser",
299
.protocol_name = "iser",
300
301
- .instance_size = sizeof(IscsiLun),
302
- .bdrv_needs_filename = true,
303
- .bdrv_file_open = iscsi_open,
304
- .bdrv_close = iscsi_close,
305
- .bdrv_create = iscsi_create,
306
- .create_opts = &iscsi_create_opts,
307
- .bdrv_reopen_prepare = iscsi_reopen_prepare,
308
- .bdrv_reopen_commit = iscsi_reopen_commit,
309
- .bdrv_invalidate_cache = iscsi_invalidate_cache,
310
+ .instance_size = sizeof(IscsiLun),
311
+ .bdrv_parse_filename = iscsi_parse_filename,
312
+ .bdrv_file_open = iscsi_open,
313
+ .bdrv_close = iscsi_close,
314
+ .bdrv_create = iscsi_create,
315
+ .create_opts = &iscsi_create_opts,
316
+ .bdrv_reopen_prepare = iscsi_reopen_prepare,
317
+ .bdrv_reopen_commit = iscsi_reopen_commit,
318
+ .bdrv_invalidate_cache = iscsi_invalidate_cache,
319
320
.bdrv_getlength = iscsi_getlength,
321
.bdrv_get_info = iscsi_get_info,
322
--
219
--
323
2.9.3
220
2.35.1
324
325
diff view generated by jsdifflib
1
From: Kevin Wolf <kwolf@redhat.com>
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
2
3
This splits the logic in the old parse_chap() function into a part that
3
The thread pool regulates itself: when idle, it kills threads until
4
parses the -iscsi options into the new driver-specific options, and
4
empty, when in demand, it creates new threads until full. This behaviour
5
another part that actually applies those options (called apply_chap()
5
doesn't play well with latency sensitive workloads where the price of
6
now).
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.
7
9
8
Note that this means that username and password specified with -iscsi
10
In order to mitigate this let's introduce a new 'EventLoopBase'
9
only take effect when a URL is provided. This is intentional, -iscsi is
11
property to set the thread pool size. The threads will be created during
10
a legacy interface only supported for compatibility, new users should
12
the pool's initialization or upon updating the property's value, remain
11
use the proper driver-specific options.
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.
12
16
13
Reviewed-by: Fam Zheng <famz@redhat.com>
17
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Signed-off-by: Jeff Cody <jcody@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>
16
---
22
---
17
block/iscsi.c | 78 +++++++++++++++++++++++++++++++++--------------------------
23
qapi/qom.json | 10 +++++-
18
1 file changed, 44 insertions(+), 34 deletions(-)
24
include/block/aio.h | 10 ++++++
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(-)
19
34
20
diff --git a/block/iscsi.c b/block/iscsi.c
35
diff --git a/qapi/qom.json b/qapi/qom.json
21
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
22
--- a/block/iscsi.c
37
--- a/qapi/qom.json
23
+++ b/block/iscsi.c
38
+++ b/qapi/qom.json
24
@@ -XXX,XX +XXX,XX @@ retry:
39
@@ -XXX,XX +XXX,XX @@
25
return 0;
40
# 0 means that the engine will use its default.
26
}
41
# (default: 0)
27
42
#
28
-static void parse_chap(struct iscsi_context *iscsi, const char *target,
43
+# @thread-pool-min: minimum number of threads reserved in the thread pool
29
+static void apply_chap(struct iscsi_context *iscsi, QemuOpts *opts,
44
+# (default:0)
30
Error **errp)
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);
84
#endif
85
diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h
86
index XXXXXXX..XXXXXXX 100644
87
--- a/include/block/thread-pool.h
88
+++ b/include/block/thread-pool.h
89
@@ -XXX,XX +XXX,XX @@
90
91
#include "block/block.h"
92
93
+#define THREAD_POOL_MAX_THREADS_DEFAULT 64
94
+
95
typedef int ThreadPoolFunc(void *opaque);
96
97
typedef struct ThreadPool ThreadPool;
98
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool,
99
int coroutine_fn thread_pool_submit_co(ThreadPool *pool,
100
ThreadPoolFunc *func, void *arg);
101
void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg);
102
+void thread_pool_update_params(ThreadPool *pool, struct AioContext *ctx);
103
104
#endif
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 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)
31
{
252
{
32
- QemuOptsList *list;
253
+ ERRP_GUARD();
33
- QemuOpts *opts;
254
+
34
const char *user = NULL;
255
if (!qemu_aio_context) {
35
const char *password = NULL;
256
error_setg(errp, "qemu aio context not ready");
36
const char *secretid;
37
char *secret = NULL;
38
39
- list = qemu_find_opts("iscsi");
40
- if (!list) {
41
- return;
42
- }
43
-
44
- opts = qemu_opts_find(list, target);
45
- if (opts == NULL) {
46
- opts = QTAILQ_FIRST(&list->head);
47
- if (!opts) {
48
- return;
49
- }
50
- }
51
-
52
user = qemu_opt_get(opts, "user");
53
if (!user) {
54
return;
257
return;
55
@@ -XXX,XX +XXX,XX @@ out:
56
}
258
}
57
}
259
58
260
aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
59
+static void iscsi_parse_iscsi_option(const char *target, QDict *options)
261
+ if (*errp) {
262
+ return;
263
+ }
264
+
265
+ aio_context_set_thread_pool_params(qemu_aio_context, base->thread_pool_min,
266
+ base->thread_pool_max, errp);
267
}
268
269
MainLoop *mloop;
270
diff --git a/util/thread-pool.c b/util/thread-pool.c
271
index XXXXXXX..XXXXXXX 100644
272
--- a/util/thread-pool.c
273
+++ b/util/thread-pool.c
274
@@ -XXX,XX +XXX,XX @@ struct ThreadPool {
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)
60
+{
291
+{
61
+ QemuOptsList *list;
292
+ /*
62
+ QemuOpts *opts;
293
+ * The semaphore timed out, we should exit the loop except when:
63
+ const char *user, *password, *password_secret;
294
+ * - There is work to do, we raced with the signal.
64
+
295
+ * - The max threads threshold just changed, we raced with the signal.
65
+ list = qemu_find_opts("iscsi");
296
+ * - The thread pool forces a minimum number of readily available threads.
66
+ if (!list) {
297
+ */
67
+ return;
298
+ if (ret == -1 && (!QTAILQ_EMPTY(&pool->request_list) ||
68
+ }
299
+ pool->cur_threads > pool->max_threads ||
69
+
300
+ pool->cur_threads <= pool->min_threads)) {
70
+ opts = qemu_opts_find(list, target);
301
+ return true;
71
+ if (opts == NULL) {
302
+ }
72
+ opts = QTAILQ_FIRST(&list->head);
303
+
73
+ if (!opts) {
304
+ return false;
74
+ return;
75
+ }
76
+ }
77
+
78
+ user = qemu_opt_get(opts, "user");
79
+ if (user) {
80
+ qdict_set_default_str(options, "user", user);
81
+ }
82
+
83
+ password = qemu_opt_get(opts, "password");
84
+ if (password) {
85
+ qdict_set_default_str(options, "password", password);
86
+ }
87
+
88
+ password_secret = qemu_opt_get(opts, "password-secret");
89
+ if (password_secret) {
90
+ qdict_set_default_str(options, "password-secret", password_secret);
91
+ }
92
+}
305
+}
93
+
306
+
94
/*
307
static void *worker_thread(void *opaque)
95
* We support iscsi url's on the form
308
{
96
* iscsi://[<username>%<password>@]<host>[:<port>]/<targetname>/<lun>
309
ThreadPool *pool = opaque;
97
@@ -XXX,XX +XXX,XX @@ static void iscsi_parse_filename(const char *filename, QDict *options,
310
@@ -XXX,XX +XXX,XX @@ static void *worker_thread(void *opaque)
98
qdict_set_default_str(options, "lun", lun_str);
311
ret = qemu_sem_timedwait(&pool->sem, 10000);
99
g_free(lun_str);
312
qemu_mutex_lock(&pool->lock);
100
313
pool->idle_threads--;
101
+ /* User/password from -iscsi take precedence over those from the URL */
314
- } while (ret == -1 && !QTAILQ_EMPTY(&pool->request_list));
102
+ iscsi_parse_iscsi_option(iscsi_url->target, options);
315
- if (ret == -1 || pool->stopping) {
103
+
316
+ } while (back_to_sleep(pool, ret));
104
if (iscsi_url->user[0] != '\0') {
317
+ if (ret == -1 || pool->stopping ||
105
qdict_set_default_str(options, "user", iscsi_url->user);
318
+ pool->cur_threads > pool->max_threads) {
106
qdict_set_default_str(options, "password", iscsi_url->passwd);
319
break;
107
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
320
}
108
.type = QEMU_OPT_STRING,
321
109
},
322
@@ -XXX,XX +XXX,XX @@ void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg)
110
{
323
thread_pool_submit_aio(pool, func, arg, NULL, NULL);
111
+ .name = "password-secret",
324
}
112
+ .type = QEMU_OPT_STRING,
325
113
+ },
326
+void thread_pool_update_params(ThreadPool *pool, AioContext *ctx)
114
+ {
327
+{
115
.name = "lun",
328
+ qemu_mutex_lock(&pool->lock);
116
.type = QEMU_OPT_NUMBER,
329
+
117
},
330
+ pool->min_threads = ctx->thread_pool_min;
118
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
331
+ pool->max_threads = ctx->thread_pool_max;
119
QemuOpts *opts;
332
+
120
Error *local_err = NULL;
333
+ /*
121
const char *transport_name, *portal, *target;
334
+ * We either have to:
122
- const char *user, *password;
335
+ * - Increase the number available of threads until over the min_threads
123
#if LIBISCSI_API_VERSION >= (20160603)
336
+ * threshold.
124
enum iscsi_transport_type transport;
337
+ * - Decrease the number of available threads until under the max_threads
125
#endif
338
+ * threshold.
126
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
339
+ * - Do nothing. The current number of threads fall in between the min and
127
transport_name = qemu_opt_get(opts, "transport");
340
+ * max thresholds. We'll let the pool manage itself.
128
portal = qemu_opt_get(opts, "portal");
341
+ */
129
target = qemu_opt_get(opts, "target");
342
+ for (int i = pool->cur_threads; i < pool->min_threads; i++) {
130
- user = qemu_opt_get(opts, "user");
343
+ spawn_thread(pool);
131
- password = qemu_opt_get(opts, "password");
344
+ }
132
lun = qemu_opt_get_number(opts, "lun", 0);
345
+
133
346
+ for (int i = pool->cur_threads; i > pool->max_threads; i--) {
134
if (!transport_name || !portal || !target) {
347
+ qemu_sem_post(&pool->sem);
135
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
348
+ }
136
ret = -EINVAL;
349
+
137
goto out;
350
+ qemu_mutex_unlock(&pool->lock);
138
}
351
+}
139
- if (user && !password) {
352
+
140
- error_setg(errp, "If a user name is given, a password is required");
353
static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
141
- ret = -EINVAL;
354
{
142
- goto out;
355
if (!ctx) {
143
- }
356
@@ -XXX,XX +XXX,XX @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
144
357
qemu_mutex_init(&pool->lock);
145
if (!strcmp(transport_name, "tcp")) {
358
qemu_cond_init(&pool->worker_stopped);
146
#if LIBISCSI_API_VERSION >= (20160603)
359
qemu_sem_init(&pool->sem, 0);
147
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
360
- pool->max_threads = 64;
148
goto out;
361
pool->new_thread_bh = aio_bh_new(ctx, spawn_thread_bh_fn, pool);
149
}
362
150
363
QLIST_INIT(&pool->head);
151
- if (user) {
364
QTAILQ_INIT(&pool->request_list);
152
- ret = iscsi_set_initiator_username_pwd(iscsi, user, password);
365
+
153
- if (ret != 0) {
366
+ thread_pool_update_params(pool, ctx);
154
- error_setg(errp, "Failed to set initiator username and password");
367
}
155
- ret = -EINVAL;
368
156
- goto out;
369
ThreadPool *thread_pool_new(AioContext *ctx)
157
- }
158
- }
159
-
160
/* check if we got CHAP username/password via the options */
161
- parse_chap(iscsi, target, &local_err);
162
+ apply_chap(iscsi, opts, &local_err);
163
if (local_err != NULL) {
164
error_propagate(errp, local_err);
165
ret = -EINVAL;
166
--
370
--
167
2.9.3
371
2.35.1
168
169
diff view generated by jsdifflib
Deleted patch
1
From: Kevin Wolf <kwolf@redhat.com>
2
1
3
This was previously only available with -iscsi. Again, after this patch,
4
the -iscsi option only takes effect if an URL is given. New users are
5
supposed to use the new driver-specific option.
6
7
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
8
Reviewed-by: Fam Zheng <famz@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Jeff Cody <jcody@redhat.com>
11
---
12
block/iscsi.c | 32 +++++++++++++++-----------------
13
1 file changed, 15 insertions(+), 17 deletions(-)
14
15
diff --git a/block/iscsi.c b/block/iscsi.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/iscsi.c
18
+++ b/block/iscsi.c
19
@@ -XXX,XX +XXX,XX @@ static void parse_header_digest(struct iscsi_context *iscsi, const char *target,
20
}
21
}
22
23
-static char *parse_initiator_name(const char *target)
24
+static char *get_initiator_name(QemuOpts *opts)
25
{
26
- QemuOptsList *list;
27
- QemuOpts *opts;
28
const char *name;
29
char *iscsi_name;
30
UuidInfo *uuid_info;
31
32
- list = qemu_find_opts("iscsi");
33
- if (list) {
34
- opts = qemu_opts_find(list, target);
35
- if (!opts) {
36
- opts = QTAILQ_FIRST(&list->head);
37
- }
38
- if (opts) {
39
- name = qemu_opt_get(opts, "initiator-name");
40
- if (name) {
41
- return g_strdup(name);
42
- }
43
- }
44
+ name = qemu_opt_get(opts, "initiator-name");
45
+ if (name) {
46
+ return g_strdup(name);
47
}
48
49
uuid_info = qmp_query_uuid(NULL);
50
@@ -XXX,XX +XXX,XX @@ static void iscsi_parse_iscsi_option(const char *target, QDict *options)
51
{
52
QemuOptsList *list;
53
QemuOpts *opts;
54
- const char *user, *password, *password_secret;
55
+ const char *user, *password, *password_secret, *initiator_name;
56
57
list = qemu_find_opts("iscsi");
58
if (!list) {
59
@@ -XXX,XX +XXX,XX @@ static void iscsi_parse_iscsi_option(const char *target, QDict *options)
60
if (password_secret) {
61
qdict_set_default_str(options, "password-secret", password_secret);
62
}
63
+
64
+ initiator_name = qemu_opt_get(opts, "initiator-name");
65
+ if (initiator_name) {
66
+ qdict_set_default_str(options, "initiator-name", initiator_name);
67
+ }
68
}
69
70
/*
71
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
72
.name = "lun",
73
.type = QEMU_OPT_NUMBER,
74
},
75
+ {
76
+ .name = "initiator-name",
77
+ .type = QEMU_OPT_STRING,
78
+ },
79
{ /* end of list */ }
80
},
81
};
82
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
83
84
memset(iscsilun, 0, sizeof(IscsiLun));
85
86
- initiator_name = parse_initiator_name(target);
87
+ initiator_name = get_initiator_name(opts);
88
89
iscsi = iscsi_create_context(initiator_name);
90
if (iscsi == NULL) {
91
--
92
2.9.3
93
94
diff view generated by jsdifflib
Deleted patch
1
From: Kevin Wolf <kwolf@redhat.com>
2
1
3
This was previously only available with -iscsi. Again, after this patch,
4
the -iscsi option only takes effect if an URL is given. New users are
5
supposed to use the new driver-specific option.
6
7
All -iscsi options have a corresponding driver-specific option for the
8
iscsi block driver now.
9
10
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
11
Reviewed-by: Fam Zheng <famz@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Jeff Cody <jcody@redhat.com>
14
---
15
block/iscsi.c | 37 +++++++++++--------------------------
16
1 file changed, 11 insertions(+), 26 deletions(-)
17
18
diff --git a/block/iscsi.c b/block/iscsi.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/iscsi.c
21
+++ b/block/iscsi.c
22
@@ -XXX,XX +XXX,XX @@ static char *get_initiator_name(QemuOpts *opts)
23
return iscsi_name;
24
}
25
26
-static int parse_timeout(const char *target)
27
-{
28
- QemuOptsList *list;
29
- QemuOpts *opts;
30
- const char *timeout;
31
-
32
- list = qemu_find_opts("iscsi");
33
- if (list) {
34
- opts = qemu_opts_find(list, target);
35
- if (!opts) {
36
- opts = QTAILQ_FIRST(&list->head);
37
- }
38
- if (opts) {
39
- timeout = qemu_opt_get(opts, "timeout");
40
- if (timeout) {
41
- return atoi(timeout);
42
- }
43
- }
44
- }
45
-
46
- return 0;
47
-}
48
-
49
static void iscsi_nop_timed_event(void *opaque)
50
{
51
IscsiLun *iscsilun = opaque;
52
@@ -XXX,XX +XXX,XX @@ static void iscsi_parse_iscsi_option(const char *target, QDict *options)
53
QemuOptsList *list;
54
QemuOpts *opts;
55
const char *user, *password, *password_secret, *initiator_name,
56
- *header_digest;
57
+ *header_digest, *timeout;
58
59
list = qemu_find_opts("iscsi");
60
if (!list) {
61
@@ -XXX,XX +XXX,XX @@ static void iscsi_parse_iscsi_option(const char *target, QDict *options)
62
if (header_digest) {
63
qdict_set_default_str(options, "header-digest", header_digest);
64
}
65
+
66
+ timeout = qemu_opt_get(opts, "timeout");
67
+ if (timeout) {
68
+ qdict_set_default_str(options, "timeout", timeout);
69
+ }
70
}
71
72
/*
73
@@ -XXX,XX +XXX,XX @@ static void iscsi_parse_filename(const char *filename, QDict *options,
74
iscsi_destroy_url(iscsi_url);
75
}
76
77
-/* TODO Add -iscsi options */
78
static QemuOptsList runtime_opts = {
79
.name = "iscsi",
80
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
81
@@ -XXX,XX +XXX,XX @@ static QemuOptsList runtime_opts = {
82
.name = "header-digest",
83
.type = QEMU_OPT_STRING,
84
},
85
+ {
86
+ .name = "timeout",
87
+ .type = QEMU_OPT_NUMBER,
88
+ },
89
{ /* end of list */ }
90
},
91
};
92
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
93
}
94
95
/* timeout handling is broken in libiscsi before 1.15.0 */
96
- timeout = parse_timeout(target);
97
+ timeout = qemu_opt_get_number(opts, "timeout", 0);
98
#if LIBISCSI_API_VERSION >= 20150621
99
iscsi_set_timeout(iscsi, timeout);
100
#else
101
--
102
2.9.3
103
104
diff view generated by jsdifflib
Deleted patch
1
From: Kevin Wolf <kwolf@redhat.com>
2
1
3
This adds blockdev-add support for iscsi devices.
4
5
Reviewed-by: Daniel P. Berrange <berrange@redhat.com>
6
Reviewed-by: Fam Zheng <famz@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Jeff Cody <jcody@redhat.com>
9
---
10
block/iscsi.c | 14 ++++++----
11
qapi/block-core.json | 75 ++++++++++++++++++++++++++++++++++++++++++++++++----
12
2 files changed, 79 insertions(+), 10 deletions(-)
13
14
diff --git a/block/iscsi.c b/block/iscsi.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/iscsi.c
17
+++ b/block/iscsi.c
18
@@ -XXX,XX +XXX,XX @@ static void apply_header_digest(struct iscsi_context *iscsi, QemuOpts *opts,
19
digest = qemu_opt_get(opts, "header-digest");
20
if (!digest) {
21
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
22
- } else if (!strcmp(digest, "CRC32C")) {
23
+ } else if (!strcmp(digest, "crc32c")) {
24
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C);
25
- } else if (!strcmp(digest, "NONE")) {
26
+ } else if (!strcmp(digest, "none")) {
27
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE);
28
- } else if (!strcmp(digest, "CRC32C-NONE")) {
29
+ } else if (!strcmp(digest, "crc32c-none")) {
30
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_CRC32C_NONE);
31
- } else if (!strcmp(digest, "NONE-CRC32C")) {
32
+ } else if (!strcmp(digest, "none-crc32c")) {
33
iscsi_set_header_digest(iscsi, ISCSI_HEADER_DIGEST_NONE_CRC32C);
34
} else {
35
error_setg(errp, "Invalid header-digest setting : %s", digest);
36
@@ -XXX,XX +XXX,XX @@ static void iscsi_parse_iscsi_option(const char *target, QDict *options)
37
38
header_digest = qemu_opt_get(opts, "header-digest");
39
if (header_digest) {
40
- qdict_set_default_str(options, "header-digest", header_digest);
41
+ /* -iscsi takes upper case values, but QAPI only supports lower case
42
+ * enum constant names, so we have to convert here. */
43
+ char *qapi_value = g_ascii_strdown(header_digest, -1);
44
+ qdict_set_default_str(options, "header-digest", qapi_value);
45
+ g_free(qapi_value);
46
}
47
48
timeout = qemu_opt_get(opts, "timeout");
49
diff --git a/qapi/block-core.json b/qapi/block-core.json
50
index XXXXXXX..XXXXXXX 100644
51
--- a/qapi/block-core.json
52
+++ b/qapi/block-core.json
53
@@ -XXX,XX +XXX,XX @@
54
# @nfs: Since 2.8
55
# @replication: Since 2.8
56
# @ssh: Since 2.8
57
+# @iscsi: Since 2.9
58
#
59
# Since: 2.0
60
##
61
{ 'enum': 'BlockdevDriver',
62
'data': [ 'archipelago', 'blkdebug', 'blkverify', 'bochs', 'cloop',
63
'dmg', 'file', 'ftp', 'ftps', 'gluster', 'host_cdrom',
64
- 'host_device', 'http', 'https', 'luks', 'nbd', 'nfs', 'null-aio',
65
- 'null-co', 'parallels', 'qcow', 'qcow2', 'qed', 'quorum', 'raw',
66
- 'replication', 'ssh', 'vdi', 'vhdx', 'vmdk', 'vpc',
67
- 'vvfat' ] }
68
+ 'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
69
+ 'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
70
+ 'quorum', 'raw', 'replication', 'ssh', 'vdi', 'vhdx', 'vmdk',
71
+ 'vpc', 'vvfat' ] }
72
73
##
74
# @BlockdevOptionsFile:
75
@@ -XXX,XX +XXX,XX @@
76
'*logfile': 'str' } }
77
78
##
79
+# @IscsiTransport:
80
+#
81
+# An enumeration of libiscsi transport types
82
+#
83
+# Since: 2.9
84
+##
85
+{ 'enum': 'IscsiTransport',
86
+ 'data': [ 'tcp', 'iser' ] }
87
+
88
+##
89
+# @IscsiHeaderDigest:
90
+#
91
+# An enumeration of header digests supported by libiscsi
92
+#
93
+# Since: 2.9
94
+##
95
+{ 'enum': 'IscsiHeaderDigest',
96
+ 'prefix': 'QAPI_ISCSI_HEADER_DIGEST',
97
+ 'data': [ 'crc32c', 'none', 'crc32c-none', 'none-crc32c' ] }
98
+
99
+##
100
+# @BlockdevOptionsIscsi:
101
+#
102
+# @transport The iscsi transport type
103
+#
104
+# @portal The address of the iscsi portal
105
+#
106
+# @target The target iqn name
107
+#
108
+# @lun #optional LUN to connect to. Defaults to 0.
109
+#
110
+# @user #optional User name to log in with. If omitted, no CHAP
111
+# authentication is performed.
112
+#
113
+# @password-secret #optional The ID of a QCryptoSecret object providing
114
+# the password for the login. This option is required if
115
+# @user is specified.
116
+#
117
+# @initiator-name #optional The iqn name we want to identify to the target
118
+# as. If this option is not specified, an initiator name is
119
+# generated automatically.
120
+#
121
+# @header-digest #optional The desired header digest. Defaults to
122
+# none-crc32c.
123
+#
124
+# @timeout #optional Timeout in seconds after which a request will
125
+# timeout. 0 means no timeout and is the default.
126
+#
127
+# Driver specific block device options for iscsi
128
+#
129
+# Since: 2.9
130
+##
131
+{ 'struct': 'BlockdevOptionsIscsi',
132
+ 'data': { 'transport': 'IscsiTransport',
133
+ 'portal': 'str',
134
+ 'target': 'str',
135
+ '*lun': 'int',
136
+ '*user': 'str',
137
+ '*password-secret': 'str',
138
+ '*initiator-name': 'str',
139
+ '*header-digest': 'IscsiHeaderDigest',
140
+ '*timeout': 'int' } }
141
+
142
+##
143
# @ReplicationMode:
144
#
145
# An enumeration of replication modes.
146
@@ -XXX,XX +XXX,XX @@
147
'host_device':'BlockdevOptionsFile',
148
'http': 'BlockdevOptionsCurl',
149
'https': 'BlockdevOptionsCurl',
150
-# TODO iscsi: Wait for structured options
151
+ 'iscsi': 'BlockdevOptionsIscsi',
152
'luks': 'BlockdevOptionsLUKS',
153
'nbd': 'BlockdevOptionsNbd',
154
'nfs': 'BlockdevOptionsNfs',
155
--
156
2.9.3
157
158
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Jeff Cody <jcody@redhat.com>
2
---
3
qapi/block-core.json | 50 +++++++++++++++++++++++++-------------------------
4
1 file changed, 25 insertions(+), 25 deletions(-)
5
1
6
diff --git a/qapi/block-core.json b/qapi/block-core.json
7
index XXXXXXX..XXXXXXX 100644
8
--- a/qapi/block-core.json
9
+++ b/qapi/block-core.json
10
@@ -XXX,XX +XXX,XX @@
11
# 1.
12
# -> { "execute": "blockdev-add",
13
# "arguments": {
14
-# "options" : { "driver": "qcow2",
15
-# "file": { "driver": "file",
16
-# "filename": "test.qcow2" } } } }
17
+# "driver": "qcow2",
18
+# "node-name": "test1",
19
+# "file": {
20
+# "driver": "file",
21
+# "filename": "test.qcow2"
22
+# }
23
+# }
24
+# }
25
# <- { "return": {} }
26
#
27
# 2.
28
# -> { "execute": "blockdev-add",
29
# "arguments": {
30
-# "options": {
31
-# "driver": "qcow2",
32
-# "node-name": "node0",
33
-# "discard": "unmap",
34
-# "cache": {
35
-# "direct": true,
36
-# "writeback": true
37
+# "driver": "qcow2",
38
+# "node-name": "node0",
39
+# "discard": "unmap",
40
+# "cache": {
41
+# "direct": true
42
# },
43
# "file": {
44
-# "driver": "file",
45
-# "filename": "/tmp/test.qcow2"
46
+# "driver": "file",
47
+# "filename": "/tmp/test.qcow2"
48
# },
49
# "backing": {
50
-# "driver": "raw",
51
-# "file": {
52
-# "driver": "file",
53
-# "filename": "/dev/fdset/4"
54
+# "driver": "raw",
55
+# "file": {
56
+# "driver": "file",
57
+# "filename": "/dev/fdset/4"
58
# }
59
# }
60
-# }
61
# }
62
# }
63
#
64
@@ -XXX,XX +XXX,XX @@
65
#
66
# -> { "execute": "blockdev-add",
67
# "arguments": {
68
-# "options": {
69
-# "driver": "qcow2",
70
-# "node-name": "node0",
71
-# "file": {
72
-# "driver": "file",
73
-# "filename": "test.qcow2"
74
-# }
75
-# }
76
+# "driver": "qcow2",
77
+# "node-name": "node0",
78
+# "file": {
79
+# "driver": "file",
80
+# "filename": "test.qcow2"
81
+# }
82
# }
83
# }
84
# <- { "return": {} }
85
--
86
2.9.3
87
88
diff view generated by jsdifflib
Deleted patch
1
From: Anton Nefedov <anton.nefedov@virtuozzo.com>
2
1
3
If explicit zeroing out before mirroring is required for the target image,
4
it moves the block job offset counter to EOF, then offset and len counters
5
count the image size twice. There is no harm but stats are confusing,
6
specifically the progress of the operation is always reported as 99% by
7
management tools.
8
9
The patch skips offset increase for the first "technical" pass over the
10
image. This should not cause any further harm.
11
12
Signed-off-by: Anton Nefedov <anton.nefedov@virtuozzo.com>
13
Signed-off-by: Denis V. Lunev <den@openvz.org>
14
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
16
Message-id: 1486045515-8009-1-git-send-email-den@openvz.org
17
CC: Jeff Cody <jcody@redhat.com>
18
CC: Kevin Wolf <kwolf@redhat.com>
19
CC: Max Reitz <mreitz@redhat.com>
20
CC: Eric Blake <eblake@redhat.com>
21
Signed-off-by: Jeff Cody <jcody@redhat.com>
22
---
23
block/mirror.c | 9 +++++++--
24
1 file changed, 7 insertions(+), 2 deletions(-)
25
26
diff --git a/block/mirror.c b/block/mirror.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/block/mirror.c
29
+++ b/block/mirror.c
30
@@ -XXX,XX +XXX,XX @@ typedef struct MirrorBlockJob {
31
bool waiting_for_io;
32
int target_cluster_sectors;
33
int max_iov;
34
+ bool initial_zeroing_ongoing;
35
} MirrorBlockJob;
36
37
typedef struct MirrorOp {
38
@@ -XXX,XX +XXX,XX @@ static void mirror_iteration_done(MirrorOp *op, int ret)
39
if (s->cow_bitmap) {
40
bitmap_set(s->cow_bitmap, chunk_num, nb_chunks);
41
}
42
- s->common.offset += (uint64_t)op->nb_sectors * BDRV_SECTOR_SIZE;
43
+ if (!s->initial_zeroing_ongoing) {
44
+ s->common.offset += (uint64_t)op->nb_sectors * BDRV_SECTOR_SIZE;
45
+ }
46
}
47
-
48
qemu_iovec_destroy(&op->qiov);
49
g_free(op);
50
51
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
52
return 0;
53
}
54
55
+ s->initial_zeroing_ongoing = true;
56
for (sector_num = 0; sector_num < end; ) {
57
int nb_sectors = MIN(end - sector_num,
58
QEMU_ALIGN_DOWN(INT_MAX, s->granularity) >> BDRV_SECTOR_BITS);
59
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
60
mirror_throttle(s);
61
62
if (block_job_is_cancelled(&s->common)) {
63
+ s->initial_zeroing_ongoing = false;
64
return 0;
65
}
66
67
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
68
}
69
70
mirror_wait_for_all_io(s);
71
+ s->initial_zeroing_ongoing = false;
72
}
73
74
/* First part, loop on the sectors and initialize the dirty bitmap. */
75
--
76
2.9.3
77
78
diff view generated by jsdifflib
Deleted patch
1
From: Thomas Huth <thuth@redhat.com>
2
1
3
The sheepdog URL is broken twice: First it uses a duplicated
4
http:// prefix, second the website seems to have moved to
5
https://sheepdog.github.io/sheepdog/ instead.
6
7
Signed-off-by: Thomas Huth <thuth@redhat.com>
8
Signed-off-by: Jeff Cody <jcody@redhat.com>
9
---
10
qemu-options.hx | 2 +-
11
1 file changed, 1 insertion(+), 1 deletion(-)
12
13
diff --git a/qemu-options.hx b/qemu-options.hx
14
index XXXXXXX..XXXXXXX 100644
15
--- a/qemu-options.hx
16
+++ b/qemu-options.hx
17
@@ -XXX,XX +XXX,XX @@ Example
18
qemu-system-i386 --drive file=sheepdog://192.0.2.1:30000/MyVirtualMachine
19
@end example
20
21
-See also @url{http://http://www.osrg.net/sheepdog/}.
22
+See also @url{https://sheepdog.github.io/sheepdog/}.
23
24
@item GlusterFS
25
GlusterFS is a user space distributed file system.
26
--
27
2.9.3
28
29
diff view generated by jsdifflib