1
The following changes since commit 3fbd3405d2b0604ea530fc7a1828f19da1e95ff9:
1
The following changes since commit 9cf289af47bcfae5c75de37d8e5d6fd23705322c:
2
2
3
Merge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2019-08-17' into staging (2019-08-19 14:14:09 +0100)
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://github.com/XanClic/qemu.git tags/pull-block-2019-08-19
7
https://gitlab.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to fa27c478102a6b5d1c6b02c005607ad9404b915f:
9
for you to fetch changes up to bef2e050d6a7feb865854c65570c496ac5a8cf53:
10
10
11
doc: Preallocation does not require writing zeroes (2019-08-19 17:13:26 +0200)
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
- preallocation=falloc/full support for LUKS
15
16
- Various minor fixes
16
Add new thread-pool-min/thread-pool-max parameters to control the thread pool
17
used for async I/O.
17
18
18
----------------------------------------------------------------
19
----------------------------------------------------------------
19
Max Reitz (16):
20
qemu-img: Fix bdrv_has_zero_init() use in convert
21
mirror: Fix bdrv_has_zero_init() use
22
block: Add bdrv_has_zero_init_truncate()
23
block: Implement .bdrv_has_zero_init_truncate()
24
block: Use bdrv_has_zero_init_truncate()
25
qcow2: Fix .bdrv_has_zero_init()
26
vdi: Fix .bdrv_has_zero_init()
27
vhdx: Fix .bdrv_has_zero_init()
28
iotests: Convert to preallocated encrypted qcow2
29
iotests: Test convert -n to pre-filled image
30
iotests: Full mirror to existing non-zero image
31
vdi: Make block_status recurse for fixed images
32
vmdk: Make block_status recurse for flat extents
33
vpc: Do not return RAW from block_status
34
iotests: Fix 141 when run with qed
35
doc: Preallocation does not require writing zeroes
36
20
37
Maxim Levitsky (1):
21
Nicolas Saenz Julienne (3):
38
LUKS: support preallocation
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
39
25
40
qapi/block-core.json | 15 +++++---
26
qapi/qom.json | 43 ++++++++--
41
include/block/block.h | 1 +
27
meson.build | 26 +++---
42
include/block/block_int.h | 9 +++++
28
include/block/aio.h | 10 +++
43
block.c | 21 +++++++++++
29
include/block/thread-pool.h | 3 +
44
block/crypto.c | 30 ++++++++++++++--
30
include/qemu/main-loop.h | 10 +++
45
block/file-posix.c | 1 +
31
include/sysemu/event-loop-base.h | 41 +++++++++
46
block/file-win32.c | 1 +
32
include/sysemu/iothread.h | 6 +-
47
block/gluster.c | 4 +++
33
event-loop-base.c | 140 +++++++++++++++++++++++++++++++
48
block/mirror.c | 11 ++++--
34
iothread.c | 68 +++++----------
49
block/nfs.c | 1 +
35
util/aio-posix.c | 1 +
50
block/parallels.c | 2 +-
36
util/async.c | 20 +++++
51
block/qcow2.c | 30 +++++++++++++++-
37
util/main-loop.c | 65 ++++++++++++++
52
block/qed.c | 1 +
38
util/thread-pool.c | 55 +++++++++++-
53
block/raw-format.c | 6 ++++
39
13 files changed, 419 insertions(+), 69 deletions(-)
54
block/rbd.c | 1 +
40
create mode 100644 include/sysemu/event-loop-base.h
55
block/sheepdog.c | 1 +
41
create mode 100644 event-loop-base.c
56
block/ssh.c | 1 +
57
block/vdi.c | 16 +++++++--
58
block/vhdx.c | 28 +++++++++++++--
59
block/vmdk.c | 3 ++
60
block/vpc.c | 2 +-
61
blockdev.c | 16 +++++++--
62
qemu-img.c | 11 ++++--
63
tests/test-block-iothread.c | 2 +-
64
docs/qemu-block-drivers.texi | 4 +--
65
qemu-img.texi | 4 +--
66
tests/qemu-iotests/041 | 62 +++++++++++++++++++++++++++++---
67
tests/qemu-iotests/041.out | 4 +--
68
tests/qemu-iotests/122 | 17 +++++++++
69
tests/qemu-iotests/122.out | 8 +++++
70
tests/qemu-iotests/141 | 9 +++--
71
tests/qemu-iotests/141.out | 5 ---
72
tests/qemu-iotests/188 | 20 ++++++++++-
73
tests/qemu-iotests/188.out | 4 +++
74
tests/qemu-iotests/common.filter | 5 +++
75
35 files changed, 313 insertions(+), 43 deletions(-)
76
42
77
--
43
--
78
2.21.0
44
2.35.1
79
80
diff view generated by jsdifflib
1
From: Maxim Levitsky <mlevitsk@redhat.com>
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
2
3
preallocation=off and preallocation=metadata
3
Introduce the 'event-loop-base' abstract class, it'll hold the
4
both allocate luks header only, and preallocation=falloc/full
4
properties common to all event loops and provide the necessary hooks for
5
is passed to underlying file.
5
their creation and maintenance. Then have iothread inherit from it.
6
6
7
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1534951
7
EventLoopBaseClass is defined as user creatable and provides a hook for
8
8
its children to attach themselves to the user creatable class 'complete'
9
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
9
function. It also provides an update_params() callback to propagate
10
Message-id: 20190716161901.1430-1-mlevitsk@redhat.com
10
property changes onto its children.
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
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>
12
---
40
---
13
qapi/block-core.json | 6 +++++-
41
qapi/qom.json | 22 +++++--
14
block/crypto.c | 30 +++++++++++++++++++++++++++---
42
meson.build | 23 ++++---
15
2 files changed, 32 insertions(+), 4 deletions(-)
43
include/sysemu/event-loop-base.h | 36 +++++++++++
16
44
include/sysemu/iothread.h | 6 +-
17
diff --git a/qapi/block-core.json b/qapi/block-core.json
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
18
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
19
--- a/qapi/block-core.json
53
--- a/qapi/qom.json
20
+++ b/qapi/block-core.json
54
+++ b/qapi/qom.json
21
@@ -XXX,XX +XXX,XX @@
55
@@ -XXX,XX +XXX,XX @@
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:
22
#
75
#
23
# @file Node to create the image format on
76
@@ -XXX,XX +XXX,XX @@
24
# @size Size of the virtual disk in bytes
77
# algorithm detects it is spending too long polling without
25
+# @preallocation Preallocation mode for the new image
78
# encountering events. 0 selects a default behaviour (default: 0)
26
+# (since: 4.2)
27
+# (default: off; allowed values: off, metadata, falloc, full)
28
#
79
#
29
# Since: 2.12
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
30
##
86
##
31
{ 'struct': 'BlockdevCreateOptionsLUKS',
87
{ 'struct': 'IothreadProperties',
32
'base': 'QCryptoBlockCreateOptionsLUKS',
88
+ 'base': 'EventLoopBaseProperties',
33
'data': { 'file': 'BlockdevRef',
89
'data': { '*poll-max-ns': 'int',
34
- 'size': 'size' } }
90
'*poll-grow': 'int',
35
+ 'size': 'size',
91
- '*poll-shrink': 'int',
36
+ '*preallocation': 'PreallocMode' } }
92
- '*aio-max-batch': 'int' } }
93
+ '*poll-shrink': 'int' } }
37
94
38
##
95
##
39
# @BlockdevCreateOptionsNfs:
96
# @MemoryBackendProperties:
40
diff --git a/block/crypto.c b/block/crypto.c
97
diff --git a/meson.build b/meson.build
41
index XXXXXXX..XXXXXXX 100644
98
index XXXXXXX..XXXXXXX 100644
42
--- a/block/crypto.c
99
--- a/meson.build
43
+++ b/block/crypto.c
100
+++ b/meson.build
44
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_read_func(QCryptoBlock *block,
101
@@ -XXX,XX +XXX,XX @@ subdir('qom')
45
struct BlockCryptoCreateData {
102
subdir('authz')
46
BlockBackend *blk;
103
subdir('crypto')
47
uint64_t size;
104
subdir('ui')
48
+ PreallocMode prealloc;
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;
49
};
226
};
50
227
typedef struct IOThread IOThread;
51
228
52
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_init_func(QCryptoBlock *block,
229
diff --git a/event-loop-base.c b/event-loop-base.c
53
* available to the guest, so we must take account of that
230
new file mode 100644
54
* which will be used by the crypto header
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)
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)
55
*/
388
*/
56
- return blk_truncate(data->blk, data->size + headerlen, PREALLOC_MODE_OFF,
389
iothread_init_gcontext(iothread);
57
+ return blk_truncate(data->blk, data->size + headerlen, data->prealloc,
390
58
errp);
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
}
59
}
417
}
60
418
61
@@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
419
-static void iothread_get_aio_param(Object *obj, Visitor *v,
62
static int block_crypto_co_create_generic(BlockDriverState *bs,
420
- const char *name, void *opaque, Error **errp)
63
int64_t size,
421
-{
64
QCryptoBlockCreateOptions *opts,
422
- IOThreadParamInfo *info = opaque;
65
+ PreallocMode prealloc,
423
-
66
Error **errp)
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)) {
434
- return;
435
- }
436
-
437
- if (iothread->ctx) {
438
- aio_context_set_aio_params(iothread->ctx,
439
- iothread->aio_max_batch,
440
- errp);
441
- }
442
-}
443
-
444
static void iothread_class_init(ObjectClass *klass, void *class_data)
67
{
445
{
68
int ret;
446
- UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
69
@@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
447
- ucc->complete = iothread_complete;
70
goto cleanup;
448
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(klass);
71
}
449
+
72
450
+ bc->init = iothread_init;
73
+ if (prealloc == PREALLOC_MODE_METADATA) {
451
+ bc->update_params = iothread_set_aio_context_params;
74
+ prealloc = PREALLOC_MODE_OFF;
452
75
+ }
453
object_class_property_add(klass, "poll-max-ns", "int",
76
+
454
iothread_get_poll_param,
77
data = (struct BlockCryptoCreateData) {
455
@@ -XXX,XX +XXX,XX @@ static void iothread_class_init(ObjectClass *klass, void *class_data)
78
.blk = blk,
456
iothread_get_poll_param,
79
.size = size,
457
iothread_set_poll_param,
80
+ .prealloc = prealloc,
458
NULL, &poll_shrink_info);
81
};
459
- object_class_property_add(klass, "aio-max-batch", "int",
82
460
- iothread_get_aio_param,
83
crypto = qcrypto_block_create(opts, NULL,
461
- iothread_set_aio_param,
84
@@ -XXX,XX +XXX,XX @@ block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp)
462
- NULL, &aio_max_batch_info);
85
BlockdevCreateOptionsLUKS *luks_opts;
463
}
86
BlockDriverState *bs = NULL;
464
87
QCryptoBlockCreateOptions create_opts;
465
static const TypeInfo iothread_info = {
88
+ PreallocMode preallocation = PREALLOC_MODE_OFF;
466
.name = TYPE_IOTHREAD,
89
int ret;
467
- .parent = TYPE_OBJECT,
90
468
+ .parent = TYPE_EVENT_LOOP_BASE,
91
assert(create_options->driver == BLOCKDEV_DRIVER_LUKS);
469
.class_init = iothread_class_init,
92
@@ -XXX,XX +XXX,XX @@ block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp)
470
.instance_size = sizeof(IOThread),
93
.u.luks = *qapi_BlockdevCreateOptionsLUKS_base(luks_opts),
471
.instance_init = iothread_instance_init,
94
};
472
.instance_finalize = iothread_instance_finalize,
95
473
- .interfaces = (InterfaceInfo[]) {
96
+ if (luks_opts->has_preallocation) {
474
- {TYPE_USER_CREATABLE},
97
+ preallocation = luks_opts->preallocation;
475
- {}
98
+ }
476
- },
99
+
477
};
100
ret = block_crypto_co_create_generic(bs, luks_opts->size, &create_opts,
478
101
- errp);
479
static void iothread_register_types(void)
102
+ preallocation, errp);
480
@@ -XXX,XX +XXX,XX @@ static int query_one_iothread(Object *object, void *opaque)
103
if (ret < 0) {
481
info->poll_max_ns = iothread->poll_max_ns;
104
goto fail;
482
info->poll_grow = iothread->poll_grow;
105
}
483
info->poll_shrink = iothread->poll_shrink;
106
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
484
- info->aio_max_batch = iothread->aio_max_batch;
107
QCryptoBlockCreateOptions *create_opts = NULL;
485
+ info->aio_max_batch = iothread->parent_obj.aio_max_batch;
108
BlockDriverState *bs = NULL;
486
109
QDict *cryptoopts;
487
QAPI_LIST_APPEND(*tail, info);
110
+ PreallocMode prealloc;
488
return 0;
111
+ char *buf = NULL;
112
int64_t size;
113
int ret;
114
+ Error *local_err = NULL;
115
116
/* Parse options */
117
size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
118
119
+ buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
120
+ prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
121
+ PREALLOC_MODE_OFF, &local_err);
122
+ g_free(buf);
123
+ if (local_err) {
124
+ error_propagate(errp, local_err);
125
+ return -EINVAL;
126
+ }
127
+
128
cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL,
129
&block_crypto_create_opts_luks,
130
true);
131
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
132
}
133
134
/* Create format layer */
135
- ret = block_crypto_co_create_generic(bs, size, create_opts, errp);
136
+ ret = block_crypto_co_create_generic(bs, size, create_opts, prealloc, errp);
137
if (ret < 0) {
138
goto fail;
139
}
140
--
489
--
141
2.21.0
490
2.35.1
142
143
diff view generated by jsdifflib
Deleted patch
1
bdrv_has_zero_init() only has meaning for newly created images or image
2
areas. If qemu-img convert did not create the image itself, it cannot
3
rely on bdrv_has_zero_init()'s result to carry any meaning.
4
1
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Message-id: 20190724171239.8764-2-mreitz@redhat.com
7
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
8
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
qemu-img.c | 11 ++++++++---
12
1 file changed, 8 insertions(+), 3 deletions(-)
13
14
diff --git a/qemu-img.c b/qemu-img.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/qemu-img.c
17
+++ b/qemu-img.c
18
@@ -XXX,XX +XXX,XX @@ typedef struct ImgConvertState {
19
bool has_zero_init;
20
bool compressed;
21
bool unallocated_blocks_are_zero;
22
+ bool target_is_new;
23
bool target_has_backing;
24
int64_t target_backing_sectors; /* negative if unknown */
25
bool wr_in_order;
26
@@ -XXX,XX +XXX,XX @@ static int convert_do_copy(ImgConvertState *s)
27
int64_t sector_num = 0;
28
29
/* Check whether we have zero initialisation or can get it efficiently */
30
- s->has_zero_init = s->min_sparse && !s->target_has_backing
31
- ? bdrv_has_zero_init(blk_bs(s->target))
32
- : false;
33
+ if (s->target_is_new && s->min_sparse && !s->target_has_backing) {
34
+ s->has_zero_init = bdrv_has_zero_init(blk_bs(s->target));
35
+ } else {
36
+ s->has_zero_init = false;
37
+ }
38
39
if (!s->has_zero_init && !s->target_has_backing &&
40
bdrv_can_write_zeroes_with_unmap(blk_bs(s->target)))
41
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
42
}
43
}
44
45
+ s.target_is_new = !skip_create;
46
+
47
flags = s.min_sparse ? (BDRV_O_RDWR | BDRV_O_UNMAP) : BDRV_O_RDWR;
48
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
49
if (ret < 0) {
50
--
51
2.21.0
52
53
diff view generated by jsdifflib
1
Fixed VHDX images cannot guarantee to be zero-initialized. If the image
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
has the "fixed" subformat, forward the call to the underlying storage
2
3
node.
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
Reported-by: Stefano Garzarella <sgarzare@redhat.com>
5
from it. This will permit tweaking the main loop's properties through
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
qapi as well as through the command line using the '-object' keyword[1].
7
Message-id: 20190724171239.8764-9-mreitz@redhat.com
7
Only one instance of 'MainLoopClass' might be created at any time.
8
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
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>
10
---
20
---
11
block/vhdx.c | 26 +++++++++++++++++++++++++-
21
qapi/qom.json | 13 ++++++++
12
1 file changed, 25 insertions(+), 1 deletion(-)
22
meson.build | 3 +-
13
23
include/qemu/main-loop.h | 10 ++++++
14
diff --git a/block/vhdx.c b/block/vhdx.c
24
include/sysemu/event-loop-base.h | 1 +
15
index XXXXXXX..XXXXXXX 100644
25
event-loop-base.c | 13 ++++++++
16
--- a/block/vhdx.c
26
util/main-loop.c | 56 ++++++++++++++++++++++++++++++++
17
+++ b/block/vhdx.c
27
6 files changed, 95 insertions(+), 1 deletion(-)
18
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_check(BlockDriverState *bs,
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)
122
}
123
}
124
125
+static bool event_loop_base_can_be_deleted(UserCreatable *uc)
126
+{
127
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_GET_CLASS(uc);
128
+ EventLoopBase *backend = EVENT_LOOP_BASE(uc);
129
+
130
+ if (bc->can_be_deleted) {
131
+ return bc->can_be_deleted(backend);
132
+ }
133
+
134
+ return true;
135
+}
136
+
137
static void event_loop_base_class_init(ObjectClass *klass, void *class_data)
138
{
139
UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
140
ucc->complete = event_loop_base_complete;
141
+ ucc->can_be_deleted = event_loop_base_can_be_deleted;
142
143
object_class_property_add(klass, "aio-max-batch", "int",
144
event_loop_base_get_param,
145
diff --git a/util/main-loop.c b/util/main-loop.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/util/main-loop.c
148
+++ b/util/main-loop.c
149
@@ -XXX,XX +XXX,XX @@
150
#include "qemu/error-report.h"
151
#include "qemu/queue.h"
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)
19
return 0;
158
return 0;
20
}
159
}
21
160
22
+static int vhdx_has_zero_init(BlockDriverState *bs)
161
+static void main_loop_update_params(EventLoopBase *base, Error **errp)
23
+{
162
+{
24
+ BDRVVHDXState *s = bs->opaque;
163
+ if (!qemu_aio_context) {
25
+ int state;
164
+ error_setg(errp, "qemu aio context not ready");
26
+
165
+ return;
27
+ /*
28
+ * Check the subformat: Fixed images have all BAT entries present,
29
+ * dynamic images have none (right after creation). It is
30
+ * therefore enough to check the first BAT entry.
31
+ */
32
+ if (!s->bat_entries) {
33
+ return 1;
34
+ }
166
+ }
35
+
167
+
36
+ state = s->bat[0] & VHDX_BAT_STATE_BIT_MASK;
168
+ aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
37
+ if (state == PAYLOAD_BLOCK_FULLY_PRESENT) {
169
+}
38
+ /* Fixed subformat */
170
+
39
+ return bdrv_has_zero_init(bs->file->bs);
171
+MainLoop *mloop;
172
+
173
+static void main_loop_init(EventLoopBase *base, Error **errp)
174
+{
175
+ MainLoop *m = MAIN_LOOP(base);
176
+
177
+ if (mloop) {
178
+ error_setg(errp, "only one main-loop instance allowed");
179
+ return;
40
+ }
180
+ }
41
+
181
+
42
+ /* Dynamic subformat */
182
+ main_loop_update_params(base, errp);
43
+ return 1;
183
+
44
+}
184
+ mloop = m;
45
+
185
+ return;
46
static QemuOptsList vhdx_create_opts = {
186
+}
47
.name = "vhdx-create-opts",
187
+
48
.head = QTAILQ_HEAD_INITIALIZER(vhdx_create_opts.head),
188
+static bool main_loop_can_be_deleted(EventLoopBase *base)
49
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vhdx = {
189
+{
50
.bdrv_co_create_opts = vhdx_co_create_opts,
190
+ return false;
51
.bdrv_get_info = vhdx_get_info,
191
+}
52
.bdrv_co_check = vhdx_co_check,
192
+
53
- .bdrv_has_zero_init = bdrv_has_zero_init_1,
193
+static void main_loop_class_init(ObjectClass *oc, void *class_data)
54
+ .bdrv_has_zero_init = vhdx_has_zero_init,
194
+{
55
195
+ EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(oc);
56
.create_opts = &vhdx_create_opts,
196
+
57
};
197
+ bc->init = main_loop_init;
198
+ bc->update_params = main_loop_update_params;
199
+ bc->can_be_deleted = main_loop_can_be_deleted;
200
+}
201
+
202
+static const TypeInfo main_loop_info = {
203
+ .name = TYPE_MAIN_LOOP,
204
+ .parent = TYPE_EVENT_LOOP_BASE,
205
+ .class_init = main_loop_class_init,
206
+ .instance_size = sizeof(MainLoop),
207
+};
208
+
209
+static void main_loop_register_types(void)
210
+{
211
+ type_register_static(&main_loop_info);
212
+}
213
+
214
+type_init(main_loop_register_types)
215
+
216
static int max_priority;
217
218
#ifndef _WIN32
58
--
219
--
59
2.21.0
220
2.35.1
60
61
diff view generated by jsdifflib
1
bdrv_has_zero_init() only has meaning for newly created images or image
1
From: Nicolas Saenz Julienne <nsaenzju@redhat.com>
2
areas. If the mirror job itself did not create the image, it cannot
3
rely on bdrv_has_zero_init()'s result to carry any meaning.
4
2
5
This is the case for drive-mirror with mode=existing and always for
3
The thread pool regulates itself: when idle, it kills threads until
6
blockdev-mirror.
4
empty, when in demand, it creates new threads until full. This behaviour
5
doesn't play well with latency sensitive workloads where the price of
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 we only have to zero-initialize the target with sync=full,
10
In order to mitigate this let's introduce a new 'EventLoopBase'
9
because other modes actually do not promise that the target will contain
11
property to set the thread pool size. The threads will be created during
10
the same data as the source after the job -- sync=top only promises to
12
the pool's initialization or upon updating the property's value, remain
11
copy anything allocated in the top layer, and sync=none will only copy
13
available during its lifetime regardless of demand, and destroyed upon
12
new I/O. (Which is how mirror has always handled it.)
14
freeing it. A properly characterized workload will then be able to
15
configure the pool to avoid any latency spikes.
13
16
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
Signed-off-by: Nicolas Saenz Julienne <nsaenzju@redhat.com>
15
Message-id: 20190724171239.8764-3-mreitz@redhat.com
18
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
16
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
19
Acked-by: Markus Armbruster <armbru@redhat.com>
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
Message-id: 20220425075723.20019-4-nsaenzju@redhat.com
21
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
---
22
---
19
include/block/block_int.h | 2 ++
23
qapi/qom.json | 10 +++++-
20
block/mirror.c | 11 ++++++++---
24
include/block/aio.h | 10 ++++++
21
blockdev.c | 16 +++++++++++++---
25
include/block/thread-pool.h | 3 ++
22
tests/test-block-iothread.c | 2 +-
26
include/sysemu/event-loop-base.h | 4 +++
23
4 files changed, 24 insertions(+), 7 deletions(-)
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(-)
24
34
25
diff --git a/include/block/block_int.h b/include/block/block_int.h
35
diff --git a/qapi/qom.json b/qapi/qom.json
26
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
27
--- a/include/block/block_int.h
37
--- a/qapi/qom.json
28
+++ b/include/block/block_int.h
38
+++ b/qapi/qom.json
29
@@ -XXX,XX +XXX,XX @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs,
39
@@ -XXX,XX +XXX,XX @@
30
* @buf_size: The amount of data that can be in flight at one time.
40
# 0 means that the engine will use its default.
31
* @mode: Whether to collapse all images in the chain to the target.
41
# (default: 0)
32
* @backing_mode: How to establish the target's backing chain after completion.
42
#
33
+ * @zero_target: Whether the target should be explicitly zero-initialized
43
+# @thread-pool-min: minimum number of threads reserved in the thread pool
34
* @on_source_error: The action to take upon error reading from the source.
44
+# (default:0)
35
* @on_target_error: The action to take upon error writing to the target.
45
+#
36
* @unmap: Whether to unmap target where source sectors only contain zeroes.
46
+# @thread-pool-max: maximum number of threads the thread pool can contain
37
@@ -XXX,XX +XXX,XX @@ void mirror_start(const char *job_id, BlockDriverState *bs,
47
+# (default:64)
38
int creation_flags, int64_t speed,
48
+#
39
uint32_t granularity, int64_t buf_size,
49
# Since: 7.1
40
MirrorSyncMode mode, BlockMirrorBackingMode backing_mode,
50
##
41
+ bool zero_target,
51
{ 'struct': 'EventLoopBaseProperties',
42
BlockdevOnError on_source_error,
52
- 'data': { '*aio-max-batch': 'int' } }
43
BlockdevOnError on_target_error,
53
+ 'data': { '*aio-max-batch': 'int',
44
bool unmap, const char *filter_node_name,
54
+ '*thread-pool-min': 'int',
45
diff --git a/block/mirror.c b/block/mirror.c
55
+ '*thread-pool-max': 'int' } }
46
index XXXXXXX..XXXXXXX 100644
56
47
--- a/block/mirror.c
57
##
48
+++ b/block/mirror.c
58
# @IothreadProperties:
49
@@ -XXX,XX +XXX,XX @@ typedef struct MirrorBlockJob {
59
diff --git a/include/block/aio.h b/include/block/aio.h
50
Error *replace_blocker;
60
index XXXXXXX..XXXXXXX 100644
51
bool is_none_mode;
61
--- a/include/block/aio.h
52
BlockMirrorBackingMode backing_mode;
62
+++ b/include/block/aio.h
53
+ /* Whether the target image requires explicit zero-initialization */
63
@@ -XXX,XX +XXX,XX @@ struct AioContext {
54
+ bool zero_target;
64
QSLIST_HEAD(, Coroutine) scheduled_coroutines;
55
MirrorCopyMode copy_mode;
65
QEMUBH *co_schedule_bh;
56
BlockdevOnError on_source_error, on_target_error;
66
57
bool synced;
67
+ int thread_pool_min;
58
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
68
+ int thread_pool_max;
59
int ret;
69
/* Thread pool for performing work and receiving completion callbacks.
60
int64_t count;
70
* Has its own locking.
61
62
- if (base == NULL && !bdrv_has_zero_init(target_bs)) {
63
+ if (s->zero_target) {
64
if (!bdrv_can_write_zeroes_with_unmap(target_bs)) {
65
bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length);
66
return 0;
67
@@ -XXX,XX +XXX,XX @@ static BlockJob *mirror_start_job(
68
const char *replaces, int64_t speed,
69
uint32_t granularity, int64_t buf_size,
70
BlockMirrorBackingMode backing_mode,
71
+ bool zero_target,
72
BlockdevOnError on_source_error,
73
BlockdevOnError on_target_error,
74
bool unmap,
75
@@ -XXX,XX +XXX,XX @@ static BlockJob *mirror_start_job(
76
s->on_target_error = on_target_error;
77
s->is_none_mode = is_none_mode;
78
s->backing_mode = backing_mode;
79
+ s->zero_target = zero_target;
80
s->copy_mode = copy_mode;
81
s->base = base;
82
s->granularity = granularity;
83
@@ -XXX,XX +XXX,XX @@ void mirror_start(const char *job_id, BlockDriverState *bs,
84
int creation_flags, int64_t speed,
85
uint32_t granularity, int64_t buf_size,
86
MirrorSyncMode mode, BlockMirrorBackingMode backing_mode,
87
+ bool zero_target,
88
BlockdevOnError on_source_error,
89
BlockdevOnError on_target_error,
90
bool unmap, const char *filter_node_name,
91
@@ -XXX,XX +XXX,XX @@ void mirror_start(const char *job_id, BlockDriverState *bs,
92
is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
93
base = mode == MIRROR_SYNC_MODE_TOP ? backing_bs(bs) : NULL;
94
mirror_start_job(job_id, bs, creation_flags, target, replaces,
95
- speed, granularity, buf_size, backing_mode,
96
+ speed, granularity, buf_size, backing_mode, zero_target,
97
on_source_error, on_target_error, unmap, NULL, NULL,
98
&mirror_job_driver, is_none_mode, base, false,
99
filter_node_name, true, copy_mode, errp);
100
@@ -XXX,XX +XXX,XX @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs,
101
102
ret = mirror_start_job(
103
job_id, bs, creation_flags, base, NULL, speed, 0, 0,
104
- MIRROR_LEAVE_BACKING_CHAIN,
105
+ MIRROR_LEAVE_BACKING_CHAIN, false,
106
on_error, on_error, true, cb, opaque,
107
&commit_active_job_driver, false, base, auto_complete,
108
filter_node_name, false, MIRROR_COPY_MODE_BACKGROUND,
109
diff --git a/blockdev.c b/blockdev.c
110
index XXXXXXX..XXXXXXX 100644
111
--- a/blockdev.c
112
+++ b/blockdev.c
113
@@ -XXX,XX +XXX,XX @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
114
bool has_replaces, const char *replaces,
115
enum MirrorSyncMode sync,
116
BlockMirrorBackingMode backing_mode,
117
+ bool zero_target,
118
bool has_speed, int64_t speed,
119
bool has_granularity, uint32_t granularity,
120
bool has_buf_size, int64_t buf_size,
121
@@ -XXX,XX +XXX,XX @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
122
*/
71
*/
123
mirror_start(job_id, bs, target,
72
@@ -XXX,XX +XXX,XX @@ void aio_context_set_poll_params(AioContext *ctx, int64_t max_ns,
124
has_replaces ? replaces : NULL, job_flags,
73
void aio_context_set_aio_params(AioContext *ctx, int64_t max_batch,
125
- speed, granularity, buf_size, sync, backing_mode,
74
Error **errp);
126
+ speed, granularity, buf_size, sync, backing_mode, zero_target,
75
127
on_source_error, on_target_error, unmap, filter_node_name,
76
+/**
128
copy_mode, errp);
77
+ * aio_context_set_thread_pool_params:
129
}
78
+ * @ctx: the aio context
130
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
79
+ * @min: min number of threads to have readily available in the thread pool
131
int flags;
80
+ * @min: max number of threads the thread pool can contain
132
int64_t size;
81
+ */
133
const char *format = arg->format;
82
+void aio_context_set_thread_pool_params(AioContext *ctx, int64_t min,
134
+ bool zero_target;
83
+ int64_t max, Error **errp);
135
int ret;
84
#endif
136
85
diff --git a/include/block/thread-pool.h b/include/block/thread-pool.h
137
bs = qmp_get_root_bs(arg->device, errp);
86
index XXXXXXX..XXXXXXX 100644
138
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
87
--- a/include/block/thread-pool.h
139
goto out;
88
+++ b/include/block/thread-pool.h
140
}
89
@@ -XXX,XX +XXX,XX @@
141
90
142
+ zero_target = (arg->sync == MIRROR_SYNC_MODE_FULL &&
91
#include "block/block.h"
143
+ (arg->mode == NEW_IMAGE_MODE_EXISTING ||
92
144
+ !bdrv_has_zero_init(target_bs)));
93
+#define THREAD_POOL_MAX_THREADS_DEFAULT 64
145
+
94
+
146
ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
95
typedef int ThreadPoolFunc(void *opaque);
147
if (ret < 0) {
96
148
bdrv_unref(target_bs);
97
typedef struct ThreadPool ThreadPool;
149
@@ -XXX,XX +XXX,XX @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
98
@@ -XXX,XX +XXX,XX @@ BlockAIOCB *thread_pool_submit_aio(ThreadPool *pool,
150
99
int coroutine_fn thread_pool_submit_co(ThreadPool *pool,
151
blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs,
100
ThreadPoolFunc *func, void *arg);
152
arg->has_replaces, arg->replaces, arg->sync,
101
void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg);
153
- backing_mode, arg->has_speed, arg->speed,
102
+void thread_pool_update_params(ThreadPool *pool, struct AioContext *ctx);
154
+ backing_mode, zero_target,
103
155
+ arg->has_speed, arg->speed,
104
#endif
156
arg->has_granularity, arg->granularity,
105
diff --git a/include/sysemu/event-loop-base.h b/include/sysemu/event-loop-base.h
157
arg->has_buf_size, arg->buf_size,
106
index XXXXXXX..XXXXXXX 100644
158
arg->has_on_source_error, arg->on_source_error,
107
--- a/include/sysemu/event-loop-base.h
159
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
108
+++ b/include/sysemu/event-loop-base.h
160
AioContext *aio_context;
109
@@ -XXX,XX +XXX,XX @@ struct EventLoopBase {
161
BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN;
110
162
Error *local_err = NULL;
111
/* AioContext AIO engine parameters */
163
+ bool zero_target;
112
int64_t aio_max_batch;
164
int ret;
113
+
165
114
+ /* AioContext thread pool parameters */
166
bs = qmp_get_root_bs(device, errp);
115
+ int64_t thread_pool_min;
167
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
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");
168
return;
257
return;
169
}
258
}
170
259
171
+ zero_target = (sync == MIRROR_SYNC_MODE_FULL);
260
aio_context_set_aio_params(qemu_aio_context, base->aio_max_batch, errp);
172
+
261
+ if (*errp) {
173
aio_context = bdrv_get_aio_context(bs);
262
+ return;
174
aio_context_acquire(aio_context);
263
+ }
175
264
+
176
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
265
+ aio_context_set_thread_pool_params(qemu_aio_context, base->thread_pool_min,
177
266
+ base->thread_pool_max, errp);
178
blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs,
267
}
179
has_replaces, replaces, sync, backing_mode,
268
180
- has_speed, speed,
269
MainLoop *mloop;
181
+ zero_target, has_speed, speed,
270
diff --git a/util/thread-pool.c b/util/thread-pool.c
182
has_granularity, granularity,
271
index XXXXXXX..XXXXXXX 100644
183
has_buf_size, buf_size,
272
--- a/util/thread-pool.c
184
has_on_source_error, on_source_error,
273
+++ b/util/thread-pool.c
185
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
274
@@ -XXX,XX +XXX,XX @@ struct ThreadPool {
186
index XXXXXXX..XXXXXXX 100644
275
QemuMutex lock;
187
--- a/tests/test-block-iothread.c
276
QemuCond worker_stopped;
188
+++ b/tests/test-block-iothread.c
277
QemuSemaphore sem;
189
@@ -XXX,XX +XXX,XX @@ static void test_propagate_mirror(void)
278
- int max_threads;
190
279
QEMUBH *new_thread_bh;
191
/* Start a mirror job */
280
192
mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0,
281
/* The following variables are only accessed from one AioContext. */
193
- MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN,
282
@@ -XXX,XX +XXX,XX @@ struct ThreadPool {
194
+ MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false,
283
int new_threads; /* backlog of threads we need to create */
195
BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
284
int pending_threads; /* threads created but not running yet */
196
false, "filter_node", MIRROR_COPY_MODE_BACKGROUND,
285
bool stopping;
197
&error_abort);
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) {
319
break;
320
}
321
322
@@ -XXX,XX +XXX,XX @@ void thread_pool_submit(ThreadPool *pool, ThreadPoolFunc *func, void *arg)
323
thread_pool_submit_aio(pool, func, arg, NULL, NULL);
324
}
325
326
+void thread_pool_update_params(ThreadPool *pool, AioContext *ctx)
327
+{
328
+ qemu_mutex_lock(&pool->lock);
329
+
330
+ pool->min_threads = ctx->thread_pool_min;
331
+ pool->max_threads = ctx->thread_pool_max;
332
+
333
+ /*
334
+ * We either have to:
335
+ * - Increase the number available of threads until over the min_threads
336
+ * threshold.
337
+ * - Decrease the number of available threads until under the max_threads
338
+ * threshold.
339
+ * - Do nothing. The current number of threads fall in between the min and
340
+ * max thresholds. We'll let the pool manage itself.
341
+ */
342
+ for (int i = pool->cur_threads; i < pool->min_threads; i++) {
343
+ spawn_thread(pool);
344
+ }
345
+
346
+ for (int i = pool->cur_threads; i > pool->max_threads; i--) {
347
+ qemu_sem_post(&pool->sem);
348
+ }
349
+
350
+ qemu_mutex_unlock(&pool->lock);
351
+}
352
+
353
static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
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)
198
--
370
--
199
2.21.0
371
2.35.1
200
201
diff view generated by jsdifflib
Deleted patch
1
No .bdrv_has_zero_init() implementation returns 1 if growing the file
2
would add non-zero areas (at least with PREALLOC_MODE_OFF), so using it
3
in lieu of this new function was always safe.
4
1
5
But on the other hand, it is possible that growing an image that is not
6
zero-initialized would still add a zero-initialized area, like when
7
using nonpreallocating truncation on a preallocated image. For callers
8
that care only about truncation, not about creation with potential
9
preallocation, this new function is useful.
10
11
Alternatively, we could have added a PreallocMode parameter to
12
bdrv_has_zero_init(). But the only user would have been qemu-img
13
convert, which does not have a plain PreallocMode value right now -- it
14
would have to parse the creation option to obtain it. Therefore, the
15
simpler solution is to let bdrv_has_zero_init() inquire the
16
preallocation status and add the new bdrv_has_zero_init_truncate() that
17
presupposes PREALLOC_MODE_OFF.
18
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
Message-id: 20190724171239.8764-4-mreitz@redhat.com
21
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
22
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
23
Signed-off-by: Max Reitz <mreitz@redhat.com>
24
---
25
include/block/block.h | 1 +
26
include/block/block_int.h | 7 +++++++
27
block.c | 21 +++++++++++++++++++++
28
3 files changed, 29 insertions(+)
29
30
diff --git a/include/block/block.h b/include/block/block.h
31
index XXXXXXX..XXXXXXX 100644
32
--- a/include/block/block.h
33
+++ b/include/block/block.h
34
@@ -XXX,XX +XXX,XX @@ int bdrv_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
35
int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int64_t bytes);
36
int bdrv_has_zero_init_1(BlockDriverState *bs);
37
int bdrv_has_zero_init(BlockDriverState *bs);
38
+int bdrv_has_zero_init_truncate(BlockDriverState *bs);
39
bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs);
40
bool bdrv_can_write_zeroes_with_unmap(BlockDriverState *bs);
41
int bdrv_block_status(BlockDriverState *bs, int64_t offset,
42
diff --git a/include/block/block_int.h b/include/block/block_int.h
43
index XXXXXXX..XXXXXXX 100644
44
--- a/include/block/block_int.h
45
+++ b/include/block/block_int.h
46
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
47
/*
48
* Returns 1 if newly created images are guaranteed to contain only
49
* zeros, 0 otherwise.
50
+ * Must return 0 if .bdrv_has_zero_init_truncate() returns 0.
51
*/
52
int (*bdrv_has_zero_init)(BlockDriverState *bs);
53
54
+ /*
55
+ * Returns 1 if new areas added by growing the image with
56
+ * PREALLOC_MODE_OFF contain only zeros, 0 otherwise.
57
+ */
58
+ int (*bdrv_has_zero_init_truncate)(BlockDriverState *bs);
59
+
60
/* Remove fd handlers, timers, and other event loop callbacks so the event
61
* loop is no longer in use. Called with no in-flight requests and in
62
* depth-first traversal order with parents before child nodes.
63
diff --git a/block.c b/block.c
64
index XXXXXXX..XXXXXXX 100644
65
--- a/block.c
66
+++ b/block.c
67
@@ -XXX,XX +XXX,XX @@ int bdrv_has_zero_init(BlockDriverState *bs)
68
return 0;
69
}
70
71
+int bdrv_has_zero_init_truncate(BlockDriverState *bs)
72
+{
73
+ if (!bs->drv) {
74
+ return 0;
75
+ }
76
+
77
+ if (bs->backing) {
78
+ /* Depends on the backing image length, but better safe than sorry */
79
+ return 0;
80
+ }
81
+ if (bs->drv->bdrv_has_zero_init_truncate) {
82
+ return bs->drv->bdrv_has_zero_init_truncate(bs);
83
+ }
84
+ if (bs->file && bs->drv->is_filter) {
85
+ return bdrv_has_zero_init_truncate(bs->file->bs);
86
+ }
87
+
88
+ /* safe default */
89
+ return 0;
90
+}
91
+
92
bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs)
93
{
94
BlockDriverInfo bdi;
95
--
96
2.21.0
97
98
diff view generated by jsdifflib
Deleted patch
1
We need to implement .bdrv_has_zero_init_truncate() for every block
2
driver that supports truncation and has a .bdrv_has_zero_init()
3
implementation.
4
1
5
Implement it the same way each driver implements .bdrv_has_zero_init().
6
This is at least not any more unsafe than what we had before.
7
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190724171239.8764-5-mreitz@redhat.com
10
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
11
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
block/file-posix.c | 1 +
15
block/file-win32.c | 1 +
16
block/gluster.c | 4 ++++
17
block/nfs.c | 1 +
18
block/qcow2.c | 1 +
19
block/qed.c | 1 +
20
block/raw-format.c | 6 ++++++
21
block/rbd.c | 1 +
22
block/sheepdog.c | 1 +
23
block/ssh.c | 1 +
24
10 files changed, 18 insertions(+)
25
26
diff --git a/block/file-posix.c b/block/file-posix.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/block/file-posix.c
29
+++ b/block/file-posix.c
30
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
31
.bdrv_co_create = raw_co_create,
32
.bdrv_co_create_opts = raw_co_create_opts,
33
.bdrv_has_zero_init = bdrv_has_zero_init_1,
34
+ .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
35
.bdrv_co_block_status = raw_co_block_status,
36
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
37
.bdrv_co_pwrite_zeroes = raw_co_pwrite_zeroes,
38
diff --git a/block/file-win32.c b/block/file-win32.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/block/file-win32.c
41
+++ b/block/file-win32.c
42
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
43
.bdrv_close = raw_close,
44
.bdrv_co_create_opts = raw_co_create_opts,
45
.bdrv_has_zero_init = bdrv_has_zero_init_1,
46
+ .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
47
48
.bdrv_aio_preadv = raw_aio_preadv,
49
.bdrv_aio_pwritev = raw_aio_pwritev,
50
diff --git a/block/gluster.c b/block/gluster.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/block/gluster.c
53
+++ b/block/gluster.c
54
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster = {
55
.bdrv_co_writev = qemu_gluster_co_writev,
56
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
57
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
58
+ .bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init,
59
#ifdef CONFIG_GLUSTERFS_DISCARD
60
.bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
61
#endif
62
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_tcp = {
63
.bdrv_co_writev = qemu_gluster_co_writev,
64
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
65
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
66
+ .bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init,
67
#ifdef CONFIG_GLUSTERFS_DISCARD
68
.bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
69
#endif
70
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_unix = {
71
.bdrv_co_writev = qemu_gluster_co_writev,
72
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
73
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
74
+ .bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init,
75
#ifdef CONFIG_GLUSTERFS_DISCARD
76
.bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
77
#endif
78
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_gluster_rdma = {
79
.bdrv_co_writev = qemu_gluster_co_writev,
80
.bdrv_co_flush_to_disk = qemu_gluster_co_flush_to_disk,
81
.bdrv_has_zero_init = qemu_gluster_has_zero_init,
82
+ .bdrv_has_zero_init_truncate = qemu_gluster_has_zero_init,
83
#ifdef CONFIG_GLUSTERFS_DISCARD
84
.bdrv_co_pdiscard = qemu_gluster_co_pdiscard,
85
#endif
86
diff --git a/block/nfs.c b/block/nfs.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/block/nfs.c
89
+++ b/block/nfs.c
90
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_nfs = {
91
.create_opts = &nfs_create_opts,
92
93
.bdrv_has_zero_init = nfs_has_zero_init,
94
+ .bdrv_has_zero_init_truncate = nfs_has_zero_init,
95
.bdrv_get_allocated_file_size = nfs_get_allocated_file_size,
96
.bdrv_co_truncate = nfs_file_co_truncate,
97
98
diff --git a/block/qcow2.c b/block/qcow2.c
99
index XXXXXXX..XXXXXXX 100644
100
--- a/block/qcow2.c
101
+++ b/block/qcow2.c
102
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
103
.bdrv_co_create_opts = qcow2_co_create_opts,
104
.bdrv_co_create = qcow2_co_create,
105
.bdrv_has_zero_init = bdrv_has_zero_init_1,
106
+ .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
107
.bdrv_co_block_status = qcow2_co_block_status,
108
109
.bdrv_co_preadv = qcow2_co_preadv,
110
diff --git a/block/qed.c b/block/qed.c
111
index XXXXXXX..XXXXXXX 100644
112
--- a/block/qed.c
113
+++ b/block/qed.c
114
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = {
115
.bdrv_co_create = bdrv_qed_co_create,
116
.bdrv_co_create_opts = bdrv_qed_co_create_opts,
117
.bdrv_has_zero_init = bdrv_has_zero_init_1,
118
+ .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
119
.bdrv_co_block_status = bdrv_qed_co_block_status,
120
.bdrv_co_readv = bdrv_qed_co_readv,
121
.bdrv_co_writev = bdrv_qed_co_writev,
122
diff --git a/block/raw-format.c b/block/raw-format.c
123
index XXXXXXX..XXXXXXX 100644
124
--- a/block/raw-format.c
125
+++ b/block/raw-format.c
126
@@ -XXX,XX +XXX,XX @@ static int raw_has_zero_init(BlockDriverState *bs)
127
return bdrv_has_zero_init(bs->file->bs);
128
}
129
130
+static int raw_has_zero_init_truncate(BlockDriverState *bs)
131
+{
132
+ return bdrv_has_zero_init_truncate(bs->file->bs);
133
+}
134
+
135
static int coroutine_fn raw_co_create_opts(const char *filename, QemuOpts *opts,
136
Error **errp)
137
{
138
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = {
139
.bdrv_co_ioctl = &raw_co_ioctl,
140
.create_opts = &raw_create_opts,
141
.bdrv_has_zero_init = &raw_has_zero_init,
142
+ .bdrv_has_zero_init_truncate = &raw_has_zero_init_truncate,
143
.strong_runtime_opts = raw_strong_runtime_opts,
144
.mutable_opts = mutable_opts,
145
};
146
diff --git a/block/rbd.c b/block/rbd.c
147
index XXXXXXX..XXXXXXX 100644
148
--- a/block/rbd.c
149
+++ b/block/rbd.c
150
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
151
.bdrv_co_create = qemu_rbd_co_create,
152
.bdrv_co_create_opts = qemu_rbd_co_create_opts,
153
.bdrv_has_zero_init = bdrv_has_zero_init_1,
154
+ .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
155
.bdrv_get_info = qemu_rbd_getinfo,
156
.create_opts = &qemu_rbd_create_opts,
157
.bdrv_getlength = qemu_rbd_getlength,
158
diff --git a/block/sheepdog.c b/block/sheepdog.c
159
index XXXXXXX..XXXXXXX 100644
160
--- a/block/sheepdog.c
161
+++ b/block/sheepdog.c
162
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_sheepdog = {
163
.bdrv_co_create = sd_co_create,
164
.bdrv_co_create_opts = sd_co_create_opts,
165
.bdrv_has_zero_init = bdrv_has_zero_init_1,
166
+ .bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
167
.bdrv_getlength = sd_getlength,
168
.bdrv_get_allocated_file_size = sd_get_allocated_file_size,
169
.bdrv_co_truncate = sd_co_truncate,
170
diff --git a/block/ssh.c b/block/ssh.c
171
index XXXXXXX..XXXXXXX 100644
172
--- a/block/ssh.c
173
+++ b/block/ssh.c
174
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_ssh = {
175
.bdrv_co_create_opts = ssh_co_create_opts,
176
.bdrv_close = ssh_close,
177
.bdrv_has_zero_init = ssh_has_zero_init,
178
+ .bdrv_has_zero_init_truncate = ssh_has_zero_init,
179
.bdrv_co_readv = ssh_co_readv,
180
.bdrv_co_writev = ssh_co_writev,
181
.bdrv_getlength = ssh_getlength,
182
--
183
2.21.0
184
185
diff view generated by jsdifflib
Deleted patch
1
vhdx and parallels call bdrv_has_zero_init() when they do not really
2
care about an image's post-create state but only about what happens when
3
you grow an image. That is a bit ugly, and also overly safe when
4
growing preallocated images without preallocating the new areas.
5
1
6
Let them use bdrv_has_zero_init_truncate() instead.
7
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190724171239.8764-6-mreitz@redhat.com
10
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
11
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
12
[mreitz: Added commit message]
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
15
block/parallels.c | 2 +-
16
block/vhdx.c | 2 +-
17
2 files changed, 2 insertions(+), 2 deletions(-)
18
19
diff --git a/block/parallels.c b/block/parallels.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/parallels.c
22
+++ b/block/parallels.c
23
@@ -XXX,XX +XXX,XX @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
24
goto fail_options;
25
}
26
27
- if (!bdrv_has_zero_init(bs->file->bs)) {
28
+ if (!bdrv_has_zero_init_truncate(bs->file->bs)) {
29
s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
30
}
31
32
diff --git a/block/vhdx.c b/block/vhdx.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/block/vhdx.c
35
+++ b/block/vhdx.c
36
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int vhdx_co_writev(BlockDriverState *bs, int64_t sector_num,
37
/* Queue another write of zero buffers if the underlying file
38
* does not zero-fill on file extension */
39
40
- if (bdrv_has_zero_init(bs->file->bs) == 0) {
41
+ if (bdrv_has_zero_init_truncate(bs->file->bs) == 0) {
42
use_zero_buffers = true;
43
44
/* zero fill the front, if any */
45
--
46
2.21.0
47
48
diff view generated by jsdifflib
Deleted patch
1
If a qcow2 file is preallocated, it can no longer guarantee that it
2
initially appears as filled with zeroes.
3
1
4
So implement .bdrv_has_zero_init() by checking whether the file is
5
preallocated; if so, forward the call to the underlying storage node,
6
except for when it is encrypted: Encrypted preallocated images always
7
return effectively random data, so .bdrv_has_zero_init() must always
8
return 0 for them.
9
10
.bdrv_has_zero_init_truncate() can remain bdrv_has_zero_init_1(),
11
because it presupposes PREALLOC_MODE_OFF.
12
13
Reported-by: Stefano Garzarella <sgarzare@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
Message-id: 20190724171239.8764-7-mreitz@redhat.com
16
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
---
19
block/qcow2.c | 29 ++++++++++++++++++++++++++++-
20
1 file changed, 28 insertions(+), 1 deletion(-)
21
22
diff --git a/block/qcow2.c b/block/qcow2.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2.c
25
+++ b/block/qcow2.c
26
@@ -XXX,XX +XXX,XX @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs,
27
return spec_info;
28
}
29
30
+static int qcow2_has_zero_init(BlockDriverState *bs)
31
+{
32
+ BDRVQcow2State *s = bs->opaque;
33
+ bool preallocated;
34
+
35
+ if (qemu_in_coroutine()) {
36
+ qemu_co_mutex_lock(&s->lock);
37
+ }
38
+ /*
39
+ * Check preallocation status: Preallocated images have all L2
40
+ * tables allocated, nonpreallocated images have none. It is
41
+ * therefore enough to check the first one.
42
+ */
43
+ preallocated = s->l1_size > 0 && s->l1_table[0] != 0;
44
+ if (qemu_in_coroutine()) {
45
+ qemu_co_mutex_unlock(&s->lock);
46
+ }
47
+
48
+ if (!preallocated) {
49
+ return 1;
50
+ } else if (bs->encrypted) {
51
+ return 0;
52
+ } else {
53
+ return bdrv_has_zero_init(s->data_file->bs);
54
+ }
55
+}
56
+
57
static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
58
int64_t pos)
59
{
60
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
61
.bdrv_child_perm = bdrv_format_default_perms,
62
.bdrv_co_create_opts = qcow2_co_create_opts,
63
.bdrv_co_create = qcow2_co_create,
64
- .bdrv_has_zero_init = bdrv_has_zero_init_1,
65
+ .bdrv_has_zero_init = qcow2_has_zero_init,
66
.bdrv_has_zero_init_truncate = bdrv_has_zero_init_1,
67
.bdrv_co_block_status = qcow2_co_block_status,
68
69
--
70
2.21.0
71
72
diff view generated by jsdifflib
Deleted patch
1
Static VDI images cannot guarantee to be zero-initialized. If the image
2
has been statically allocated, forward the call to the underlying
3
storage node.
4
1
5
Reported-by: Stefano Garzarella <sgarzare@redhat.com>
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Stefan Weil <sw@weilnetz.de>
8
Acked-by: Stefano Garzarella <sgarzare@redhat.com>
9
Tested-by: Stefano Garzarella <sgarzare@redhat.com>
10
Message-id: 20190724171239.8764-8-mreitz@redhat.com
11
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
block/vdi.c | 13 ++++++++++++-
15
1 file changed, 12 insertions(+), 1 deletion(-)
16
17
diff --git a/block/vdi.c b/block/vdi.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/vdi.c
20
+++ b/block/vdi.c
21
@@ -XXX,XX +XXX,XX @@ static void vdi_close(BlockDriverState *bs)
22
error_free(s->migration_blocker);
23
}
24
25
+static int vdi_has_zero_init(BlockDriverState *bs)
26
+{
27
+ BDRVVdiState *s = bs->opaque;
28
+
29
+ if (s->header.image_type == VDI_TYPE_STATIC) {
30
+ return bdrv_has_zero_init(bs->file->bs);
31
+ } else {
32
+ return 1;
33
+ }
34
+}
35
+
36
static QemuOptsList vdi_create_opts = {
37
.name = "vdi-create-opts",
38
.head = QTAILQ_HEAD_INITIALIZER(vdi_create_opts.head),
39
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vdi = {
40
.bdrv_child_perm = bdrv_format_default_perms,
41
.bdrv_co_create = vdi_co_create,
42
.bdrv_co_create_opts = vdi_co_create_opts,
43
- .bdrv_has_zero_init = bdrv_has_zero_init_1,
44
+ .bdrv_has_zero_init = vdi_has_zero_init,
45
.bdrv_co_block_status = vdi_co_block_status,
46
.bdrv_make_empty = vdi_make_empty,
47
48
--
49
2.21.0
50
51
diff view generated by jsdifflib
Deleted patch
1
Add a test case for converting an empty image (which only returns zeroes
2
when read) to a preallocated encrypted qcow2 image.
3
qcow2_has_zero_init() should return 0 then, thus forcing qemu-img
4
convert to create zero clusters.
5
1
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Acked-by: Stefano Garzarella <sgarzare@redhat.com>
8
Tested-by: Stefano Garzarella <sgarzare@redhat.com>
9
Message-id: 20190724171239.8764-10-mreitz@redhat.com
10
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
tests/qemu-iotests/188 | 20 +++++++++++++++++++-
14
tests/qemu-iotests/188.out | 4 ++++
15
2 files changed, 23 insertions(+), 1 deletion(-)
16
17
diff --git a/tests/qemu-iotests/188 b/tests/qemu-iotests/188
18
index XXXXXXX..XXXXXXX 100755
19
--- a/tests/qemu-iotests/188
20
+++ b/tests/qemu-iotests/188
21
@@ -XXX,XX +XXX,XX @@ SECRETALT="secret,id=sec0,data=platypus"
22
23
_make_test_img --object $SECRET -o "encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10" $size
24
25
-IMGSPEC="driver=$IMGFMT,file.filename=$TEST_IMG,encrypt.key-secret=sec0"
26
+IMGSPEC="driver=$IMGFMT,encrypt.key-secret=sec0,file.filename=$TEST_IMG"
27
28
QEMU_IO_OPTIONS=$QEMU_IO_OPTIONS_NO_FMT
29
30
@@ -XXX,XX +XXX,XX @@ echo
31
echo "== verify open failure with wrong password =="
32
$QEMU_IO --object $SECRETALT -c "read -P 0xa 0 $size" --image-opts $IMGSPEC | _filter_qemu_io | _filter_testdir
33
34
+_cleanup_test_img
35
+
36
+echo
37
+echo "== verify that has_zero_init returns false when preallocating =="
38
+
39
+# Empty source file
40
+if [ -n "$TEST_IMG_FILE" ]; then
41
+ TEST_IMG_FILE="${TEST_IMG_FILE}.orig" _make_test_img $size
42
+else
43
+ TEST_IMG="${TEST_IMG}.orig" _make_test_img $size
44
+fi
45
+
46
+$QEMU_IMG convert -O "$IMGFMT" --object $SECRET \
47
+ -o "encrypt.format=luks,encrypt.key-secret=sec0,encrypt.iter-time=10,preallocation=metadata" \
48
+ "${TEST_IMG}.orig" "$TEST_IMG"
49
+
50
+$QEMU_IMG compare --object $SECRET --image-opts "${IMGSPEC}.orig" "$IMGSPEC"
51
+
52
53
# success, all done
54
echo "*** done"
55
diff --git a/tests/qemu-iotests/188.out b/tests/qemu-iotests/188.out
56
index XXXXXXX..XXXXXXX 100644
57
--- a/tests/qemu-iotests/188.out
58
+++ b/tests/qemu-iotests/188.out
59
@@ -XXX,XX +XXX,XX @@ read 16777216/16777216 bytes at offset 0
60
61
== verify open failure with wrong password ==
62
qemu-io: can't open: Invalid password, cannot unlock any keyslot
63
+
64
+== verify that has_zero_init returns false when preallocating ==
65
+Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=16777216
66
+Images are identical.
67
*** done
68
--
69
2.21.0
70
71
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Max Reitz <mreitz@redhat.com>
2
Message-id: 20190724171239.8764-11-mreitz@redhat.com
3
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
---
6
tests/qemu-iotests/122 | 17 +++++++++++++++++
7
tests/qemu-iotests/122.out | 8 ++++++++
8
2 files changed, 25 insertions(+)
9
1
10
diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122
11
index XXXXXXX..XXXXXXX 100755
12
--- a/tests/qemu-iotests/122
13
+++ b/tests/qemu-iotests/122
14
@@ -XXX,XX +XXX,XX @@ for min_sparse in 4k 8k; do
15
$QEMU_IMG map --output=json "$TEST_IMG".orig | _filter_qemu_img_map
16
done
17
18
+
19
+echo
20
+echo '=== -n to a non-zero image ==='
21
+echo
22
+
23
+# Keep source zero
24
+_make_test_img 64M
25
+
26
+# Output is not zero, but has bdrv_has_zero_init() == 1
27
+TEST_IMG="$TEST_IMG".orig _make_test_img 64M
28
+$QEMU_IO -c "write -P 42 0 64k" "$TEST_IMG".orig | _filter_qemu_io
29
+
30
+# Convert with -n, which should not assume that the target is zeroed
31
+$QEMU_IMG convert -O $IMGFMT -n "$TEST_IMG" "$TEST_IMG".orig
32
+
33
+$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG".orig
34
+
35
# success, all done
36
echo '*** done'
37
rm -f $seq.full
38
diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out
39
index XXXXXXX..XXXXXXX 100644
40
--- a/tests/qemu-iotests/122.out
41
+++ b/tests/qemu-iotests/122.out
42
@@ -XXX,XX +XXX,XX @@ convert -c -S 8k
43
{ "start": 9216, "length": 8192, "depth": 0, "zero": true, "data": false},
44
{ "start": 17408, "length": 1024, "depth": 0, "zero": false, "data": true},
45
{ "start": 18432, "length": 67090432, "depth": 0, "zero": true, "data": false}]
46
+
47
+=== -n to a non-zero image ===
48
+
49
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
50
+Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864
51
+wrote 65536/65536 bytes at offset 0
52
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
53
+Images are identical.
54
*** done
55
--
56
2.21.0
57
58
diff view generated by jsdifflib
Deleted patch
1
The result of a sync=full mirror should always be the equal to the
2
input. Therefore, existing images should be treated as potentially
3
non-zero and thus should be explicitly initialized to be zero
4
beforehand.
5
1
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Message-id: 20190724171239.8764-12-mreitz@redhat.com
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
10
tests/qemu-iotests/041 | 62 +++++++++++++++++++++++++++++++++++---
11
tests/qemu-iotests/041.out | 4 +--
12
2 files changed, 60 insertions(+), 6 deletions(-)
13
14
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
15
index XXXXXXX..XXXXXXX 100755
16
--- a/tests/qemu-iotests/041
17
+++ b/tests/qemu-iotests/041
18
@@ -XXX,XX +XXX,XX @@ class TestUnbackedSource(iotests.QMPTestCase):
19
def setUp(self):
20
qemu_img('create', '-f', iotests.imgfmt, test_img,
21
str(TestUnbackedSource.image_len))
22
- self.vm = iotests.VM().add_drive(test_img)
23
+ self.vm = iotests.VM()
24
self.vm.launch()
25
+ result = self.vm.qmp('blockdev-add', node_name='drive0',
26
+ driver=iotests.imgfmt,
27
+ file={
28
+ 'driver': 'file',
29
+ 'filename': test_img,
30
+ })
31
+ self.assert_qmp(result, 'return', {})
32
33
def tearDown(self):
34
self.vm.shutdown()
35
@@ -XXX,XX +XXX,XX @@ class TestUnbackedSource(iotests.QMPTestCase):
36
37
def test_absolute_paths_full(self):
38
self.assert_no_active_block_jobs()
39
- result = self.vm.qmp('drive-mirror', device='drive0',
40
+ result = self.vm.qmp('drive-mirror', job_id='drive0', device='drive0',
41
sync='full', target=target_img,
42
mode='absolute-paths')
43
self.assert_qmp(result, 'return', {})
44
@@ -XXX,XX +XXX,XX @@ class TestUnbackedSource(iotests.QMPTestCase):
45
46
def test_absolute_paths_top(self):
47
self.assert_no_active_block_jobs()
48
- result = self.vm.qmp('drive-mirror', device='drive0',
49
+ result = self.vm.qmp('drive-mirror', job_id='drive0', device='drive0',
50
sync='top', target=target_img,
51
mode='absolute-paths')
52
self.assert_qmp(result, 'return', {})
53
@@ -XXX,XX +XXX,XX @@ class TestUnbackedSource(iotests.QMPTestCase):
54
55
def test_absolute_paths_none(self):
56
self.assert_no_active_block_jobs()
57
- result = self.vm.qmp('drive-mirror', device='drive0',
58
+ result = self.vm.qmp('drive-mirror', job_id='drive0', device='drive0',
59
sync='none', target=target_img,
60
mode='absolute-paths')
61
self.assert_qmp(result, 'return', {})
62
self.complete_and_wait()
63
self.assert_no_active_block_jobs()
64
65
+ def test_existing_full(self):
66
+ qemu_img('create', '-f', iotests.imgfmt, target_img,
67
+ str(self.image_len))
68
+ qemu_io('-c', 'write -P 42 0 64k', target_img)
69
+
70
+ self.assert_no_active_block_jobs()
71
+ result = self.vm.qmp('drive-mirror', job_id='drive0', device='drive0',
72
+ sync='full', target=target_img, mode='existing')
73
+ self.assert_qmp(result, 'return', {})
74
+ self.complete_and_wait()
75
+ self.assert_no_active_block_jobs()
76
+
77
+ result = self.vm.qmp('blockdev-del', node_name='drive0')
78
+ self.assert_qmp(result, 'return', {})
79
+
80
+ self.assertTrue(iotests.compare_images(test_img, target_img),
81
+ 'target image does not match source after mirroring')
82
+
83
+ def test_blockdev_full(self):
84
+ qemu_img('create', '-f', iotests.imgfmt, target_img,
85
+ str(self.image_len))
86
+ qemu_io('-c', 'write -P 42 0 64k', target_img)
87
+
88
+ result = self.vm.qmp('blockdev-add', node_name='target',
89
+ driver=iotests.imgfmt,
90
+ file={
91
+ 'driver': 'file',
92
+ 'filename': target_img,
93
+ })
94
+ self.assert_qmp(result, 'return', {})
95
+
96
+ self.assert_no_active_block_jobs()
97
+ result = self.vm.qmp('blockdev-mirror', job_id='drive0', device='drive0',
98
+ sync='full', target='target')
99
+ self.assert_qmp(result, 'return', {})
100
+ self.complete_and_wait()
101
+ self.assert_no_active_block_jobs()
102
+
103
+ result = self.vm.qmp('blockdev-del', node_name='drive0')
104
+ self.assert_qmp(result, 'return', {})
105
+
106
+ result = self.vm.qmp('blockdev-del', node_name='target')
107
+ self.assert_qmp(result, 'return', {})
108
+
109
+ self.assertTrue(iotests.compare_images(test_img, target_img),
110
+ 'target image does not match source after mirroring')
111
+
112
class TestGranularity(iotests.QMPTestCase):
113
image_len = 10 * 1024 * 1024 # MB
114
115
diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out
116
index XXXXXXX..XXXXXXX 100644
117
--- a/tests/qemu-iotests/041.out
118
+++ b/tests/qemu-iotests/041.out
119
@@ -XXX,XX +XXX,XX @@
120
-........................................................................................
121
+..........................................................................................
122
----------------------------------------------------------------------
123
-Ran 88 tests
124
+Ran 90 tests
125
126
OK
127
--
128
2.21.0
129
130
diff view generated by jsdifflib
Deleted patch
1
Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
Fixes: 69f47505ee66afaa513305de0c1895a224e52c45
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
Message-id: 20190725155512.9827-2-mreitz@redhat.com
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: John Snow <jsnow@redhat.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
9
block/vdi.c | 3 ++-
10
1 file changed, 2 insertions(+), 1 deletion(-)
11
1
12
diff --git a/block/vdi.c b/block/vdi.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/block/vdi.c
15
+++ b/block/vdi.c
16
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_block_status(BlockDriverState *bs,
17
*map = s->header.offset_data + (uint64_t)bmap_entry * s->block_size +
18
index_in_block;
19
*file = bs->file->bs;
20
- return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
21
+ return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID |
22
+ (s->header.image_type == VDI_TYPE_STATIC ? BDRV_BLOCK_RECURSE : 0);
23
}
24
25
static int coroutine_fn
26
--
27
2.21.0
28
29
diff view generated by jsdifflib
Deleted patch
1
Fixes: 69f47505ee66afaa513305de0c1895a224e52c45
2
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
Message-id: 20190725155512.9827-3-mreitz@redhat.com
4
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
Reviewed-by: John Snow <jsnow@redhat.com>
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
8
block/vmdk.c | 3 +++
9
1 file changed, 3 insertions(+)
10
1
11
diff --git a/block/vmdk.c b/block/vmdk.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/vmdk.c
14
+++ b/block/vmdk.c
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_block_status(BlockDriverState *bs,
16
if (!extent->compressed) {
17
ret |= BDRV_BLOCK_OFFSET_VALID;
18
*map = cluster_offset + index_in_cluster;
19
+ if (extent->flat) {
20
+ ret |= BDRV_BLOCK_RECURSE;
21
+ }
22
}
23
*file = extent->file->bs;
24
break;
25
--
26
2.21.0
27
28
diff view generated by jsdifflib
Deleted patch
1
vpc is not really a passthrough driver, even when using the fixed
2
subformat (where host and guest offsets are equal). It should handle
3
preallocation like all other drivers do, namely by returning
4
DATA | RECURSE instead of RAW.
5
1
6
There is no tangible difference but the fact that bdrv_is_allocated() no
7
longer falls through to the protocol layer.
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 20190725155512.9827-4-mreitz@redhat.com
11
Reviewed-by: John Snow <jsnow@redhat.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
block/vpc.c | 2 +-
15
1 file changed, 1 insertion(+), 1 deletion(-)
16
17
diff --git a/block/vpc.c b/block/vpc.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/vpc.c
20
+++ b/block/vpc.c
21
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_block_status(BlockDriverState *bs,
22
*pnum = bytes;
23
*map = offset;
24
*file = bs->file->bs;
25
- return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID;
26
+ return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_RECURSE;
27
}
28
29
qemu_co_mutex_lock(&s->lock);
30
--
31
2.21.0
32
33
diff view generated by jsdifflib
Deleted patch
1
69f47505ee has changed qcow2 in such a way that the commit job run in
2
test 141 (and 144[1]) returns before it emits the READY event. However,
3
141 also runs with qed, where the order is still the other way around.
4
Just filter out the {"return": {}} so the test passes for qed again.
5
1
6
[1] 144 only runs with qcow2, so it is fine as it is.
7
8
Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Fixes: 69f47505ee66afaa513305de0c1895a224e52c45
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Message-id: 20190809185253.17535-1-mreitz@redhat.com
12
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Reviewed-by: John Snow <jsnow@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
tests/qemu-iotests/141 | 9 +++++++--
17
tests/qemu-iotests/141.out | 5 -----
18
tests/qemu-iotests/common.filter | 5 +++++
19
3 files changed, 12 insertions(+), 7 deletions(-)
20
21
diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141
22
index XXXXXXX..XXXXXXX 100755
23
--- a/tests/qemu-iotests/141
24
+++ b/tests/qemu-iotests/141
25
@@ -XXX,XX +XXX,XX @@ test_blockjob()
26
}}}" \
27
'return'
28
29
+ # If "$2" is an event, we may or may not see it before the
30
+ # {"return": {}}. Therefore, filter the {"return": {}} out both
31
+ # here and in the next command. (Naturally, if we do not see it
32
+ # here, we will see it before the next command can be executed,
33
+ # so it will appear in the next _send_qemu_cmd's output.)
34
_send_qemu_cmd $QEMU_HANDLE \
35
"$1" \
36
"$2" \
37
- | _filter_img_create
38
+ | _filter_img_create | _filter_qmp_empty_return
39
40
# We want this to return an error because the block job is still running
41
_send_qemu_cmd $QEMU_HANDLE \
42
"{'execute': 'blockdev-del',
43
'arguments': {'node-name': 'drv0'}}" \
44
- 'error' | _filter_generated_node_ids
45
+ 'error' | _filter_generated_node_ids | _filter_qmp_empty_return
46
47
_send_qemu_cmd $QEMU_HANDLE \
48
"{'execute': 'block-job-cancel',
49
diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out
50
index XXXXXXX..XXXXXXX 100644
51
--- a/tests/qemu-iotests/141.out
52
+++ b/tests/qemu-iotests/141.out
53
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m.
54
Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
55
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
56
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
57
-{"return": {}}
58
{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
59
{"return": {}}
60
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}}
61
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.
62
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
63
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}}
64
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}}
65
-{"return": {}}
66
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: mirror"}}
67
{"return": {}}
68
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}}
69
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.
70
{"return": {}}
71
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
72
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
73
-{"return": {}}
74
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}}
75
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
76
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}}
77
@@ -XXX,XX +XXX,XX @@ wrote 1048576/1048576 bytes at offset 0
78
{"return": {}}
79
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
80
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
81
-{"return": {}}
82
{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
83
{"return": {}}
84
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}}
85
@@ -XXX,XX +XXX,XX @@ wrote 1048576/1048576 bytes at offset 0
86
{"return": {}}
87
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
88
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
89
-{"return": {}}
90
{"error": {"class": "GenericError", "desc": "Node drv0 is in use"}}
91
{"return": {}}
92
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}}
93
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
94
index XXXXXXX..XXXXXXX 100644
95
--- a/tests/qemu-iotests/common.filter
96
+++ b/tests/qemu-iotests/common.filter
97
@@ -XXX,XX +XXX,XX @@ _filter_nbd()
98
-e 's#\(foo\|PORT/\?\|.sock\): Failed to .*$#\1#'
99
}
100
101
+_filter_qmp_empty_return()
102
+{
103
+ grep -v '{"return": {}}'
104
+}
105
+
106
# make sure this script returns success
107
true
108
--
109
2.21.0
110
111
diff view generated by jsdifflib
Deleted patch
1
When preallocating an encrypted qcow2 image, it just lets the protocol
2
driver write data and then does not mark the clusters as zero.
3
Therefore, reading this image will yield effectively random data.
4
1
5
As such, we have not fulfilled the promise of always writing zeroes when
6
preallocating an image in a while. It seems that nobody has really
7
cared, so change the documentation to conform to qemu's actual behavior.
8
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 20190711132935.13070-1-mreitz@redhat.com
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
13
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
16
qapi/block-core.json | 9 +++++----
17
docs/qemu-block-drivers.texi | 4 ++--
18
qemu-img.texi | 4 ++--
19
3 files changed, 9 insertions(+), 8 deletions(-)
20
21
diff --git a/qapi/block-core.json b/qapi/block-core.json
22
index XXXXXXX..XXXXXXX 100644
23
--- a/qapi/block-core.json
24
+++ b/qapi/block-core.json
25
@@ -XXX,XX +XXX,XX @@
26
# @off: no preallocation
27
# @metadata: preallocate only for metadata
28
# @falloc: like @full preallocation but allocate disk space by
29
-# posix_fallocate() rather than writing zeros.
30
-# @full: preallocate all data by writing zeros to device to ensure disk
31
-# space is really available. @full preallocation also sets up
32
-# metadata correctly.
33
+# posix_fallocate() rather than writing data.
34
+# @full: preallocate all data by writing it to the device to ensure
35
+# disk space is really available. This data may or may not be
36
+# zero, depending on the image format and storage.
37
+# @full preallocation also sets up metadata correctly.
38
#
39
# Since: 2.2
40
##
41
diff --git a/docs/qemu-block-drivers.texi b/docs/qemu-block-drivers.texi
42
index XXXXXXX..XXXXXXX 100644
43
--- a/docs/qemu-block-drivers.texi
44
+++ b/docs/qemu-block-drivers.texi
45
@@ -XXX,XX +XXX,XX @@ Supported options:
46
@item preallocation
47
Preallocation mode (allowed values: @code{off}, @code{falloc}, @code{full}).
48
@code{falloc} mode preallocates space for image by calling posix_fallocate().
49
-@code{full} mode preallocates space for image by writing zeros to underlying
50
-storage.
51
+@code{full} mode preallocates space for image by writing data to underlying
52
+storage. This data may or may not be zero, depending on the storage location.
53
@end table
54
55
@item qcow2
56
diff --git a/qemu-img.texi b/qemu-img.texi
57
index XXXXXXX..XXXXXXX 100644
58
--- a/qemu-img.texi
59
+++ b/qemu-img.texi
60
@@ -XXX,XX +XXX,XX @@ Supported options:
61
@item preallocation
62
Preallocation mode (allowed values: @code{off}, @code{falloc}, @code{full}).
63
@code{falloc} mode preallocates space for image by calling posix_fallocate().
64
-@code{full} mode preallocates space for image by writing zeros to underlying
65
-storage.
66
+@code{full} mode preallocates space for image by writing data to underlying
67
+storage. This data may or may not be zero, depending on the storage location.
68
@end table
69
70
@item qcow2
71
--
72
2.21.0
73
74
diff view generated by jsdifflib