1
The following changes since commit 22ef7ba8e8ce7fef297549b3defcac333742b804:
1
The following changes since commit b2f7a038bb4c4fc5ce6b8486e8513dfd97665e2a:
2
2
3
Merge remote-tracking branch 'remotes/famz/tags/staging-pull-request' into staging (2018-03-13 11:42:45 +0000)
3
Merge remote-tracking branch 'remotes/rth/tags/pull-softfloat-20181104' into staging (2018-11-05 10:32:49 +0000)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to be6c885842efded81a20f4ca24f0d4e123a80c00:
9
for you to fetch changes up to 1240ac558d348f6c7a5752b1a57c1da58e4efe3e:
10
10
11
block/mirror: change the semantic of 'force' of block-job-cancel (2018-03-13 16:54:47 +0100)
11
include: Add a comment to explain the origin of sizes' lookup table (2018-11-05 15:29:59 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches
14
Block layer patches:
15
16
- auto-read-only option to fix commit job when used with -blockdev
17
- Fix help text related qemu-iotests failure (by improving the help text
18
and updating the reference output)
19
- quorum: Add missing checks when adding/removing child nodes
20
- Don't take address of fields in packed structs
21
- vvfat: Fix crash when reporting error about too many files in directory
15
22
16
----------------------------------------------------------------
23
----------------------------------------------------------------
17
Fam Zheng (2):
24
Alberto Garcia (7):
18
block: Fix flags in reopen queue
25
block: replace "discard" literal with BDRV_OPT_DISCARD macro
19
iotests: Add regression test for commit base locking
26
qcow2: Get the request alignment for encrypted images from QCryptoBlock
27
quorum: Remove quorum_err()
28
quorum: Return an error if the blkverify mode has invalid settings
29
iotest: Test the blkverify mode of the Quorum driver
30
quorum: Forbid adding children in blkverify mode
31
iotest: Test x-blockdev-change on a Quorum
20
32
21
John Snow (21):
33
Cleber Rosa (1):
22
blockjobs: fix set-speed kick
34
iotests: make 083 specific to raw
23
blockjobs: model single jobs as transactions
24
Blockjobs: documentation touchup
25
blockjobs: add status enum
26
blockjobs: add state transition table
27
iotests: add pause_wait
28
blockjobs: add block_job_verb permission table
29
blockjobs: add ABORTING state
30
blockjobs: add CONCLUDED state
31
blockjobs: add NULL state
32
blockjobs: add block_job_dismiss
33
blockjobs: ensure abort is called for cancelled jobs
34
blockjobs: add commit, abort, clean helpers
35
blockjobs: add block_job_txn_apply function
36
blockjobs: add prepare callback
37
blockjobs: add waiting status
38
blockjobs: add PENDING status and event
39
blockjobs: add block-job-finalize
40
blockjobs: Expose manual property
41
iotests: test manual job dismissal
42
tests/test-blockjob: test cancellations
43
35
44
Kevin Wolf (14):
36
Daniel P. Berrangé (1):
45
luks: Separate image file creation from formatting
37
crypto: initialize sector size even when opening with no IO flag
46
luks: Create block_crypto_co_create_generic()
47
luks: Support .bdrv_co_create
48
luks: Turn invalid assertion into check
49
luks: Catch integer overflow for huge sizes
50
qemu-iotests: Test luks QMP image creation
51
parallels: Support .bdrv_co_create
52
qemu-iotests: Enable write tests for parallels
53
qcow: Support .bdrv_co_create
54
qed: Support .bdrv_co_create
55
vdi: Make comments consistent with other drivers
56
vhdx: Support .bdrv_co_create
57
vpc: Support .bdrv_co_create
58
vpc: Require aligned size in .bdrv_co_create
59
38
60
Liang Li (1):
39
Kevin Wolf (12):
61
block/mirror: change the semantic of 'force' of block-job-cancel
40
vpc: Don't leak opts in vpc_open()
41
block: Update flags in bdrv_set_read_only()
42
block: Add auto-read-only option
43
rbd: Close image in qemu_rbd_open() error path
44
block: Require auto-read-only for existing fallbacks
45
nbd: Support auto-read-only option
46
file-posix: Support auto-read-only option
47
curl: Support auto-read-only option
48
gluster: Support auto-read-only option
49
iscsi: Support auto-read-only option
50
block: Make auto-read-only=on default for -drive
51
qemu-iotests: Test auto-read-only with -drive and -blockdev
62
52
63
Max Reitz (3):
53
Leonid Bloch (2):
64
vdi: Pull option parsing from vdi_co_create
54
vdi: Use a literal number of bytes for DEFAULT_CLUSTER_SIZE
65
vdi: Move file creation to vdi_co_create_opts
55
include: Add a comment to explain the origin of sizes' lookup table
66
vdi: Implement .bdrv_co_create
67
56
68
qapi/block-core.json | 363 ++++++++++++++++++++++++++++++++++++++++--
57
Li Qiang (1):
69
include/block/blockjob.h | 71 ++++++++-
58
block: change some function return type to bool
70
include/block/blockjob_int.h | 17 +-
71
block.c | 8 +
72
block/backup.c | 5 +-
73
block/commit.c | 2 +-
74
block/crypto.c | 150 ++++++++++++-----
75
block/mirror.c | 12 +-
76
block/parallels.c | 199 +++++++++++++++++------
77
block/qcow.c | 196 +++++++++++++++--------
78
block/qed.c | 204 ++++++++++++++++--------
79
block/stream.c | 2 +-
80
block/vdi.c | 147 +++++++++++++----
81
block/vhdx.c | 216 +++++++++++++++++++------
82
block/vpc.c | 241 +++++++++++++++++++++-------
83
blockdev.c | 71 +++++++--
84
blockjob.c | 358 +++++++++++++++++++++++++++++++++++------
85
tests/test-bdrv-drain.c | 5 +-
86
tests/test-blockjob-txn.c | 27 ++--
87
tests/test-blockjob.c | 233 ++++++++++++++++++++++++++-
88
block/trace-events | 7 +
89
hmp-commands.hx | 3 +-
90
tests/qemu-iotests/030 | 6 +-
91
tests/qemu-iotests/055 | 17 +-
92
tests/qemu-iotests/056 | 187 ++++++++++++++++++++++
93
tests/qemu-iotests/056.out | 4 +-
94
tests/qemu-iotests/109.out | 24 +--
95
tests/qemu-iotests/153 | 12 ++
96
tests/qemu-iotests/153.out | 5 +
97
tests/qemu-iotests/181 | 2 +-
98
tests/qemu-iotests/209 | 210 ++++++++++++++++++++++++
99
tests/qemu-iotests/209.out | 136 ++++++++++++++++
100
tests/qemu-iotests/check | 1 -
101
tests/qemu-iotests/common.rc | 2 +-
102
tests/qemu-iotests/group | 1 +
103
tests/qemu-iotests/iotests.py | 12 +-
104
36 files changed, 2642 insertions(+), 514 deletions(-)
105
create mode 100755 tests/qemu-iotests/209
106
create mode 100644 tests/qemu-iotests/209.out
107
59
60
Max Reitz (5):
61
option: Make option help nicer to read
62
chardev: Indent list of chardevs
63
qdev-monitor: Make device options help nicer
64
object: Make option help nicer to read
65
fw_cfg: Drop newline in @file description
66
67
Peter Maydell (5):
68
block/qcow2: Don't take address of fields in packed structs
69
block/qcow: Don't take address of fields in packed structs
70
block/qcow2-bitmap: Don't take address of fields in packed structs
71
block/vhdx: Don't take address of fields in packed structs
72
block/vdi: Don't take address of fields in packed structs
73
74
Stefan Weil (1):
75
qemu-io-cmds: Fix two format strings
76
77
Thomas Huth (1):
78
block/vvfat: Fix crash when reporting error about too many files in directory
79
80
qapi/block-core.json | 7 +
81
block/vhdx.h | 12 +-
82
include/block/block.h | 5 +-
83
include/qemu/option.h | 2 +-
84
include/qemu/units.h | 18 +
85
include/sysemu/block-backend.h | 6 +-
86
block.c | 60 ++-
87
block/block-backend.c | 8 +-
88
block/bochs.c | 17 +-
89
block/cloop.c | 16 +-
90
block/curl.c | 8 +-
91
block/dmg.c | 16 +-
92
block/file-posix.c | 19 +-
93
block/gluster.c | 12 +-
94
block/iscsi.c | 8 +-
95
block/nbd-client.c | 10 +-
96
block/qcow.c | 18 +-
97
block/qcow2-bitmap.c | 24 +-
98
block/qcow2.c | 66 +--
99
block/quorum.c | 45 +-
100
block/rbd.c | 14 +-
101
block/vdi.c | 68 +--
102
block/vhdx-endian.c | 118 ++---
103
block/vhdx-log.c | 4 +-
104
block/vhdx.c | 18 +-
105
block/vpc.c | 2 +
106
block/vvfat.c | 15 +-
107
blockdev.c | 3 +-
108
chardev/char.c | 2 +-
109
crypto/block-qcow.c | 2 +
110
qdev-monitor.c | 13 +-
111
qemu-img.c | 4 +-
112
qemu-io-cmds.c | 4 +-
113
util/qemu-option.c | 32 +-
114
vl.c | 15 +-
115
tests/qemu-iotests/081 | 116 +++++
116
tests/qemu-iotests/081.out | 70 +++
117
tests/qemu-iotests/082.out | 956 ++++++++++++++++++++---------------------
118
tests/qemu-iotests/083 | 2 +-
119
tests/qemu-iotests/232 | 147 +++++++
120
tests/qemu-iotests/232.out | 59 +++
121
tests/qemu-iotests/group | 1 +
122
42 files changed, 1266 insertions(+), 776 deletions(-)
123
create mode 100755 tests/qemu-iotests/232
124
create mode 100644 tests/qemu-iotests/232.out
125
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
Whatever the state a blockjob is in, it should be able to be canceled
3
When using the vvfat driver with a directory that contains too many files,
4
by the block layer.
4
QEMU currently crashes. This can be triggered like this for example:
5
5
6
Signed-off-by: John Snow <jsnow@redhat.com>
6
mkdir /tmp/vvfattest
7
cd /tmp/vvfattest
8
for ((x=0;x<=513;x++)); do mkdir $x; done
9
qemu-system-x86_64 -drive \
10
file.driver=vvfat,file.dir=.,read-only=on,media=cdrom
11
12
Seems like read_directory() is changing the mapping->path variable. Make
13
sure we use the right pointer instead.
14
15
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
17
---
9
tests/test-blockjob.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++-
18
block/vvfat.c | 4 ++--
10
1 file changed, 229 insertions(+), 4 deletions(-)
19
1 file changed, 2 insertions(+), 2 deletions(-)
11
20
12
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
21
diff --git a/block/vvfat.c b/block/vvfat.c
13
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
14
--- a/tests/test-blockjob.c
23
--- a/block/vvfat.c
15
+++ b/tests/test-blockjob.c
24
+++ b/block/vvfat.c
16
@@ -XXX,XX +XXX,XX @@ static void block_job_cb(void *opaque, int ret)
25
@@ -XXX,XX +XXX,XX @@ static int init_directories(BDRVVVFATState* s,
17
{
26
mapping = array_get(&(s->mapping), i);
18
}
27
19
28
if (mapping->mode & MODE_DIRECTORY) {
20
-static BlockJob *do_test_id(BlockBackend *blk, const char *id,
29
+ char *path = mapping->path;
21
- bool should_succeed)
30
mapping->begin = cluster;
22
+static BlockJob *mk_job(BlockBackend *blk, const char *id,
31
if(read_directory(s, i)) {
23
+ const BlockJobDriver *drv, bool should_succeed,
32
- error_setg(errp, "Could not read directory %s",
24
+ int flags)
33
- mapping->path);
25
{
34
+ error_setg(errp, "Could not read directory %s", path);
26
BlockJob *job;
35
return -1;
27
Error *errp = NULL;
36
}
28
37
mapping = array_get(&(s->mapping), i);
29
- job = block_job_create(id, &test_block_job_driver, NULL, blk_bs(blk),
30
- 0, BLK_PERM_ALL, 0, BLOCK_JOB_DEFAULT, block_job_cb,
31
+ job = block_job_create(id, drv, NULL, blk_bs(blk),
32
+ 0, BLK_PERM_ALL, 0, flags, block_job_cb,
33
NULL, &errp);
34
if (should_succeed) {
35
g_assert_null(errp);
36
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_test_id(BlockBackend *blk, const char *id,
37
return job;
38
}
39
40
+static BlockJob *do_test_id(BlockBackend *blk, const char *id,
41
+ bool should_succeed)
42
+{
43
+ return mk_job(blk, id, &test_block_job_driver,
44
+ should_succeed, BLOCK_JOB_DEFAULT);
45
+}
46
+
47
/* This creates a BlockBackend (optionally with a name) with a
48
* BlockDriverState inserted. */
49
static BlockBackend *create_blk(const char *name)
50
@@ -XXX,XX +XXX,XX @@ static void test_job_ids(void)
51
destroy_blk(blk[2]);
52
}
53
54
+typedef struct CancelJob {
55
+ BlockJob common;
56
+ BlockBackend *blk;
57
+ bool should_converge;
58
+ bool should_complete;
59
+ bool completed;
60
+} CancelJob;
61
+
62
+static void cancel_job_completed(BlockJob *job, void *opaque)
63
+{
64
+ CancelJob *s = opaque;
65
+ s->completed = true;
66
+ block_job_completed(job, 0);
67
+}
68
+
69
+static void cancel_job_complete(BlockJob *job, Error **errp)
70
+{
71
+ CancelJob *s = container_of(job, CancelJob, common);
72
+ s->should_complete = true;
73
+}
74
+
75
+static void coroutine_fn cancel_job_start(void *opaque)
76
+{
77
+ CancelJob *s = opaque;
78
+
79
+ while (!s->should_complete) {
80
+ if (block_job_is_cancelled(&s->common)) {
81
+ goto defer;
82
+ }
83
+
84
+ if (!s->common.ready && s->should_converge) {
85
+ block_job_event_ready(&s->common);
86
+ }
87
+
88
+ block_job_sleep_ns(&s->common, 100000);
89
+ }
90
+
91
+ defer:
92
+ block_job_defer_to_main_loop(&s->common, cancel_job_completed, s);
93
+}
94
+
95
+static const BlockJobDriver test_cancel_driver = {
96
+ .instance_size = sizeof(CancelJob),
97
+ .start = cancel_job_start,
98
+ .complete = cancel_job_complete,
99
+};
100
+
101
+static CancelJob *create_common(BlockJob **pjob)
102
+{
103
+ BlockBackend *blk;
104
+ BlockJob *job;
105
+ CancelJob *s;
106
+
107
+ blk = create_blk(NULL);
108
+ job = mk_job(blk, "Steve", &test_cancel_driver, true,
109
+ BLOCK_JOB_MANUAL_FINALIZE | BLOCK_JOB_MANUAL_DISMISS);
110
+ block_job_ref(job);
111
+ assert(job->status == BLOCK_JOB_STATUS_CREATED);
112
+ s = container_of(job, CancelJob, common);
113
+ s->blk = blk;
114
+
115
+ *pjob = job;
116
+ return s;
117
+}
118
+
119
+static void cancel_common(CancelJob *s)
120
+{
121
+ BlockJob *job = &s->common;
122
+ BlockBackend *blk = s->blk;
123
+ BlockJobStatus sts = job->status;
124
+
125
+ block_job_cancel_sync(job);
126
+ if ((sts != BLOCK_JOB_STATUS_CREATED) &&
127
+ (sts != BLOCK_JOB_STATUS_CONCLUDED)) {
128
+ BlockJob *dummy = job;
129
+ block_job_dismiss(&dummy, &error_abort);
130
+ }
131
+ assert(job->status == BLOCK_JOB_STATUS_NULL);
132
+ block_job_unref(job);
133
+ destroy_blk(blk);
134
+}
135
+
136
+static void test_cancel_created(void)
137
+{
138
+ BlockJob *job;
139
+ CancelJob *s;
140
+
141
+ s = create_common(&job);
142
+ cancel_common(s);
143
+}
144
+
145
+static void test_cancel_running(void)
146
+{
147
+ BlockJob *job;
148
+ CancelJob *s;
149
+
150
+ s = create_common(&job);
151
+
152
+ block_job_start(job);
153
+ assert(job->status == BLOCK_JOB_STATUS_RUNNING);
154
+
155
+ cancel_common(s);
156
+}
157
+
158
+static void test_cancel_paused(void)
159
+{
160
+ BlockJob *job;
161
+ CancelJob *s;
162
+
163
+ s = create_common(&job);
164
+
165
+ block_job_start(job);
166
+ assert(job->status == BLOCK_JOB_STATUS_RUNNING);
167
+
168
+ block_job_user_pause(job, &error_abort);
169
+ block_job_enter(job);
170
+ assert(job->status == BLOCK_JOB_STATUS_PAUSED);
171
+
172
+ cancel_common(s);
173
+}
174
+
175
+static void test_cancel_ready(void)
176
+{
177
+ BlockJob *job;
178
+ CancelJob *s;
179
+
180
+ s = create_common(&job);
181
+
182
+ block_job_start(job);
183
+ assert(job->status == BLOCK_JOB_STATUS_RUNNING);
184
+
185
+ s->should_converge = true;
186
+ block_job_enter(job);
187
+ assert(job->status == BLOCK_JOB_STATUS_READY);
188
+
189
+ cancel_common(s);
190
+}
191
+
192
+static void test_cancel_standby(void)
193
+{
194
+ BlockJob *job;
195
+ CancelJob *s;
196
+
197
+ s = create_common(&job);
198
+
199
+ block_job_start(job);
200
+ assert(job->status == BLOCK_JOB_STATUS_RUNNING);
201
+
202
+ s->should_converge = true;
203
+ block_job_enter(job);
204
+ assert(job->status == BLOCK_JOB_STATUS_READY);
205
+
206
+ block_job_user_pause(job, &error_abort);
207
+ block_job_enter(job);
208
+ assert(job->status == BLOCK_JOB_STATUS_STANDBY);
209
+
210
+ cancel_common(s);
211
+}
212
+
213
+static void test_cancel_pending(void)
214
+{
215
+ BlockJob *job;
216
+ CancelJob *s;
217
+
218
+ s = create_common(&job);
219
+
220
+ block_job_start(job);
221
+ assert(job->status == BLOCK_JOB_STATUS_RUNNING);
222
+
223
+ s->should_converge = true;
224
+ block_job_enter(job);
225
+ assert(job->status == BLOCK_JOB_STATUS_READY);
226
+
227
+ block_job_complete(job, &error_abort);
228
+ block_job_enter(job);
229
+ while (!s->completed) {
230
+ aio_poll(qemu_get_aio_context(), true);
231
+ }
232
+ assert(job->status == BLOCK_JOB_STATUS_PENDING);
233
+
234
+ cancel_common(s);
235
+}
236
+
237
+static void test_cancel_concluded(void)
238
+{
239
+ BlockJob *job;
240
+ CancelJob *s;
241
+
242
+ s = create_common(&job);
243
+
244
+ block_job_start(job);
245
+ assert(job->status == BLOCK_JOB_STATUS_RUNNING);
246
+
247
+ s->should_converge = true;
248
+ block_job_enter(job);
249
+ assert(job->status == BLOCK_JOB_STATUS_READY);
250
+
251
+ block_job_complete(job, &error_abort);
252
+ block_job_enter(job);
253
+ while (!s->completed) {
254
+ aio_poll(qemu_get_aio_context(), true);
255
+ }
256
+ assert(job->status == BLOCK_JOB_STATUS_PENDING);
257
+
258
+ block_job_finalize(job, &error_abort);
259
+ assert(job->status == BLOCK_JOB_STATUS_CONCLUDED);
260
+
261
+ cancel_common(s);
262
+}
263
+
264
int main(int argc, char **argv)
265
{
266
qemu_init_main_loop(&error_abort);
267
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
268
269
g_test_init(&argc, &argv, NULL);
270
g_test_add_func("/blockjob/ids", test_job_ids);
271
+ g_test_add_func("/blockjob/cancel/created", test_cancel_created);
272
+ g_test_add_func("/blockjob/cancel/running", test_cancel_running);
273
+ g_test_add_func("/blockjob/cancel/paused", test_cancel_paused);
274
+ g_test_add_func("/blockjob/cancel/ready", test_cancel_ready);
275
+ g_test_add_func("/blockjob/cancel/standby", test_cancel_standby);
276
+ g_test_add_func("/blockjob/cancel/pending", test_cancel_pending);
277
+ g_test_add_func("/blockjob/cancel/concluded", test_cancel_concluded);
278
return g_test_run();
279
}
280
--
38
--
281
2.13.6
39
2.19.1
282
40
283
41
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Reopen flags are not synchronized according to the
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
4
bdrv_reopen_queue_child precedence until bdrv_reopen_prepare. It is a
5
bit too late: we already check the consistency in bdrv_check_perm before
6
that.
7
8
This fixes the bug that when bdrv_reopen a RO node as RW, the flags for
9
backing child are wrong. Before, we could recurse with flags.rw=1; now,
10
role->inherit_options + update_flags_from_options will make sure to
11
clear the bit when necessary. Note that this will not clear an
12
explicitly set bit, as in the case of parallel block jobs (e.g.
13
test_stream_parallel in 030), because the explicit options include
14
'read-only=false' (for an intermediate node used by a different job).
15
16
Signed-off-by: Fam Zheng <famz@redhat.com>
17
Reviewed-by: Max Reitz <mreitz@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
5
---
20
block.c | 8 ++++++++
6
block.c | 6 +++---
21
1 file changed, 8 insertions(+)
7
1 file changed, 3 insertions(+), 3 deletions(-)
22
8
23
diff --git a/block.c b/block.c
9
diff --git a/block.c b/block.c
24
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
25
--- a/block.c
11
--- a/block.c
26
+++ b/block.c
12
+++ b/block.c
27
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
13
@@ -XXX,XX +XXX,XX @@ QemuOptsList bdrv_runtime_opts = {
28
14
.help = "try to optimize zero writes (off, on, unmap)",
29
/* Inherit from parent node */
15
},
30
if (parent_options) {
16
{
31
+ QemuOpts *opts;
17
- .name = "discard",
32
+ QDict *options_copy;
18
+ .name = BDRV_OPT_DISCARD,
33
assert(!flags);
19
.type = QEMU_OPT_STRING,
34
role->inherit_options(&flags, options, parent_flags, parent_options);
20
.help = "discard operation (ignore/off, unmap/on)",
35
+ options_copy = qdict_clone_shallow(options);
21
},
36
+ opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
22
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
37
+ qemu_opts_absorb_qdict(opts, options_copy, NULL);
23
}
38
+ update_flags_from_options(&flags, opts);
39
+ qemu_opts_del(opts);
40
+ QDECREF(options_copy);
41
}
24
}
42
25
43
/* Old values are used for options that aren't set yet */
26
- discard = qemu_opt_get(opts, "discard");
27
+ discard = qemu_opt_get(opts, BDRV_OPT_DISCARD);
28
if (discard != NULL) {
29
if (bdrv_parse_discard_flags(discard, &bs->open_flags) != 0) {
30
error_setg(errp, "Invalid discard option");
31
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
32
33
update_flags_from_options(&reopen_state->flags, opts);
34
35
- discard = qemu_opt_get_del(opts, "discard");
36
+ discard = qemu_opt_get_del(opts, BDRV_OPT_DISCARD);
37
if (discard != NULL) {
38
if (bdrv_parse_discard_flags(discard, &reopen_state->flags) != 0) {
39
error_setg(errp, "Invalid discard option");
44
--
40
--
45
2.13.6
41
2.19.1
46
42
47
43
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Stefan Weil <sw@weilnetz.de>
2
2
3
Expose the "manual" property via QAPI for the backup-related jobs.
3
Use %zu instead of %zd for unsigned numbers.
4
As of this commit, this allows the management API to request the
5
"concluded" and "dismiss" semantics for backup jobs.
6
4
7
Signed-off-by: John Snow <jsnow@redhat.com>
5
This fixes two error messages from the LSTM static code analyzer:
6
7
This argument should be of type 'ssize_t' but is of type 'unsigned long'
8
9
Signed-off-by: Stefan Weil <sw@weilnetz.de>
10
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
12
---
10
qapi/block-core.json | 48 ++++++++++++++++++++++++++++++++++++++--------
13
qemu-io-cmds.c | 4 ++--
11
blockdev.c | 31 +++++++++++++++++++++++++++---
14
1 file changed, 2 insertions(+), 2 deletions(-)
12
blockjob.c | 2 ++
13
tests/qemu-iotests/109.out | 24 +++++++++++------------
14
4 files changed, 82 insertions(+), 23 deletions(-)
15
15
16
diff --git a/qapi/block-core.json b/qapi/block-core.json
16
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
17
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
18
--- a/qapi/block-core.json
18
--- a/qemu-io-cmds.c
19
+++ b/qapi/block-core.json
19
+++ b/qemu-io-cmds.c
20
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ static int readv_f(BlockBackend *blk, int argc, char **argv)
21
#
21
memset(cmp_buf, pattern, qiov.size);
22
# @status: Current job state/status (since 2.12)
22
if (memcmp(buf, cmp_buf, qiov.size)) {
23
#
23
printf("Pattern verification failed at offset %"
24
+# @auto-finalize: Job will finalize itself when PENDING, moving to
24
- PRId64 ", %zd bytes\n", offset, qiov.size);
25
+# the CONCLUDED state. (since 2.12)
25
+ PRId64 ", %zu bytes\n", offset, qiov.size);
26
+#
26
ret = -EINVAL;
27
+# @auto-dismiss: Job will dismiss itself when CONCLUDED, moving to the NULL
27
}
28
+# state and disappearing from the query list. (since 2.12)
28
g_free(cmp_buf);
29
+#
29
@@ -XXX,XX +XXX,XX @@ static void aio_read_done(void *opaque, int ret)
30
# Since: 1.1
30
memset(cmp_buf, ctx->pattern, ctx->qiov.size);
31
##
31
if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
32
{ 'struct': 'BlockJobInfo',
32
printf("Pattern verification failed at offset %"
33
'data': {'type': 'str', 'device': 'str', 'len': 'int',
33
- PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
34
'offset': 'int', 'busy': 'bool', 'paused': 'bool', 'speed': 'int',
34
+ PRId64 ", %zu bytes\n", ctx->offset, ctx->qiov.size);
35
'io-status': 'BlockDeviceIoStatus', 'ready': 'bool',
35
}
36
- 'status': 'BlockJobStatus' } }
36
g_free(cmp_buf);
37
+ 'status': 'BlockJobStatus',
38
+ 'auto-finalize': 'bool', 'auto-dismiss': 'bool' } }
39
40
##
41
# @query-block-jobs:
42
@@ -XXX,XX +XXX,XX @@
43
# default 'report' (no limitations, since this applies to
44
# a different block device than @device).
45
#
46
+# @auto-finalize: When false, this job will wait in a PENDING state after it has
47
+# finished its work, waiting for @block-job-finalize.
48
+# When true, this job will automatically perform its abort or
49
+# commit actions.
50
+# Defaults to true. (Since 2.12)
51
+#
52
+# @auto-dismiss: When false, this job will wait in a CONCLUDED state after it
53
+# has completed ceased all work, and wait for @block-job-dismiss.
54
+# When true, this job will automatically disappear from the query
55
+# list without user intervention.
56
+# Defaults to true. (Since 2.12)
57
+#
58
# Note: @on-source-error and @on-target-error only affect background
59
# I/O. If an error occurs during a guest write request, the device's
60
# rerror/werror actions will be used.
61
@@ -XXX,XX +XXX,XX @@
62
##
63
{ 'struct': 'DriveBackup',
64
'data': { '*job-id': 'str', 'device': 'str', 'target': 'str',
65
- '*format': 'str', 'sync': 'MirrorSyncMode', '*mode': 'NewImageMode',
66
- '*speed': 'int', '*bitmap': 'str', '*compress': 'bool',
67
+ '*format': 'str', 'sync': 'MirrorSyncMode',
68
+ '*mode': 'NewImageMode', '*speed': 'int',
69
+ '*bitmap': 'str', '*compress': 'bool',
70
'*on-source-error': 'BlockdevOnError',
71
- '*on-target-error': 'BlockdevOnError' } }
72
+ '*on-target-error': 'BlockdevOnError',
73
+ '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } }
74
75
##
76
# @BlockdevBackup:
77
@@ -XXX,XX +XXX,XX @@
78
# default 'report' (no limitations, since this applies to
79
# a different block device than @device).
80
#
81
+# @auto-finalize: When false, this job will wait in a PENDING state after it has
82
+# finished its work, waiting for @block-job-finalize.
83
+# When true, this job will automatically perform its abort or
84
+# commit actions.
85
+# Defaults to true. (Since 2.12)
86
+#
87
+# @auto-dismiss: When false, this job will wait in a CONCLUDED state after it
88
+# has completed ceased all work, and wait for @block-job-dismiss.
89
+# When true, this job will automatically disappear from the query
90
+# list without user intervention.
91
+# Defaults to true. (Since 2.12)
92
+#
93
# Note: @on-source-error and @on-target-error only affect background
94
# I/O. If an error occurs during a guest write request, the device's
95
# rerror/werror actions will be used.
96
@@ -XXX,XX +XXX,XX @@
97
##
98
{ 'struct': 'BlockdevBackup',
99
'data': { '*job-id': 'str', 'device': 'str', 'target': 'str',
100
- 'sync': 'MirrorSyncMode',
101
- '*speed': 'int',
102
- '*compress': 'bool',
103
+ 'sync': 'MirrorSyncMode', '*speed': 'int', '*compress': 'bool',
104
'*on-source-error': 'BlockdevOnError',
105
- '*on-target-error': 'BlockdevOnError' } }
106
+ '*on-target-error': 'BlockdevOnError',
107
+ '*auto-finalize': 'bool', '*auto-dismiss': 'bool' } }
108
109
##
110
# @blockdev-snapshot-sync:
111
diff --git a/blockdev.c b/blockdev.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/blockdev.c
114
+++ b/blockdev.c
115
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
116
AioContext *aio_context;
117
QDict *options = NULL;
118
Error *local_err = NULL;
119
- int flags;
120
+ int flags, job_flags = BLOCK_JOB_DEFAULT;
121
int64_t size;
122
bool set_backing_hd = false;
123
124
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
125
if (!backup->has_job_id) {
126
backup->job_id = NULL;
127
}
37
}
128
+ if (!backup->has_auto_finalize) {
129
+ backup->auto_finalize = true;
130
+ }
131
+ if (!backup->has_auto_dismiss) {
132
+ backup->auto_dismiss = true;
133
+ }
134
if (!backup->has_compress) {
135
backup->compress = false;
136
}
137
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
138
goto out;
139
}
140
}
141
+ if (!backup->auto_finalize) {
142
+ job_flags |= BLOCK_JOB_MANUAL_FINALIZE;
143
+ }
144
+ if (!backup->auto_dismiss) {
145
+ job_flags |= BLOCK_JOB_MANUAL_DISMISS;
146
+ }
147
148
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
149
backup->sync, bmap, backup->compress,
150
backup->on_source_error, backup->on_target_error,
151
- BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err);
152
+ job_flags, NULL, NULL, txn, &local_err);
153
bdrv_unref(target_bs);
154
if (local_err != NULL) {
155
error_propagate(errp, local_err);
156
@@ -XXX,XX +XXX,XX @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
157
Error *local_err = NULL;
158
AioContext *aio_context;
159
BlockJob *job = NULL;
160
+ int job_flags = BLOCK_JOB_DEFAULT;
161
162
if (!backup->has_speed) {
163
backup->speed = 0;
164
@@ -XXX,XX +XXX,XX @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
165
if (!backup->has_job_id) {
166
backup->job_id = NULL;
167
}
168
+ if (!backup->has_auto_finalize) {
169
+ backup->auto_finalize = true;
170
+ }
171
+ if (!backup->has_auto_dismiss) {
172
+ backup->auto_dismiss = true;
173
+ }
174
if (!backup->has_compress) {
175
backup->compress = false;
176
}
177
@@ -XXX,XX +XXX,XX @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
178
goto out;
179
}
180
}
181
+ if (!backup->auto_finalize) {
182
+ job_flags |= BLOCK_JOB_MANUAL_FINALIZE;
183
+ }
184
+ if (!backup->auto_dismiss) {
185
+ job_flags |= BLOCK_JOB_MANUAL_DISMISS;
186
+ }
187
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
188
backup->sync, NULL, backup->compress,
189
backup->on_source_error, backup->on_target_error,
190
- BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err);
191
+ job_flags, NULL, NULL, txn, &local_err);
192
if (local_err != NULL) {
193
error_propagate(errp, local_err);
194
}
195
diff --git a/blockjob.c b/blockjob.c
196
index XXXXXXX..XXXXXXX 100644
197
--- a/blockjob.c
198
+++ b/blockjob.c
199
@@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
200
info->io_status = job->iostatus;
201
info->ready = job->ready;
202
info->status = job->status;
203
+ info->auto_finalize = job->auto_finalize;
204
+ info->auto_dismiss = job->auto_dismiss;
205
return info;
206
}
207
208
diff --git a/tests/qemu-iotests/109.out b/tests/qemu-iotests/109.out
209
index XXXXXXX..XXXXXXX 100644
210
--- a/tests/qemu-iotests/109.out
211
+++ b/tests/qemu-iotests/109.out
212
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
213
{"return": {}}
214
{"return": {}}
215
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
216
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
217
+{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
218
{"return": {}}
219
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
220
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
221
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
222
{"return": {}}
223
{"return": {}}
224
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}}
225
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 197120, "offset": 197120, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
226
+{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 197120, "offset": 197120, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
227
{"return": {}}
228
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
229
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}}
230
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
231
{"return": {}}
232
{"return": {}}
233
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
234
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
235
+{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
236
{"return": {}}
237
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
238
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
239
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
240
{"return": {}}
241
{"return": {}}
242
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
243
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
244
+{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
245
{"return": {}}
246
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
247
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
248
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
249
{"return": {}}
250
{"return": {}}
251
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
252
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 65536, "offset": 65536, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
253
+{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 65536, "offset": 65536, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
254
{"return": {}}
255
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
256
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
257
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
258
{"return": {}}
259
{"return": {}}
260
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
261
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
262
+{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
263
{"return": {}}
264
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
265
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
266
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
267
{"return": {}}
268
{"return": {}}
269
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
270
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
271
+{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
272
{"return": {}}
273
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
274
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
275
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
276
{"return": {}}
277
{"return": {}}
278
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}}
279
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 31457280, "offset": 31457280, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
280
+{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 31457280, "offset": 31457280, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
281
{"return": {}}
282
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
283
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}}
284
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
285
{"return": {}}
286
{"return": {}}
287
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
288
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
289
+{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
290
{"return": {}}
291
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
292
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
293
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
294
{"return": {}}
295
{"return": {}}
296
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}}
297
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 2048, "offset": 2048, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
298
+{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2048, "offset": 2048, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
299
{"return": {}}
300
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
301
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}}
302
@@ -XXX,XX +XXX,XX @@ Automatically detecting the format is dangerous for raw images, write operations
303
Specify the 'raw' format explicitly to remove the restrictions.
304
{"return": {}}
305
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
306
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
307
+{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
308
{"return": {}}
309
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
310
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
311
@@ -XXX,XX +XXX,XX @@ Images are identical.
312
{"return": {}}
313
{"return": {}}
314
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
315
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
316
+{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
317
{"return": {}}
318
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
319
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
320
--
38
--
321
2.13.6
39
2.19.1
322
40
323
41
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Peter Maydell <peter.maydell@linaro.org>
2
2
3
model all independent jobs as single job transactions.
3
Taking the address of a field in a packed struct is a bad idea, because
4
it might not be actually aligned enough for that pointer type (and
5
thus cause a crash on dereference on some host architectures). Newer
6
versions of clang warn about this. Avoid the bug by not using the
7
"modify in place" byte swapping functions.
4
8
5
It's one less case we have to worry about when we add more states to the
9
There are a few places where the in-place swap function is
6
transition machine. This way, we can just treat all job lifetimes exactly
10
used on something other than a packed struct field; we convert
7
the same. This helps tighten assertions of the STM graph and removes some
11
those anyway, for consistency.
8
conditionals that would have been needed in the coming commits adding a
9
more explicit job lifetime management API.
10
12
11
Signed-off-by: John Snow <jsnow@redhat.com>
13
This patch was produced with the following spatch script
12
Reviewed-by: Eric Blake <eblake@redhat.com>
14
(and hand-editing to fold a few resulting overlength lines):
13
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
15
16
@@
17
expression E;
18
@@
19
-be16_to_cpus(&E);
20
+E = be16_to_cpu(E);
21
@@
22
expression E;
23
@@
24
-be32_to_cpus(&E);
25
+E = be32_to_cpu(E);
26
@@
27
expression E;
28
@@
29
-be64_to_cpus(&E);
30
+E = be64_to_cpu(E);
31
@@
32
expression E;
33
@@
34
-cpu_to_be16s(&E);
35
+E = cpu_to_be16(E);
36
@@
37
expression E;
38
@@
39
-cpu_to_be32s(&E);
40
+E = cpu_to_be32(E);
41
@@
42
expression E;
43
@@
44
-cpu_to_be64s(&E);
45
+E = cpu_to_be64(E);
46
47
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
48
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
49
Tested-by: John Snow <jsnow@redhat.com>
50
Reviewed-by: John Snow <jsnow@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
51
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
52
---
16
include/block/blockjob.h | 1 -
53
block/qcow2.c | 64 +++++++++++++++++++++++++++------------------------
17
include/block/blockjob_int.h | 3 ++-
54
1 file changed, 34 insertions(+), 30 deletions(-)
18
block/backup.c | 3 +--
19
block/commit.c | 2 +-
20
block/mirror.c | 2 +-
21
block/stream.c | 2 +-
22
blockjob.c | 25 ++++++++++++++++---------
23
tests/test-bdrv-drain.c | 4 ++--
24
tests/test-blockjob-txn.c | 19 +++++++------------
25
tests/test-blockjob.c | 2 +-
26
10 files changed, 32 insertions(+), 31 deletions(-)
27
55
28
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
56
diff --git a/block/qcow2.c b/block/qcow2.c
29
index XXXXXXX..XXXXXXX 100644
57
index XXXXXXX..XXXXXXX 100644
30
--- a/include/block/blockjob.h
58
--- a/block/qcow2.c
31
+++ b/include/block/blockjob.h
59
+++ b/block/qcow2.c
32
@@ -XXX,XX +XXX,XX @@ typedef struct BlockJob {
60
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
33
*/
61
"pread fail from offset %" PRIu64, offset);
34
QEMUTimer sleep_timer;
62
return 1;
35
63
}
36
- /** Non-NULL if this job is part of a transaction */
64
- be32_to_cpus(&ext.magic);
37
BlockJobTxn *txn;
65
- be32_to_cpus(&ext.len);
38
QLIST_ENTRY(BlockJob) txn_list;
66
+ ext.magic = be32_to_cpu(ext.magic);
39
} BlockJob;
67
+ ext.len = be32_to_cpu(ext.len);
40
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
68
offset += sizeof(ext);
41
index XXXXXXX..XXXXXXX 100644
69
#ifdef DEBUG_EXT
42
--- a/include/block/blockjob_int.h
70
printf("ext.magic = 0x%x\n", ext.magic);
43
+++ b/include/block/blockjob_int.h
71
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
44
@@ -XXX,XX +XXX,XX @@ struct BlockJobDriver {
72
"Unable to read CRYPTO header extension");
45
* @job_id: The id of the newly-created job, or %NULL to have one
73
return ret;
46
* generated automatically.
74
}
47
* @job_type: The class object for the newly-created job.
75
- be64_to_cpus(&s->crypto_header.offset);
48
+ * @txn: The transaction this job belongs to, if any. %NULL otherwise.
76
- be64_to_cpus(&s->crypto_header.length);
49
* @bs: The block
77
+ s->crypto_header.offset = be64_to_cpu(s->crypto_header.offset);
50
* @perm, @shared_perm: Permissions to request for @bs
78
+ s->crypto_header.length = be64_to_cpu(s->crypto_header.length);
51
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
79
52
@@ -XXX,XX +XXX,XX @@ struct BlockJobDriver {
80
if ((s->crypto_header.offset % s->cluster_size) != 0) {
53
* called from a wrapper that is specific to the job type.
81
error_setg(errp, "Encryption header offset '%" PRIu64 "' is "
54
*/
82
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
55
void *block_job_create(const char *job_id, const BlockJobDriver *driver,
83
return -EINVAL;
56
- BlockDriverState *bs, uint64_t perm,
84
}
57
+ BlockJobTxn *txn, BlockDriverState *bs, uint64_t perm,
85
58
uint64_t shared_perm, int64_t speed, int flags,
86
- be32_to_cpus(&bitmaps_ext.nb_bitmaps);
59
BlockCompletionFunc *cb, void *opaque, Error **errp);
87
- be64_to_cpus(&bitmaps_ext.bitmap_directory_size);
60
88
- be64_to_cpus(&bitmaps_ext.bitmap_directory_offset);
61
diff --git a/block/backup.c b/block/backup.c
89
+ bitmaps_ext.nb_bitmaps = be32_to_cpu(bitmaps_ext.nb_bitmaps);
62
index XXXXXXX..XXXXXXX 100644
90
+ bitmaps_ext.bitmap_directory_size =
63
--- a/block/backup.c
91
+ be64_to_cpu(bitmaps_ext.bitmap_directory_size);
64
+++ b/block/backup.c
92
+ bitmaps_ext.bitmap_directory_offset =
65
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
93
+ be64_to_cpu(bitmaps_ext.bitmap_directory_offset);
94
95
if (bitmaps_ext.nb_bitmaps > QCOW2_MAX_BITMAPS) {
96
error_setg(errp,
97
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
98
error_setg_errno(errp, -ret, "Could not read qcow2 header");
99
goto fail;
66
}
100
}
67
101
- be32_to_cpus(&header.magic);
68
/* job->common.len is fixed, so we can't allow resize */
102
- be32_to_cpus(&header.version);
69
- job = block_job_create(job_id, &backup_job_driver, bs,
103
- be64_to_cpus(&header.backing_file_offset);
70
+ job = block_job_create(job_id, &backup_job_driver, txn, bs,
104
- be32_to_cpus(&header.backing_file_size);
71
BLK_PERM_CONSISTENT_READ,
105
- be64_to_cpus(&header.size);
72
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE |
106
- be32_to_cpus(&header.cluster_bits);
73
BLK_PERM_WRITE_UNCHANGED | BLK_PERM_GRAPH_MOD,
107
- be32_to_cpus(&header.crypt_method);
74
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
108
- be64_to_cpus(&header.l1_table_offset);
75
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
109
- be32_to_cpus(&header.l1_size);
76
&error_abort);
110
- be64_to_cpus(&header.refcount_table_offset);
77
job->common.len = len;
111
- be32_to_cpus(&header.refcount_table_clusters);
78
- block_job_txn_add_job(txn, &job->common);
112
- be64_to_cpus(&header.snapshots_offset);
79
113
- be32_to_cpus(&header.nb_snapshots);
80
return &job->common;
114
+ header.magic = be32_to_cpu(header.magic);
81
115
+ header.version = be32_to_cpu(header.version);
82
diff --git a/block/commit.c b/block/commit.c
116
+ header.backing_file_offset = be64_to_cpu(header.backing_file_offset);
83
index XXXXXXX..XXXXXXX 100644
117
+ header.backing_file_size = be32_to_cpu(header.backing_file_size);
84
--- a/block/commit.c
118
+ header.size = be64_to_cpu(header.size);
85
+++ b/block/commit.c
119
+ header.cluster_bits = be32_to_cpu(header.cluster_bits);
86
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
120
+ header.crypt_method = be32_to_cpu(header.crypt_method);
87
return;
121
+ header.l1_table_offset = be64_to_cpu(header.l1_table_offset);
88
}
122
+ header.l1_size = be32_to_cpu(header.l1_size);
89
123
+ header.refcount_table_offset = be64_to_cpu(header.refcount_table_offset);
90
- s = block_job_create(job_id, &commit_job_driver, bs, 0, BLK_PERM_ALL,
124
+ header.refcount_table_clusters =
91
+ s = block_job_create(job_id, &commit_job_driver, NULL, bs, 0, BLK_PERM_ALL,
125
+ be32_to_cpu(header.refcount_table_clusters);
92
speed, BLOCK_JOB_DEFAULT, NULL, NULL, errp);
126
+ header.snapshots_offset = be64_to_cpu(header.snapshots_offset);
93
if (!s) {
127
+ header.nb_snapshots = be32_to_cpu(header.nb_snapshots);
94
return;
128
95
diff --git a/block/mirror.c b/block/mirror.c
129
if (header.magic != QCOW_MAGIC) {
96
index XXXXXXX..XXXXXXX 100644
130
error_setg(errp, "Image is not in qcow2 format");
97
--- a/block/mirror.c
131
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
98
+++ b/block/mirror.c
132
header.refcount_order = 4;
99
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
133
header.header_length = 72;
100
}
134
} else {
101
135
- be64_to_cpus(&header.incompatible_features);
102
/* Make sure that the source is not resized while the job is running */
136
- be64_to_cpus(&header.compatible_features);
103
- s = block_job_create(job_id, driver, mirror_top_bs,
137
- be64_to_cpus(&header.autoclear_features);
104
+ s = block_job_create(job_id, driver, NULL, mirror_top_bs,
138
- be32_to_cpus(&header.refcount_order);
105
BLK_PERM_CONSISTENT_READ,
139
- be32_to_cpus(&header.header_length);
106
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
140
+ header.incompatible_features =
107
BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, speed,
141
+ be64_to_cpu(header.incompatible_features);
108
diff --git a/block/stream.c b/block/stream.c
142
+ header.compatible_features = be64_to_cpu(header.compatible_features);
109
index XXXXXXX..XXXXXXX 100644
143
+ header.autoclear_features = be64_to_cpu(header.autoclear_features);
110
--- a/block/stream.c
144
+ header.refcount_order = be32_to_cpu(header.refcount_order);
111
+++ b/block/stream.c
145
+ header.header_length = be32_to_cpu(header.header_length);
112
@@ -XXX,XX +XXX,XX @@ void stream_start(const char *job_id, BlockDriverState *bs,
146
113
/* Prevent concurrent jobs trying to modify the graph structure here, we
147
if (header.header_length < 104) {
114
* already have our own plans. Also don't allow resize as the image size is
148
error_setg(errp, "qcow2 header too short");
115
* queried only at the job start and then cached. */
149
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
116
- s = block_job_create(job_id, &stream_job_driver, bs,
150
goto fail;
117
+ s = block_job_create(job_id, &stream_job_driver, NULL, bs,
151
}
118
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
152
for(i = 0;i < s->l1_size; i++) {
119
BLK_PERM_GRAPH_MOD,
153
- be64_to_cpus(&s->l1_table[i]);
120
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
154
+ s->l1_table[i] = be64_to_cpu(s->l1_table[i]);
121
diff --git a/blockjob.c b/blockjob.c
122
index XXXXXXX..XXXXXXX 100644
123
--- a/blockjob.c
124
+++ b/blockjob.c
125
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_single(BlockJob *job)
126
}
155
}
127
}
156
}
128
157
129
- if (job->txn) {
158
@@ -XXX,XX +XXX,XX @@ int qcow2_update_header(BlockDriverState *bs)
130
- QLIST_REMOVE(job, txn_list);
159
131
- block_job_txn_unref(job->txn);
160
/* Full disk encryption header pointer extension */
132
- }
161
if (s->crypto_header.offset != 0) {
133
+ QLIST_REMOVE(job, txn_list);
162
- cpu_to_be64s(&s->crypto_header.offset);
134
+ block_job_txn_unref(job->txn);
163
- cpu_to_be64s(&s->crypto_header.length);
135
block_job_unref(job);
164
+ s->crypto_header.offset = cpu_to_be64(s->crypto_header.offset);
136
}
165
+ s->crypto_header.length = cpu_to_be64(s->crypto_header.length);
137
166
ret = header_ext_add(buf, QCOW2_EXT_MAGIC_CRYPTO_HEADER,
138
@@ -XXX,XX +XXX,XX @@ static void block_job_event_completed(BlockJob *job, const char *msg)
167
&s->crypto_header, sizeof(s->crypto_header),
139
*/
168
buflen);
140
169
- be64_to_cpus(&s->crypto_header.offset);
141
void *block_job_create(const char *job_id, const BlockJobDriver *driver,
170
- be64_to_cpus(&s->crypto_header.length);
142
- BlockDriverState *bs, uint64_t perm,
171
+ s->crypto_header.offset = be64_to_cpu(s->crypto_header.offset);
143
+ BlockJobTxn *txn, BlockDriverState *bs, uint64_t perm,
172
+ s->crypto_header.length = be64_to_cpu(s->crypto_header.length);
144
uint64_t shared_perm, int64_t speed, int flags,
173
if (ret < 0) {
145
BlockCompletionFunc *cb, void *opaque, Error **errp)
174
goto fail;
146
{
147
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
148
return NULL;
149
}
175
}
150
}
151
+
152
+ /* Single jobs are modeled as single-job transactions for sake of
153
+ * consolidating the job management logic */
154
+ if (!txn) {
155
+ txn = block_job_txn_new();
156
+ block_job_txn_add_job(txn, job);
157
+ block_job_txn_unref(txn);
158
+ } else {
159
+ block_job_txn_add_job(txn, job);
160
+ }
161
+
162
return job;
163
}
164
165
@@ -XXX,XX +XXX,XX @@ void block_job_early_fail(BlockJob *job)
166
167
void block_job_completed(BlockJob *job, int ret)
168
{
169
+ assert(job && job->txn && !job->completed);
170
assert(blk_bs(job->blk)->job == job);
171
- assert(!job->completed);
172
job->completed = true;
173
job->ret = ret;
174
- if (!job->txn) {
175
- block_job_completed_single(job);
176
- } else if (ret < 0 || block_job_is_cancelled(job)) {
177
+ if (ret < 0 || block_job_is_cancelled(job)) {
178
block_job_completed_txn_abort(job);
179
} else {
180
block_job_completed_txn_success(job);
181
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
182
index XXXXXXX..XXXXXXX 100644
183
--- a/tests/test-bdrv-drain.c
184
+++ b/tests/test-bdrv-drain.c
185
@@ -XXX,XX +XXX,XX @@ static void test_blockjob_common(enum drain_type drain_type)
186
blk_target = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
187
blk_insert_bs(blk_target, target, &error_abort);
188
189
- job = block_job_create("job0", &test_job_driver, src, 0, BLK_PERM_ALL, 0,
190
- 0, NULL, NULL, &error_abort);
191
+ job = block_job_create("job0", &test_job_driver, NULL, src, 0, BLK_PERM_ALL,
192
+ 0, 0, NULL, NULL, &error_abort);
193
block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort);
194
block_job_start(job);
195
196
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
197
index XXXXXXX..XXXXXXX 100644
198
--- a/tests/test-blockjob-txn.c
199
+++ b/tests/test-blockjob-txn.c
200
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver test_block_job_driver = {
201
*/
202
static BlockJob *test_block_job_start(unsigned int iterations,
203
bool use_timer,
204
- int rc, int *result)
205
+ int rc, int *result, BlockJobTxn *txn)
206
{
207
BlockDriverState *bs;
208
TestBlockJob *s;
209
@@ -XXX,XX +XXX,XX @@ static BlockJob *test_block_job_start(unsigned int iterations,
210
g_assert_nonnull(bs);
211
212
snprintf(job_id, sizeof(job_id), "job%u", counter++);
213
- s = block_job_create(job_id, &test_block_job_driver, bs,
214
+ s = block_job_create(job_id, &test_block_job_driver, txn, bs,
215
0, BLK_PERM_ALL, 0, BLOCK_JOB_DEFAULT,
216
test_block_job_cb, data, &error_abort);
217
s->iterations = iterations;
218
@@ -XXX,XX +XXX,XX @@ static void test_single_job(int expected)
219
int result = -EINPROGRESS;
220
221
txn = block_job_txn_new();
222
- job = test_block_job_start(1, true, expected, &result);
223
- block_job_txn_add_job(txn, job);
224
+ job = test_block_job_start(1, true, expected, &result, txn);
225
block_job_start(job);
226
227
if (expected == -ECANCELED) {
228
@@ -XXX,XX +XXX,XX @@ static void test_pair_jobs(int expected1, int expected2)
229
int result2 = -EINPROGRESS;
230
231
txn = block_job_txn_new();
232
- job1 = test_block_job_start(1, true, expected1, &result1);
233
- block_job_txn_add_job(txn, job1);
234
- job2 = test_block_job_start(2, true, expected2, &result2);
235
- block_job_txn_add_job(txn, job2);
236
+ job1 = test_block_job_start(1, true, expected1, &result1, txn);
237
+ job2 = test_block_job_start(2, true, expected2, &result2, txn);
238
block_job_start(job1);
239
block_job_start(job2);
240
241
@@ -XXX,XX +XXX,XX @@ static void test_pair_jobs_fail_cancel_race(void)
242
int result2 = -EINPROGRESS;
243
244
txn = block_job_txn_new();
245
- job1 = test_block_job_start(1, true, -ECANCELED, &result1);
246
- block_job_txn_add_job(txn, job1);
247
- job2 = test_block_job_start(2, false, 0, &result2);
248
- block_job_txn_add_job(txn, job2);
249
+ job1 = test_block_job_start(1, true, -ECANCELED, &result1, txn);
250
+ job2 = test_block_job_start(2, false, 0, &result2, txn);
251
block_job_start(job1);
252
block_job_start(job2);
253
254
diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c
255
index XXXXXXX..XXXXXXX 100644
256
--- a/tests/test-blockjob.c
257
+++ b/tests/test-blockjob.c
258
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_test_id(BlockBackend *blk, const char *id,
259
BlockJob *job;
260
Error *errp = NULL;
261
262
- job = block_job_create(id, &test_block_job_driver, blk_bs(blk),
263
+ job = block_job_create(id, &test_block_job_driver, NULL, blk_bs(blk),
264
0, BLK_PERM_ALL, 0, BLOCK_JOB_DEFAULT, block_job_cb,
265
NULL, &errp);
266
if (should_succeed) {
267
--
176
--
268
2.13.6
177
2.19.1
269
178
270
179
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to qcow, which
1
From: Peter Maydell <peter.maydell@linaro.org>
2
enables image creation over QMP.
3
2
3
Taking the address of a field in a packed struct is a bad idea, because
4
it might not be actually aligned enough for that pointer type (and
5
thus cause a crash on dereference on some host architectures). Newer
6
versions of clang warn about this. Avoid the bug by not using the
7
"modify in place" byte swapping functions.
8
9
There are a few places where the in-place swap function is
10
used on something other than a packed struct field; we convert
11
those anyway, for consistency.
12
13
This patch was produced with the following spatch script:
14
15
@@
16
expression E;
17
@@
18
-be16_to_cpus(&E);
19
+E = be16_to_cpu(E);
20
@@
21
expression E;
22
@@
23
-be32_to_cpus(&E);
24
+E = be32_to_cpu(E);
25
@@
26
expression E;
27
@@
28
-be64_to_cpus(&E);
29
+E = be64_to_cpu(E);
30
@@
31
expression E;
32
@@
33
-cpu_to_be16s(&E);
34
+E = cpu_to_be16(E);
35
@@
36
expression E;
37
@@
38
-cpu_to_be32s(&E);
39
+E = cpu_to_be32(E);
40
@@
41
expression E;
42
@@
43
-cpu_to_be64s(&E);
44
+E = cpu_to_be64(E);
45
46
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
47
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
48
Tested-by: John Snow <jsnow@redhat.com>
49
Reviewed-by: John Snow <jsnow@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
50
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Jeff Cody <jcody@redhat.com>
7
---
51
---
8
qapi/block-core.json | 21 +++++-
52
block/qcow.c | 18 +++++++++---------
9
block/qcow.c | 196 ++++++++++++++++++++++++++++++++++-----------------
53
1 file changed, 9 insertions(+), 9 deletions(-)
10
2 files changed, 150 insertions(+), 67 deletions(-)
11
54
12
diff --git a/qapi/block-core.json b/qapi/block-core.json
13
index XXXXXXX..XXXXXXX 100644
14
--- a/qapi/block-core.json
15
+++ b/qapi/block-core.json
16
@@ -XXX,XX +XXX,XX @@
17
'*cluster-size': 'size' } }
18
19
##
20
+# @BlockdevCreateOptionsQcow:
21
+#
22
+# Driver specific image creation options for qcow.
23
+#
24
+# @file Node to create the image format on
25
+# @size Size of the virtual disk in bytes
26
+# @backing-file File name of the backing file if a backing file
27
+# should be used
28
+# @encrypt Encryption options if the image should be encrypted
29
+#
30
+# Since: 2.12
31
+##
32
+{ 'struct': 'BlockdevCreateOptionsQcow',
33
+ 'data': { 'file': 'BlockdevRef',
34
+ 'size': 'size',
35
+ '*backing-file': 'str',
36
+ '*encrypt': 'QCryptoBlockCreateOptions' } }
37
+
38
+##
39
# @BlockdevQcow2Version:
40
#
41
# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2)
42
@@ -XXX,XX +XXX,XX @@
43
'null-co': 'BlockdevCreateNotSupported',
44
'nvme': 'BlockdevCreateNotSupported',
45
'parallels': 'BlockdevCreateOptionsParallels',
46
+ 'qcow': 'BlockdevCreateOptionsQcow',
47
'qcow2': 'BlockdevCreateOptionsQcow2',
48
- 'qcow': 'BlockdevCreateNotSupported',
49
'qed': 'BlockdevCreateNotSupported',
50
'quorum': 'BlockdevCreateNotSupported',
51
'raw': 'BlockdevCreateNotSupported',
52
diff --git a/block/qcow.c b/block/qcow.c
55
diff --git a/block/qcow.c b/block/qcow.c
53
index XXXXXXX..XXXXXXX 100644
56
index XXXXXXX..XXXXXXX 100644
54
--- a/block/qcow.c
57
--- a/block/qcow.c
55
+++ b/block/qcow.c
58
+++ b/block/qcow.c
56
@@ -XXX,XX +XXX,XX @@
59
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
57
#include <zlib.h>
60
if (ret < 0) {
58
#include "qapi/qmp/qdict.h"
61
goto fail;
59
#include "qapi/qmp/qstring.h"
60
+#include "qapi/qobject-input-visitor.h"
61
+#include "qapi/qapi-visit-block-core.h"
62
#include "crypto/block.h"
63
#include "migration/blocker.h"
64
#include "block/crypto.h"
65
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcowState {
66
Error *migration_blocker;
67
} BDRVQcowState;
68
69
+static QemuOptsList qcow_create_opts;
70
+
71
static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset);
72
73
static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
74
@@ -XXX,XX +XXX,XX @@ static void qcow_close(BlockDriverState *bs)
75
error_free(s->migration_blocker);
76
}
77
78
-static int coroutine_fn qcow_co_create_opts(const char *filename, QemuOpts *opts,
79
- Error **errp)
80
+static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
81
+ Error **errp)
82
{
83
+ BlockdevCreateOptionsQcow *qcow_opts;
84
int header_size, backing_filename_len, l1_size, shift, i;
85
QCowHeader header;
86
uint8_t *tmp;
87
int64_t total_size = 0;
88
- char *backing_file = NULL;
89
- Error *local_err = NULL;
90
int ret;
91
+ BlockDriverState *bs;
92
BlockBackend *qcow_blk;
93
- char *encryptfmt = NULL;
94
- QDict *options;
95
- QDict *encryptopts = NULL;
96
- QCryptoBlockCreateOptions *crypto_opts = NULL;
97
QCryptoBlock *crypto = NULL;
98
99
- /* Read out options */
100
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
101
- BDRV_SECTOR_SIZE);
102
+ assert(opts->driver == BLOCKDEV_DRIVER_QCOW);
103
+ qcow_opts = &opts->u.qcow;
104
+
105
+ /* Sanity checks */
106
+ total_size = qcow_opts->size;
107
if (total_size == 0) {
108
error_setg(errp, "Image size is too small, cannot be zero length");
109
- ret = -EINVAL;
110
- goto cleanup;
111
+ return -EINVAL;
112
}
62
}
113
63
- be32_to_cpus(&header.magic);
114
- backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
64
- be32_to_cpus(&header.version);
115
- encryptfmt = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT);
65
- be64_to_cpus(&header.backing_file_offset);
116
- if (encryptfmt) {
66
- be32_to_cpus(&header.backing_file_size);
117
- if (qemu_opt_get(opts, BLOCK_OPT_ENCRYPT)) {
67
- be32_to_cpus(&header.mtime);
118
- error_setg(errp, "Options " BLOCK_OPT_ENCRYPT " and "
68
- be64_to_cpus(&header.size);
119
- BLOCK_OPT_ENCRYPT_FORMAT " are mutually exclusive");
69
- be32_to_cpus(&header.crypt_method);
120
- ret = -EINVAL;
70
- be64_to_cpus(&header.l1_table_offset);
121
- goto cleanup;
71
+ header.magic = be32_to_cpu(header.magic);
122
- }
72
+ header.version = be32_to_cpu(header.version);
123
- } else if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) {
73
+ header.backing_file_offset = be64_to_cpu(header.backing_file_offset);
124
- encryptfmt = g_strdup("aes");
74
+ header.backing_file_size = be32_to_cpu(header.backing_file_size);
125
+ if (qcow_opts->has_encrypt &&
75
+ header.mtime = be32_to_cpu(header.mtime);
126
+ qcow_opts->encrypt->format != Q_CRYPTO_BLOCK_FORMAT_QCOW)
76
+ header.size = be64_to_cpu(header.size);
127
+ {
77
+ header.crypt_method = be32_to_cpu(header.crypt_method);
128
+ error_setg(errp, "Unsupported encryption format");
78
+ header.l1_table_offset = be64_to_cpu(header.l1_table_offset);
129
+ return -EINVAL;
79
80
if (header.magic != QCOW_MAGIC) {
81
error_setg(errp, "Image not in qcow format");
82
@@ -XXX,XX +XXX,XX @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
130
}
83
}
131
84
132
- ret = bdrv_create_file(filename, opts, &local_err);
85
for(i = 0;i < s->l1_size; i++) {
133
- if (ret < 0) {
86
- be64_to_cpus(&s->l1_table[i]);
134
- error_propagate(errp, local_err);
87
+ s->l1_table[i] = be64_to_cpu(s->l1_table[i]);
135
- goto cleanup;
136
+ /* Create BlockBackend to write to the image */
137
+ bs = bdrv_open_blockdev_ref(qcow_opts->file, errp);
138
+ if (bs == NULL) {
139
+ return -EIO;
140
}
88
}
141
89
142
- qcow_blk = blk_new_open(filename, NULL, NULL,
90
/* alloc L2 cache (max. 64k * 16 * 8 = 8 MB) */
143
- BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
144
- &local_err);
145
- if (qcow_blk == NULL) {
146
- error_propagate(errp, local_err);
147
- ret = -EIO;
148
- goto cleanup;
149
+ qcow_blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
150
+ ret = blk_insert_bs(qcow_blk, bs, errp);
151
+ if (ret < 0) {
152
+ goto exit;
153
}
154
-
155
blk_set_allow_write_beyond_eof(qcow_blk, true);
156
157
+ /* Create image format */
158
ret = blk_truncate(qcow_blk, 0, PREALLOC_MODE_OFF, errp);
159
if (ret < 0) {
160
goto exit;
161
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename, QemuOpts *opts
162
header.size = cpu_to_be64(total_size);
163
header_size = sizeof(header);
164
backing_filename_len = 0;
165
- if (backing_file) {
166
- if (strcmp(backing_file, "fat:")) {
167
+ if (qcow_opts->has_backing_file) {
168
+ if (strcmp(qcow_opts->backing_file, "fat:")) {
169
header.backing_file_offset = cpu_to_be64(header_size);
170
- backing_filename_len = strlen(backing_file);
171
+ backing_filename_len = strlen(qcow_opts->backing_file);
172
header.backing_file_size = cpu_to_be32(backing_filename_len);
173
header_size += backing_filename_len;
174
} else {
175
/* special backing file for vvfat */
176
- g_free(backing_file);
177
- backing_file = NULL;
178
+ qcow_opts->has_backing_file = false;
179
}
180
header.cluster_bits = 9; /* 512 byte cluster to avoid copying
181
unmodified sectors */
182
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename, QemuOpts *opts
183
184
header.l1_table_offset = cpu_to_be64(header_size);
185
186
- options = qemu_opts_to_qdict(opts, NULL);
187
- qdict_extract_subqdict(options, &encryptopts, "encrypt.");
188
- QDECREF(options);
189
- if (encryptfmt) {
190
- if (!g_str_equal(encryptfmt, "aes")) {
191
- error_setg(errp, "Unknown encryption format '%s', expected 'aes'",
192
- encryptfmt);
193
- ret = -EINVAL;
194
- goto exit;
195
- }
196
+ if (qcow_opts->has_encrypt) {
197
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
198
199
- crypto_opts = block_crypto_create_opts_init(
200
- Q_CRYPTO_BLOCK_FORMAT_QCOW, encryptopts, errp);
201
- if (!crypto_opts) {
202
- ret = -EINVAL;
203
- goto exit;
204
- }
205
-
206
- crypto = qcrypto_block_create(crypto_opts, "encrypt.",
207
+ crypto = qcrypto_block_create(qcow_opts->encrypt, "encrypt.",
208
NULL, NULL, NULL, errp);
209
if (!crypto) {
210
ret = -EINVAL;
211
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename, QemuOpts *opts
212
goto exit;
213
}
214
215
- if (backing_file) {
216
+ if (qcow_opts->has_backing_file) {
217
ret = blk_pwrite(qcow_blk, sizeof(header),
218
- backing_file, backing_filename_len, 0);
219
+ qcow_opts->backing_file, backing_filename_len, 0);
220
if (ret != backing_filename_len) {
221
goto exit;
222
}
223
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow_co_create_opts(const char *filename, QemuOpts *opts
224
ret = 0;
225
exit:
226
blk_unref(qcow_blk);
227
-cleanup:
228
- QDECREF(encryptopts);
229
- g_free(encryptfmt);
230
qcrypto_block_free(crypto);
231
- qapi_free_QCryptoBlockCreateOptions(crypto_opts);
232
- g_free(backing_file);
233
+ return ret;
234
+}
235
+
236
+static int coroutine_fn qcow_co_create_opts(const char *filename,
237
+ QemuOpts *opts, Error **errp)
238
+{
239
+ BlockdevCreateOptions *create_options = NULL;
240
+ BlockDriverState *bs = NULL;
241
+ QDict *qdict = NULL;
242
+ QObject *qobj;
243
+ Visitor *v;
244
+ const char *val;
245
+ Error *local_err = NULL;
246
+ int ret;
247
+
248
+ static const QDictRenames opt_renames[] = {
249
+ { BLOCK_OPT_BACKING_FILE, "backing-file" },
250
+ { BLOCK_OPT_ENCRYPT, BLOCK_OPT_ENCRYPT_FORMAT },
251
+ { NULL, NULL },
252
+ };
253
+
254
+ /* Parse options and convert legacy syntax */
255
+ qdict = qemu_opts_to_qdict_filtered(opts, NULL, &qcow_create_opts, true);
256
+
257
+ val = qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT);
258
+ if (val && !strcmp(val, "on")) {
259
+ qdict_put_str(qdict, BLOCK_OPT_ENCRYPT, "qcow");
260
+ } else if (val && !strcmp(val, "off")) {
261
+ qdict_del(qdict, BLOCK_OPT_ENCRYPT);
262
+ }
263
+
264
+ val = qdict_get_try_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT);
265
+ if (val && !strcmp(val, "aes")) {
266
+ qdict_put_str(qdict, BLOCK_OPT_ENCRYPT_FORMAT, "qcow");
267
+ }
268
+
269
+ if (!qdict_rename_keys(qdict, opt_renames, errp)) {
270
+ ret = -EINVAL;
271
+ goto fail;
272
+ }
273
+
274
+ /* Create and open the file (protocol layer) */
275
+ ret = bdrv_create_file(filename, opts, &local_err);
276
+ if (ret < 0) {
277
+ error_propagate(errp, local_err);
278
+ goto fail;
279
+ }
280
+
281
+ bs = bdrv_open(filename, NULL, NULL,
282
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
283
+ if (bs == NULL) {
284
+ ret = -EIO;
285
+ goto fail;
286
+ }
287
+
288
+ /* Now get the QAPI type BlockdevCreateOptions */
289
+ qdict_put_str(qdict, "driver", "qcow");
290
+ qdict_put_str(qdict, "file", bs->node_name);
291
+
292
+ qobj = qdict_crumple(qdict, errp);
293
+ QDECREF(qdict);
294
+ qdict = qobject_to_qdict(qobj);
295
+ if (qdict == NULL) {
296
+ ret = -EINVAL;
297
+ goto fail;
298
+ }
299
+
300
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
301
+ visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
302
+ visit_free(v);
303
+
304
+ if (local_err) {
305
+ error_propagate(errp, local_err);
306
+ ret = -EINVAL;
307
+ goto fail;
308
+ }
309
+
310
+ /* Silently round up size */
311
+ assert(create_options->driver == BLOCKDEV_DRIVER_QCOW);
312
+ create_options->u.qcow.size =
313
+ ROUND_UP(create_options->u.qcow.size, BDRV_SECTOR_SIZE);
314
+
315
+ /* Create the qcow image (format layer) */
316
+ ret = qcow_co_create(create_options, errp);
317
+ if (ret < 0) {
318
+ goto fail;
319
+ }
320
+
321
+ ret = 0;
322
+fail:
323
+ QDECREF(qdict);
324
+ bdrv_unref(bs);
325
+ qapi_free_BlockdevCreateOptions(create_options);
326
return ret;
327
}
328
329
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qcow = {
330
.bdrv_close        = qcow_close,
331
.bdrv_child_perm = bdrv_format_default_perms,
332
.bdrv_reopen_prepare = qcow_reopen_prepare,
333
+ .bdrv_co_create = qcow_co_create,
334
.bdrv_co_create_opts = qcow_co_create_opts,
335
.bdrv_has_zero_init = bdrv_has_zero_init_1,
336
.supports_backing = true,
337
--
91
--
338
2.13.6
92
2.19.1
339
93
340
94
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Peter Maydell <peter.maydell@linaro.org>
2
2
3
Instead of automatically transitioning from PENDING to CONCLUDED, gate
3
Taking the address of a field in a packed struct is a bad idea, because
4
the .prepare() and .commit() phases behind an explicit acknowledgement
4
it might not be actually aligned enough for that pointer type (and
5
provided by the QMP monitor if auto_finalize = false has been requested.
5
thus cause a crash on dereference on some host architectures). Newer
6
versions of clang warn about this. Avoid the bug by not using the
7
"modify in place" byte swapping functions.
6
8
7
This allows us to perform graph changes in prepare and/or commit so that
9
There are a few places where the in-place swap function is
8
graph changes do not occur autonomously without knowledge of the
10
used on something other than a packed struct field; we convert
9
controlling management layer.
11
those anyway, for consistency.
10
12
11
Transactions that have reached the "PENDING" state together can all be
13
This patch was produced with the following spatch script:
12
moved to invoke their finalization methods by issuing block_job_finalize
13
to any one job in the transaction.
14
14
15
Jobs in a transaction with mixed job->auto_finalize settings will all
15
@@
16
remain stuck in the "PENDING" state, as if the entire transaction was
16
expression E;
17
specified with auto_finalize = false. Jobs that specified
17
@@
18
auto_finalize = true, however, will still not emit the PENDING event.
18
-be16_to_cpus(&E);
19
+E = be16_to_cpu(E);
20
@@
21
expression E;
22
@@
23
-be32_to_cpus(&E);
24
+E = be32_to_cpu(E);
25
@@
26
expression E;
27
@@
28
-be64_to_cpus(&E);
29
+E = be64_to_cpu(E);
30
@@
31
expression E;
32
@@
33
-cpu_to_be16s(&E);
34
+E = cpu_to_be16(E);
35
@@
36
expression E;
37
@@
38
-cpu_to_be32s(&E);
39
+E = cpu_to_be32(E);
40
@@
41
expression E;
42
@@
43
-cpu_to_be64s(&E);
44
+E = cpu_to_be64(E);
19
45
20
Signed-off-by: John Snow <jsnow@redhat.com>
46
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
47
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
48
Tested-by: John Snow <jsnow@redhat.com>
49
Reviewed-by: John Snow <jsnow@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
50
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
51
---
23
qapi/block-core.json | 23 ++++++++++++++++++-
52
block/qcow2-bitmap.c | 24 ++++++++++++------------
24
include/block/blockjob.h | 17 ++++++++++++++
53
1 file changed, 12 insertions(+), 12 deletions(-)
25
blockdev.c | 14 +++++++++++
26
blockjob.c | 60 +++++++++++++++++++++++++++++++++++-------------
27
block/trace-events | 1 +
28
5 files changed, 98 insertions(+), 17 deletions(-)
29
54
30
diff --git a/qapi/block-core.json b/qapi/block-core.json
55
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
31
index XXXXXXX..XXXXXXX 100644
56
index XXXXXXX..XXXXXXX 100644
32
--- a/qapi/block-core.json
57
--- a/block/qcow2-bitmap.c
33
+++ b/qapi/block-core.json
58
+++ b/block/qcow2-bitmap.c
34
@@ -XXX,XX +XXX,XX @@
59
@@ -XXX,XX +XXX,XX @@ static inline void bitmap_table_to_be(uint64_t *bitmap_table, size_t size)
35
#
60
size_t i;
36
# @dismiss: see @block-job-dismiss
61
37
#
62
for (i = 0; i < size; ++i) {
38
+# @finalize: see @block-job-finalize
63
- cpu_to_be64s(&bitmap_table[i]);
39
+#
64
+ bitmap_table[i] = cpu_to_be64(bitmap_table[i]);
40
# Since: 2.12
41
##
42
{ 'enum': 'BlockJobVerb',
43
- 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete', 'dismiss' ] }
44
+ 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete', 'dismiss',
45
+ 'finalize' ] }
46
47
##
48
# @BlockJobStatus:
49
@@ -XXX,XX +XXX,XX @@
50
{ 'command': 'block-job-dismiss', 'data': { 'id': 'str' } }
51
52
##
53
+# @block-job-finalize:
54
+#
55
+# Once a job that has manual=true reaches the pending state, it can be
56
+# instructed to finalize any graph changes and do any necessary cleanup
57
+# via this command.
58
+# For jobs in a transaction, instructing one job to finalize will force
59
+# ALL jobs in the transaction to finalize, so it is only necessary to instruct
60
+# a single member job to finalize.
61
+#
62
+# @id: The job identifier.
63
+#
64
+# Returns: Nothing on success
65
+#
66
+# Since: 2.12
67
+##
68
+{ 'command': 'block-job-finalize', 'data': { 'id': 'str' } }
69
+
70
+##
71
# @BlockdevDiscardOptions:
72
#
73
# Determines how to handle discard requests.
74
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
75
index XXXXXXX..XXXXXXX 100644
76
--- a/include/block/blockjob.h
77
+++ b/include/block/blockjob.h
78
@@ -XXX,XX +XXX,XX @@ void block_job_cancel(BlockJob *job);
79
*/
80
void block_job_complete(BlockJob *job, Error **errp);
81
82
+
83
+/**
84
+ * block_job_finalize:
85
+ * @job: The job to fully commit and finish.
86
+ * @errp: Error object.
87
+ *
88
+ * For jobs that have finished their work and are pending
89
+ * awaiting explicit acknowledgement to commit their work,
90
+ * This will commit that work.
91
+ *
92
+ * FIXME: Make the below statement universally true:
93
+ * For jobs that support the manual workflow mode, all graph
94
+ * changes that occur as a result will occur after this command
95
+ * and before a successful reply.
96
+ */
97
+void block_job_finalize(BlockJob *job, Error **errp);
98
+
99
/**
100
* block_job_dismiss:
101
* @job: The job to be dismissed.
102
diff --git a/blockdev.c b/blockdev.c
103
index XXXXXXX..XXXXXXX 100644
104
--- a/blockdev.c
105
+++ b/blockdev.c
106
@@ -XXX,XX +XXX,XX @@ void qmp_block_job_complete(const char *device, Error **errp)
107
aio_context_release(aio_context);
108
}
109
110
+void qmp_block_job_finalize(const char *id, Error **errp)
111
+{
112
+ AioContext *aio_context;
113
+ BlockJob *job = find_block_job(id, &aio_context, errp);
114
+
115
+ if (!job) {
116
+ return;
117
+ }
118
+
119
+ trace_qmp_block_job_finalize(job);
120
+ block_job_finalize(job, errp);
121
+ aio_context_release(aio_context);
122
+}
123
+
124
void qmp_block_job_dismiss(const char *id, Error **errp)
125
{
126
AioContext *aio_context;
127
diff --git a/blockjob.c b/blockjob.c
128
index XXXXXXX..XXXXXXX 100644
129
--- a/blockjob.c
130
+++ b/blockjob.c
131
@@ -XXX,XX +XXX,XX @@ bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] = {
132
[BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
133
[BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
134
[BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
135
+ [BLOCK_JOB_VERB_FINALIZE] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
136
[BLOCK_JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
137
};
138
139
@@ -XXX,XX +XXX,XX @@ static void block_job_clean(BlockJob *job)
140
}
65
}
141
}
66
}
142
67
143
-static int block_job_completed_single(BlockJob *job)
68
@@ -XXX,XX +XXX,XX @@ static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb,
144
+static int block_job_finalize_single(BlockJob *job)
69
}
70
71
for (i = 0; i < tb->size; ++i) {
72
- be64_to_cpus(&table[i]);
73
+ table[i] = be64_to_cpu(table[i]);
74
ret = check_table_entry(table[i], s->cluster_size);
75
if (ret < 0) {
76
goto fail;
77
@@ -XXX,XX +XXX,XX @@ fail:
78
79
static inline void bitmap_dir_entry_to_cpu(Qcow2BitmapDirEntry *entry)
145
{
80
{
146
assert(job->completed);
81
- be64_to_cpus(&entry->bitmap_table_offset);
147
82
- be32_to_cpus(&entry->bitmap_table_size);
148
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_txn_abort(BlockJob *job)
83
- be32_to_cpus(&entry->flags);
149
assert(other_job->cancelled);
84
- be16_to_cpus(&entry->name_size);
150
block_job_finish_sync(other_job, NULL, NULL);
85
- be32_to_cpus(&entry->extra_data_size);
151
}
86
+ entry->bitmap_table_offset = be64_to_cpu(entry->bitmap_table_offset);
152
- block_job_completed_single(other_job);
87
+ entry->bitmap_table_size = be32_to_cpu(entry->bitmap_table_size);
153
+ block_job_finalize_single(other_job);
88
+ entry->flags = be32_to_cpu(entry->flags);
154
aio_context_release(ctx);
89
+ entry->name_size = be16_to_cpu(entry->name_size);
155
}
90
+ entry->extra_data_size = be32_to_cpu(entry->extra_data_size);
156
157
block_job_txn_unref(txn);
158
}
91
}
159
92
160
+static int block_job_needs_finalize(BlockJob *job)
93
static inline void bitmap_dir_entry_to_be(Qcow2BitmapDirEntry *entry)
161
+{
162
+ return !job->auto_finalize;
163
+}
164
+
165
+static void block_job_do_finalize(BlockJob *job)
166
+{
167
+ int rc;
168
+ assert(job && job->txn);
169
+
170
+ /* prepare the transaction to complete */
171
+ rc = block_job_txn_apply(job->txn, block_job_prepare, true);
172
+ if (rc) {
173
+ block_job_completed_txn_abort(job);
174
+ } else {
175
+ block_job_txn_apply(job->txn, block_job_finalize_single, true);
176
+ }
177
+}
178
+
179
static void block_job_completed_txn_success(BlockJob *job)
180
{
94
{
181
BlockJobTxn *txn = job->txn;
95
- cpu_to_be64s(&entry->bitmap_table_offset);
182
BlockJob *other_job;
96
- cpu_to_be32s(&entry->bitmap_table_size);
183
- int rc = 0;
97
- cpu_to_be32s(&entry->flags);
184
98
- cpu_to_be16s(&entry->name_size);
185
block_job_state_transition(job, BLOCK_JOB_STATUS_WAITING);
99
- cpu_to_be32s(&entry->extra_data_size);
186
100
+ entry->bitmap_table_offset = cpu_to_be64(entry->bitmap_table_offset);
187
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_txn_success(BlockJob *job)
101
+ entry->bitmap_table_size = cpu_to_be32(entry->bitmap_table_size);
188
assert(other_job->ret == 0);
102
+ entry->flags = cpu_to_be32(entry->flags);
189
}
103
+ entry->name_size = cpu_to_be16(entry->name_size);
190
104
+ entry->extra_data_size = cpu_to_be32(entry->extra_data_size);
191
- /* Jobs may require some prep-work to complete without failure */
192
- rc = block_job_txn_apply(txn, block_job_prepare, true);
193
- if (rc) {
194
- block_job_completed_txn_abort(job);
195
- return;
196
- }
197
-
198
- /* We are the last completed job, commit the transaction. */
199
block_job_txn_apply(txn, block_job_event_pending, false);
200
- block_job_txn_apply(txn, block_job_completed_single, true);
201
+
202
+ /* If no jobs need manual finalization, automatically do so */
203
+ if (block_job_txn_apply(txn, block_job_needs_finalize, false) == 0) {
204
+ block_job_do_finalize(job);
205
+ }
206
}
105
}
207
106
208
/* Assumes the block_job_mutex is held */
107
static inline int calc_dir_entry_size(size_t name_size, size_t extra_data_size)
209
@@ -XXX,XX +XXX,XX @@ void block_job_complete(BlockJob *job, Error **errp)
210
job->driver->complete(job, errp);
211
}
212
213
+void block_job_finalize(BlockJob *job, Error **errp)
214
+{
215
+ assert(job && job->id && job->txn);
216
+ if (block_job_apply_verb(job, BLOCK_JOB_VERB_FINALIZE, errp)) {
217
+ return;
218
+ }
219
+ block_job_do_finalize(job);
220
+}
221
+
222
void block_job_dismiss(BlockJob **jobptr, Error **errp)
223
{
224
BlockJob *job = *jobptr;
225
@@ -XXX,XX +XXX,XX @@ void block_job_cancel(BlockJob *job)
226
{
227
if (job->status == BLOCK_JOB_STATUS_CONCLUDED) {
228
block_job_do_dismiss(job);
229
- } else if (block_job_started(job)) {
230
- block_job_cancel_async(job);
231
- block_job_enter(job);
232
- } else {
233
+ return;
234
+ }
235
+ block_job_cancel_async(job);
236
+ if (!block_job_started(job)) {
237
block_job_completed(job, -ECANCELED);
238
+ } else if (job->deferred_to_main_loop) {
239
+ block_job_completed_txn_abort(job);
240
+ } else {
241
+ block_job_enter(job);
242
}
243
}
244
245
diff --git a/block/trace-events b/block/trace-events
246
index XXXXXXX..XXXXXXX 100644
247
--- a/block/trace-events
248
+++ b/block/trace-events
249
@@ -XXX,XX +XXX,XX @@ qmp_block_job_cancel(void *job) "job %p"
250
qmp_block_job_pause(void *job) "job %p"
251
qmp_block_job_resume(void *job) "job %p"
252
qmp_block_job_complete(void *job) "job %p"
253
+qmp_block_job_finalize(void *job) "job %p"
254
qmp_block_job_dismiss(void *job) "job %p"
255
qmp_block_stream(void *bs, void *job) "bs %p job %p"
256
257
--
108
--
258
2.13.6
109
2.19.1
259
110
260
111
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Daniel P. Berrangé <berrange@redhat.com>
2
2
3
For jobs that are stuck waiting on others in a transaction, it would
3
The qcow2 block driver expects to see a valid sector size even when it
4
be nice to know that they are no longer "running" in that sense, but
4
has opened the crypto layer with QCRYPTO_BLOCK_OPEN_NO_IO.
5
instead are waiting on other jobs in the transaction.
6
5
7
Jobs that are "waiting" in this sense cannot be meaningfully altered
6
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
8
any longer as they have left their running loop. The only meaningful
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
user verb for jobs in this state is "cancel," which will cancel the
10
whole transaction, too.
11
12
Transitions:
13
Running -> Waiting: Normal transition.
14
Ready -> Waiting: Normal transition.
15
Waiting -> Aborting: Transactional cancellation.
16
Waiting -> Concluded: Normal transition.
17
18
Removed Transitions:
19
Running -> Concluded: Jobs must go to WAITING first.
20
Ready -> Concluded: Jobs must go to WAITING first.
21
22
Verbs:
23
Cancel: Can be applied to WAITING jobs.
24
25
+---------+
26
|UNDEFINED|
27
+--+------+
28
|
29
+--v----+
30
+---------+CREATED+-----------------+
31
| +--+----+ |
32
| | |
33
| +--v----+ +------+ |
34
+---------+RUNNING<----->PAUSED| |
35
| +--+-+--+ +------+ |
36
| | | |
37
| | +------------------+ |
38
| | | |
39
| +--v--+ +-------+ | |
40
+---------+READY<------->STANDBY| | |
41
| +--+--+ +-------+ | |
42
| | | |
43
| +--v----+ | |
44
+---------+WAITING<---------------+ |
45
| +--+----+ |
46
| | |
47
+--v-----+ +--v------+ |
48
|ABORTING+--->CONCLUDED| |
49
+--------+ +--+------+ |
50
| |
51
+--v-+ |
52
|NULL<--------------------+
53
+----+
54
55
Signed-off-by: John Snow <jsnow@redhat.com>
56
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
57
---
9
---
58
qapi/block-core.json | 6 +++++-
10
crypto/block-qcow.c | 2 ++
59
blockjob.c | 37 ++++++++++++++++++++-----------------
11
1 file changed, 2 insertions(+)
60
2 files changed, 25 insertions(+), 18 deletions(-)
61
12
62
diff --git a/qapi/block-core.json b/qapi/block-core.json
13
diff --git a/crypto/block-qcow.c b/crypto/block-qcow.c
63
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
64
--- a/qapi/block-core.json
15
--- a/crypto/block-qcow.c
65
+++ b/qapi/block-core.json
16
+++ b/crypto/block-qcow.c
66
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@ qcrypto_block_qcow_open(QCryptoBlock *block,
67
# @standby: The job is ready, but paused. This is nearly identical to @paused.
18
Error **errp)
68
# The job may return to @ready or otherwise be canceled.
19
{
69
#
20
if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) {
70
+# @waiting: The job is waiting for other jobs in the transaction to converge
21
+ block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE;
71
+# to the waiting state. This status will likely not be visible for
22
+ block->payload_offset = 0;
72
+# the last job in a transaction.
23
return 0;
73
+#
24
} else {
74
# @aborting: The job is in the process of being aborted, and will finish with
25
if (!options->u.qcow.key_secret) {
75
# an error. The job will afterwards report that it is @concluded.
76
# This status may not be visible to the management process.
77
@@ -XXX,XX +XXX,XX @@
78
##
79
{ 'enum': 'BlockJobStatus',
80
'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby',
81
- 'aborting', 'concluded', 'null' ] }
82
+ 'waiting', 'aborting', 'concluded', 'null' ] }
83
84
##
85
# @BlockJobInfo:
86
diff --git a/blockjob.c b/blockjob.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/blockjob.c
89
+++ b/blockjob.c
90
@@ -XXX,XX +XXX,XX @@ static QemuMutex block_job_mutex;
91
92
/* BlockJob State Transition Table */
93
bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] = {
94
- /* U, C, R, P, Y, S, X, E, N */
95
- /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0, 0},
96
- /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 1, 0, 1},
97
- /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1, 1, 0},
98
- /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0, 0},
99
- /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 1, 0},
100
- /* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0, 0},
101
- /* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 1, 1, 0},
102
- /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0, 1},
103
- /* N: */ [BLOCK_JOB_STATUS_NULL] = {0, 0, 0, 0, 0, 0, 0, 0, 0},
104
+ /* U, C, R, P, Y, S, W, X, E, N */
105
+ /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
106
+ /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 0, 1, 0, 1},
107
+ /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1, 1, 0, 0},
108
+ /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
109
+ /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 1, 0, 0},
110
+ /* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
111
+ /* W: */ [BLOCK_JOB_STATUS_WAITING] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
112
+ /* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
113
+ /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
114
+ /* N: */ [BLOCK_JOB_STATUS_NULL] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
115
};
116
117
bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] = {
118
- /* U, C, R, P, Y, S, X, E, N */
119
- [BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 0, 0, 0},
120
- [BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0, 0, 0},
121
- [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0},
122
- [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0},
123
- [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0, 0},
124
- [BLOCK_JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 1, 0},
125
+ /* U, C, R, P, Y, S, W, X, E, N */
126
+ [BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 1, 0, 0, 0},
127
+ [BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0},
128
+ [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0},
129
+ [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0},
130
+ [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
131
+ [BLOCK_JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
132
};
133
134
static void block_job_state_transition(BlockJob *job, BlockJobStatus s1)
135
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_txn_success(BlockJob *job)
136
BlockJob *other_job;
137
int rc = 0;
138
139
+ block_job_state_transition(job, BLOCK_JOB_STATUS_WAITING);
140
+
141
/*
142
* Successful completion, see if there are other running jobs in this
143
* txn.
144
--
26
--
145
2.13.6
27
2.19.1
146
28
147
29
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Simply apply a function transaction-wide.
3
This doesn't have any practical effect at the moment because the
4
A few more uses of this in forthcoming patches.
4
values of BDRV_SECTOR_SIZE, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE and
5
QCRYPTO_BLOCK_QCOW_SECTOR_SIZE are all the same (512 bytes), but
6
future encryption methods could have different requirements.
5
7
6
Signed-off-by: John Snow <jsnow@redhat.com>
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
11
---
9
blockjob.c | 25 ++++++++++++++++---------
12
block/qcow2.c | 2 +-
10
1 file changed, 16 insertions(+), 9 deletions(-)
13
1 file changed, 1 insertion(+), 1 deletion(-)
11
14
12
diff --git a/blockjob.c b/blockjob.c
15
diff --git a/block/qcow2.c b/block/qcow2.c
13
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
14
--- a/blockjob.c
17
--- a/block/qcow2.c
15
+++ b/blockjob.c
18
+++ b/block/qcow2.c
16
@@ -XXX,XX +XXX,XX @@ static void block_job_cancel_async(BlockJob *job)
19
@@ -XXX,XX +XXX,XX @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
17
job->cancelled = true;
20
18
}
21
if (bs->encrypted) {
19
22
/* Encryption works on a sector granularity */
20
+static void block_job_txn_apply(BlockJobTxn *txn, void fn(BlockJob *))
23
- bs->bl.request_alignment = BDRV_SECTOR_SIZE;
21
+{
24
+ bs->bl.request_alignment = qcrypto_block_get_sector_size(s->crypto);
22
+ AioContext *ctx;
23
+ BlockJob *job, *next;
24
+
25
+ QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) {
26
+ ctx = blk_get_aio_context(job->blk);
27
+ aio_context_acquire(ctx);
28
+ fn(job);
29
+ aio_context_release(ctx);
30
+ }
31
+}
32
+
33
static int block_job_finish_sync(BlockJob *job,
34
void (*finish)(BlockJob *, Error **errp),
35
Error **errp)
36
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_txn_abort(BlockJob *job)
37
38
static void block_job_completed_txn_success(BlockJob *job)
39
{
40
- AioContext *ctx;
41
BlockJobTxn *txn = job->txn;
42
- BlockJob *other_job, *next;
43
+ BlockJob *other_job;
44
/*
45
* Successful completion, see if there are other running jobs in this
46
* txn.
47
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_txn_success(BlockJob *job)
48
if (!other_job->completed) {
49
return;
50
}
51
- }
52
- /* We are the last completed job, commit the transaction. */
53
- QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) {
54
- ctx = blk_get_aio_context(other_job->blk);
55
- aio_context_acquire(ctx);
56
assert(other_job->ret == 0);
57
- block_job_completed_single(other_job);
58
- aio_context_release(ctx);
59
}
25
}
60
+ /* We are the last completed job, commit the transaction. */
26
bs->bl.pwrite_zeroes_alignment = s->cluster_size;
61
+ block_job_txn_apply(txn, block_job_completed_single);
27
bs->bl.pdiscard_alignment = s->cluster_size;
62
}
63
64
/* Assumes the block_job_mutex is held */
65
--
28
--
66
2.13.6
29
2.19.1
67
30
68
31
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Li Qiang <liq3ea@163.com>
2
2
3
Some jobs upon finalization may need to perform some work that can
3
Signed-off-by: Li Qiang <liq3ea@163.com>
4
still fail. If these jobs are part of a transaction, it's important
4
Reviewed-by: Alberto Garcia <berto@igalia.com>
5
that these callbacks fail the entire transaction.
6
7
We allow for a new callback in addition to commit/abort/clean that
8
allows us the opportunity to have fairly late-breaking failures
9
in the transactional process.
10
11
The expected flow is:
12
13
- All jobs in a transaction converge to the PENDING state,
14
added in a forthcoming commit.
15
- Upon being finalized, either automatically or explicitly
16
by the user, jobs prepare to complete.
17
- If any job fails preparation, all jobs call .abort.
18
- Otherwise, they succeed and call .commit.
19
20
Signed-off-by: John Snow <jsnow@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
6
---
23
include/block/blockjob_int.h | 10 ++++++++++
7
include/sysemu/block-backend.h | 6 +++---
24
blockjob.c | 30 +++++++++++++++++++++++++++---
8
block/block-backend.c | 8 ++++----
25
2 files changed, 37 insertions(+), 3 deletions(-)
9
2 files changed, 7 insertions(+), 7 deletions(-)
26
10
27
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
11
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
28
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
29
--- a/include/block/blockjob_int.h
13
--- a/include/sysemu/block-backend.h
30
+++ b/include/block/blockjob_int.h
14
+++ b/include/sysemu/block-backend.h
31
@@ -XXX,XX +XXX,XX @@ struct BlockJobDriver {
15
@@ -XXX,XX +XXX,XX @@ BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read,
32
void (*complete)(BlockJob *job, Error **errp);
16
int error);
33
17
void blk_error_action(BlockBackend *blk, BlockErrorAction action,
34
/**
18
bool is_read, int error);
35
+ * If the callback is not NULL, prepare will be invoked when all the jobs
19
-int blk_is_read_only(BlockBackend *blk);
36
+ * belonging to the same transaction complete; or upon this job's completion
20
-int blk_is_sg(BlockBackend *blk);
37
+ * if it is not in a transaction.
21
-int blk_enable_write_cache(BlockBackend *blk);
38
+ *
22
+bool blk_is_read_only(BlockBackend *blk);
39
+ * This callback will not be invoked if the job has already failed.
23
+bool blk_is_sg(BlockBackend *blk);
40
+ * If it fails, abort and then clean will be called.
24
+bool blk_enable_write_cache(BlockBackend *blk);
41
+ */
25
void blk_set_enable_write_cache(BlockBackend *blk, bool wce);
42
+ int (*prepare)(BlockJob *job);
26
void blk_invalidate_cache(BlockBackend *blk, Error **errp);
43
+
27
bool blk_is_inserted(BlockBackend *blk);
44
+ /**
28
diff --git a/block/block-backend.c b/block/block-backend.c
45
* If the callback is not NULL, it will be invoked when all the jobs
46
* belonging to the same transaction complete; or upon this job's
47
* completion if it is not in a transaction. Skipped if NULL.
48
diff --git a/blockjob.c b/blockjob.c
49
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
50
--- a/blockjob.c
30
--- a/block/block-backend.c
51
+++ b/blockjob.c
31
+++ b/block/block-backend.c
52
@@ -XXX,XX +XXX,XX @@ static void block_job_update_rc(BlockJob *job)
32
@@ -XXX,XX +XXX,XX @@ void blk_error_action(BlockBackend *blk, BlockErrorAction action,
53
}
33
}
54
}
34
}
55
35
56
+static int block_job_prepare(BlockJob *job)
36
-int blk_is_read_only(BlockBackend *blk)
57
+{
37
+bool blk_is_read_only(BlockBackend *blk)
58
+ if (job->ret == 0 && job->driver->prepare) {
59
+ job->ret = job->driver->prepare(job);
60
+ }
61
+ return job->ret;
62
+}
63
+
64
static void block_job_commit(BlockJob *job)
65
{
38
{
66
assert(!job->ret);
39
BlockDriverState *bs = blk_bs(blk);
67
@@ -XXX,XX +XXX,XX @@ static void block_job_clean(BlockJob *job)
40
41
@@ -XXX,XX +XXX,XX @@ int blk_is_read_only(BlockBackend *blk)
68
}
42
}
69
}
43
}
70
44
71
-static void block_job_completed_single(BlockJob *job)
45
-int blk_is_sg(BlockBackend *blk)
72
+static int block_job_completed_single(BlockJob *job)
46
+bool blk_is_sg(BlockBackend *blk)
73
{
47
{
74
assert(job->completed);
48
BlockDriverState *bs = blk_bs(blk);
75
49
76
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_single(BlockJob *job)
50
if (!bs) {
77
QLIST_REMOVE(job, txn_list);
51
- return 0;
78
block_job_txn_unref(job->txn);
52
+ return false;
79
block_job_conclude(job);
53
}
80
+ return 0;
54
55
return bdrv_is_sg(bs);
81
}
56
}
82
57
83
static void block_job_cancel_async(BlockJob *job)
58
-int blk_enable_write_cache(BlockBackend *blk)
84
@@ -XXX,XX +XXX,XX @@ static void block_job_cancel_async(BlockJob *job)
59
+bool blk_enable_write_cache(BlockBackend *blk)
85
job->cancelled = true;
86
}
87
88
-static void block_job_txn_apply(BlockJobTxn *txn, void fn(BlockJob *))
89
+static int block_job_txn_apply(BlockJobTxn *txn, int fn(BlockJob *))
90
{
60
{
91
AioContext *ctx;
61
return blk->enable_write_cache;
92
BlockJob *job, *next;
93
+ int rc;
94
95
QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) {
96
ctx = blk_get_aio_context(job->blk);
97
aio_context_acquire(ctx);
98
- fn(job);
99
+ rc = fn(job);
100
aio_context_release(ctx);
101
+ if (rc) {
102
+ break;
103
+ }
104
}
105
+ return rc;
106
}
107
108
static int block_job_finish_sync(BlockJob *job,
109
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_txn_success(BlockJob *job)
110
{
111
BlockJobTxn *txn = job->txn;
112
BlockJob *other_job;
113
+ int rc = 0;
114
+
115
/*
116
* Successful completion, see if there are other running jobs in this
117
* txn.
118
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_txn_success(BlockJob *job)
119
}
120
assert(other_job->ret == 0);
121
}
122
+
123
+ /* Jobs may require some prep-work to complete without failure */
124
+ rc = block_job_txn_apply(txn, block_job_prepare);
125
+ if (rc) {
126
+ block_job_completed_txn_abort(job);
127
+ return;
128
+ }
129
+
130
/* We are the last completed job, commit the transaction. */
131
block_job_txn_apply(txn, block_job_completed_single);
132
}
62
}
133
--
63
--
134
2.13.6
64
2.19.1
135
65
136
66
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Cleber Rosa <crosa@redhat.com>
2
2
3
Presently, even if a job is canceled post-completion as a result of
3
While testing the Python 3 changes which touch the 083 test, I noticed
4
a failing peer in a transaction, it will still call .commit because
4
that it would fail with qcow2. Expanding the testing, I noticed it
5
nothing has updated or changed its return code.
5
had nothing to do with the Python 3 changes, and in fact, it would not
6
pass on anything but raw:
6
7
7
The reason why this does not cause problems currently is because
8
raw: pass
8
backup's implementation of .commit checks for cancellation itself.
9
bochs: not generic
10
cloop: not generic
11
parallels: fail
12
qcow: fail
13
qcow2: fail
14
qed: fail
15
vdi: fail
16
vhdx: fail
17
vmdk: fail
18
vpc: fail
19
luks: fail
9
20
10
I'd like to simplify this contract:
21
The errors are a mixture I/O and "image not in xxx format", such as:
11
22
12
(1) Abort is called if the job/transaction fails
23
=== Check disconnect before data ===
13
(2) Commit is called if the job/transaction succeeds
14
24
15
To this end: A job's return code, if 0, will be forcibly set as
25
Unexpected end-of-file before all bytes were read
16
-ECANCELED if that job has already concluded. Remove the now
26
-read failed: Input/output error
17
redundant check in the backup job implementation.
27
+can't open device nbd+tcp://127.0.0.1:PORT/foo: Could not open 'nbd://127.0.0.1:PORT/foo': Input/output error
18
28
19
We need to check for cancellation in both block_job_completed
29
=== Check disconnect after data ===
20
AND block_job_completed_single, because jobs may be cancelled between
21
those two calls; for instance in transactions. This also necessitates
22
an ABORTING -> ABORTING transition to be allowed.
23
30
24
The check in block_job_completed could be removed, but there's no
31
-read 512/512 bytes at offset 0
25
point in starting to attempt to succeed a transaction that we know
32
-512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
26
in advance will fail.
33
+can't open device nbd+tcp://127.0.0.1:PORT/foo: Image not in qcow format
27
34
28
This does NOT affect mirror jobs that are "canceled" during their
35
I'm not aware if there's a quick fix, so, for the time being, it looks
29
synchronous phase. The mirror job itself forcibly sets the canceled
36
like the honest approach is to make the test known to work on raw
30
property to false prior to ceding control, so such cases will invoke
37
only.
31
the "commit" callback.
32
38
33
Signed-off-by: John Snow <jsnow@redhat.com>
39
Signed-off-by: Cleber Rosa <crosa@redhat.com>
34
Reviewed-by: Eric Blake <eblake@redhat.com>
35
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
36
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
40
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
37
---
41
---
38
block/backup.c | 2 +-
42
tests/qemu-iotests/083 | 2 +-
39
blockjob.c | 21 ++++++++++++++++-----
43
1 file changed, 1 insertion(+), 1 deletion(-)
40
block/trace-events | 1 +
41
3 files changed, 18 insertions(+), 6 deletions(-)
42
44
43
diff --git a/block/backup.c b/block/backup.c
45
diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083
44
index XXXXXXX..XXXXXXX 100644
46
index XXXXXXX..XXXXXXX 100755
45
--- a/block/backup.c
47
--- a/tests/qemu-iotests/083
46
+++ b/block/backup.c
48
+++ b/tests/qemu-iotests/083
47
@@ -XXX,XX +XXX,XX @@ static void backup_cleanup_sync_bitmap(BackupBlockJob *job, int ret)
49
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
48
BdrvDirtyBitmap *bm;
50
. ./common.rc
49
BlockDriverState *bs = blk_bs(job->common.blk);
51
. ./common.filter
50
52
51
- if (ret < 0 || block_job_is_cancelled(&job->common)) {
53
-_supported_fmt generic
52
+ if (ret < 0) {
54
+_supported_fmt raw
53
/* Merge the successor back into the parent, delete nothing. */
55
_supported_proto nbd
54
bm = bdrv_reclaim_dirty_bitmap(bs, job->sync_bitmap, NULL);
56
_supported_os Linux
55
assert(bm);
56
diff --git a/blockjob.c b/blockjob.c
57
index XXXXXXX..XXXXXXX 100644
58
--- a/blockjob.c
59
+++ b/blockjob.c
60
@@ -XXX,XX +XXX,XX @@ bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] = {
61
/* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0, 0},
62
/* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 1, 0},
63
/* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0, 0},
64
- /* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0, 1, 0},
65
+ /* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 1, 1, 0},
66
/* E: */ [BLOCK_JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0, 1},
67
/* N: */ [BLOCK_JOB_STATUS_NULL] = {0, 0, 0, 0, 0, 0, 0, 0, 0},
68
};
69
@@ -XXX,XX +XXX,XX @@ static void block_job_conclude(BlockJob *job)
70
}
71
}
72
73
+static void block_job_update_rc(BlockJob *job)
74
+{
75
+ if (!job->ret && block_job_is_cancelled(job)) {
76
+ job->ret = -ECANCELED;
77
+ }
78
+ if (job->ret) {
79
+ block_job_state_transition(job, BLOCK_JOB_STATUS_ABORTING);
80
+ }
81
+}
82
+
83
static void block_job_completed_single(BlockJob *job)
84
{
85
assert(job->completed);
86
87
- if (job->ret || block_job_is_cancelled(job)) {
88
- block_job_state_transition(job, BLOCK_JOB_STATUS_ABORTING);
89
- }
90
+ /* Ensure abort is called for late-transactional failures */
91
+ block_job_update_rc(job);
92
93
if (!job->ret) {
94
if (job->driver->commit) {
95
@@ -XXX,XX +XXX,XX @@ void block_job_completed(BlockJob *job, int ret)
96
assert(blk_bs(job->blk)->job == job);
97
job->completed = true;
98
job->ret = ret;
99
- if (ret < 0 || block_job_is_cancelled(job)) {
100
+ block_job_update_rc(job);
101
+ trace_block_job_completed(job, ret, job->ret);
102
+ if (job->ret) {
103
block_job_completed_txn_abort(job);
104
} else {
105
block_job_completed_txn_success(job);
106
diff --git a/block/trace-events b/block/trace-events
107
index XXXXXXX..XXXXXXX 100644
108
--- a/block/trace-events
109
+++ b/block/trace-events
110
@@ -XXX,XX +XXX,XX @@ bdrv_open_common(void *bs, const char *filename, int flags, const char *format_n
111
bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
112
113
# blockjob.c
114
+block_job_completed(void *job, int ret, int jret) "job %p ret %d corrected ret %d"
115
block_job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)"
116
block_job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)"
117
57
118
--
58
--
119
2.13.6
59
2.19.1
120
60
121
61
diff view generated by jsdifflib
1
Perform the rounding to match a CHS geometry only in the legacy code
2
path in .bdrv_co_create_opts. QMP now requires that the user already
3
passes a CHS aligned image size, unless force-size=true is given.
4
5
CHS alignment is required to make the image compatible with Virtual PC,
6
but not for use with newer Microsoft hypervisors.
7
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
2
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
---
3
---
11
block/vpc.c | 113 +++++++++++++++++++++++++++++++++++++++++++-----------------
4
block/vpc.c | 2 ++
12
1 file changed, 82 insertions(+), 31 deletions(-)
5
1 file changed, 2 insertions(+)
13
6
14
diff --git a/block/vpc.c b/block/vpc.c
7
diff --git a/block/vpc.c b/block/vpc.c
15
index XXXXXXX..XXXXXXX 100644
8
index XXXXXXX..XXXXXXX 100644
16
--- a/block/vpc.c
9
--- a/block/vpc.c
17
+++ b/block/vpc.c
10
+++ b/block/vpc.c
18
@@ -XXX,XX +XXX,XX @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
11
@@ -XXX,XX +XXX,XX @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
19
return ret;
20
}
21
22
+static int calculate_rounded_image_size(BlockdevCreateOptionsVpc *vpc_opts,
23
+ uint16_t *out_cyls,
24
+ uint8_t *out_heads,
25
+ uint8_t *out_secs_per_cyl,
26
+ int64_t *out_total_sectors,
27
+ Error **errp)
28
+{
29
+ int64_t total_size = vpc_opts->size;
30
+ uint16_t cyls = 0;
31
+ uint8_t heads = 0;
32
+ uint8_t secs_per_cyl = 0;
33
+ int64_t total_sectors;
34
+ int i;
35
+
36
+ /*
37
+ * Calculate matching total_size and geometry. Increase the number of
38
+ * sectors requested until we get enough (or fail). This ensures that
39
+ * qemu-img convert doesn't truncate images, but rather rounds up.
40
+ *
41
+ * If the image size can't be represented by a spec conformant CHS geometry,
42
+ * we set the geometry to 65535 x 16 x 255 (CxHxS) sectors and use
43
+ * the image size from the VHD footer to calculate total_sectors.
44
+ */
45
+ if (vpc_opts->force_size) {
46
+ /* This will force the use of total_size for sector count, below */
47
+ cyls = VHD_CHS_MAX_C;
48
+ heads = VHD_CHS_MAX_H;
49
+ secs_per_cyl = VHD_CHS_MAX_S;
50
+ } else {
51
+ total_sectors = MIN(VHD_MAX_GEOMETRY, total_size / BDRV_SECTOR_SIZE);
52
+ for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
53
+ calculate_geometry(total_sectors + i, &cyls, &heads, &secs_per_cyl);
54
+ }
55
+ }
56
+
57
+ if ((int64_t)cyls * heads * secs_per_cyl == VHD_MAX_GEOMETRY) {
58
+ total_sectors = total_size / BDRV_SECTOR_SIZE;
59
+ /* Allow a maximum disk size of 2040 GiB */
60
+ if (total_sectors > VHD_MAX_SECTORS) {
61
+ error_setg(errp, "Disk size is too large, max size is 2040 GiB");
62
+ return -EFBIG;
63
+ }
64
+ } else {
65
+ total_sectors = (int64_t) cyls * heads * secs_per_cyl;
66
+ }
67
+
68
+ *out_total_sectors = total_sectors;
69
+ if (out_cyls) {
70
+ *out_cyls = cyls;
71
+ *out_heads = heads;
72
+ *out_secs_per_cyl = secs_per_cyl;
73
+ }
74
+
75
+ return 0;
76
+}
77
+
78
static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
79
Error **errp)
80
{
81
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
82
83
uint8_t buf[1024];
84
VHDFooter *footer = (VHDFooter *) buf;
85
- int i;
86
uint16_t cyls = 0;
87
uint8_t heads = 0;
88
uint8_t secs_per_cyl = 0;
89
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
90
}
12
}
91
blk_set_allow_write_beyond_eof(blk, true);
13
92
14
qemu_co_mutex_init(&s->lock);
93
- /*
15
+ qemu_opts_del(opts);
94
- * Calculate matching total_size and geometry. Increase the number of
16
95
- * sectors requested until we get enough (or fail). This ensures that
17
return 0;
96
- * qemu-img convert doesn't truncate images, but rather rounds up.
18
97
- *
19
fail:
98
- * If the image size can't be represented by a spec conformant CHS geometry,
20
+ qemu_opts_del(opts);
99
- * we set the geometry to 65535 x 16 x 255 (CxHxS) sectors and use
21
qemu_vfree(s->pagetable);
100
- * the image size from the VHD footer to calculate total_sectors.
22
#ifdef CACHE
101
- */
23
g_free(s->pageentry_u8);
102
- if (vpc_opts->force_size) {
103
- /* This will force the use of total_size for sector count, below */
104
- cyls = VHD_CHS_MAX_C;
105
- heads = VHD_CHS_MAX_H;
106
- secs_per_cyl = VHD_CHS_MAX_S;
107
- } else {
108
- total_sectors = MIN(VHD_MAX_GEOMETRY, total_size / BDRV_SECTOR_SIZE);
109
- for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
110
- calculate_geometry(total_sectors + i, &cyls, &heads, &secs_per_cyl);
111
- }
112
+ /* Get geometry and check that it matches the image size*/
113
+ ret = calculate_rounded_image_size(vpc_opts, &cyls, &heads, &secs_per_cyl,
114
+ &total_sectors, errp);
115
+ if (ret < 0) {
116
+ goto out;
117
}
118
119
- if ((int64_t)cyls * heads * secs_per_cyl == VHD_MAX_GEOMETRY) {
120
- total_sectors = total_size / BDRV_SECTOR_SIZE;
121
- /* Allow a maximum disk size of 2040 GiB */
122
- if (total_sectors > VHD_MAX_SECTORS) {
123
- error_setg(errp, "Disk size is too large, max size is 2040 GiB");
124
- ret = -EFBIG;
125
- goto out;
126
- }
127
- } else {
128
- total_sectors = (int64_t)cyls * heads * secs_per_cyl;
129
- total_size = total_sectors * BDRV_SECTOR_SIZE;
130
+ if (total_size != total_sectors * BDRV_SECTOR_SIZE) {
131
+ error_setg(errp, "The requested image size cannot be represented in "
132
+ "CHS geometry");
133
+ error_append_hint(errp, "Try size=%llu or force-size=on (the "
134
+ "latter makes the image incompatible with "
135
+ "Virtual PC)",
136
+ total_sectors * BDRV_SECTOR_SIZE);
137
+ ret = -EINVAL;
138
+ goto out;
139
}
140
141
/* Prepare the Hard Disk Footer */
142
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename,
143
create_options->u.vpc.size =
144
ROUND_UP(create_options->u.vpc.size, BDRV_SECTOR_SIZE);
145
146
+ if (!create_options->u.vpc.force_size) {
147
+ int64_t total_sectors;
148
+ ret = calculate_rounded_image_size(&create_options->u.vpc, NULL, NULL,
149
+ NULL, &total_sectors, errp);
150
+ if (ret < 0) {
151
+ goto fail;
152
+ }
153
+
154
+ create_options->u.vpc.size = total_sectors * BDRV_SECTOR_SIZE;
155
+ }
156
+
157
+
158
/* Create the vpc image (format layer) */
159
ret = vpc_co_create(create_options, errp);
160
161
--
24
--
162
2.13.6
25
2.19.1
163
26
164
27
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to vhdx, which
1
From: Peter Maydell <peter.maydell@linaro.org>
2
enables image creation over QMP.
2
3
3
Taking the address of a field in a packed struct is a bad idea, because
4
it might not be actually aligned enough for that pointer type (and
5
thus cause a crash on dereference on some host architectures). Newer
6
versions of clang warn about this. Avoid the bug by not using the
7
"modify in place" byte swapping functions.
8
9
There are a few places where the in-place swap function is
10
used on something other than a packed struct field; we convert
11
those anyway, for consistency.
12
13
Patch produced with scripts/coccinelle/inplace-byteswaps.cocci.
14
15
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
16
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
18
---
7
qapi/block-core.json | 40 +++++++++-
19
block/vhdx.h | 12 ++---
8
block/vhdx.c | 216 ++++++++++++++++++++++++++++++++++++++-------------
20
block/vhdx-endian.c | 118 ++++++++++++++++++++++----------------------
9
2 files changed, 203 insertions(+), 53 deletions(-)
21
block/vhdx-log.c | 4 +-
10
22
block/vhdx.c | 18 +++----
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
23
4 files changed, 76 insertions(+), 76 deletions(-)
24
25
diff --git a/block/vhdx.h b/block/vhdx.h
12
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
27
--- a/block/vhdx.h
14
+++ b/qapi/block-core.json
28
+++ b/block/vhdx.h
15
@@ -XXX,XX +XXX,XX @@
29
@@ -XXX,XX +XXX,XX @@ int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
16
'*static': 'bool' } }
30
17
31
static inline void leguid_to_cpus(MSGUID *guid)
18
##
32
{
19
+# @BlockdevVhdxSubformat:
33
- le32_to_cpus(&guid->data1);
20
+#
34
- le16_to_cpus(&guid->data2);
21
+# @dynamic: Growing image file
35
- le16_to_cpus(&guid->data3);
22
+# @fixed: Preallocated fixed-size image file
36
+ guid->data1 = le32_to_cpu(guid->data1);
23
+#
37
+ guid->data2 = le16_to_cpu(guid->data2);
24
+# Since: 2.12
38
+ guid->data3 = le16_to_cpu(guid->data3);
25
+##
39
}
26
+{ 'enum': 'BlockdevVhdxSubformat',
40
27
+ 'data': [ 'dynamic', 'fixed' ] }
41
static inline void cpu_to_leguids(MSGUID *guid)
28
+
42
{
29
+##
43
- cpu_to_le32s(&guid->data1);
30
+# @BlockdevCreateOptionsVhdx:
44
- cpu_to_le16s(&guid->data2);
31
+#
45
- cpu_to_le16s(&guid->data3);
32
+# Driver specific image creation options for vhdx.
46
+ guid->data1 = cpu_to_le32(guid->data1);
33
+#
47
+ guid->data2 = cpu_to_le16(guid->data2);
34
+# @file Node to create the image format on
48
+ guid->data3 = cpu_to_le16(guid->data3);
35
+# @size Size of the virtual disk in bytes
49
}
36
+# @log-size Log size in bytes, must be a multiple of 1 MB
50
37
+# (default: 1 MB)
51
void vhdx_header_le_import(VHDXHeader *h);
38
+# @block-size Block size in bytes, must be a multiple of 1 MB and not
52
diff --git a/block/vhdx-endian.c b/block/vhdx-endian.c
39
+# larger than 256 MB (default: automatically choose a block
53
index XXXXXXX..XXXXXXX 100644
40
+# size depending on the image size)
54
--- a/block/vhdx-endian.c
41
+# @subformat vhdx subformat (default: dynamic)
55
+++ b/block/vhdx-endian.c
42
+# @block-state-zero Force use of payload blocks of type 'ZERO'. Non-standard,
56
@@ -XXX,XX +XXX,XX @@ void vhdx_header_le_import(VHDXHeader *h)
43
+# but default. Do not set to 'off' when using 'qemu-img
57
{
44
+# convert' with subformat=dynamic.
58
assert(h != NULL);
45
+#
59
46
+# Since: 2.12
60
- le32_to_cpus(&h->signature);
47
+##
61
- le32_to_cpus(&h->checksum);
48
+{ 'struct': 'BlockdevCreateOptionsVhdx',
62
- le64_to_cpus(&h->sequence_number);
49
+ 'data': { 'file': 'BlockdevRef',
63
+ h->signature = le32_to_cpu(h->signature);
50
+ 'size': 'size',
64
+ h->checksum = le32_to_cpu(h->checksum);
51
+ '*log-size': 'size',
65
+ h->sequence_number = le64_to_cpu(h->sequence_number);
52
+ '*block-size': 'size',
66
53
+ '*subformat': 'BlockdevVhdxSubformat',
67
leguid_to_cpus(&h->file_write_guid);
54
+ '*block-state-zero': 'bool' } }
68
leguid_to_cpus(&h->data_write_guid);
55
+
69
leguid_to_cpus(&h->log_guid);
56
+##
70
57
# @BlockdevCreateNotSupported:
71
- le16_to_cpus(&h->log_version);
58
#
72
- le16_to_cpus(&h->version);
59
# This is used for all drivers that don't support creating images.
73
- le32_to_cpus(&h->log_length);
60
@@ -XXX,XX +XXX,XX @@
74
- le64_to_cpus(&h->log_offset);
61
'ssh': 'BlockdevCreateOptionsSsh',
75
+ h->log_version = le16_to_cpu(h->log_version);
62
'throttle': 'BlockdevCreateNotSupported',
76
+ h->version = le16_to_cpu(h->version);
63
'vdi': 'BlockdevCreateOptionsVdi',
77
+ h->log_length = le32_to_cpu(h->log_length);
64
- 'vhdx': 'BlockdevCreateNotSupported',
78
+ h->log_offset = le64_to_cpu(h->log_offset);
65
+ 'vhdx': 'BlockdevCreateOptionsVhdx',
79
}
66
'vmdk': 'BlockdevCreateNotSupported',
80
67
'vpc': 'BlockdevCreateNotSupported',
81
void vhdx_header_le_export(VHDXHeader *orig_h, VHDXHeader *new_h)
68
'vvfat': 'BlockdevCreateNotSupported',
82
@@ -XXX,XX +XXX,XX @@ void vhdx_log_desc_le_import(VHDXLogDescriptor *d)
83
{
84
assert(d != NULL);
85
86
- le32_to_cpus(&d->signature);
87
- le64_to_cpus(&d->file_offset);
88
- le64_to_cpus(&d->sequence_number);
89
+ d->signature = le32_to_cpu(d->signature);
90
+ d->file_offset = le64_to_cpu(d->file_offset);
91
+ d->sequence_number = le64_to_cpu(d->sequence_number);
92
}
93
94
void vhdx_log_desc_le_export(VHDXLogDescriptor *d)
95
{
96
assert(d != NULL);
97
98
- cpu_to_le32s(&d->signature);
99
- cpu_to_le32s(&d->trailing_bytes);
100
- cpu_to_le64s(&d->leading_bytes);
101
- cpu_to_le64s(&d->file_offset);
102
- cpu_to_le64s(&d->sequence_number);
103
+ d->signature = cpu_to_le32(d->signature);
104
+ d->trailing_bytes = cpu_to_le32(d->trailing_bytes);
105
+ d->leading_bytes = cpu_to_le64(d->leading_bytes);
106
+ d->file_offset = cpu_to_le64(d->file_offset);
107
+ d->sequence_number = cpu_to_le64(d->sequence_number);
108
}
109
110
void vhdx_log_data_le_import(VHDXLogDataSector *d)
111
{
112
assert(d != NULL);
113
114
- le32_to_cpus(&d->data_signature);
115
- le32_to_cpus(&d->sequence_high);
116
- le32_to_cpus(&d->sequence_low);
117
+ d->data_signature = le32_to_cpu(d->data_signature);
118
+ d->sequence_high = le32_to_cpu(d->sequence_high);
119
+ d->sequence_low = le32_to_cpu(d->sequence_low);
120
}
121
122
void vhdx_log_data_le_export(VHDXLogDataSector *d)
123
{
124
assert(d != NULL);
125
126
- cpu_to_le32s(&d->data_signature);
127
- cpu_to_le32s(&d->sequence_high);
128
- cpu_to_le32s(&d->sequence_low);
129
+ d->data_signature = cpu_to_le32(d->data_signature);
130
+ d->sequence_high = cpu_to_le32(d->sequence_high);
131
+ d->sequence_low = cpu_to_le32(d->sequence_low);
132
}
133
134
void vhdx_log_entry_hdr_le_import(VHDXLogEntryHeader *hdr)
135
{
136
assert(hdr != NULL);
137
138
- le32_to_cpus(&hdr->signature);
139
- le32_to_cpus(&hdr->checksum);
140
- le32_to_cpus(&hdr->entry_length);
141
- le32_to_cpus(&hdr->tail);
142
- le64_to_cpus(&hdr->sequence_number);
143
- le32_to_cpus(&hdr->descriptor_count);
144
+ hdr->signature = le32_to_cpu(hdr->signature);
145
+ hdr->checksum = le32_to_cpu(hdr->checksum);
146
+ hdr->entry_length = le32_to_cpu(hdr->entry_length);
147
+ hdr->tail = le32_to_cpu(hdr->tail);
148
+ hdr->sequence_number = le64_to_cpu(hdr->sequence_number);
149
+ hdr->descriptor_count = le32_to_cpu(hdr->descriptor_count);
150
leguid_to_cpus(&hdr->log_guid);
151
- le64_to_cpus(&hdr->flushed_file_offset);
152
- le64_to_cpus(&hdr->last_file_offset);
153
+ hdr->flushed_file_offset = le64_to_cpu(hdr->flushed_file_offset);
154
+ hdr->last_file_offset = le64_to_cpu(hdr->last_file_offset);
155
}
156
157
void vhdx_log_entry_hdr_le_export(VHDXLogEntryHeader *hdr)
158
{
159
assert(hdr != NULL);
160
161
- cpu_to_le32s(&hdr->signature);
162
- cpu_to_le32s(&hdr->checksum);
163
- cpu_to_le32s(&hdr->entry_length);
164
- cpu_to_le32s(&hdr->tail);
165
- cpu_to_le64s(&hdr->sequence_number);
166
- cpu_to_le32s(&hdr->descriptor_count);
167
+ hdr->signature = cpu_to_le32(hdr->signature);
168
+ hdr->checksum = cpu_to_le32(hdr->checksum);
169
+ hdr->entry_length = cpu_to_le32(hdr->entry_length);
170
+ hdr->tail = cpu_to_le32(hdr->tail);
171
+ hdr->sequence_number = cpu_to_le64(hdr->sequence_number);
172
+ hdr->descriptor_count = cpu_to_le32(hdr->descriptor_count);
173
cpu_to_leguids(&hdr->log_guid);
174
- cpu_to_le64s(&hdr->flushed_file_offset);
175
- cpu_to_le64s(&hdr->last_file_offset);
176
+ hdr->flushed_file_offset = cpu_to_le64(hdr->flushed_file_offset);
177
+ hdr->last_file_offset = cpu_to_le64(hdr->last_file_offset);
178
}
179
180
181
@@ -XXX,XX +XXX,XX @@ void vhdx_region_header_le_import(VHDXRegionTableHeader *hdr)
182
{
183
assert(hdr != NULL);
184
185
- le32_to_cpus(&hdr->signature);
186
- le32_to_cpus(&hdr->checksum);
187
- le32_to_cpus(&hdr->entry_count);
188
+ hdr->signature = le32_to_cpu(hdr->signature);
189
+ hdr->checksum = le32_to_cpu(hdr->checksum);
190
+ hdr->entry_count = le32_to_cpu(hdr->entry_count);
191
}
192
193
void vhdx_region_header_le_export(VHDXRegionTableHeader *hdr)
194
{
195
assert(hdr != NULL);
196
197
- cpu_to_le32s(&hdr->signature);
198
- cpu_to_le32s(&hdr->checksum);
199
- cpu_to_le32s(&hdr->entry_count);
200
+ hdr->signature = cpu_to_le32(hdr->signature);
201
+ hdr->checksum = cpu_to_le32(hdr->checksum);
202
+ hdr->entry_count = cpu_to_le32(hdr->entry_count);
203
}
204
205
void vhdx_region_entry_le_import(VHDXRegionTableEntry *e)
206
@@ -XXX,XX +XXX,XX @@ void vhdx_region_entry_le_import(VHDXRegionTableEntry *e)
207
assert(e != NULL);
208
209
leguid_to_cpus(&e->guid);
210
- le64_to_cpus(&e->file_offset);
211
- le32_to_cpus(&e->length);
212
- le32_to_cpus(&e->data_bits);
213
+ e->file_offset = le64_to_cpu(e->file_offset);
214
+ e->length = le32_to_cpu(e->length);
215
+ e->data_bits = le32_to_cpu(e->data_bits);
216
}
217
218
void vhdx_region_entry_le_export(VHDXRegionTableEntry *e)
219
@@ -XXX,XX +XXX,XX @@ void vhdx_region_entry_le_export(VHDXRegionTableEntry *e)
220
assert(e != NULL);
221
222
cpu_to_leguids(&e->guid);
223
- cpu_to_le64s(&e->file_offset);
224
- cpu_to_le32s(&e->length);
225
- cpu_to_le32s(&e->data_bits);
226
+ e->file_offset = cpu_to_le64(e->file_offset);
227
+ e->length = cpu_to_le32(e->length);
228
+ e->data_bits = cpu_to_le32(e->data_bits);
229
}
230
231
232
@@ -XXX,XX +XXX,XX @@ void vhdx_metadata_header_le_import(VHDXMetadataTableHeader *hdr)
233
{
234
assert(hdr != NULL);
235
236
- le64_to_cpus(&hdr->signature);
237
- le16_to_cpus(&hdr->entry_count);
238
+ hdr->signature = le64_to_cpu(hdr->signature);
239
+ hdr->entry_count = le16_to_cpu(hdr->entry_count);
240
}
241
242
void vhdx_metadata_header_le_export(VHDXMetadataTableHeader *hdr)
243
{
244
assert(hdr != NULL);
245
246
- cpu_to_le64s(&hdr->signature);
247
- cpu_to_le16s(&hdr->entry_count);
248
+ hdr->signature = cpu_to_le64(hdr->signature);
249
+ hdr->entry_count = cpu_to_le16(hdr->entry_count);
250
}
251
252
void vhdx_metadata_entry_le_import(VHDXMetadataTableEntry *e)
253
@@ -XXX,XX +XXX,XX @@ void vhdx_metadata_entry_le_import(VHDXMetadataTableEntry *e)
254
assert(e != NULL);
255
256
leguid_to_cpus(&e->item_id);
257
- le32_to_cpus(&e->offset);
258
- le32_to_cpus(&e->length);
259
- le32_to_cpus(&e->data_bits);
260
+ e->offset = le32_to_cpu(e->offset);
261
+ e->length = le32_to_cpu(e->length);
262
+ e->data_bits = le32_to_cpu(e->data_bits);
263
}
264
void vhdx_metadata_entry_le_export(VHDXMetadataTableEntry *e)
265
{
266
assert(e != NULL);
267
268
cpu_to_leguids(&e->item_id);
269
- cpu_to_le32s(&e->offset);
270
- cpu_to_le32s(&e->length);
271
- cpu_to_le32s(&e->data_bits);
272
+ e->offset = cpu_to_le32(e->offset);
273
+ e->length = cpu_to_le32(e->length);
274
+ e->data_bits = cpu_to_le32(e->data_bits);
275
}
276
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
277
index XXXXXXX..XXXXXXX 100644
278
--- a/block/vhdx-log.c
279
+++ b/block/vhdx-log.c
280
@@ -XXX,XX +XXX,XX @@ static void vhdx_log_raw_to_le_sector(VHDXLogDescriptor *desc,
281
/* 8 + 4084 + 4 = 4096, 1 log sector */
282
memcpy(&desc->leading_bytes, data, 8);
283
data += 8;
284
- cpu_to_le64s(&desc->leading_bytes);
285
+ desc->leading_bytes = cpu_to_le64(desc->leading_bytes);
286
memcpy(sector->data, data, 4084);
287
data += 4084;
288
memcpy(&desc->trailing_bytes, data, 4);
289
- cpu_to_le32s(&desc->trailing_bytes);
290
+ desc->trailing_bytes = cpu_to_le32(desc->trailing_bytes);
291
data += 4;
292
293
sector->sequence_high = (uint32_t) (seq >> 32);
69
diff --git a/block/vhdx.c b/block/vhdx.c
294
diff --git a/block/vhdx.c b/block/vhdx.c
70
index XXXXXXX..XXXXXXX 100644
295
index XXXXXXX..XXXXXXX 100644
71
--- a/block/vhdx.c
296
--- a/block/vhdx.c
72
+++ b/block/vhdx.c
297
+++ b/block/vhdx.c
73
@@ -XXX,XX +XXX,XX @@
298
@@ -XXX,XX +XXX,XX @@ uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset)
74
#include "block/vhdx.h"
299
75
#include "migration/blocker.h"
300
memset(buf + crc_offset, 0, sizeof(crc));
76
#include "qemu/uuid.h"
301
crc = crc32c(0xffffffff, buf, size);
77
+#include "qapi/qmp/qdict.h"
302
- cpu_to_le32s(&crc);
78
+#include "qapi/qobject-input-visitor.h"
303
+ crc = cpu_to_le32(crc);
79
+#include "qapi/qapi-visit-block-core.h"
304
memcpy(buf + crc_offset, &crc, sizeof(crc));
80
305
81
/* Options for VHDX creation */
306
return crc;
82
307
@@ -XXX,XX +XXX,XX @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
83
@@ -XXX,XX +XXX,XX @@ typedef enum VHDXImageType {
308
goto exit;
84
VHDX_TYPE_DIFFERENCING, /* Currently unsupported */
85
} VHDXImageType;
86
87
+static QemuOptsList vhdx_create_opts;
88
+
89
/* Several metadata and region table data entries are identified by
90
* guids in a MS-specific GUID format. */
91
92
@@ -XXX,XX +XXX,XX @@ exit:
93
* .---- ~ ----------- ~ ------------ ~ ---------------- ~ -----------.
94
* 1MB
95
*/
96
-static int coroutine_fn vhdx_co_create_opts(const char *filename, QemuOpts *opts,
97
- Error **errp)
98
+static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
99
+ Error **errp)
100
{
101
+ BlockdevCreateOptionsVhdx *vhdx_opts;
102
+ BlockBackend *blk = NULL;
103
+ BlockDriverState *bs = NULL;
104
+
105
int ret = 0;
106
- uint64_t image_size = (uint64_t) 2 * GiB;
107
- uint32_t log_size = 1 * MiB;
108
- uint32_t block_size = 0;
109
+ uint64_t image_size;
110
+ uint32_t log_size;
111
+ uint32_t block_size;
112
uint64_t signature;
113
uint64_t metadata_offset;
114
bool use_zero_blocks = false;
115
116
gunichar2 *creator = NULL;
117
glong creator_items;
118
- BlockBackend *blk;
119
- char *type = NULL;
120
VHDXImageType image_type;
121
- Error *local_err = NULL;
122
123
- image_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
124
- BDRV_SECTOR_SIZE);
125
- log_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_LOG_SIZE, 0);
126
- block_size = qemu_opt_get_size_del(opts, VHDX_BLOCK_OPT_BLOCK_SIZE, 0);
127
- type = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
128
- use_zero_blocks = qemu_opt_get_bool_del(opts, VHDX_BLOCK_OPT_ZERO, true);
129
+ assert(opts->driver == BLOCKDEV_DRIVER_VHDX);
130
+ vhdx_opts = &opts->u.vhdx;
131
132
+ /* Validate options and set default values */
133
+ image_size = vhdx_opts->size;
134
if (image_size > VHDX_MAX_IMAGE_SIZE) {
135
error_setg_errno(errp, EINVAL, "Image size too large; max of 64TB");
136
- ret = -EINVAL;
137
- goto exit;
138
+ return -EINVAL;
139
}
309
}
140
310
141
- if (type == NULL) {
311
- le32_to_cpus(&s->params.block_size);
142
- type = g_strdup("dynamic");
312
- le32_to_cpus(&s->params.data_bits);
143
+ if (!vhdx_opts->has_log_size) {
313
+ s->params.block_size = le32_to_cpu(s->params.block_size);
144
+ log_size = DEFAULT_LOG_SIZE;
314
+ s->params.data_bits = le32_to_cpu(s->params.data_bits);
145
+ } else {
315
146
+ log_size = vhdx_opts->log_size;
316
147
+ }
317
/* We now have the file parameters, so we can tell if this is a
148
+ if (log_size < MiB || (log_size % MiB) != 0) {
318
@@ -XXX,XX +XXX,XX @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
149
+ error_setg_errno(errp, EINVAL, "Log size must be a multiple of 1 MB");
319
goto exit;
150
+ return -EINVAL;
151
}
320
}
152
321
153
- if (!strcmp(type, "dynamic")) {
322
- le64_to_cpus(&s->virtual_disk_size);
154
+ if (!vhdx_opts->has_block_state_zero) {
323
- le32_to_cpus(&s->logical_sector_size);
155
+ use_zero_blocks = true;
324
- le32_to_cpus(&s->physical_sector_size);
156
+ } else {
325
+ s->virtual_disk_size = le64_to_cpu(s->virtual_disk_size);
157
+ use_zero_blocks = vhdx_opts->block_state_zero;
326
+ s->logical_sector_size = le32_to_cpu(s->logical_sector_size);
158
+ }
327
+ s->physical_sector_size = le32_to_cpu(s->physical_sector_size);
159
+
328
160
+ if (!vhdx_opts->has_subformat) {
329
if (s->params.block_size < VHDX_BLOCK_SIZE_MIN ||
161
+ vhdx_opts->subformat = BLOCKDEV_VHDX_SUBFORMAT_DYNAMIC;
330
s->params.block_size > VHDX_BLOCK_SIZE_MAX) {
162
+ }
331
@@ -XXX,XX +XXX,XX @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
163
+
332
/* endian convert, and verify populated BAT field file offsets against
164
+ switch (vhdx_opts->subformat) {
333
* region table and log entries */
165
+ case BLOCKDEV_VHDX_SUBFORMAT_DYNAMIC:
334
for (i = 0; i < s->bat_entries; i++) {
166
image_type = VHDX_TYPE_DYNAMIC;
335
- le64_to_cpus(&s->bat[i]);
167
- } else if (!strcmp(type, "fixed")) {
336
+ s->bat[i] = le64_to_cpu(s->bat[i]);
168
+ break;
337
if (payblocks--) {
169
+ case BLOCKDEV_VHDX_SUBFORMAT_FIXED:
338
/* payload bat entries */
170
image_type = VHDX_TYPE_FIXED;
339
if ((s->bat[i] & VHDX_BAT_STATE_BIT_MASK) ==
171
- } else if (!strcmp(type, "differencing")) {
340
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_new_metadata(BlockBackend *blk,
172
- error_setg_errno(errp, ENOTSUP,
341
mt_file_params->block_size = cpu_to_le32(block_size);
173
- "Differencing files not yet supported");
342
if (type == VHDX_TYPE_FIXED) {
174
- ret = -ENOTSUP;
343
mt_file_params->data_bits |= VHDX_PARAMS_LEAVE_BLOCKS_ALLOCED;
175
- goto exit;
344
- cpu_to_le32s(&mt_file_params->data_bits);
176
- } else {
345
+ mt_file_params->data_bits = cpu_to_le32(mt_file_params->data_bits);
177
- error_setg(errp, "Invalid subformat '%s'", type);
178
- ret = -EINVAL;
179
- goto exit;
180
+ break;
181
+ default:
182
+ g_assert_not_reached();
183
}
346
}
184
347
185
/* These are pretty arbitrary, and mainly designed to keep the BAT
348
vhdx_guid_generate(&mt_page83->page_83_data);
186
* size reasonable to load into RAM */
349
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
187
- if (block_size == 0) {
350
sinfo.file_offset = ROUND_UP(sinfo.file_offset, MiB);
188
+ if (vhdx_opts->has_block_size) {
351
vhdx_update_bat_table_entry(blk_bs(blk), s, &sinfo, &unused, &unused,
189
+ block_size = vhdx_opts->block_size;
352
block_state);
190
+ } else {
353
- cpu_to_le64s(&s->bat[sinfo.bat_idx]);
191
if (image_size > 32 * TiB) {
354
+ s->bat[sinfo.bat_idx] = cpu_to_le64(s->bat[sinfo.bat_idx]);
192
block_size = 64 * MiB;
355
sector_num += s->sectors_per_block;
193
} else if (image_size > (uint64_t) 100 * GiB) {
194
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename, QemuOpts *opts
195
}
356
}
196
}
357
ret = blk_pwrite(blk, file_offset, s->bat, length, 0);
197
198
-
199
- /* make the log size close to what was specified, but must be
200
- * min 1MB, and multiple of 1MB */
201
- log_size = ROUND_UP(log_size, MiB);
202
-
203
- block_size = ROUND_UP(block_size, MiB);
204
- block_size = block_size > VHDX_BLOCK_SIZE_MAX ? VHDX_BLOCK_SIZE_MAX :
205
- block_size;
206
-
207
- ret = bdrv_create_file(filename, opts, &local_err);
208
- if (ret < 0) {
209
- error_propagate(errp, local_err);
210
- goto exit;
211
+ if (block_size < MiB || (block_size % MiB) != 0) {
212
+ error_setg_errno(errp, EINVAL, "Block size must be a multiple of 1 MB");
213
+ return -EINVAL;
214
+ }
215
+ if (block_size > VHDX_BLOCK_SIZE_MAX) {
216
+ error_setg_errno(errp, EINVAL, "Block size must not exceed %d",
217
+ VHDX_BLOCK_SIZE_MAX);
218
+ return -EINVAL;
219
}
220
221
- blk = blk_new_open(filename, NULL, NULL,
222
- BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
223
- &local_err);
224
- if (blk == NULL) {
225
- error_propagate(errp, local_err);
226
- ret = -EIO;
227
- goto exit;
228
+ /* Create BlockBackend to write to the image */
229
+ bs = bdrv_open_blockdev_ref(vhdx_opts->file, errp);
230
+ if (bs == NULL) {
231
+ return -EIO;
232
}
233
234
+ blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
235
+ ret = blk_insert_bs(blk, bs, errp);
236
+ if (ret < 0) {
237
+ goto delete_and_exit;
238
+ }
239
blk_set_allow_write_beyond_eof(blk, true);
240
241
/* Create (A) */
242
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vhdx_co_create_opts(const char *filename, QemuOpts *opts
243
244
delete_and_exit:
245
blk_unref(blk);
246
-exit:
247
- g_free(type);
248
+ bdrv_unref(bs);
249
g_free(creator);
250
return ret;
251
}
252
253
+static int coroutine_fn vhdx_co_create_opts(const char *filename,
254
+ QemuOpts *opts,
255
+ Error **errp)
256
+{
257
+ BlockdevCreateOptions *create_options = NULL;
258
+ QDict *qdict = NULL;
259
+ QObject *qobj;
260
+ Visitor *v;
261
+ BlockDriverState *bs = NULL;
262
+ Error *local_err = NULL;
263
+ int ret;
264
+
265
+ static const QDictRenames opt_renames[] = {
266
+ { VHDX_BLOCK_OPT_LOG_SIZE, "log-size" },
267
+ { VHDX_BLOCK_OPT_BLOCK_SIZE, "block-size" },
268
+ { VHDX_BLOCK_OPT_ZERO, "block-state-zero" },
269
+ { NULL, NULL },
270
+ };
271
+
272
+ /* Parse options and convert legacy syntax */
273
+ qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vhdx_create_opts, true);
274
+
275
+ if (!qdict_rename_keys(qdict, opt_renames, errp)) {
276
+ ret = -EINVAL;
277
+ goto fail;
278
+ }
279
+
280
+ /* Create and open the file (protocol layer) */
281
+ ret = bdrv_create_file(filename, opts, &local_err);
282
+ if (ret < 0) {
283
+ error_propagate(errp, local_err);
284
+ goto fail;
285
+ }
286
+
287
+ bs = bdrv_open(filename, NULL, NULL,
288
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
289
+ if (bs == NULL) {
290
+ ret = -EIO;
291
+ goto fail;
292
+ }
293
+
294
+ /* Now get the QAPI type BlockdevCreateOptions */
295
+ qdict_put_str(qdict, "driver", "vhdx");
296
+ qdict_put_str(qdict, "file", bs->node_name);
297
+
298
+ qobj = qdict_crumple(qdict, errp);
299
+ QDECREF(qdict);
300
+ qdict = qobject_to_qdict(qobj);
301
+ if (qdict == NULL) {
302
+ ret = -EINVAL;
303
+ goto fail;
304
+ }
305
+
306
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
307
+ visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
308
+ visit_free(v);
309
+
310
+ if (local_err) {
311
+ error_propagate(errp, local_err);
312
+ ret = -EINVAL;
313
+ goto fail;
314
+ }
315
+
316
+ /* Silently round up sizes:
317
+ * The image size is rounded to 512 bytes. Make the block and log size
318
+ * close to what was specified, but must be at least 1MB, and a multiple of
319
+ * 1 MB. Also respect VHDX_BLOCK_SIZE_MAX for block sizes. block_size = 0
320
+ * means auto, which is represented by a missing key in QAPI. */
321
+ assert(create_options->driver == BLOCKDEV_DRIVER_VHDX);
322
+ create_options->u.vhdx.size =
323
+ ROUND_UP(create_options->u.vhdx.size, BDRV_SECTOR_SIZE);
324
+
325
+ if (create_options->u.vhdx.has_log_size) {
326
+ create_options->u.vhdx.log_size =
327
+ ROUND_UP(create_options->u.vhdx.log_size, MiB);
328
+ }
329
+ if (create_options->u.vhdx.has_block_size) {
330
+ create_options->u.vhdx.block_size =
331
+ ROUND_UP(create_options->u.vhdx.block_size, MiB);
332
+
333
+ if (create_options->u.vhdx.block_size == 0) {
334
+ create_options->u.vhdx.has_block_size = false;
335
+ }
336
+ if (create_options->u.vhdx.block_size > VHDX_BLOCK_SIZE_MAX) {
337
+ create_options->u.vhdx.block_size = VHDX_BLOCK_SIZE_MAX;
338
+ }
339
+ }
340
+
341
+ /* Create the vhdx image (format layer) */
342
+ ret = vhdx_co_create(create_options, errp);
343
+
344
+fail:
345
+ QDECREF(qdict);
346
+ bdrv_unref(bs);
347
+ qapi_free_BlockdevCreateOptions(create_options);
348
+ return ret;
349
+}
350
+
351
/* If opened r/w, the VHDX driver will automatically replay the log,
352
* if one is present, inside the vhdx_open() call.
353
*
354
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vhdx = {
355
.bdrv_child_perm = bdrv_format_default_perms,
356
.bdrv_co_readv = vhdx_co_readv,
357
.bdrv_co_writev = vhdx_co_writev,
358
+ .bdrv_co_create = vhdx_co_create,
359
.bdrv_co_create_opts = vhdx_co_create_opts,
360
.bdrv_get_info = vhdx_get_info,
361
.bdrv_co_check = vhdx_co_check,
362
--
358
--
363
2.13.6
359
2.19.1
364
360
365
361
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Peter Maydell <peter.maydell@linaro.org>
2
2
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
Taking the address of a field in a packed struct is a bad idea, because
4
it might not be actually aligned enough for that pointer type (and
5
thus cause a crash on dereference on some host architectures). Newer
6
versions of clang warn about this. Avoid the bug by not using the
7
"modify in place" byte swapping functions.
8
9
There are a few places where the in-place swap function is
10
used on something other than a packed struct field; we convert
11
those anyway, for consistency.
12
13
Patch produced with scripts/coccinelle/inplace-byteswaps.cocci.
14
15
There are other places where we take the address of a packed member
16
in this file for other purposes than passing it to a byteswap
17
function (all the calls to qemu_uuid_*()); we leave those for now.
18
19
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
20
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
22
---
6
block/vdi.c | 46 ++++++++++++++++++++++++++++------------------
23
block/vdi.c | 64 ++++++++++++++++++++++++++---------------------------
7
1 file changed, 28 insertions(+), 18 deletions(-)
24
1 file changed, 32 insertions(+), 32 deletions(-)
8
25
9
diff --git a/block/vdi.c b/block/vdi.c
26
diff --git a/block/vdi.c b/block/vdi.c
10
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
11
--- a/block/vdi.c
28
--- a/block/vdi.c
12
+++ b/block/vdi.c
29
+++ b/block/vdi.c
13
@@ -XXX,XX +XXX,XX @@ nonallocating_write:
30
@@ -XXX,XX +XXX,XX @@ typedef struct {
14
return ret;
31
15
}
32
static void vdi_header_to_cpu(VdiHeader *header)
16
17
-static int coroutine_fn vdi_co_do_create(const char *filename,
18
- QemuOpts *file_opts,
19
- BlockdevCreateOptionsVdi *vdi_opts,
20
+static int coroutine_fn vdi_co_do_create(BlockdevCreateOptionsVdi *vdi_opts,
21
size_t block_size, Error **errp)
22
{
33
{
23
int ret = 0;
34
- le32_to_cpus(&header->signature);
24
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(const char *filename,
35
- le32_to_cpus(&header->version);
25
size_t i;
36
- le32_to_cpus(&header->header_size);
26
size_t bmap_size;
37
- le32_to_cpus(&header->image_type);
27
int64_t offset = 0;
38
- le32_to_cpus(&header->image_flags);
28
- Error *local_err = NULL;
39
- le32_to_cpus(&header->offset_bmap);
29
+ BlockDriverState *bs_file = NULL;
40
- le32_to_cpus(&header->offset_data);
30
BlockBackend *blk = NULL;
41
- le32_to_cpus(&header->cylinders);
31
uint32_t *bmap = NULL;
42
- le32_to_cpus(&header->heads);
32
43
- le32_to_cpus(&header->sectors);
33
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(const char *filename,
44
- le32_to_cpus(&header->sector_size);
34
goto exit;
45
- le64_to_cpus(&header->disk_size);
35
}
46
- le32_to_cpus(&header->block_size);
36
47
- le32_to_cpus(&header->block_extra);
37
- ret = bdrv_create_file(filename, file_opts, &local_err);
48
- le32_to_cpus(&header->blocks_in_image);
38
- if (ret < 0) {
49
- le32_to_cpus(&header->blocks_allocated);
39
- error_propagate(errp, local_err);
50
+ header->signature = le32_to_cpu(header->signature);
40
+ bs_file = bdrv_open_blockdev_ref(vdi_opts->file, errp);
51
+ header->version = le32_to_cpu(header->version);
41
+ if (!bs_file) {
52
+ header->header_size = le32_to_cpu(header->header_size);
42
+ ret = -EIO;
53
+ header->image_type = le32_to_cpu(header->image_type);
43
goto exit;
54
+ header->image_flags = le32_to_cpu(header->image_flags);
44
}
55
+ header->offset_bmap = le32_to_cpu(header->offset_bmap);
45
56
+ header->offset_data = le32_to_cpu(header->offset_data);
46
- blk = blk_new_open(filename, NULL, NULL,
57
+ header->cylinders = le32_to_cpu(header->cylinders);
47
- BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
58
+ header->heads = le32_to_cpu(header->heads);
48
- &local_err);
59
+ header->sectors = le32_to_cpu(header->sectors);
49
- if (blk == NULL) {
60
+ header->sector_size = le32_to_cpu(header->sector_size);
50
- error_propagate(errp, local_err);
61
+ header->disk_size = le64_to_cpu(header->disk_size);
51
- ret = -EIO;
62
+ header->block_size = le32_to_cpu(header->block_size);
52
+ blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
63
+ header->block_extra = le32_to_cpu(header->block_extra);
53
+ ret = blk_insert_bs(blk, bs_file, errp);
64
+ header->blocks_in_image = le32_to_cpu(header->blocks_in_image);
54
+ if (ret < 0) {
65
+ header->blocks_allocated = le32_to_cpu(header->blocks_allocated);
55
goto exit;
66
qemu_uuid_bswap(&header->uuid_image);
56
}
67
qemu_uuid_bswap(&header->uuid_last_snap);
57
68
qemu_uuid_bswap(&header->uuid_link);
58
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(const char *filename,
69
@@ -XXX,XX +XXX,XX @@ static void vdi_header_to_cpu(VdiHeader *header)
59
vdi_header_to_le(&header);
70
60
ret = blk_pwrite(blk, offset, &header, sizeof(header), 0);
71
static void vdi_header_to_le(VdiHeader *header)
61
if (ret < 0) {
62
- error_setg(errp, "Error writing header to %s", filename);
63
+ error_setg(errp, "Error writing header");
64
goto exit;
65
}
66
offset += sizeof(header);
67
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(const char *filename,
68
}
69
ret = blk_pwrite(blk, offset, bmap, bmap_size, 0);
70
if (ret < 0) {
71
- error_setg(errp, "Error writing bmap to %s", filename);
72
+ error_setg(errp, "Error writing bmap");
73
goto exit;
74
}
75
offset += bmap_size;
76
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(const char *filename,
77
ret = blk_truncate(blk, offset + blocks * block_size,
78
PREALLOC_MODE_OFF, errp);
79
if (ret < 0) {
80
- error_prepend(errp, "Failed to statically allocate %s", filename);
81
+ error_prepend(errp, "Failed to statically allocate file");
82
goto exit;
83
}
84
}
85
86
exit:
87
blk_unref(blk);
88
+ bdrv_unref(bs_file);
89
g_free(bmap);
90
return ret;
91
}
92
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
93
{
72
{
94
QDict *qdict = NULL;
73
- cpu_to_le32s(&header->signature);
95
BlockdevCreateOptionsVdi *create_options = NULL;
74
- cpu_to_le32s(&header->version);
96
+ BlockDriverState *bs_file = NULL;
75
- cpu_to_le32s(&header->header_size);
97
uint64_t block_size = DEFAULT_CLUSTER_SIZE;
76
- cpu_to_le32s(&header->image_type);
98
Visitor *v;
77
- cpu_to_le32s(&header->image_flags);
99
Error *local_err = NULL;
78
- cpu_to_le32s(&header->offset_bmap);
100
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
79
- cpu_to_le32s(&header->offset_data);
101
80
- cpu_to_le32s(&header->cylinders);
102
qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vdi_create_opts, true);
81
- cpu_to_le32s(&header->heads);
103
82
- cpu_to_le32s(&header->sectors);
104
- qdict_put_str(qdict, "file", ""); /* FIXME */
83
- cpu_to_le32s(&header->sector_size);
105
+ ret = bdrv_create_file(filename, opts, errp);
84
- cpu_to_le64s(&header->disk_size);
106
+ if (ret < 0) {
85
- cpu_to_le32s(&header->block_size);
107
+ goto done;
86
- cpu_to_le32s(&header->block_extra);
108
+ }
87
- cpu_to_le32s(&header->blocks_in_image);
109
+
88
- cpu_to_le32s(&header->blocks_allocated);
110
+ bs_file = bdrv_open(filename, NULL, NULL,
89
+ header->signature = cpu_to_le32(header->signature);
111
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
90
+ header->version = cpu_to_le32(header->version);
112
+ if (!bs_file) {
91
+ header->header_size = cpu_to_le32(header->header_size);
113
+ ret = -EIO;
92
+ header->image_type = cpu_to_le32(header->image_type);
114
+ goto done;
93
+ header->image_flags = cpu_to_le32(header->image_flags);
115
+ }
94
+ header->offset_bmap = cpu_to_le32(header->offset_bmap);
116
+
95
+ header->offset_data = cpu_to_le32(header->offset_data);
117
+ qdict_put_str(qdict, "file", bs_file->node_name);
96
+ header->cylinders = cpu_to_le32(header->cylinders);
118
97
+ header->heads = cpu_to_le32(header->heads);
119
/* Get the QAPI object */
98
+ header->sectors = cpu_to_le32(header->sectors);
120
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
99
+ header->sector_size = cpu_to_le32(header->sector_size);
121
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
100
+ header->disk_size = cpu_to_le64(header->disk_size);
122
101
+ header->block_size = cpu_to_le32(header->block_size);
123
create_options->size = ROUND_UP(create_options->size, BDRV_SECTOR_SIZE);
102
+ header->block_extra = cpu_to_le32(header->block_extra);
124
103
+ header->blocks_in_image = cpu_to_le32(header->blocks_in_image);
125
- ret = vdi_co_do_create(filename, opts, create_options, block_size, errp);
104
+ header->blocks_allocated = cpu_to_le32(header->blocks_allocated);
126
+ ret = vdi_co_do_create(create_options, block_size, errp);
105
qemu_uuid_bswap(&header->uuid_image);
127
done:
106
qemu_uuid_bswap(&header->uuid_last_snap);
128
QDECREF(qdict);
107
qemu_uuid_bswap(&header->uuid_link);
129
qapi_free_BlockdevCreateOptionsVdi(create_options);
130
+ bdrv_unref(bs_file);
131
return ret;
132
}
133
134
--
108
--
135
2.13.6
109
2.19.1
136
110
137
111
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
add a new state "CONCLUDED" that identifies a job that has ceased all
3
This is a static function with only one caller, so there's no need to
4
operations. The wording was chosen to avoid any phrasing that might
4
keep it. Inlining the code in quorum_compare() makes it much simpler.
5
imply success, error, or cancellation. The task has simply ceased all
6
operation and can never again perform any work.
7
5
8
("finished", "done", and "completed" might all imply success.)
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
7
Reported-by: Markus Armbruster <armbru@redhat.com>
10
Transitions:
11
Running -> Concluded: normal completion
12
Ready -> Concluded: normal completion
13
Aborting -> Concluded: error and cancellations
14
15
Verbs:
16
None as of this commit. (a future commit adds 'dismiss')
17
18
+---------+
19
|UNDEFINED|
20
+--+------+
21
|
22
+--v----+
23
+---------+CREATED|
24
| +--+----+
25
| |
26
| +--v----+ +------+
27
+---------+RUNNING<----->PAUSED|
28
| +--+-+--+ +------+
29
| | |
30
| | +------------------+
31
| | |
32
| +--v--+ +-------+ |
33
+---------+READY<------->STANDBY| |
34
| +--+--+ +-------+ |
35
| | |
36
+--v-----+ +--v------+ |
37
|ABORTING+--->CONCLUDED<-------------+
38
+--------+ +---------+
39
40
Signed-off-by: John Snow <jsnow@redhat.com>
41
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
42
---
9
---
43
qapi/block-core.json | 7 +++++--
10
block/quorum.c | 24 +++++-------------------
44
blockjob.c | 39 ++++++++++++++++++++++++---------------
11
1 file changed, 5 insertions(+), 19 deletions(-)
45
2 files changed, 29 insertions(+), 17 deletions(-)
46
12
47
diff --git a/qapi/block-core.json b/qapi/block-core.json
13
diff --git a/block/quorum.c b/block/quorum.c
48
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
49
--- a/qapi/block-core.json
15
--- a/block/quorum.c
50
+++ b/qapi/block-core.json
16
+++ b/block/quorum.c
51
@@ -XXX,XX +XXX,XX @@
17
@@ -XXX,XX +XXX,XX @@ static bool quorum_iovec_compare(QEMUIOVector *a, QEMUIOVector *b)
52
# The job may return to @ready or otherwise be canceled.
18
return true;
53
#
54
# @aborting: The job is in the process of being aborted, and will finish with
55
-# an error.
56
+# an error. The job will afterwards report that it is @concluded.
57
# This status may not be visible to the management process.
58
#
59
+# @concluded: The job has finished all work. If manual was set to true, the job
60
+# will remain in the query list until it is dismissed.
61
+#
62
# Since: 2.12
63
##
64
{ 'enum': 'BlockJobStatus',
65
'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby',
66
- 'aborting' ] }
67
+ 'aborting', 'concluded' ] }
68
69
##
70
# @BlockJobInfo:
71
diff --git a/blockjob.c b/blockjob.c
72
index XXXXXXX..XXXXXXX 100644
73
--- a/blockjob.c
74
+++ b/blockjob.c
75
@@ -XXX,XX +XXX,XX @@ static QemuMutex block_job_mutex;
76
77
/* BlockJob State Transition Table */
78
bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] = {
79
- /* U, C, R, P, Y, S, X */
80
- /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0},
81
- /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 1},
82
- /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1},
83
- /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0},
84
- /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1},
85
- /* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0},
86
- /* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0},
87
+ /* U, C, R, P, Y, S, X, E */
88
+ /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0},
89
+ /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 1, 0},
90
+ /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1, 1},
91
+ /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0},
92
+ /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 1},
93
+ /* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0},
94
+ /* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0, 1},
95
+ /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0},
96
};
97
98
bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] = {
99
- /* U, C, R, P, Y, S, X */
100
- [BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 0},
101
- [BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0},
102
- [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0},
103
- [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0},
104
- [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0},
105
+ /* U, C, R, P, Y, S, X, E */
106
+ [BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 0, 0},
107
+ [BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0, 0},
108
+ [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0},
109
+ [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0},
110
+ [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0},
111
};
112
113
static void block_job_state_transition(BlockJob *job, BlockJobStatus s1)
114
@@ -XXX,XX +XXX,XX @@ void block_job_start(BlockJob *job)
115
bdrv_coroutine_enter(blk_bs(job->blk), job->co);
116
}
19
}
117
20
118
+static void block_job_conclude(BlockJob *job)
21
-static void GCC_FMT_ATTR(2, 3) quorum_err(QuorumAIOCB *acb,
119
+{
22
- const char *fmt, ...)
120
+ block_job_state_transition(job, BLOCK_JOB_STATUS_CONCLUDED);
23
-{
121
+}
24
- va_list ap;
122
+
25
-
123
static void block_job_completed_single(BlockJob *job)
26
- va_start(ap, fmt);
27
- fprintf(stderr, "quorum: offset=%" PRIu64 " bytes=%" PRIu64 " ",
28
- acb->offset, acb->bytes);
29
- vfprintf(stderr, fmt, ap);
30
- fprintf(stderr, "\n");
31
- va_end(ap);
32
- exit(1);
33
-}
34
-
35
-static bool quorum_compare(QuorumAIOCB *acb,
36
- QEMUIOVector *a,
37
- QEMUIOVector *b)
38
+static bool quorum_compare(QuorumAIOCB *acb, QEMUIOVector *a, QEMUIOVector *b)
124
{
39
{
125
assert(job->completed);
40
BDRVQuorumState *s = acb->bs->opaque;
126
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_single(BlockJob *job)
41
ssize_t offset;
127
42
@@ -XXX,XX +XXX,XX @@ static bool quorum_compare(QuorumAIOCB *acb,
128
QLIST_REMOVE(job, txn_list);
43
if (s->is_blkverify) {
129
block_job_txn_unref(job->txn);
44
offset = qemu_iovec_compare(a, b);
130
+ block_job_conclude(job);
45
if (offset != -1) {
131
block_job_unref(job);
46
- quorum_err(acb, "contents mismatch at offset %" PRIu64,
132
}
47
- acb->offset + offset);
133
48
+ fprintf(stderr, "quorum: offset=%" PRIu64 " bytes=%" PRIu64
134
@@ -XXX,XX +XXX,XX @@ void block_job_user_resume(BlockJob *job, Error **errp)
49
+ " contents mismatch at offset %" PRIu64 "\n",
135
50
+ acb->offset, acb->bytes, acb->offset + offset);
136
void block_job_cancel(BlockJob *job)
51
+ exit(1);
137
{
52
}
138
- if (block_job_started(job)) {
53
return true;
139
+ if (job->status == BLOCK_JOB_STATUS_CONCLUDED) {
54
}
140
+ return;
141
+ } else if (block_job_started(job)) {
142
block_job_cancel_async(job);
143
block_job_enter(job);
144
} else {
145
--
55
--
146
2.13.6
56
2.19.1
147
57
148
58
diff view generated by jsdifflib
1
From: Liang Li <liliang.opensource@gmail.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
When doing drive mirror to a low speed shared storage, if there was heavy
3
The blkverify mode of Quorum can only be enabled if the number of
4
BLK IO write workload in VM after the 'ready' event, drive mirror block job
4
children is exactly two and the value of vote-threshold is also two.
5
can't be canceled immediately, it would keep running until the heavy BLK IO
6
workload stopped in the VM.
7
5
8
Libvirt depends on the current block-job-cancel semantics, which is that
6
If the user tries to enable it but the other settings are incorrect
9
when used without a flag after the 'ready' event, the command blocks
7
then QEMU simply prints an error message to stderr and carries on
10
until data is in sync. However, these semantics are awkward in other
8
disabling the blkverify setting.
11
situations, for example, people may use drive mirror for realtime
12
backups while still wanting to use block live migration. Libvirt cannot
13
start a block live migration while another drive mirror is in progress,
14
but the user would rather abandon the backup attempt as broken and
15
proceed with the live migration than be stuck waiting for the current
16
drive mirror backup to finish.
17
9
18
The drive-mirror command already includes a 'force' flag, which libvirt
10
This patch makes quorum_open() fail and return an error in this case.
19
does not use, although it documented the flag as only being useful to
20
quit a job which is paused. However, since quitting a paused job has
21
the same effect as abandoning a backup in a non-paused job (namely, the
22
destination file is not in sync, and the command completes immediately),
23
we can just improve the documentation to make the force flag obviously
24
useful.
25
11
26
Cc: Paolo Bonzini <pbonzini@redhat.com>
12
Signed-off-by: Alberto Garcia <berto@igalia.com>
27
Cc: Jeff Cody <jcody@redhat.com>
13
Reported-by: Markus Armbruster <armbru@redhat.com>
28
Cc: Kevin Wolf <kwolf@redhat.com>
29
Cc: Max Reitz <mreitz@redhat.com>
30
Cc: Eric Blake <eblake@redhat.com>
31
Cc: John Snow <jsnow@redhat.com>
32
Reported-by: Huaitong Han <huanhuaitong@didichuxing.com>
33
Signed-off-by: Huaitong Han <huanhuaitong@didichuxing.com>
34
Signed-off-by: Liang Li <liliangleo@didichuxing.com>
35
Signed-off-by: Jeff Cody <jcody@redhat.com>
36
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
37
---
15
---
38
qapi/block-core.json | 5 +++--
16
block/quorum.c | 13 ++++++-------
39
include/block/blockjob.h | 12 ++++++++++--
17
1 file changed, 6 insertions(+), 7 deletions(-)
40
block/mirror.c | 10 ++++------
41
blockdev.c | 4 ++--
42
blockjob.c | 16 +++++++++-------
43
tests/test-blockjob-txn.c | 8 ++++----
44
hmp-commands.hx | 3 ++-
45
7 files changed, 34 insertions(+), 24 deletions(-)
46
18
47
diff --git a/qapi/block-core.json b/qapi/block-core.json
19
diff --git a/block/quorum.c b/block/quorum.c
48
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
49
--- a/qapi/block-core.json
21
--- a/block/quorum.c
50
+++ b/qapi/block-core.json
22
+++ b/block/quorum.c
51
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
52
# the name of the parameter), but since QEMU 2.7 it can have
24
s->read_pattern = ret;
53
# other values.
25
54
#
26
if (s->read_pattern == QUORUM_READ_PATTERN_QUORUM) {
55
-# @force: whether to allow cancellation of a paused job (default
27
- /* is the driver in blkverify mode */
56
-# false). Since 1.3.
28
- if (qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false) &&
57
+# @force: If true, and the job has already emitted the event BLOCK_JOB_READY,
29
- s->num_children == 2 && s->threshold == 2) {
58
+# abandon the job immediately (even if it is paused) instead of waiting
30
- s->is_blkverify = true;
59
+# for the destination to complete its final synchronization (since 1.3)
31
- } else if (qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false)) {
60
#
32
- fprintf(stderr, "blkverify mode is set by setting blkverify=on "
61
# Returns: Nothing on success
33
- "and using two files with vote_threshold=2\n");
62
# If no background operation is active on this device, DeviceNotActive
34
+ s->is_blkverify = qemu_opt_get_bool(opts, QUORUM_OPT_BLKVERIFY, false);
63
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
35
+ if (s->is_blkverify && (s->num_children != 2 || s->threshold != 2)) {
64
index XXXXXXX..XXXXXXX 100644
36
+ error_setg(&local_err, "blkverify=on can only be set if there are "
65
--- a/include/block/blockjob.h
37
+ "exactly two files and vote-threshold is 2");
66
+++ b/include/block/blockjob.h
38
+ ret = -EINVAL;
67
@@ -XXX,XX +XXX,XX @@ typedef struct BlockJob {
39
+ goto exit;
68
bool cancelled;
69
70
/**
71
+ * Set to true if the job should abort immediately without waiting
72
+ * for data to be in sync.
73
+ */
74
+ bool force;
75
+
76
+ /**
77
* Counter for pause request. If non-zero, the block job is either paused,
78
* or if busy == true will pause itself as soon as possible.
79
*/
80
@@ -XXX,XX +XXX,XX @@ void block_job_start(BlockJob *job);
81
/**
82
* block_job_cancel:
83
* @job: The job to be canceled.
84
+ * @force: Quit a job without waiting for data to be in sync.
85
*
86
* Asynchronously cancel the specified job.
87
*/
88
-void block_job_cancel(BlockJob *job);
89
+void block_job_cancel(BlockJob *job, bool force);
90
91
/**
92
* block_job_complete:
93
@@ -XXX,XX +XXX,XX @@ void block_job_user_resume(BlockJob *job, Error **errp);
94
/**
95
* block_job_user_cancel:
96
* @job: The job to be cancelled.
97
+ * @force: Quit a job without waiting for data to be in sync.
98
*
99
* Cancels the specified job, but may refuse to do so if the
100
* operation isn't currently meaningful.
101
*/
102
-void block_job_user_cancel(BlockJob *job, Error **errp);
103
+void block_job_user_cancel(BlockJob *job, bool force, Error **errp);
104
105
/**
106
* block_job_cancel_sync:
107
diff --git a/block/mirror.c b/block/mirror.c
108
index XXXXXXX..XXXXXXX 100644
109
--- a/block/mirror.c
110
+++ b/block/mirror.c
111
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_run(void *opaque)
112
113
ret = 0;
114
trace_mirror_before_sleep(s, cnt, s->synced, delay_ns);
115
- if (!s->synced) {
116
- block_job_sleep_ns(&s->common, delay_ns);
117
- if (block_job_is_cancelled(&s->common)) {
118
- break;
119
- }
120
+ if (block_job_is_cancelled(&s->common) && s->common.force) {
121
+ break;
122
} else if (!should_complete) {
123
delay_ns = (s->in_flight == 0 && cnt == 0 ? SLICE_TIME : 0);
124
block_job_sleep_ns(&s->common, delay_ns);
125
@@ -XXX,XX +XXX,XX @@ immediate_exit:
126
* or it was cancelled prematurely so that we do not guarantee that
127
* the target is a copy of the source.
128
*/
129
- assert(ret < 0 || (!s->synced && block_job_is_cancelled(&s->common)));
130
+ assert(ret < 0 || ((s->common.force || !s->synced) &&
131
+ block_job_is_cancelled(&s->common)));
132
assert(need_drain);
133
mirror_wait_for_all_io(s);
134
}
135
diff --git a/blockdev.c b/blockdev.c
136
index XXXXXXX..XXXXXXX 100644
137
--- a/blockdev.c
138
+++ b/blockdev.c
139
@@ -XXX,XX +XXX,XX @@ void blockdev_mark_auto_del(BlockBackend *blk)
140
aio_context_acquire(aio_context);
141
142
if (bs->job) {
143
- block_job_cancel(bs->job);
144
+ block_job_cancel(bs->job, false);
145
}
40
}
146
41
147
aio_context_release(aio_context);
42
s->rewrite_corrupted = qemu_opt_get_bool(opts, QUORUM_OPT_REWRITE,
148
@@ -XXX,XX +XXX,XX @@ void qmp_block_job_cancel(const char *device,
149
}
150
151
trace_qmp_block_job_cancel(job);
152
- block_job_user_cancel(job, errp);
153
+ block_job_user_cancel(job, force, errp);
154
out:
155
aio_context_release(aio_context);
156
}
157
diff --git a/blockjob.c b/blockjob.c
158
index XXXXXXX..XXXXXXX 100644
159
--- a/blockjob.c
160
+++ b/blockjob.c
161
@@ -XXX,XX +XXX,XX @@ static int block_job_finalize_single(BlockJob *job)
162
return 0;
163
}
164
165
-static void block_job_cancel_async(BlockJob *job)
166
+static void block_job_cancel_async(BlockJob *job, bool force)
167
{
168
if (job->iostatus != BLOCK_DEVICE_IO_STATUS_OK) {
169
block_job_iostatus_reset(job);
170
@@ -XXX,XX +XXX,XX @@ static void block_job_cancel_async(BlockJob *job)
171
job->pause_count--;
172
}
173
job->cancelled = true;
174
+ /* To prevent 'force == false' overriding a previous 'force == true' */
175
+ job->force |= force;
176
}
177
178
static int block_job_txn_apply(BlockJobTxn *txn, int fn(BlockJob *), bool lock)
179
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_txn_abort(BlockJob *job)
180
* on the caller, so leave it. */
181
QLIST_FOREACH(other_job, &txn->jobs, txn_list) {
182
if (other_job != job) {
183
- block_job_cancel_async(other_job);
184
+ block_job_cancel_async(other_job, false);
185
}
186
}
187
while (!QLIST_EMPTY(&txn->jobs)) {
188
@@ -XXX,XX +XXX,XX @@ void block_job_user_resume(BlockJob *job, Error **errp)
189
block_job_resume(job);
190
}
191
192
-void block_job_cancel(BlockJob *job)
193
+void block_job_cancel(BlockJob *job, bool force)
194
{
195
if (job->status == BLOCK_JOB_STATUS_CONCLUDED) {
196
block_job_do_dismiss(job);
197
return;
198
}
199
- block_job_cancel_async(job);
200
+ block_job_cancel_async(job, force);
201
if (!block_job_started(job)) {
202
block_job_completed(job, -ECANCELED);
203
} else if (job->deferred_to_main_loop) {
204
@@ -XXX,XX +XXX,XX @@ void block_job_cancel(BlockJob *job)
205
}
206
}
207
208
-void block_job_user_cancel(BlockJob *job, Error **errp)
209
+void block_job_user_cancel(BlockJob *job, bool force, Error **errp)
210
{
211
if (block_job_apply_verb(job, BLOCK_JOB_VERB_CANCEL, errp)) {
212
return;
213
}
214
- block_job_cancel(job);
215
+ block_job_cancel(job, force);
216
}
217
218
/* A wrapper around block_job_cancel() taking an Error ** parameter so it may be
219
@@ -XXX,XX +XXX,XX @@ void block_job_user_cancel(BlockJob *job, Error **errp)
220
* function pointer casts there. */
221
static void block_job_cancel_err(BlockJob *job, Error **errp)
222
{
223
- block_job_cancel(job);
224
+ block_job_cancel(job, false);
225
}
226
227
int block_job_cancel_sync(BlockJob *job)
228
diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c
229
index XXXXXXX..XXXXXXX 100644
230
--- a/tests/test-blockjob-txn.c
231
+++ b/tests/test-blockjob-txn.c
232
@@ -XXX,XX +XXX,XX @@ static void test_single_job(int expected)
233
block_job_start(job);
234
235
if (expected == -ECANCELED) {
236
- block_job_cancel(job);
237
+ block_job_cancel(job, false);
238
}
239
240
while (result == -EINPROGRESS) {
241
@@ -XXX,XX +XXX,XX @@ static void test_pair_jobs(int expected1, int expected2)
242
block_job_txn_unref(txn);
243
244
if (expected1 == -ECANCELED) {
245
- block_job_cancel(job1);
246
+ block_job_cancel(job1, false);
247
}
248
if (expected2 == -ECANCELED) {
249
- block_job_cancel(job2);
250
+ block_job_cancel(job2, false);
251
}
252
253
while (result1 == -EINPROGRESS || result2 == -EINPROGRESS) {
254
@@ -XXX,XX +XXX,XX @@ static void test_pair_jobs_fail_cancel_race(void)
255
block_job_start(job1);
256
block_job_start(job2);
257
258
- block_job_cancel(job1);
259
+ block_job_cancel(job1, false);
260
261
/* Now make job2 finish before the main loop kicks jobs. This simulates
262
* the race between a pending kick and another job completing.
263
diff --git a/hmp-commands.hx b/hmp-commands.hx
264
index XXXXXXX..XXXXXXX 100644
265
--- a/hmp-commands.hx
266
+++ b/hmp-commands.hx
267
@@ -XXX,XX +XXX,XX @@ ETEXI
268
.args_type = "force:-f,device:B",
269
.params = "[-f] device",
270
.help = "stop an active background block operation (use -f"
271
- "\n\t\t\t if the operation is currently paused)",
272
+ "\n\t\t\t if you want to abort the operation immediately"
273
+ "\n\t\t\t instead of keep running until data is in sync)",
274
.cmd = hmp_block_job_cancel,
275
},
276
277
--
43
--
278
2.13.6
44
2.19.1
279
45
280
46
diff view generated by jsdifflib
1
From: Fam Zheng <famz@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Signed-off-by: Fam Zheng <famz@redhat.com>
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
4
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
5
---
7
tests/qemu-iotests/153 | 12 ++++++++++++
6
tests/qemu-iotests/081 | 30 ++++++++++++++++++++++++++++++
8
tests/qemu-iotests/153.out | 5 +++++
7
tests/qemu-iotests/081.out | 16 ++++++++++++++++
9
2 files changed, 17 insertions(+)
8
2 files changed, 46 insertions(+)
10
9
11
diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153
10
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
12
index XXXXXXX..XXXXXXX 100755
11
index XXXXXXX..XXXXXXX 100755
13
--- a/tests/qemu-iotests/153
12
--- a/tests/qemu-iotests/081
14
+++ b/tests/qemu-iotests/153
13
+++ b/tests/qemu-iotests/081
15
@@ -XXX,XX +XXX,XX @@ rm -f "${TEST_IMG}.lnk" &>/dev/null
14
@@ -XXX,XX +XXX,XX @@ echo "== checking that quorum is broken =="
16
ln -s ${TEST_IMG} "${TEST_IMG}.lnk" || echo "Failed to create link"
15
17
_run_qemu_with_images "${TEST_IMG}.lnk" "${TEST_IMG}"
16
$QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
18
17
19
+echo
18
+echo
20
+echo "== Active commit to intermediate layer should work when base in use =="
19
+echo "== checking the blkverify mode with broken content =="
21
+_launch_qemu -drive format=$IMGFMT,file="${TEST_IMG}.a",id=drive0,if=none \
22
+ -device virtio-blk,drive=drive0
23
+
20
+
24
+_send_qemu_cmd $QEMU_HANDLE \
21
+quorum="driver=raw,file.driver=quorum,file.vote-threshold=2,file.blkverify=on"
25
+ "{ 'execute': 'qmp_capabilities' }" \
22
+quorum="$quorum,file.children.0.file.filename=$TEST_DIR/1.raw"
26
+ 'return'
23
+quorum="$quorum,file.children.1.file.filename=$TEST_DIR/2.raw"
27
+_run_cmd $QEMU_IMG commit -b "${TEST_IMG}.b" "${TEST_IMG}.c"
24
+quorum="$quorum,file.children.0.driver=raw"
25
+quorum="$quorum,file.children.1.driver=raw"
28
+
26
+
29
+_cleanup_qemu
27
+$QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
30
+
28
+
31
_launch_qemu
29
+echo
32
30
+echo "== writing the same data to both files =="
33
_send_qemu_cmd $QEMU_HANDLE \
31
+
34
diff --git a/tests/qemu-iotests/153.out b/tests/qemu-iotests/153.out
32
+$QEMU_IO -c "write -P 0x32 0 $size" "$TEST_DIR/1.raw" | _filter_qemu_io
33
+$QEMU_IO -c "write -P 0x32 0 $size" "$TEST_DIR/2.raw" | _filter_qemu_io
34
+
35
+echo
36
+echo "== checking the blkverify mode with valid content =="
37
+
38
+$QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
39
+
40
+echo
41
+echo "== checking the blkverify mode with invalid settings =="
42
+
43
+quorum="$quorum,file.children.2.file.filename=$TEST_DIR/3.raw"
44
+quorum="$quorum,file.children.2.driver=raw"
45
+
46
+$QEMU_IO -c "open -o $quorum" | _filter_qemu_io
47
+
48
# success, all done
49
echo "*** done"
50
rm -f $seq.full
51
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
35
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
36
--- a/tests/qemu-iotests/153.out
53
--- a/tests/qemu-iotests/081.out
37
+++ b/tests/qemu-iotests/153.out
54
+++ b/tests/qemu-iotests/081.out
38
@@ -XXX,XX +XXX,XX @@ Is another process using the image?
55
@@ -XXX,XX +XXX,XX @@ wrote 10485760/10485760 bytes at offset 0
39
== Symbolic link ==
56
40
QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2: Failed to get "write" lock
57
== checking that quorum is broken ==
41
Is another process using the image?
58
read failed: Input/output error
42
+
59
+
43
+== Active commit to intermediate layer should work when base in use ==
60
+== checking the blkverify mode with broken content ==
44
+{"return": {}}
61
+quorum: offset=0 bytes=10485760 contents mismatch at offset 0
45
+
62
+
46
+_qemu_img_wrapper commit -b TEST_DIR/t.qcow2.b TEST_DIR/t.qcow2.c
63
+== writing the same data to both files ==
47
{"return": {}}
64
+wrote 10485760/10485760 bytes at offset 0
48
Adding drive
65
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
49
66
+wrote 10485760/10485760 bytes at offset 0
67
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
68
+
69
+== checking the blkverify mode with valid content ==
70
+read 10485760/10485760 bytes at offset 0
71
+10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
72
+
73
+== checking the blkverify mode with invalid settings ==
74
+can't open: blkverify=on can only be set if there are exactly two files and vote-threshold is 2
75
*** done
50
--
76
--
51
2.13.6
77
2.19.1
52
78
53
79
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
For jobs utilizing the new manual workflow, we intend to prohibit
3
The blkverify mode of Quorum only works when the number of children is
4
them from modifying the block graph until the management layer provides
4
exactly two, so any attempt to add a new one must return an error.
5
an explicit ACK via block-job-finalize to move the process forward.
6
5
7
To distinguish this runstate from "ready" or "waiting," we add a new
6
quorum_del_child() on the other hand doesn't need any additional check
8
"pending" event and status.
7
because decreasing the number of children would make it go under the
8
vote threshold.
9
9
10
For now, the transition from PENDING to CONCLUDED/ABORTING is automatic,
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
but a future commit will add the explicit block-job-finalize step.
11
Reported-by: Kevin Wolf <kwolf@redhat.com>
12
13
Transitions:
14
Waiting -> Pending: Normal transition.
15
Pending -> Concluded: Normal transition.
16
Pending -> Aborting: Late transactional failures and cancellations.
17
18
Removed Transitions:
19
Waiting -> Concluded: Jobs must go to PENDING first.
20
21
Verbs:
22
Cancel: Can be applied to a pending job.
23
24
+---------+
25
|UNDEFINED|
26
+--+------+
27
|
28
+--v----+
29
+---------+CREATED+-----------------+
30
| +--+----+ |
31
| | |
32
| +--+----+ +------+ |
33
+---------+RUNNING<----->PAUSED| |
34
| +--+-+--+ +------+ |
35
| | | |
36
| | +------------------+ |
37
| | | |
38
| +--v--+ +-------+ | |
39
+---------+READY<------->STANDBY| | |
40
| +--+--+ +-------+ | |
41
| | | |
42
| +--v----+ | |
43
+---------+WAITING<---------------+ |
44
| +--+----+ |
45
| | |
46
| +--v----+ |
47
+---------+PENDING| |
48
| +--+----+ |
49
| | |
50
+--v-----+ +--v------+ |
51
|ABORTING+--->CONCLUDED| |
52
+--------+ +--+------+ |
53
| |
54
+--v-+ |
55
|NULL<--------------------+
56
+----+
57
58
Signed-off-by: John Snow <jsnow@redhat.com>
59
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
60
---
13
---
61
qapi/block-core.json | 31 +++++++++++++++++++++-
14
block/quorum.c | 8 ++++++++
62
include/block/blockjob.h | 5 ++++
15
1 file changed, 8 insertions(+)
63
blockjob.c | 67 +++++++++++++++++++++++++++++++-----------------
64
3 files changed, 78 insertions(+), 25 deletions(-)
65
16
66
diff --git a/qapi/block-core.json b/qapi/block-core.json
17
diff --git a/block/quorum.c b/block/quorum.c
67
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
68
--- a/qapi/block-core.json
19
--- a/block/quorum.c
69
+++ b/qapi/block-core.json
20
+++ b/block/quorum.c
70
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
71
# to the waiting state. This status will likely not be visible for
22
char indexstr[32];
72
# the last job in a transaction.
23
int ret;
73
#
24
74
+# @pending: The job has finished its work, but has finalization steps that it
25
+ if (s->is_blkverify) {
75
+# needs to make prior to completing. These changes may require
26
+ error_setg(errp, "Cannot add a child to a quorum in blkverify mode");
76
+# manual intervention by the management process if manual was set
27
+ return;
77
+# to true. These changes may still fail.
28
+ }
78
+#
79
# @aborting: The job is in the process of being aborted, and will finish with
80
# an error. The job will afterwards report that it is @concluded.
81
# This status may not be visible to the management process.
82
@@ -XXX,XX +XXX,XX @@
83
##
84
{ 'enum': 'BlockJobStatus',
85
'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby',
86
- 'waiting', 'aborting', 'concluded', 'null' ] }
87
+ 'waiting', 'pending', 'aborting', 'concluded', 'null' ] }
88
89
##
90
# @BlockJobInfo:
91
@@ -XXX,XX +XXX,XX @@
92
'speed' : 'int' } }
93
94
##
95
+# @BLOCK_JOB_PENDING:
96
+#
97
+# Emitted when a block job is awaiting explicit authorization to finalize graph
98
+# changes via @block-job-finalize. If this job is part of a transaction, it will
99
+# not emit this event until the transaction has converged first.
100
+#
101
+# @type: job type
102
+#
103
+# @id: The job identifier.
104
+#
105
+# Since: 2.12
106
+#
107
+# Example:
108
+#
109
+# <- { "event": "BLOCK_JOB_WAITING",
110
+# "data": { "device": "drive0", "type": "mirror" },
111
+# "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
112
+#
113
+##
114
+{ 'event': 'BLOCK_JOB_PENDING',
115
+ 'data': { 'type' : 'BlockJobType',
116
+ 'id' : 'str' } }
117
+
29
+
118
+##
30
assert(s->num_children <= INT_MAX / sizeof(BdrvChild *));
119
# @PreallocMode:
31
if (s->num_children == INT_MAX / sizeof(BdrvChild *) ||
120
#
32
s->next_child_index == UINT_MAX) {
121
# Preallocation mode of QEMU image file
33
@@ -XXX,XX +XXX,XX @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child,
122
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
123
index XXXXXXX..XXXXXXX 100644
124
--- a/include/block/blockjob.h
125
+++ b/include/block/blockjob.h
126
@@ -XXX,XX +XXX,XX @@ typedef struct BlockJob {
127
/** Current state; See @BlockJobStatus for details. */
128
BlockJobStatus status;
129
130
+ /** True if this job should automatically finalize itself */
131
+ bool auto_finalize;
132
+
133
/** True if this job should automatically dismiss itself */
134
bool auto_dismiss;
135
136
@@ -XXX,XX +XXX,XX @@ typedef enum BlockJobCreateFlags {
137
BLOCK_JOB_DEFAULT = 0x00,
138
/* BlockJob is not QMP-created and should not send QMP events */
139
BLOCK_JOB_INTERNAL = 0x01,
140
+ /* BlockJob requires manual finalize step */
141
+ BLOCK_JOB_MANUAL_FINALIZE = 0x02,
142
/* BlockJob requires manual dismiss step */
143
BLOCK_JOB_MANUAL_DISMISS = 0x04,
144
} BlockJobCreateFlags;
145
diff --git a/blockjob.c b/blockjob.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/blockjob.c
148
+++ b/blockjob.c
149
@@ -XXX,XX +XXX,XX @@ static QemuMutex block_job_mutex;
150
151
/* BlockJob State Transition Table */
152
bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] = {
153
- /* U, C, R, P, Y, S, W, X, E, N */
154
- /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
155
- /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 0, 1, 0, 1},
156
- /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1, 1, 0, 0},
157
- /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
158
- /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 1, 0, 0},
159
- /* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
160
- /* W: */ [BLOCK_JOB_STATUS_WAITING] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
161
- /* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
162
- /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
163
- /* N: */ [BLOCK_JOB_STATUS_NULL] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
164
+ /* U, C, R, P, Y, S, W, D, X, E, N */
165
+ /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
166
+ /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1},
167
+ /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0},
168
+ /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
169
+ /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0},
170
+ /* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
171
+ /* W: */ [BLOCK_JOB_STATUS_WAITING] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0},
172
+ /* D: */ [BLOCK_JOB_STATUS_PENDING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
173
+ /* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0},
174
+ /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
175
+ /* N: */ [BLOCK_JOB_STATUS_NULL] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
176
};
177
178
bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] = {
179
- /* U, C, R, P, Y, S, W, X, E, N */
180
- [BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 1, 0, 0, 0},
181
- [BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0},
182
- [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0},
183
- [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0},
184
- [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
185
- [BLOCK_JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
186
+ /* U, C, R, P, Y, S, W, D, X, E, N */
187
+ [BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
188
+ [BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
189
+ [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
190
+ [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
191
+ [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
192
+ [BLOCK_JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
193
};
194
195
static void block_job_state_transition(BlockJob *job, BlockJobStatus s1)
196
@@ -XXX,XX +XXX,XX @@ static void __attribute__((__constructor__)) block_job_init(void)
197
198
static void block_job_event_cancelled(BlockJob *job);
199
static void block_job_event_completed(BlockJob *job, const char *msg);
200
+static int block_job_event_pending(BlockJob *job);
201
static void block_job_enter_cond(BlockJob *job, bool(*fn)(BlockJob *job));
202
203
/* Transactional group of block jobs */
204
@@ -XXX,XX +XXX,XX @@ static void block_job_cancel_async(BlockJob *job)
205
job->cancelled = true;
206
}
207
208
-static int block_job_txn_apply(BlockJobTxn *txn, int fn(BlockJob *))
209
+static int block_job_txn_apply(BlockJobTxn *txn, int fn(BlockJob *), bool lock)
210
{
211
AioContext *ctx;
212
BlockJob *job, *next;
213
int rc;
214
215
QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) {
216
- ctx = blk_get_aio_context(job->blk);
217
- aio_context_acquire(ctx);
218
+ if (lock) {
219
+ ctx = blk_get_aio_context(job->blk);
220
+ aio_context_acquire(ctx);
221
+ }
222
rc = fn(job);
223
- aio_context_release(ctx);
224
+ if (lock) {
225
+ aio_context_release(ctx);
226
+ }
227
if (rc) {
228
break;
229
}
230
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_txn_success(BlockJob *job)
231
}
232
233
/* Jobs may require some prep-work to complete without failure */
234
- rc = block_job_txn_apply(txn, block_job_prepare);
235
+ rc = block_job_txn_apply(txn, block_job_prepare, true);
236
if (rc) {
237
block_job_completed_txn_abort(job);
238
return;
34
return;
239
}
35
}
240
36
241
/* We are the last completed job, commit the transaction. */
37
+ /* We know now that num_children > threshold, so blkverify must be false */
242
- block_job_txn_apply(txn, block_job_completed_single);
38
+ assert(!s->is_blkverify);
243
+ block_job_txn_apply(txn, block_job_event_pending, false);
244
+ block_job_txn_apply(txn, block_job_completed_single, true);
245
}
246
247
/* Assumes the block_job_mutex is held */
248
@@ -XXX,XX +XXX,XX @@ static void block_job_event_completed(BlockJob *job, const char *msg)
249
&error_abort);
250
}
251
252
+static int block_job_event_pending(BlockJob *job)
253
+{
254
+ block_job_state_transition(job, BLOCK_JOB_STATUS_PENDING);
255
+ if (!job->auto_finalize && !block_job_is_internal(job)) {
256
+ qapi_event_send_block_job_pending(job->driver->job_type,
257
+ job->id,
258
+ &error_abort);
259
+ }
260
+ return 0;
261
+}
262
+
39
+
263
/*
40
bdrv_drained_begin(bs);
264
* API for block job drivers and the block layer. These functions are
41
265
* declared in blockjob_int.h.
42
/* We can safely remove this child now */
266
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
267
job->paused = true;
268
job->pause_count = 1;
269
job->refcnt = 1;
270
+ job->auto_finalize = !(flags & BLOCK_JOB_MANUAL_FINALIZE);
271
job->auto_dismiss = !(flags & BLOCK_JOB_MANUAL_DISMISS);
272
block_job_state_transition(job, BLOCK_JOB_STATUS_CREATED);
273
aio_timer_init(qemu_get_aio_context(), &job->sleep_timer,
274
--
43
--
275
2.13.6
44
2.19.1
276
45
277
46
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Signed-off-by: John Snow <jsnow@redhat.com>
3
This patch tests that you can add and remove drives from a Quorum
4
using the x-blockdev-change command.
5
6
Signed-off-by: Alberto Garcia <berto@igalia.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
8
---
6
tests/qemu-iotests/056 | 187 +++++++++++++++++++++++++++++++++++++++++++++
9
tests/qemu-iotests/081 | 86 ++++++++++++++++++++++++++++++++++++++
7
tests/qemu-iotests/056.out | 4 +-
10
tests/qemu-iotests/081.out | 54 ++++++++++++++++++++++++
8
2 files changed, 189 insertions(+), 2 deletions(-)
11
2 files changed, 140 insertions(+)
9
12
10
diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056
13
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
11
index XXXXXXX..XXXXXXX 100755
14
index XXXXXXX..XXXXXXX 100755
12
--- a/tests/qemu-iotests/056
15
--- a/tests/qemu-iotests/081
13
+++ b/tests/qemu-iotests/056
16
+++ b/tests/qemu-iotests/081
14
@@ -XXX,XX +XXX,XX @@ backing_img = os.path.join(iotests.test_dir, 'backing.img')
17
@@ -XXX,XX +XXX,XX @@ quorum="$quorum,file.children.2.driver=raw"
15
test_img = os.path.join(iotests.test_dir, 'test.img')
18
16
target_img = os.path.join(iotests.test_dir, 'target.img')
19
$QEMU_IO -c "open -o $quorum" | _filter_qemu_io
17
20
18
+def img_create(img, fmt=iotests.imgfmt, size='64M', **kwargs):
21
+echo
19
+ fullname = os.path.join(iotests.test_dir, '%s.%s' % (img, fmt))
22
+echo "== dynamically adding a child to a quorum =="
20
+ optargs = []
21
+ for k,v in kwargs.iteritems():
22
+ optargs = optargs + ['-o', '%s=%s' % (k,v)]
23
+ args = ['create', '-f', fmt] + optargs + [fullname, size]
24
+ iotests.qemu_img(*args)
25
+ return fullname
26
+
23
+
27
+def try_remove(img):
24
+for verify in false true; do
28
+ try:
25
+ run_qemu <<EOF
29
+ os.remove(img)
26
+ { "execute": "qmp_capabilities" }
30
+ except OSError:
27
+ { "execute": "blockdev-add",
31
+ pass
28
+ "arguments": {
29
+ "driver": "quorum",
30
+ "node-name": "drive0-quorum",
31
+ "vote-threshold": 2,
32
+ "blkverify": ${verify},
33
+ "children": [
34
+ {
35
+ "driver": "$IMGFMT",
36
+ "file": {
37
+ "driver": "file",
38
+ "filename": "$TEST_DIR/1.raw"
39
+ }
40
+ },
41
+ {
42
+ "driver": "$IMGFMT",
43
+ "file": {
44
+ "driver": "file",
45
+ "filename": "$TEST_DIR/2.raw"
46
+ }
47
+ }
48
+ ]
49
+ }
50
+ }
51
+ { "execute": "blockdev-add",
52
+ "arguments": {
53
+ "node-name": "drive3",
54
+ "driver": "$IMGFMT",
55
+ "file": {
56
+ "driver": "file",
57
+ "filename": "$TEST_DIR/2.raw"
58
+ }
59
+ }
60
+ }
61
+ { "execute": "x-blockdev-change",
62
+ "arguments": { "parent": "drive0-quorum",
63
+ "node": "drive3" } }
64
+ { "execute": "quit" }
65
+EOF
66
+done
32
+
67
+
33
+def io_write_patterns(img, patterns):
68
+echo
34
+ for pattern in patterns:
69
+echo "== dynamically removing a child from a quorum =="
35
+ iotests.qemu_io('-c', 'write -P%s %s %s' % pattern, img)
70
+
71
+for verify in false true; do
72
+ for vote_threshold in 1 2; do
73
+ run_qemu <<EOF
74
+ { "execute": "qmp_capabilities" }
75
+ { "execute": "blockdev-add",
76
+ "arguments": {
77
+ "driver": "quorum",
78
+ "node-name": "drive0-quorum",
79
+ "vote-threshold": ${vote_threshold},
80
+ "blkverify": ${verify},
81
+ "children": [
82
+ {
83
+ "driver": "$IMGFMT",
84
+ "file": {
85
+ "driver": "file",
86
+ "filename": "$TEST_DIR/1.raw"
87
+ }
88
+ },
89
+ {
90
+ "driver": "$IMGFMT",
91
+ "file": {
92
+ "driver": "file",
93
+ "filename": "$TEST_DIR/2.raw"
94
+ }
95
+ }
96
+ ]
97
+ }
98
+ }
99
+ { "execute": "x-blockdev-change",
100
+ "arguments": { "parent": "drive0-quorum",
101
+ "child": "children.1" } }
102
+ { "execute": "quit" }
103
+EOF
104
+ done
105
+done
106
+
107
# success, all done
108
echo "*** done"
109
rm -f $seq.full
110
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
111
index XXXXXXX..XXXXXXX 100644
112
--- a/tests/qemu-iotests/081.out
113
+++ b/tests/qemu-iotests/081.out
114
@@ -XXX,XX +XXX,XX @@ read 10485760/10485760 bytes at offset 0
115
116
== checking the blkverify mode with invalid settings ==
117
can't open: blkverify=on can only be set if there are exactly two files and vote-threshold is 2
118
+
119
+== dynamically adding a child to a quorum ==
120
+Testing:
121
+QMP_VERSION
122
+{"return": {}}
123
+{"return": {}}
124
+{"return": {}}
125
+{"return": {}}
126
+{"return": {}}
127
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
128
+
129
+Testing:
130
+QMP_VERSION
131
+{"return": {}}
132
+{"return": {}}
133
+{"return": {}}
134
+{"error": {"class": "GenericError", "desc": "Cannot add a child to a quorum in blkverify mode"}}
135
+{"return": {}}
136
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
36
+
137
+
37
+
138
+
38
class TestSyncModesNoneAndTop(iotests.QMPTestCase):
139
+== dynamically removing a child from a quorum ==
39
image_len = 64 * 1024 * 1024 # MB
140
+Testing:
40
141
+QMP_VERSION
41
@@ -XXX,XX +XXX,XX @@ class TestBeforeWriteNotifier(iotests.QMPTestCase):
142
+{"return": {}}
42
event = self.cancel_and_wait()
143
+{"return": {}}
43
self.assert_qmp(event, 'data/type', 'backup')
144
+{"return": {}}
44
145
+{"return": {}}
45
+class BackupTest(iotests.QMPTestCase):
146
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
46
+ def setUp(self):
47
+ self.vm = iotests.VM()
48
+ self.test_img = img_create('test')
49
+ self.dest_img = img_create('dest')
50
+ self.vm.add_drive(self.test_img)
51
+ self.vm.launch()
52
+
147
+
53
+ def tearDown(self):
148
+Testing:
54
+ self.vm.shutdown()
149
+QMP_VERSION
55
+ try_remove(self.test_img)
150
+{"return": {}}
56
+ try_remove(self.dest_img)
151
+{"return": {}}
152
+{"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}}
153
+{"return": {}}
154
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
57
+
155
+
58
+ def hmp_io_writes(self, drive, patterns):
156
+Testing:
59
+ for pattern in patterns:
157
+QMP_VERSION
60
+ self.vm.hmp_qemu_io(drive, 'write -P%s %s %s' % pattern)
158
+{"return": {}}
61
+ self.vm.hmp_qemu_io(drive, 'flush')
159
+{"error": {"class": "GenericError", "desc": "blkverify=on can only be set if there are exactly two files and vote-threshold is 2"}}
160
+{"error": {"class": "GenericError", "desc": "Cannot find device=drive0-quorum nor node_name=drive0-quorum"}}
161
+{"return": {}}
162
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
62
+
163
+
63
+ def qmp_backup_and_wait(self, cmd='drive-backup', serror=None,
164
+Testing:
64
+ aerror=None, **kwargs):
165
+QMP_VERSION
65
+ if not self.qmp_backup(cmd, serror, **kwargs):
166
+{"return": {}}
66
+ return False
167
+{"return": {}}
67
+ return self.qmp_backup_wait(kwargs['device'], aerror)
168
+{"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}}
169
+{"return": {}}
170
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
68
+
171
+
69
+ def qmp_backup(self, cmd='drive-backup',
172
*** done
70
+ error=None, **kwargs):
71
+ self.assertTrue('device' in kwargs)
72
+ res = self.vm.qmp(cmd, **kwargs)
73
+ if error:
74
+ self.assert_qmp(res, 'error/desc', error)
75
+ return False
76
+ self.assert_qmp(res, 'return', {})
77
+ return True
78
+
79
+ def qmp_backup_wait(self, device, error=None):
80
+ event = self.vm.event_wait(name="BLOCK_JOB_COMPLETED",
81
+ match={'data': {'device': device}})
82
+ self.assertNotEqual(event, None)
83
+ try:
84
+ failure = self.dictpath(event, 'data/error')
85
+ except AssertionError:
86
+ # Backup succeeded.
87
+ self.assert_qmp(event, 'data/offset', event['data']['len'])
88
+ return True
89
+ else:
90
+ # Failure.
91
+ self.assert_qmp(event, 'data/error', qerror)
92
+ return False
93
+
94
+ def test_dismiss_false(self):
95
+ res = self.vm.qmp('query-block-jobs')
96
+ self.assert_qmp(res, 'return', [])
97
+ self.qmp_backup_and_wait(device='drive0', format=iotests.imgfmt,
98
+ sync='full', target=self.dest_img,
99
+ auto_dismiss=True)
100
+ res = self.vm.qmp('query-block-jobs')
101
+ self.assert_qmp(res, 'return', [])
102
+
103
+ def test_dismiss_true(self):
104
+ res = self.vm.qmp('query-block-jobs')
105
+ self.assert_qmp(res, 'return', [])
106
+ self.qmp_backup_and_wait(device='drive0', format=iotests.imgfmt,
107
+ sync='full', target=self.dest_img,
108
+ auto_dismiss=False)
109
+ res = self.vm.qmp('query-block-jobs')
110
+ self.assert_qmp(res, 'return[0]/status', 'concluded')
111
+ res = self.vm.qmp('block-job-dismiss', id='drive0')
112
+ self.assert_qmp(res, 'return', {})
113
+ res = self.vm.qmp('query-block-jobs')
114
+ self.assert_qmp(res, 'return', [])
115
+
116
+ def test_dismiss_bad_id(self):
117
+ res = self.vm.qmp('query-block-jobs')
118
+ self.assert_qmp(res, 'return', [])
119
+ res = self.vm.qmp('block-job-dismiss', id='foobar')
120
+ self.assert_qmp(res, 'error/class', 'DeviceNotActive')
121
+
122
+ def test_dismiss_collision(self):
123
+ res = self.vm.qmp('query-block-jobs')
124
+ self.assert_qmp(res, 'return', [])
125
+ self.qmp_backup_and_wait(device='drive0', format=iotests.imgfmt,
126
+ sync='full', target=self.dest_img,
127
+ auto_dismiss=False)
128
+ res = self.vm.qmp('query-block-jobs')
129
+ self.assert_qmp(res, 'return[0]/status', 'concluded')
130
+ # Leave zombie job un-dismissed, observe a failure:
131
+ res = self.qmp_backup_and_wait(serror='Need a root block node',
132
+ device='drive0', format=iotests.imgfmt,
133
+ sync='full', target=self.dest_img,
134
+ auto_dismiss=False)
135
+ self.assertEqual(res, False)
136
+ # OK, dismiss the zombie.
137
+ res = self.vm.qmp('block-job-dismiss', id='drive0')
138
+ self.assert_qmp(res, 'return', {})
139
+ res = self.vm.qmp('query-block-jobs')
140
+ self.assert_qmp(res, 'return', [])
141
+ # Ensure it's really gone.
142
+ self.qmp_backup_and_wait(device='drive0', format=iotests.imgfmt,
143
+ sync='full', target=self.dest_img,
144
+ auto_dismiss=False)
145
+
146
+ def dismissal_failure(self, dismissal_opt):
147
+ res = self.vm.qmp('query-block-jobs')
148
+ self.assert_qmp(res, 'return', [])
149
+ # Give blkdebug something to chew on
150
+ self.hmp_io_writes('drive0',
151
+ (('0x9a', 0, 512),
152
+ ('0x55', '8M', '352k'),
153
+ ('0x78', '15872k', '1M')))
154
+ # Add destination node via blkdebug
155
+ res = self.vm.qmp('blockdev-add',
156
+ node_name='target0',
157
+ driver=iotests.imgfmt,
158
+ file={
159
+ 'driver': 'blkdebug',
160
+ 'image': {
161
+ 'driver': 'file',
162
+ 'filename': self.dest_img
163
+ },
164
+ 'inject-error': [{
165
+ 'event': 'write_aio',
166
+ 'errno': 5,
167
+ 'immediately': False,
168
+ 'once': True
169
+ }],
170
+ })
171
+ self.assert_qmp(res, 'return', {})
172
+
173
+ res = self.qmp_backup(cmd='blockdev-backup',
174
+ device='drive0', target='target0',
175
+ on_target_error='stop',
176
+ sync='full',
177
+ auto_dismiss=dismissal_opt)
178
+ self.assertTrue(res)
179
+ event = self.vm.event_wait(name="BLOCK_JOB_ERROR",
180
+ match={'data': {'device': 'drive0'}})
181
+ self.assertNotEqual(event, None)
182
+ # OK, job should be wedged
183
+ res = self.vm.qmp('query-block-jobs')
184
+ self.assert_qmp(res, 'return[0]/status', 'paused')
185
+ res = self.vm.qmp('block-job-dismiss', id='drive0')
186
+ self.assert_qmp(res, 'error/desc',
187
+ "Job 'drive0' in state 'paused' cannot accept"
188
+ " command verb 'dismiss'")
189
+ res = self.vm.qmp('query-block-jobs')
190
+ self.assert_qmp(res, 'return[0]/status', 'paused')
191
+ # OK, unstick job and move forward.
192
+ res = self.vm.qmp('block-job-resume', device='drive0')
193
+ self.assert_qmp(res, 'return', {})
194
+ # And now we need to wait for it to conclude;
195
+ res = self.qmp_backup_wait(device='drive0')
196
+ self.assertTrue(res)
197
+ if not dismissal_opt:
198
+ # Job should now be languishing:
199
+ res = self.vm.qmp('query-block-jobs')
200
+ self.assert_qmp(res, 'return[0]/status', 'concluded')
201
+ res = self.vm.qmp('block-job-dismiss', id='drive0')
202
+ self.assert_qmp(res, 'return', {})
203
+ res = self.vm.qmp('query-block-jobs')
204
+ self.assert_qmp(res, 'return', [])
205
+
206
+ def test_dismiss_premature(self):
207
+ self.dismissal_failure(False)
208
+
209
+ def test_dismiss_erroneous(self):
210
+ self.dismissal_failure(True)
211
+
212
if __name__ == '__main__':
213
iotests.main(supported_fmts=['qcow2', 'qed'])
214
diff --git a/tests/qemu-iotests/056.out b/tests/qemu-iotests/056.out
215
index XXXXXXX..XXXXXXX 100644
216
--- a/tests/qemu-iotests/056.out
217
+++ b/tests/qemu-iotests/056.out
218
@@ -XXX,XX +XXX,XX @@
219
-...
220
+.........
221
----------------------------------------------------------------------
222
-Ran 3 tests
223
+Ran 9 tests
224
225
OK
226
--
173
--
227
2.13.6
174
2.19.1
228
175
229
176
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to vpc, which
1
To fully change the read-only state of a node, we must not only change
2
enables image creation over QMP.
2
bs->read_only, but also update bs->open_flags.
3
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
---
7
---
7
qapi/block-core.json | 33 ++++++++++-
8
block.c | 7 +++++++
8
block/vpc.c | 152 ++++++++++++++++++++++++++++++++++++++-------------
9
1 file changed, 7 insertions(+)
9
2 files changed, 147 insertions(+), 38 deletions(-)
10
10
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
11
diff --git a/block.c b/block.c
12
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
13
--- a/block.c
14
+++ b/qapi/block-core.json
14
+++ b/block.c
15
@@ -XXX,XX +XXX,XX @@
15
@@ -XXX,XX +XXX,XX @@ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
16
'*block-state-zero': 'bool' } }
16
}
17
17
18
##
18
bs->read_only = read_only;
19
+# @BlockdevVpcSubformat:
20
+#
21
+# @dynamic: Growing image file
22
+# @fixed: Preallocated fixed-size image file
23
+#
24
+# Since: 2.12
25
+##
26
+{ 'enum': 'BlockdevVpcSubformat',
27
+ 'data': [ 'dynamic', 'fixed' ] }
28
+
19
+
29
+##
20
+ if (read_only) {
30
+# @BlockdevCreateOptionsVpc:
21
+ bs->open_flags &= ~BDRV_O_RDWR;
31
+#
22
+ } else {
32
+# Driver specific image creation options for vpc (VHD).
23
+ bs->open_flags |= BDRV_O_RDWR;
33
+#
34
+# @file Node to create the image format on
35
+# @size Size of the virtual disk in bytes
36
+# @subformat vhdx subformat (default: dynamic)
37
+# @force-size Force use of the exact byte size instead of rounding to the
38
+# next size that can be represented in CHS geometry
39
+# (default: false)
40
+#
41
+# Since: 2.12
42
+##
43
+{ 'struct': 'BlockdevCreateOptionsVpc',
44
+ 'data': { 'file': 'BlockdevRef',
45
+ 'size': 'size',
46
+ '*subformat': 'BlockdevVpcSubformat',
47
+ '*force-size': 'bool' } }
48
+
49
+##
50
# @BlockdevCreateNotSupported:
51
#
52
# This is used for all drivers that don't support creating images.
53
@@ -XXX,XX +XXX,XX @@
54
'vdi': 'BlockdevCreateOptionsVdi',
55
'vhdx': 'BlockdevCreateOptionsVhdx',
56
'vmdk': 'BlockdevCreateNotSupported',
57
- 'vpc': 'BlockdevCreateNotSupported',
58
+ 'vpc': 'BlockdevCreateOptionsVpc',
59
'vvfat': 'BlockdevCreateNotSupported',
60
'vxhs': 'BlockdevCreateNotSupported'
61
} }
62
diff --git a/block/vpc.c b/block/vpc.c
63
index XXXXXXX..XXXXXXX 100644
64
--- a/block/vpc.c
65
+++ b/block/vpc.c
66
@@ -XXX,XX +XXX,XX @@
67
#include "migration/blocker.h"
68
#include "qemu/bswap.h"
69
#include "qemu/uuid.h"
70
+#include "qapi/qmp/qdict.h"
71
+#include "qapi/qobject-input-visitor.h"
72
+#include "qapi/qapi-visit-block-core.h"
73
74
/**************************************************************/
75
76
@@ -XXX,XX +XXX,XX @@ static QemuOptsList vpc_runtime_opts = {
77
}
78
};
79
80
+static QemuOptsList vpc_create_opts;
81
+
82
static uint32_t vpc_checksum(uint8_t* buf, size_t size)
83
{
84
uint32_t res = 0;
85
@@ -XXX,XX +XXX,XX @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
86
return ret;
87
}
88
89
-static int coroutine_fn vpc_co_create_opts(const char *filename, QemuOpts *opts,
90
- Error **errp)
91
+static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
92
+ Error **errp)
93
{
94
+ BlockdevCreateOptionsVpc *vpc_opts;
95
+ BlockBackend *blk = NULL;
96
+ BlockDriverState *bs = NULL;
97
+
98
uint8_t buf[1024];
99
VHDFooter *footer = (VHDFooter *) buf;
100
- char *disk_type_param;
101
int i;
102
uint16_t cyls = 0;
103
uint8_t heads = 0;
104
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename, QemuOpts *opts,
105
int64_t total_size;
106
int disk_type;
107
int ret = -EIO;
108
- bool force_size;
109
- Error *local_err = NULL;
110
- BlockBackend *blk = NULL;
111
112
- /* Read out options */
113
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
114
- BDRV_SECTOR_SIZE);
115
- disk_type_param = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
116
- if (disk_type_param) {
117
- if (!strcmp(disk_type_param, "dynamic")) {
118
- disk_type = VHD_DYNAMIC;
119
- } else if (!strcmp(disk_type_param, "fixed")) {
120
- disk_type = VHD_FIXED;
121
- } else {
122
- error_setg(errp, "Invalid disk type, %s", disk_type_param);
123
- ret = -EINVAL;
124
- goto out;
125
- }
126
- } else {
127
+ assert(opts->driver == BLOCKDEV_DRIVER_VPC);
128
+ vpc_opts = &opts->u.vpc;
129
+
130
+ /* Validate options and set default values */
131
+ total_size = vpc_opts->size;
132
+
133
+ if (!vpc_opts->has_subformat) {
134
+ vpc_opts->subformat = BLOCKDEV_VPC_SUBFORMAT_DYNAMIC;
135
+ }
136
+ switch (vpc_opts->subformat) {
137
+ case BLOCKDEV_VPC_SUBFORMAT_DYNAMIC:
138
disk_type = VHD_DYNAMIC;
139
+ break;
140
+ case BLOCKDEV_VPC_SUBFORMAT_FIXED:
141
+ disk_type = VHD_FIXED;
142
+ break;
143
+ default:
144
+ g_assert_not_reached();
145
}
146
147
- force_size = qemu_opt_get_bool_del(opts, VPC_OPT_FORCE_SIZE, false);
148
-
149
- ret = bdrv_create_file(filename, opts, &local_err);
150
- if (ret < 0) {
151
- error_propagate(errp, local_err);
152
- goto out;
153
+ /* Create BlockBackend to write to the image */
154
+ bs = bdrv_open_blockdev_ref(vpc_opts->file, errp);
155
+ if (bs == NULL) {
156
+ return -EIO;
157
}
158
159
- blk = blk_new_open(filename, NULL, NULL,
160
- BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
161
- &local_err);
162
- if (blk == NULL) {
163
- error_propagate(errp, local_err);
164
- ret = -EIO;
165
+ blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
166
+ ret = blk_insert_bs(blk, bs, errp);
167
+ if (ret < 0) {
168
goto out;
169
}
170
-
171
blk_set_allow_write_beyond_eof(blk, true);
172
173
/*
174
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename, QemuOpts *opts,
175
* we set the geometry to 65535 x 16 x 255 (CxHxS) sectors and use
176
* the image size from the VHD footer to calculate total_sectors.
177
*/
178
- if (force_size) {
179
+ if (vpc_opts->force_size) {
180
/* This will force the use of total_size for sector count, below */
181
cyls = VHD_CHS_MAX_C;
182
heads = VHD_CHS_MAX_H;
183
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename, QemuOpts *opts,
184
memset(buf, 0, 1024);
185
186
memcpy(footer->creator, "conectix", 8);
187
- if (force_size) {
188
+ if (vpc_opts->force_size) {
189
memcpy(footer->creator_app, "qem2", 4);
190
} else {
191
memcpy(footer->creator_app, "qemu", 4);
192
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vpc_co_create_opts(const char *filename, QemuOpts *opts,
193
194
out:
195
blk_unref(blk);
196
- g_free(disk_type_param);
197
+ bdrv_unref(bs);
198
+ return ret;
199
+}
200
+
201
+static int coroutine_fn vpc_co_create_opts(const char *filename,
202
+ QemuOpts *opts, Error **errp)
203
+{
204
+ BlockdevCreateOptions *create_options = NULL;
205
+ QDict *qdict = NULL;
206
+ QObject *qobj;
207
+ Visitor *v;
208
+ BlockDriverState *bs = NULL;
209
+ Error *local_err = NULL;
210
+ int ret;
211
+
212
+ static const QDictRenames opt_renames[] = {
213
+ { VPC_OPT_FORCE_SIZE, "force-size" },
214
+ { NULL, NULL },
215
+ };
216
+
217
+ /* Parse options and convert legacy syntax */
218
+ qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vpc_create_opts, true);
219
+
220
+ if (!qdict_rename_keys(qdict, opt_renames, errp)) {
221
+ ret = -EINVAL;
222
+ goto fail;
223
+ }
24
+ }
224
+
25
+
225
+ /* Create and open the file (protocol layer) */
26
return 0;
226
+ ret = bdrv_create_file(filename, opts, &local_err);
227
+ if (ret < 0) {
228
+ error_propagate(errp, local_err);
229
+ goto fail;
230
+ }
231
+
232
+ bs = bdrv_open(filename, NULL, NULL,
233
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
234
+ if (bs == NULL) {
235
+ ret = -EIO;
236
+ goto fail;
237
+ }
238
+
239
+ /* Now get the QAPI type BlockdevCreateOptions */
240
+ qdict_put_str(qdict, "driver", "vpc");
241
+ qdict_put_str(qdict, "file", bs->node_name);
242
+
243
+ qobj = qdict_crumple(qdict, errp);
244
+ QDECREF(qdict);
245
+ qdict = qobject_to_qdict(qobj);
246
+ if (qdict == NULL) {
247
+ ret = -EINVAL;
248
+ goto fail;
249
+ }
250
+
251
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
252
+ visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
253
+ visit_free(v);
254
+
255
+ if (local_err) {
256
+ error_propagate(errp, local_err);
257
+ ret = -EINVAL;
258
+ goto fail;
259
+ }
260
+
261
+ /* Silently round up size */
262
+ assert(create_options->driver == BLOCKDEV_DRIVER_VPC);
263
+ create_options->u.vpc.size =
264
+ ROUND_UP(create_options->u.vpc.size, BDRV_SECTOR_SIZE);
265
+
266
+ /* Create the vpc image (format layer) */
267
+ ret = vpc_co_create(create_options, errp);
268
+
269
+fail:
270
+ QDECREF(qdict);
271
+ bdrv_unref(bs);
272
+ qapi_free_BlockdevCreateOptions(create_options);
273
return ret;
274
}
27
}
275
28
276
+
277
static int vpc_has_zero_init(BlockDriverState *bs)
278
{
279
BDRVVPCState *s = bs->opaque;
280
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vpc = {
281
.bdrv_close = vpc_close,
282
.bdrv_reopen_prepare = vpc_reopen_prepare,
283
.bdrv_child_perm = bdrv_format_default_perms,
284
+ .bdrv_co_create = vpc_co_create,
285
.bdrv_co_create_opts = vpc_co_create_opts,
286
287
.bdrv_co_preadv = vpc_co_preadv,
288
--
29
--
289
2.13.6
30
2.19.1
290
31
291
32
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
If a management application builds the block graph node by node, the
2
protocol layer doesn't inherit its read-only option from the format
3
layer any more, so it must be set explicitly.
2
4
3
For jobs that have reached their CONCLUDED state, prior to having their
5
Backing files should work on read-only storage, but at the same time, a
4
last reference put down (meaning jobs that have completed successfully,
6
block job like commit should be able to reopen them read-write if they
5
unsuccessfully, or have been canceled), allow the user to dismiss the
7
are on read-write storage. However, without option inheritance, reopen
6
job's lingering status report via block-job-dismiss.
8
only changes the read-only option for the root node (typically the
9
format layer), but not the protocol layer, so reopening fails (the
10
format layer wants to get write permissions, but the protocol layer is
11
still read-only).
7
12
8
This gives management APIs the chance to conclusively determine if a job
13
A simple workaround for the problem in the management tool would be to
9
failed or succeeded, even if the event broadcast was missed.
14
open the protocol layer always read-write and to make only the format
15
layer read-only for backing files. However, sometimes the file is
16
actually stored on read-only storage and we don't know whether the image
17
can be opened read-write (for example, for NBD it depends on the server
18
we're trying to connect to). This adds an option that makes QEMU try to
19
open the image read-write, but allows it to degrade to a read-only mode
20
without returning an error.
10
21
11
Note: block_job_do_dismiss and block_job_decommission happen to do
22
The documentation for this option is consciously phrased in a way that
12
exactly the same thing, but they're called from different semantic
23
allows QEMU to switch to a better model eventually: Instead of trying
13
contexts, so both aliases are kept to improve readability.
24
when the image is first opened, making the read-only flag dynamic and
25
changing it automatically whenever the first BLK_PERM_WRITE user is
26
attached or the last one is detached would be much more useful
27
behaviour.
14
28
15
Note 2: Don't worry about the 0x04 flag definition for AUTO_DISMISS, she
29
Unfortunately, this more useful behaviour is also a lot harder to
16
has a friend coming in a future patch to fill the hole where 0x02 is.
30
implement, and libvirt needs a solution now before it can switch to
31
-blockdev, so let's start with this easier approach for now.
17
32
18
Verbs:
33
Instead of adding a new auto-read-only option, turning the existing
19
Dismiss: operates on CONCLUDED jobs only.
34
read-only into an enum (with a bool alternate for compatibility) was
20
Signed-off-by: John Snow <jsnow@redhat.com>
35
considered, but it complicated the implementation to the point that it
36
didn't seem to be worth it.
37
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
38
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
39
Reviewed-by: Eric Blake <eblake@redhat.com>
22
---
40
---
23
qapi/block-core.json | 24 +++++++++++++++++++++++-
41
qapi/block-core.json | 7 +++++++
24
include/block/blockjob.h | 14 ++++++++++++++
42
include/block/block.h | 2 ++
25
blockdev.c | 14 ++++++++++++++
43
block.c | 17 +++++++++++++++++
26
blockjob.c | 26 ++++++++++++++++++++++++--
44
block/vvfat.c | 1 +
27
block/trace-events | 1 +
45
blockdev.c | 2 +-
28
5 files changed, 76 insertions(+), 3 deletions(-)
46
5 files changed, 28 insertions(+), 1 deletion(-)
29
47
30
diff --git a/qapi/block-core.json b/qapi/block-core.json
48
diff --git a/qapi/block-core.json b/qapi/block-core.json
31
index XXXXXXX..XXXXXXX 100644
49
index XXXXXXX..XXXXXXX 100644
32
--- a/qapi/block-core.json
50
--- a/qapi/block-core.json
33
+++ b/qapi/block-core.json
51
+++ b/qapi/block-core.json
34
@@ -XXX,XX +XXX,XX @@
52
@@ -XXX,XX +XXX,XX @@
35
#
53
# either generally or in certain configurations. In this case,
36
# @complete: see @block-job-complete
54
# the default value does not work and the option must be
37
#
55
# specified explicitly.
38
+# @dismiss: see @block-job-dismiss
56
+# @auto-read-only: if true and @read-only is false, QEMU may automatically
39
+#
57
+# decide not to open the image read-write as requested, but
40
# Since: 2.12
58
+# fall back to read-only instead (and switch between the modes
41
##
59
+# later), e.g. depending on whether the image file is writable
42
{ 'enum': 'BlockJobVerb',
60
+# or whether a writing user is attached to the node
43
- 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete' ] }
61
+# (default: false, since 3.1)
44
+ 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete', 'dismiss' ] }
62
# @detect-zeroes: detect and optimize zero writes (Since 2.1)
45
63
# (default: off)
46
##
64
# @force-share: force share all permission on added nodes.
47
# @BlockJobStatus:
48
@@ -XXX,XX +XXX,XX @@
65
@@ -XXX,XX +XXX,XX @@
49
{ 'command': 'block-job-complete', 'data': { 'device': 'str' } }
66
'*discard': 'BlockdevDiscardOptions',
50
67
'*cache': 'BlockdevCacheOptions',
51
##
68
'*read-only': 'bool',
52
+# @block-job-dismiss:
69
+ '*auto-read-only': 'bool',
53
+#
70
'*force-share': 'bool',
54
+# For jobs that have already concluded, remove them from the block-job-query
71
'*detect-zeroes': 'BlockdevDetectZeroesOptions' },
55
+# list. This command only needs to be run for jobs which were started with
72
'discriminator': 'driver',
56
+# QEMU 2.12+ job lifetime management semantics.
73
diff --git a/include/block/block.h b/include/block/block.h
57
+#
74
index XXXXXXX..XXXXXXX 100644
58
+# This command will refuse to operate on any job that has not yet reached
75
--- a/include/block/block.h
59
+# its terminal state, BLOCK_JOB_STATUS_CONCLUDED. For jobs that make use of
76
+++ b/include/block/block.h
60
+# BLOCK_JOB_READY event, block-job-cancel or block-job-complete will still need
77
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
61
+# to be used as appropriate.
78
select an appropriate protocol driver,
62
+#
79
ignoring the format layer */
63
+# @id: The job identifier.
80
#define BDRV_O_NO_IO 0x10000 /* don't initialize for I/O */
64
+#
81
+#define BDRV_O_AUTO_RDONLY 0x20000 /* degrade to read-only if opening read-write fails */
65
+# Returns: Nothing on success
82
66
+#
83
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH)
67
+# Since: 2.12
84
68
+##
85
@@ -XXX,XX +XXX,XX @@ typedef struct HDGeometry {
69
+{ 'command': 'block-job-dismiss', 'data': { 'id': 'str' } }
86
#define BDRV_OPT_CACHE_DIRECT "cache.direct"
87
#define BDRV_OPT_CACHE_NO_FLUSH "cache.no-flush"
88
#define BDRV_OPT_READ_ONLY "read-only"
89
+#define BDRV_OPT_AUTO_READ_ONLY "auto-read-only"
90
#define BDRV_OPT_DISCARD "discard"
91
#define BDRV_OPT_FORCE_SHARE "force-share"
92
93
diff --git a/block.c b/block.c
94
index XXXXXXX..XXXXXXX 100644
95
--- a/block.c
96
+++ b/block.c
97
@@ -XXX,XX +XXX,XX @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options,
98
99
/* Inherit the read-only option from the parent if it's not set */
100
qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
101
+ qdict_copy_default(child_options, parent_options, BDRV_OPT_AUTO_READ_ONLY);
102
103
/* Our block drivers take care to send flushes and respect unmap policy,
104
* so we can default to enable both on lower layers regardless of the
105
@@ -XXX,XX +XXX,XX @@ static void bdrv_backing_options(int *child_flags, QDict *child_options,
106
107
/* backing files always opened read-only */
108
qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on");
109
+ qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
110
flags &= ~BDRV_O_COPY_ON_READ;
111
112
/* snapshot=on is handled on the top layer */
113
@@ -XXX,XX +XXX,XX @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
114
*flags |= BDRV_O_RDWR;
115
}
116
117
+ assert(qemu_opt_find(opts, BDRV_OPT_AUTO_READ_ONLY));
118
+ if (qemu_opt_get_bool_del(opts, BDRV_OPT_AUTO_READ_ONLY, false)) {
119
+ *flags |= BDRV_O_AUTO_RDONLY;
120
+ }
121
}
122
123
static void update_options_from_flags(QDict *options, int flags)
124
@@ -XXX,XX +XXX,XX @@ static void update_options_from_flags(QDict *options, int flags)
125
if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) {
126
qdict_put_bool(options, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
127
}
128
+ if (!qdict_haskey(options, BDRV_OPT_AUTO_READ_ONLY)) {
129
+ qdict_put_bool(options, BDRV_OPT_AUTO_READ_ONLY,
130
+ flags & BDRV_O_AUTO_RDONLY);
131
+ }
132
}
133
134
static void bdrv_assign_node_name(BlockDriverState *bs,
135
@@ -XXX,XX +XXX,XX @@ QemuOptsList bdrv_runtime_opts = {
136
.type = QEMU_OPT_BOOL,
137
.help = "Node is opened in read-only mode",
138
},
139
+ {
140
+ .name = BDRV_OPT_AUTO_READ_ONLY,
141
+ .type = QEMU_OPT_BOOL,
142
+ .help = "Node can become read-only if opening read-write fails",
143
+ },
144
{
145
.name = "detect-zeroes",
146
.type = QEMU_OPT_STRING,
147
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp)
148
qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
149
qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
150
qdict_set_default_str(qdict, BDRV_OPT_READ_ONLY, "off");
151
+ qdict_set_default_str(qdict, BDRV_OPT_AUTO_READ_ONLY, "off");
70
+
152
+
71
+##
153
}
72
# @BlockdevDiscardOptions:
154
73
#
155
bs = bdrv_open_inherit(NULL, reference, qdict, 0, NULL, NULL, errp);
74
# Determines how to handle discard requests.
156
diff --git a/block/vvfat.c b/block/vvfat.c
75
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
76
index XXXXXXX..XXXXXXX 100644
157
index XXXXXXX..XXXXXXX 100644
77
--- a/include/block/blockjob.h
158
--- a/block/vvfat.c
78
+++ b/include/block/blockjob.h
159
+++ b/block/vvfat.c
79
@@ -XXX,XX +XXX,XX @@ typedef struct BlockJob {
160
@@ -XXX,XX +XXX,XX @@ static void vvfat_qcow_options(int *child_flags, QDict *child_options,
80
/** Current state; See @BlockJobStatus for details. */
161
int parent_flags, QDict *parent_options)
81
BlockJobStatus status;
162
{
82
163
qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "off");
83
+ /** True if this job should automatically dismiss itself */
164
+ qdict_set_default_str(child_options, BDRV_OPT_AUTO_READ_ONLY, "off");
84
+ bool auto_dismiss;
165
qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
85
+
166
}
86
BlockJobTxn *txn;
167
87
QLIST_ENTRY(BlockJob) txn_list;
88
} BlockJob;
89
@@ -XXX,XX +XXX,XX @@ typedef enum BlockJobCreateFlags {
90
BLOCK_JOB_DEFAULT = 0x00,
91
/* BlockJob is not QMP-created and should not send QMP events */
92
BLOCK_JOB_INTERNAL = 0x01,
93
+ /* BlockJob requires manual dismiss step */
94
+ BLOCK_JOB_MANUAL_DISMISS = 0x04,
95
} BlockJobCreateFlags;
96
97
/**
98
@@ -XXX,XX +XXX,XX @@ void block_job_cancel(BlockJob *job);
99
void block_job_complete(BlockJob *job, Error **errp);
100
101
/**
102
+ * block_job_dismiss:
103
+ * @job: The job to be dismissed.
104
+ * @errp: Error object.
105
+ *
106
+ * Remove a concluded job from the query list.
107
+ */
108
+void block_job_dismiss(BlockJob **job, Error **errp);
109
+
110
+/**
111
* block_job_query:
112
* @job: The job to get information about.
113
*
114
diff --git a/blockdev.c b/blockdev.c
168
diff --git a/blockdev.c b/blockdev.c
115
index XXXXXXX..XXXXXXX 100644
169
index XXXXXXX..XXXXXXX 100644
116
--- a/blockdev.c
170
--- a/blockdev.c
117
+++ b/blockdev.c
171
+++ b/blockdev.c
118
@@ -XXX,XX +XXX,XX @@ void qmp_block_job_complete(const char *device, Error **errp)
172
@@ -XXX,XX +XXX,XX @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
119
aio_context_release(aio_context);
173
120
}
174
bdrv_flags = blk_get_open_flags_from_root_state(blk);
121
175
bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
122
+void qmp_block_job_dismiss(const char *id, Error **errp)
176
- BDRV_O_PROTOCOL);
123
+{
177
+ BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
124
+ AioContext *aio_context;
178
125
+ BlockJob *job = find_block_job(id, &aio_context, errp);
179
if (!has_read_only) {
126
+
180
read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
127
+ if (!job) {
128
+ return;
129
+ }
130
+
131
+ trace_qmp_block_job_dismiss(job);
132
+ block_job_dismiss(&job, errp);
133
+ aio_context_release(aio_context);
134
+}
135
+
136
void qmp_change_backing_file(const char *device,
137
const char *image_node_name,
138
const char *backing_file,
139
diff --git a/blockjob.c b/blockjob.c
140
index XXXXXXX..XXXXXXX 100644
141
--- a/blockjob.c
142
+++ b/blockjob.c
143
@@ -XXX,XX +XXX,XX @@ bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] = {
144
[BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0},
145
[BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0},
146
[BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0, 0},
147
+ [BLOCK_JOB_VERB_DISMISS] = {0, 0, 0, 0, 0, 0, 0, 1, 0},
148
};
149
150
static void block_job_state_transition(BlockJob *job, BlockJobStatus s1)
151
@@ -XXX,XX +XXX,XX @@ static void block_job_decommission(BlockJob *job)
152
block_job_unref(job);
153
}
154
155
+static void block_job_do_dismiss(BlockJob *job)
156
+{
157
+ block_job_decommission(job);
158
+}
159
+
160
static void block_job_conclude(BlockJob *job)
161
{
162
block_job_state_transition(job, BLOCK_JOB_STATUS_CONCLUDED);
163
+ if (job->auto_dismiss || !block_job_started(job)) {
164
+ block_job_do_dismiss(job);
165
+ }
166
}
167
168
static void block_job_completed_single(BlockJob *job)
169
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_single(BlockJob *job)
170
QLIST_REMOVE(job, txn_list);
171
block_job_txn_unref(job->txn);
172
block_job_conclude(job);
173
- block_job_decommission(job);
174
}
175
176
static void block_job_cancel_async(BlockJob *job)
177
@@ -XXX,XX +XXX,XX @@ void block_job_complete(BlockJob *job, Error **errp)
178
job->driver->complete(job, errp);
179
}
180
181
+void block_job_dismiss(BlockJob **jobptr, Error **errp)
182
+{
183
+ BlockJob *job = *jobptr;
184
+ /* similarly to _complete, this is QMP-interface only. */
185
+ assert(job->id);
186
+ if (block_job_apply_verb(job, BLOCK_JOB_VERB_DISMISS, errp)) {
187
+ return;
188
+ }
189
+
190
+ block_job_do_dismiss(job);
191
+ *jobptr = NULL;
192
+}
193
+
194
void block_job_user_pause(BlockJob *job, Error **errp)
195
{
196
if (block_job_apply_verb(job, BLOCK_JOB_VERB_PAUSE, errp)) {
197
@@ -XXX,XX +XXX,XX @@ void block_job_user_resume(BlockJob *job, Error **errp)
198
void block_job_cancel(BlockJob *job)
199
{
200
if (job->status == BLOCK_JOB_STATUS_CONCLUDED) {
201
- return;
202
+ block_job_do_dismiss(job);
203
} else if (block_job_started(job)) {
204
block_job_cancel_async(job);
205
block_job_enter(job);
206
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
207
job->paused = true;
208
job->pause_count = 1;
209
job->refcnt = 1;
210
+ job->auto_dismiss = !(flags & BLOCK_JOB_MANUAL_DISMISS);
211
block_job_state_transition(job, BLOCK_JOB_STATUS_CREATED);
212
aio_timer_init(qemu_get_aio_context(), &job->sleep_timer,
213
QEMU_CLOCK_REALTIME, SCALE_NS,
214
diff --git a/block/trace-events b/block/trace-events
215
index XXXXXXX..XXXXXXX 100644
216
--- a/block/trace-events
217
+++ b/block/trace-events
218
@@ -XXX,XX +XXX,XX @@ qmp_block_job_cancel(void *job) "job %p"
219
qmp_block_job_pause(void *job) "job %p"
220
qmp_block_job_resume(void *job) "job %p"
221
qmp_block_job_complete(void *job) "job %p"
222
+qmp_block_job_dismiss(void *job) "job %p"
223
qmp_block_stream(void *bs, void *job) "bs %p job %p"
224
225
# block/file-win32.c
226
--
181
--
227
2.13.6
182
2.19.1
228
183
229
184
diff view generated by jsdifflib
1
Originally we added parallels as a read-only format to qemu-iotests
1
Commit e2b8247a322 introduced an error path in qemu_rbd_open() after
2
where we did just some tests with a binary image. Since then, write and
2
calling rbd_open(), but neglected to close the image again in this error
3
image creation support has been added to the driver, so we can now
3
path. The error path should contain everything that the regular close
4
enable it in _supported_fmt generic.
4
function qemu_rbd_close() contains.
5
5
6
The driver doesn't support migration yet, though, so we need to add it
6
This adds the missing rbd_close() call.
7
to the list of exceptions in 181.
8
7
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: Jeff Cody <jcody@redhat.com>
12
---
10
---
13
tests/qemu-iotests/181 | 2 +-
11
block/rbd.c | 1 +
14
tests/qemu-iotests/check | 1 -
12
1 file changed, 1 insertion(+)
15
2 files changed, 1 insertion(+), 2 deletions(-)
16
13
17
diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181
14
diff --git a/block/rbd.c b/block/rbd.c
18
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/181
16
--- a/block/rbd.c
20
+++ b/tests/qemu-iotests/181
17
+++ b/block/rbd.c
21
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
18
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
22
19
"automatically marking the image read-only.");
23
_supported_fmt generic
20
r = bdrv_set_read_only(bs, true, &local_err);
24
# Formats that do not support live migration
21
if (r < 0) {
25
-_unsupported_fmt qcow vdi vhdx vmdk vpc vvfat
22
+ rbd_close(s->image);
26
+_unsupported_fmt qcow vdi vhdx vmdk vpc vvfat parallels
23
error_propagate(errp, local_err);
27
_supported_proto generic
24
goto failed_open;
28
_supported_os Linux
25
}
29
30
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
31
index XXXXXXX..XXXXXXX 100755
32
--- a/tests/qemu-iotests/check
33
+++ b/tests/qemu-iotests/check
34
@@ -XXX,XX +XXX,XX @@ testlist options
35
36
-parallels)
37
IMGFMT=parallels
38
- IMGFMT_GENERIC=false
39
xpand=false
40
;;
41
42
--
26
--
43
2.13.6
27
2.19.1
44
28
45
29
diff view generated by jsdifflib
1
The crypto driver used to create the image file in a callback from the
1
Some block drivers have traditionally changed their node to read-only
2
crypto subsystem. If we want to implement .bdrv_co_create, this needs to
2
mode without asking the user. This behaviour has been marked deprecated
3
go away because that callback will get a reference to an already
3
since 2.11, expecting users to provide an explicit read-only=on option.
4
existing block node.
4
5
5
Now that we have auto-read-only=on, enable these drivers to make use of
6
Move the image file creation to block_crypto_create_generic().
6
the option.
7
8
This is the only use of bdrv_set_read_only(), so we can make it a bit
9
more specific and turn it into a bdrv_apply_auto_read_only() that is
10
more convenient for drivers to use.
7
11
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Reviewed-by: Eric Blake <eblake@redhat.com>
11
---
14
---
12
block/crypto.c | 37 +++++++++++++++++--------------------
15
include/block/block.h | 3 ++-
13
1 file changed, 17 insertions(+), 20 deletions(-)
16
block.c | 42 +++++++++++++++++++++++++++---------------
14
17
block/bochs.c | 17 ++++++-----------
15
diff --git a/block/crypto.c b/block/crypto.c
18
block/cloop.c | 16 +++++-----------
16
index XXXXXXX..XXXXXXX 100644
19
block/dmg.c | 16 +++++-----------
17
--- a/block/crypto.c
20
block/rbd.c | 15 ++++-----------
18
+++ b/block/crypto.c
21
block/vvfat.c | 10 ++--------
19
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_read_func(QCryptoBlock *block,
22
7 files changed, 51 insertions(+), 68 deletions(-)
20
23
21
24
diff --git a/include/block/block.h b/include/block/block.h
22
struct BlockCryptoCreateData {
25
index XXXXXXX..XXXXXXX 100644
23
- const char *filename;
26
--- a/include/block/block.h
24
- QemuOpts *opts;
27
+++ b/include/block/block.h
25
BlockBackend *blk;
28
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
26
uint64_t size;
29
bool bdrv_is_read_only(BlockDriverState *bs);
27
};
30
int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
28
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_init_func(QCryptoBlock *block,
31
bool ignore_allow_rdw, Error **errp);
29
Error **errp)
32
-int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
33
+int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
34
+ Error **errp);
35
bool bdrv_is_writable(BlockDriverState *bs);
36
bool bdrv_is_sg(BlockDriverState *bs);
37
bool bdrv_is_inserted(BlockDriverState *bs);
38
diff --git a/block.c b/block.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/block.c
41
+++ b/block.c
42
@@ -XXX,XX +XXX,XX @@ int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
43
return 0;
44
}
45
46
-/* TODO Remove (deprecated since 2.11)
47
- * Block drivers are not supposed to automatically change bs->read_only.
48
- * Instead, they should just check whether they can provide what the user
49
- * explicitly requested and error out if read-write is requested, but they can
50
- * only provide read-only access. */
51
-int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
52
+/*
53
+ * Called by a driver that can only provide a read-only image.
54
+ *
55
+ * Returns 0 if the node is already read-only or it could switch the node to
56
+ * read-only because BDRV_O_AUTO_RDONLY is set.
57
+ *
58
+ * Returns -EACCES if the node is read-write and BDRV_O_AUTO_RDONLY is not set
59
+ * or bdrv_can_set_read_only() forbids making the node read-only. If @errmsg
60
+ * is not NULL, it is used as the error message for the Error object.
61
+ */
62
+int bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg,
63
+ Error **errp)
30
{
64
{
31
struct BlockCryptoCreateData *data = opaque;
65
int ret = 0;
32
- int ret;
66
33
67
- ret = bdrv_can_set_read_only(bs, read_only, false, errp);
34
/* User provided size should reflect amount of space made
35
* available to the guest, so we must take account of that
36
* which will be used by the crypto header
37
*/
38
- data->size += headerlen;
39
-
40
- qemu_opt_set_number(data->opts, BLOCK_OPT_SIZE, data->size, &error_abort);
41
- ret = bdrv_create_file(data->filename, data->opts, errp);
42
- if (ret < 0) {
68
- if (ret < 0) {
43
- return -1;
69
- return ret;
70
+ if (!(bs->open_flags & BDRV_O_RDWR)) {
71
+ return 0;
72
+ }
73
+ if (!(bs->open_flags & BDRV_O_AUTO_RDONLY)) {
74
+ goto fail;
75
}
76
77
- bs->read_only = read_only;
78
-
79
- if (read_only) {
80
- bs->open_flags &= ~BDRV_O_RDWR;
81
- } else {
82
- bs->open_flags |= BDRV_O_RDWR;
83
+ ret = bdrv_can_set_read_only(bs, true, false, NULL);
84
+ if (ret < 0) {
85
+ goto fail;
86
}
87
88
+ bs->read_only = true;
89
+ bs->open_flags &= ~BDRV_O_RDWR;
90
+
91
return 0;
92
+
93
+fail:
94
+ error_setg(errp, "%s", errmsg ?: "Image is read-only");
95
+ return -EACCES;
96
}
97
98
void bdrv_get_full_backing_filename_from_filename(const char *backed,
99
diff --git a/block/bochs.c b/block/bochs.c
100
index XXXXXXX..XXXXXXX 100644
101
--- a/block/bochs.c
102
+++ b/block/bochs.c
103
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
104
struct bochs_header bochs;
105
int ret;
106
107
+ /* No write support yet */
108
+ ret = bdrv_apply_auto_read_only(bs, NULL, errp);
109
+ if (ret < 0) {
110
+ return ret;
111
+ }
112
+
113
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
114
false, errp);
115
if (!bs->file) {
116
return -EINVAL;
117
}
118
119
- if (!bdrv_is_read_only(bs)) {
120
- error_report("Opening bochs images without an explicit read-only=on "
121
- "option is deprecated. Future versions will refuse to "
122
- "open the image instead of automatically marking the "
123
- "image read-only.");
124
- ret = bdrv_set_read_only(bs, true, errp); /* no write support yet */
125
- if (ret < 0) {
126
- return ret;
127
- }
44
- }
128
- }
45
-
129
-
46
- data->blk = blk_new_open(data->filename, NULL, NULL,
130
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
47
- BDRV_O_RDWR | BDRV_O_PROTOCOL, errp);
131
if (ret < 0) {
48
- if (!data->blk) {
132
return ret;
49
- return -1;
133
diff --git a/block/cloop.c b/block/cloop.c
134
index XXXXXXX..XXXXXXX 100644
135
--- a/block/cloop.c
136
+++ b/block/cloop.c
137
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
138
uint32_t offsets_size, max_compressed_block_size = 1, i;
139
int ret;
140
141
+ ret = bdrv_apply_auto_read_only(bs, NULL, errp);
142
+ if (ret < 0) {
143
+ return ret;
144
+ }
145
+
146
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
147
false, errp);
148
if (!bs->file) {
149
return -EINVAL;
150
}
151
152
- if (!bdrv_is_read_only(bs)) {
153
- error_report("Opening cloop images without an explicit read-only=on "
154
- "option is deprecated. Future versions will refuse to "
155
- "open the image instead of automatically marking the "
156
- "image read-only.");
157
- ret = bdrv_set_read_only(bs, true, errp);
158
- if (ret < 0) {
159
- return ret;
160
- }
50
- }
161
- }
51
-
162
-
52
- return 0;
163
/* read header */
53
+ return blk_truncate(data->blk, data->size + headerlen, PREALLOC_MODE_OFF,
164
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
54
+ errp);
165
if (ret < 0) {
55
}
166
diff --git a/block/dmg.c b/block/dmg.c
56
167
index XXXXXXX..XXXXXXX 100644
57
168
--- a/block/dmg.c
58
@@ -XXX,XX +XXX,XX @@ static int block_crypto_create_generic(QCryptoBlockFormat format,
169
+++ b/block/dmg.c
59
struct BlockCryptoCreateData data = {
170
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
60
.size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
171
int64_t offset;
61
BDRV_SECTOR_SIZE),
172
int ret;
62
- .opts = opts,
173
63
- .filename = filename,
174
+ ret = bdrv_apply_auto_read_only(bs, NULL, errp);
64
};
65
QDict *cryptoopts;
66
67
+ /* Parse options */
68
cryptoopts = qemu_opts_to_qdict(opts, NULL);
69
70
create_opts = block_crypto_create_opts_init(format, cryptoopts, errp);
71
@@ -XXX,XX +XXX,XX @@ static int block_crypto_create_generic(QCryptoBlockFormat format,
72
return -1;
73
}
74
75
+ /* Create protocol layer */
76
+ ret = bdrv_create_file(filename, opts, errp);
77
+ if (ret < 0) {
175
+ if (ret < 0) {
78
+ return ret;
176
+ return ret;
79
+ }
177
+ }
80
+
178
+
81
+ data.blk = blk_new_open(filename, NULL, NULL,
179
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
82
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
180
false, errp);
83
+ errp);
181
if (!bs->file) {
84
+ if (!data.blk) {
182
return -EINVAL;
85
+ return -EINVAL;
183
}
86
+ }
184
87
+
185
- if (!bdrv_is_read_only(bs)) {
88
+ /* Create format layer */
186
- error_report("Opening dmg images without an explicit read-only=on "
89
crypto = qcrypto_block_create(create_opts, NULL,
187
- "option is deprecated. Future versions will refuse to "
90
block_crypto_init_func,
188
- "open the image instead of automatically marking the "
91
block_crypto_write_func,
189
- "image read-only.");
190
- ret = bdrv_set_read_only(bs, true, errp);
191
- if (ret < 0) {
192
- return ret;
193
- }
194
- }
195
-
196
block_module_load_one("dmg-bz2");
197
198
s->n_chunks = 0;
199
diff --git a/block/rbd.c b/block/rbd.c
200
index XXXXXXX..XXXXXXX 100644
201
--- a/block/rbd.c
202
+++ b/block/rbd.c
203
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
204
/* If we are using an rbd snapshot, we must be r/o, otherwise
205
* leave as-is */
206
if (s->snap != NULL) {
207
- if (!bdrv_is_read_only(bs)) {
208
- error_report("Opening rbd snapshots without an explicit "
209
- "read-only=on option is deprecated. Future versions "
210
- "will refuse to open the image instead of "
211
- "automatically marking the image read-only.");
212
- r = bdrv_set_read_only(bs, true, &local_err);
213
- if (r < 0) {
214
- rbd_close(s->image);
215
- error_propagate(errp, local_err);
216
- goto failed_open;
217
- }
218
+ r = bdrv_apply_auto_read_only(bs, "rbd snapshots are read-only", errp);
219
+ if (r < 0) {
220
+ rbd_close(s->image);
221
+ goto failed_open;
222
}
223
}
224
225
diff --git a/block/vvfat.c b/block/vvfat.c
226
index XXXXXXX..XXXXXXX 100644
227
--- a/block/vvfat.c
228
+++ b/block/vvfat.c
229
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
230
"Unable to set VVFAT to 'rw' when drive is read-only");
231
goto fail;
232
}
233
- } else if (!bdrv_is_read_only(bs)) {
234
- error_report("Opening non-rw vvfat images without an explicit "
235
- "read-only=on option is deprecated. Future versions "
236
- "will refuse to open the image instead of "
237
- "automatically marking the image read-only.");
238
- /* read only is the default for safety */
239
- ret = bdrv_set_read_only(bs, true, &local_err);
240
+ } else {
241
+ ret = bdrv_apply_auto_read_only(bs, NULL, errp);
242
if (ret < 0) {
243
- error_propagate(errp, local_err);
244
goto fail;
245
}
246
}
92
--
247
--
93
2.13.6
248
2.19.1
94
249
95
250
diff view generated by jsdifflib
1
When you request an image size close to UINT64_MAX, the addition of the
1
If read-only=off, but auto-read-only=on is given, open a read-write NBD
2
crypto header may cause an integer overflow. Catch it instead of
2
connection if the server provides a read-write export, but instead of
3
silently truncating the image size.
3
erroring out for read-only exports, just degrade to read-only.
4
4
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
7
---
8
block/crypto.c | 5 +++++
8
block/nbd-client.c | 10 +++++-----
9
1 file changed, 5 insertions(+)
9
1 file changed, 5 insertions(+), 5 deletions(-)
10
10
11
diff --git a/block/crypto.c b/block/crypto.c
11
diff --git a/block/nbd-client.c b/block/nbd-client.c
12
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
13
--- a/block/crypto.c
13
--- a/block/nbd-client.c
14
+++ b/block/crypto.c
14
+++ b/block/nbd-client.c
15
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_init_func(QCryptoBlock *block,
15
@@ -XXX,XX +XXX,XX @@ int nbd_client_init(BlockDriverState *bs,
16
{
16
logout("Failed to negotiate with the NBD server\n");
17
struct BlockCryptoCreateData *data = opaque;
17
return ret;
18
18
}
19
+ if (data->size > INT64_MAX || headerlen > INT64_MAX - data->size) {
19
- if (client->info.flags & NBD_FLAG_READ_ONLY &&
20
+ error_setg(errp, "The requested file size is too large");
20
- !bdrv_is_read_only(bs)) {
21
+ return -EFBIG;
21
- error_setg(errp,
22
+ }
22
- "request for write access conflicts with read-only export");
23
+
23
- return -EACCES;
24
/* User provided size should reflect amount of space made
24
+ if (client->info.flags & NBD_FLAG_READ_ONLY) {
25
* available to the guest, so we must take account of that
25
+ ret = bdrv_apply_auto_read_only(bs, "NBD export is read-only", errp);
26
* which will be used by the crypto header
26
+ if (ret < 0) {
27
+ return ret;
28
+ }
29
}
30
if (client->info.flags & NBD_FLAG_SEND_FUA) {
31
bs->supported_write_flags = BDRV_REQ_FUA;
27
--
32
--
28
2.13.6
33
2.19.1
29
34
30
35
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to luks, which enables
1
If read-only=off, but auto-read-only=on is given, open the file
2
image creation over QMP.
2
read-write if we have the permissions, but instead of erroring out for
3
read-only files, just degrade to read-only.
3
4
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
6
---
7
---
7
qapi/block-core.json | 17 ++++++++++++++++-
8
block/file-posix.c | 19 ++++++++++++++++---
8
block/crypto.c | 34 ++++++++++++++++++++++++++++++++++
9
1 file changed, 16 insertions(+), 3 deletions(-)
9
2 files changed, 50 insertions(+), 1 deletion(-)
10
10
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
11
diff --git a/block/file-posix.c b/block/file-posix.c
12
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
13
--- a/block/file-posix.c
14
+++ b/qapi/block-core.json
14
+++ b/block/file-posix.c
15
@@ -XXX,XX +XXX,XX @@
15
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
16
'*preallocation': 'PreallocMode' } }
16
17
17
s->fd = -1;
18
##
18
fd = qemu_open(filename, s->open_flags, 0644);
19
+# @BlockdevCreateOptionsLUKS:
19
- if (fd < 0) {
20
+#
20
- ret = -errno;
21
+# Driver specific image creation options for LUKS.
21
- error_setg_errno(errp, errno, "Could not open '%s'", filename);
22
+#
22
+ ret = fd < 0 ? -errno : 0;
23
+# @file Node to create the image format on
24
+# @size Size of the virtual disk in bytes
25
+#
26
+# Since: 2.12
27
+##
28
+{ 'struct': 'BlockdevCreateOptionsLUKS',
29
+ 'base': 'QCryptoBlockCreateOptionsLUKS',
30
+ 'data': { 'file': 'BlockdevRef',
31
+ 'size': 'size' } }
32
+
23
+
33
+##
24
+ if (ret == -EACCES || ret == -EROFS) {
34
# @BlockdevCreateOptionsNfs:
25
+ /* Try to degrade to read-only, but if it doesn't work, still use the
35
#
26
+ * normal error message. */
36
# Driver specific image creation options for NFS.
27
+ if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
37
@@ -XXX,XX +XXX,XX @@
28
+ bdrv_flags &= ~BDRV_O_RDWR;
38
'http': 'BlockdevCreateNotSupported',
29
+ raw_parse_flags(bdrv_flags, &s->open_flags);
39
'https': 'BlockdevCreateNotSupported',
30
+ assert(!(s->open_flags & O_CREAT));
40
'iscsi': 'BlockdevCreateNotSupported',
31
+ fd = qemu_open(filename, s->open_flags);
41
- 'luks': 'BlockdevCreateNotSupported',
32
+ ret = fd < 0 ? -errno : 0;
42
+ 'luks': 'BlockdevCreateOptionsLUKS',
33
+ }
43
'nbd': 'BlockdevCreateNotSupported',
44
'nfs': 'BlockdevCreateOptionsNfs',
45
'null-aio': 'BlockdevCreateNotSupported',
46
diff --git a/block/crypto.c b/block/crypto.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/block/crypto.c
49
+++ b/block/crypto.c
50
@@ -XXX,XX +XXX,XX @@ static int block_crypto_open_luks(BlockDriverState *bs,
51
bs, options, flags, errp);
52
}
53
54
+static int coroutine_fn
55
+block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp)
56
+{
57
+ BlockdevCreateOptionsLUKS *luks_opts;
58
+ BlockDriverState *bs = NULL;
59
+ QCryptoBlockCreateOptions create_opts;
60
+ int ret;
61
+
62
+ assert(create_options->driver == BLOCKDEV_DRIVER_LUKS);
63
+ luks_opts = &create_options->u.luks;
64
+
65
+ bs = bdrv_open_blockdev_ref(luks_opts->file, errp);
66
+ if (bs == NULL) {
67
+ return -EIO;
68
+ }
34
+ }
69
+
35
+
70
+ create_opts = (QCryptoBlockCreateOptions) {
71
+ .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
72
+ .u.luks = *qapi_BlockdevCreateOptionsLUKS_base(luks_opts),
73
+ };
74
+
75
+ ret = block_crypto_co_create_generic(bs, luks_opts->size, &create_opts,
76
+ errp);
77
+ if (ret < 0) {
36
+ if (ret < 0) {
78
+ goto fail;
37
+ error_setg_errno(errp, -ret, "Could not open '%s'", filename);
79
+ }
38
if (ret == -EROFS) {
80
+
39
ret = -EACCES;
81
+ ret = 0;
40
}
82
+fail:
83
+ bdrv_unref(bs);
84
+ return ret;
85
+}
86
+
87
static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
88
QemuOpts *opts,
89
Error **errp)
90
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_crypto_luks = {
91
.bdrv_open = block_crypto_open_luks,
92
.bdrv_close = block_crypto_close,
93
.bdrv_child_perm = bdrv_format_default_perms,
94
+ .bdrv_co_create = block_crypto_co_create_luks,
95
.bdrv_co_create_opts = block_crypto_co_create_opts_luks,
96
.bdrv_truncate = block_crypto_truncate,
97
.create_opts = &block_crypto_create_opts_luks,
98
--
41
--
99
2.13.6
42
2.19.1
100
43
101
44
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to parallels, which
1
If read-only=off, but auto-read-only=on is given, just degrade to
2
enables image creation over QMP.
2
read-only.
3
3
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Jeff Cody <jcody@redhat.com>
7
---
6
---
8
qapi/block-core.json | 18 ++++-
7
block/curl.c | 8 ++++----
9
block/parallels.c | 199 ++++++++++++++++++++++++++++++++++++++-------------
8
1 file changed, 4 insertions(+), 4 deletions(-)
10
2 files changed, 168 insertions(+), 49 deletions(-)
11
9
12
diff --git a/qapi/block-core.json b/qapi/block-core.json
10
diff --git a/block/curl.c b/block/curl.c
13
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
14
--- a/qapi/block-core.json
12
--- a/block/curl.c
15
+++ b/qapi/block-core.json
13
+++ b/block/curl.c
16
@@ -XXX,XX +XXX,XX @@
14
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
17
'size': 'size' } }
15
const char *protocol_delimiter;
18
19
##
20
+# @BlockdevCreateOptionsParallels:
21
+#
22
+# Driver specific image creation options for parallels.
23
+#
24
+# @file Node to create the image format on
25
+# @size Size of the virtual disk in bytes
26
+# @cluster-size Cluster size in bytes (default: 1 MB)
27
+#
28
+# Since: 2.12
29
+##
30
+{ 'struct': 'BlockdevCreateOptionsParallels',
31
+ 'data': { 'file': 'BlockdevRef',
32
+ 'size': 'size',
33
+ '*cluster-size': 'size' } }
34
+
35
+##
36
# @BlockdevQcow2Version:
37
#
38
# @v2: The original QCOW2 format as introduced in qemu 0.10 (version 2)
39
@@ -XXX,XX +XXX,XX @@
40
'null-aio': 'BlockdevCreateNotSupported',
41
'null-co': 'BlockdevCreateNotSupported',
42
'nvme': 'BlockdevCreateNotSupported',
43
- 'parallels': 'BlockdevCreateNotSupported',
44
+ 'parallels': 'BlockdevCreateOptionsParallels',
45
'qcow2': 'BlockdevCreateOptionsQcow2',
46
'qcow': 'BlockdevCreateNotSupported',
47
'qed': 'BlockdevCreateNotSupported',
48
diff --git a/block/parallels.c b/block/parallels.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/block/parallels.c
51
+++ b/block/parallels.c
52
@@ -XXX,XX +XXX,XX @@
53
#include "sysemu/block-backend.h"
54
#include "qemu/module.h"
55
#include "qemu/option.h"
56
+#include "qapi/qmp/qdict.h"
57
+#include "qapi/qobject-input-visitor.h"
58
+#include "qapi/qapi-visit-block-core.h"
59
#include "qemu/bswap.h"
60
#include "qemu/bitmap.h"
61
#include "migration/blocker.h"
62
@@ -XXX,XX +XXX,XX @@ static QemuOptsList parallels_runtime_opts = {
63
},
64
};
65
66
+static QemuOptsList parallels_create_opts = {
67
+ .name = "parallels-create-opts",
68
+ .head = QTAILQ_HEAD_INITIALIZER(parallels_create_opts.head),
69
+ .desc = {
70
+ {
71
+ .name = BLOCK_OPT_SIZE,
72
+ .type = QEMU_OPT_SIZE,
73
+ .help = "Virtual disk size",
74
+ },
75
+ {
76
+ .name = BLOCK_OPT_CLUSTER_SIZE,
77
+ .type = QEMU_OPT_SIZE,
78
+ .help = "Parallels image cluster size",
79
+ .def_value_str = stringify(DEFAULT_CLUSTER_SIZE),
80
+ },
81
+ { /* end of list */ }
82
+ }
83
+};
84
+
85
86
static int64_t bat2sect(BDRVParallelsState *s, uint32_t idx)
87
{
88
@@ -XXX,XX +XXX,XX @@ out:
89
}
90
91
92
-static int coroutine_fn parallels_co_create_opts(const char *filename,
93
- QemuOpts *opts,
94
- Error **errp)
95
+static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts,
96
+ Error **errp)
97
{
98
+ BlockdevCreateOptionsParallels *parallels_opts;
99
+ BlockDriverState *bs;
100
+ BlockBackend *blk;
101
int64_t total_size, cl_size;
102
- uint8_t tmp[BDRV_SECTOR_SIZE];
103
- Error *local_err = NULL;
104
- BlockBackend *file;
105
uint32_t bat_entries, bat_sectors;
106
ParallelsHeader header;
107
+ uint8_t tmp[BDRV_SECTOR_SIZE];
108
int ret;
16
int ret;
109
17
110
- total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
18
-
111
- BDRV_SECTOR_SIZE);
19
- if (flags & BDRV_O_RDWR) {
112
- cl_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
20
- error_setg(errp, "curl block device does not support writes");
113
- DEFAULT_CLUSTER_SIZE), BDRV_SECTOR_SIZE);
21
- return -EROFS;
114
+ assert(opts->driver == BLOCKDEV_DRIVER_PARALLELS);
22
+ ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes",
115
+ parallels_opts = &opts->u.parallels;
23
+ errp);
116
+
24
+ if (ret < 0) {
117
+ /* Sanity checks */
25
+ return ret;
118
+ total_size = parallels_opts->size;
119
+
120
+ if (parallels_opts->has_cluster_size) {
121
+ cl_size = parallels_opts->cluster_size;
122
+ } else {
123
+ cl_size = DEFAULT_CLUSTER_SIZE;
124
+ }
125
+
126
if (total_size >= MAX_PARALLELS_IMAGE_FACTOR * cl_size) {
127
- error_propagate(errp, local_err);
128
+ error_setg(errp, "Image size is too large for this cluster size");
129
return -E2BIG;
130
}
26
}
131
27
132
- ret = bdrv_create_file(filename, opts, &local_err);
28
if (!libcurl_initialized) {
133
- if (ret < 0) {
134
- error_propagate(errp, local_err);
135
- return ret;
136
+ if (!QEMU_IS_ALIGNED(total_size, BDRV_SECTOR_SIZE)) {
137
+ error_setg(errp, "Image size must be a multiple of 512 bytes");
138
+ return -EINVAL;
139
}
140
141
- file = blk_new_open(filename, NULL, NULL,
142
- BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
143
- &local_err);
144
- if (file == NULL) {
145
- error_propagate(errp, local_err);
146
+ if (!QEMU_IS_ALIGNED(cl_size, BDRV_SECTOR_SIZE)) {
147
+ error_setg(errp, "Cluster size must be a multiple of 512 bytes");
148
+ return -EINVAL;
149
+ }
150
+
151
+ /* Create BlockBackend to write to the image */
152
+ bs = bdrv_open_blockdev_ref(parallels_opts->file, errp);
153
+ if (bs == NULL) {
154
return -EIO;
155
}
156
157
- blk_set_allow_write_beyond_eof(file, true);
158
+ blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
159
+ ret = blk_insert_bs(blk, bs, errp);
160
+ if (ret < 0) {
161
+ goto out;
162
+ }
163
+ blk_set_allow_write_beyond_eof(blk, true);
164
165
- ret = blk_truncate(file, 0, PREALLOC_MODE_OFF, errp);
166
+ /* Create image format */
167
+ ret = blk_truncate(blk, 0, PREALLOC_MODE_OFF, errp);
168
if (ret < 0) {
169
- goto exit;
170
+ goto out;
171
}
172
173
bat_entries = DIV_ROUND_UP(total_size, cl_size);
174
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_create_opts(const char *filename,
175
memset(tmp, 0, sizeof(tmp));
176
memcpy(tmp, &header, sizeof(header));
177
178
- ret = blk_pwrite(file, 0, tmp, BDRV_SECTOR_SIZE, 0);
179
+ ret = blk_pwrite(blk, 0, tmp, BDRV_SECTOR_SIZE, 0);
180
if (ret < 0) {
181
goto exit;
182
}
183
- ret = blk_pwrite_zeroes(file, BDRV_SECTOR_SIZE,
184
+ ret = blk_pwrite_zeroes(blk, BDRV_SECTOR_SIZE,
185
(bat_sectors - 1) << BDRV_SECTOR_BITS, 0);
186
if (ret < 0) {
187
goto exit;
188
}
189
- ret = 0;
190
191
-done:
192
- blk_unref(file);
193
+ ret = 0;
194
+out:
195
+ blk_unref(blk);
196
+ bdrv_unref(bs);
197
return ret;
198
199
exit:
200
error_setg_errno(errp, -ret, "Failed to create Parallels image");
201
- goto done;
202
+ goto out;
203
+}
204
+
205
+static int coroutine_fn parallels_co_create_opts(const char *filename,
206
+ QemuOpts *opts,
207
+ Error **errp)
208
+{
209
+ BlockdevCreateOptions *create_options = NULL;
210
+ Error *local_err = NULL;
211
+ BlockDriverState *bs = NULL;
212
+ QDict *qdict = NULL;
213
+ QObject *qobj;
214
+ Visitor *v;
215
+ int ret;
216
+
217
+ static const QDictRenames opt_renames[] = {
218
+ { BLOCK_OPT_CLUSTER_SIZE, "cluster-size" },
219
+ { NULL, NULL },
220
+ };
221
+
222
+ /* Parse options and convert legacy syntax */
223
+ qdict = qemu_opts_to_qdict_filtered(opts, NULL, &parallels_create_opts,
224
+ true);
225
+
226
+ if (!qdict_rename_keys(qdict, opt_renames, errp)) {
227
+ ret = -EINVAL;
228
+ goto done;
229
+ }
230
+
231
+ /* Create and open the file (protocol layer) */
232
+ ret = bdrv_create_file(filename, opts, &local_err);
233
+ if (ret < 0) {
234
+ error_propagate(errp, local_err);
235
+ goto done;
236
+ }
237
+
238
+ bs = bdrv_open(filename, NULL, NULL,
239
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
240
+ if (bs == NULL) {
241
+ ret = -EIO;
242
+ goto done;
243
+ }
244
+
245
+ /* Now get the QAPI type BlockdevCreateOptions */
246
+ qdict_put_str(qdict, "driver", "parallels");
247
+ qdict_put_str(qdict, "file", bs->node_name);
248
+
249
+ qobj = qdict_crumple(qdict, errp);
250
+ QDECREF(qdict);
251
+ qdict = qobject_to_qdict(qobj);
252
+ if (qdict == NULL) {
253
+ ret = -EINVAL;
254
+ goto done;
255
+ }
256
+
257
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
258
+ visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
259
+ visit_free(v);
260
+
261
+ if (local_err) {
262
+ error_propagate(errp, local_err);
263
+ ret = -EINVAL;
264
+ goto done;
265
+ }
266
+
267
+ /* Silently round up sizes */
268
+ create_options->u.parallels.size =
269
+ ROUND_UP(create_options->u.parallels.size, BDRV_SECTOR_SIZE);
270
+ create_options->u.parallels.cluster_size =
271
+ ROUND_UP(create_options->u.parallels.cluster_size, BDRV_SECTOR_SIZE);
272
+
273
+ /* Create the Parallels image (format layer) */
274
+ ret = parallels_co_create(create_options, errp);
275
+ if (ret < 0) {
276
+ goto done;
277
+ }
278
+ ret = 0;
279
+
280
+done:
281
+ QDECREF(qdict);
282
+ bdrv_unref(bs);
283
+ qapi_free_BlockdevCreateOptions(create_options);
284
+ return ret;
285
}
286
287
288
@@ -XXX,XX +XXX,XX @@ static void parallels_close(BlockDriverState *bs)
289
error_free(s->migration_blocker);
290
}
291
292
-static QemuOptsList parallels_create_opts = {
293
- .name = "parallels-create-opts",
294
- .head = QTAILQ_HEAD_INITIALIZER(parallels_create_opts.head),
295
- .desc = {
296
- {
297
- .name = BLOCK_OPT_SIZE,
298
- .type = QEMU_OPT_SIZE,
299
- .help = "Virtual disk size",
300
- },
301
- {
302
- .name = BLOCK_OPT_CLUSTER_SIZE,
303
- .type = QEMU_OPT_SIZE,
304
- .help = "Parallels image cluster size",
305
- .def_value_str = stringify(DEFAULT_CLUSTER_SIZE),
306
- },
307
- { /* end of list */ }
308
- }
309
-};
310
-
311
static BlockDriver bdrv_parallels = {
312
.format_name    = "parallels",
313
.instance_size    = sizeof(BDRVParallelsState),
314
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_parallels = {
315
.bdrv_co_readv = parallels_co_readv,
316
.bdrv_co_writev = parallels_co_writev,
317
.supports_backing = true,
318
+ .bdrv_co_create = parallels_co_create,
319
.bdrv_co_create_opts = parallels_co_create_opts,
320
.bdrv_co_check = parallels_co_check,
321
.create_opts = &parallels_create_opts,
322
--
29
--
323
2.13.6
30
2.19.1
324
31
325
32
diff view generated by jsdifflib
1
This adds the .bdrv_co_create driver callback to qed, which
1
If read-only=off, but auto-read-only=on is given, open the file
2
enables image creation over QMP.
2
read-write if we have the permissions, but instead of erroring out for
3
read-only files, just degrade to read-only.
3
4
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Niels de Vos <ndevos@redhat.com>
6
---
7
---
7
qapi/block-core.json | 25 ++++++-
8
block/gluster.c | 12 ++++++++++--
8
block/qed.c | 204 ++++++++++++++++++++++++++++++++++-----------------
9
1 file changed, 10 insertions(+), 2 deletions(-)
9
2 files changed, 162 insertions(+), 67 deletions(-)
10
10
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
11
diff --git a/block/gluster.c b/block/gluster.c
12
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
13
--- a/block/gluster.c
14
+++ b/qapi/block-core.json
14
+++ b/block/gluster.c
15
@@ -XXX,XX +XXX,XX @@
15
@@ -XXX,XX +XXX,XX @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
16
'*refcount-bits': 'int' } }
16
qemu_gluster_parse_flags(bdrv_flags, &open_flags);
17
17
18
##
18
s->fd = glfs_open(s->glfs, gconf->path, open_flags);
19
+# @BlockdevCreateOptionsQed:
19
- if (!s->fd) {
20
+#
20
- ret = -errno;
21
+# Driver specific image creation options for qed.
21
+ ret = s->fd ? 0 : -errno;
22
+#
23
+# @file Node to create the image format on
24
+# @size Size of the virtual disk in bytes
25
+# @backing-file File name of the backing file if a backing file
26
+# should be used
27
+# @backing-fmt Name of the block driver to use for the backing file
28
+# @cluster-size Cluster size in bytes (default: 65536)
29
+# @table-size L1/L2 table size (in clusters)
30
+#
31
+# Since: 2.12
32
+##
33
+{ 'struct': 'BlockdevCreateOptionsQed',
34
+ 'data': { 'file': 'BlockdevRef',
35
+ 'size': 'size',
36
+ '*backing-file': 'str',
37
+ '*backing-fmt': 'BlockdevDriver',
38
+ '*cluster-size': 'size',
39
+ '*table-size': 'int' } }
40
+
22
+
41
+##
23
+ if (ret == -EACCES || ret == -EROFS) {
42
# @BlockdevCreateOptionsRbd:
24
+ /* Try to degrade to read-only, but if it doesn't work, still use the
43
#
25
+ * normal error message. */
44
# Driver specific image creation options for rbd/Ceph.
26
+ if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
45
@@ -XXX,XX +XXX,XX @@
27
+ open_flags = (open_flags & ~O_RDWR) | O_RDONLY;
46
'parallels': 'BlockdevCreateOptionsParallels',
28
+ s->fd = glfs_open(s->glfs, gconf->path, open_flags);
47
'qcow': 'BlockdevCreateOptionsQcow',
29
+ ret = s->fd ? 0 : -errno;
48
'qcow2': 'BlockdevCreateOptionsQcow2',
30
+ }
49
- 'qed': 'BlockdevCreateNotSupported',
50
+ 'qed': 'BlockdevCreateOptionsQed',
51
'quorum': 'BlockdevCreateNotSupported',
52
'raw': 'BlockdevCreateNotSupported',
53
'rbd': 'BlockdevCreateOptionsRbd',
54
diff --git a/block/qed.c b/block/qed.c
55
index XXXXXXX..XXXXXXX 100644
56
--- a/block/qed.c
57
+++ b/block/qed.c
58
@@ -XXX,XX +XXX,XX @@
59
#include "trace.h"
60
#include "qed.h"
61
#include "sysemu/block-backend.h"
62
+#include "qapi/qmp/qdict.h"
63
+#include "qapi/qobject-input-visitor.h"
64
+#include "qapi/qapi-visit-block-core.h"
65
+
66
+static QemuOptsList qed_create_opts;
67
68
static int bdrv_qed_probe(const uint8_t *buf, int buf_size,
69
const char *filename)
70
@@ -XXX,XX +XXX,XX @@ static void bdrv_qed_close(BlockDriverState *bs)
71
qemu_vfree(s->l1_table);
72
}
73
74
-static int qed_create(const char *filename, uint32_t cluster_size,
75
- uint64_t image_size, uint32_t table_size,
76
- const char *backing_file, const char *backing_fmt,
77
- QemuOpts *opts, Error **errp)
78
+static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
79
+ Error **errp)
80
{
81
- QEDHeader header = {
82
- .magic = QED_MAGIC,
83
- .cluster_size = cluster_size,
84
- .table_size = table_size,
85
- .header_size = 1,
86
- .features = 0,
87
- .compat_features = 0,
88
- .l1_table_offset = cluster_size,
89
- .image_size = image_size,
90
- };
91
+ BlockdevCreateOptionsQed *qed_opts;
92
+ BlockBackend *blk = NULL;
93
+ BlockDriverState *bs = NULL;
94
+
95
+ QEDHeader header;
96
QEDHeader le_header;
97
uint8_t *l1_table = NULL;
98
- size_t l1_size = header.cluster_size * header.table_size;
99
- Error *local_err = NULL;
100
+ size_t l1_size;
101
int ret = 0;
102
- BlockBackend *blk;
103
104
- ret = bdrv_create_file(filename, opts, &local_err);
105
- if (ret < 0) {
106
- error_propagate(errp, local_err);
107
- return ret;
108
+ assert(opts->driver == BLOCKDEV_DRIVER_QED);
109
+ qed_opts = &opts->u.qed;
110
+
111
+ /* Validate options and set default values */
112
+ if (!qed_opts->has_cluster_size) {
113
+ qed_opts->cluster_size = QED_DEFAULT_CLUSTER_SIZE;
114
+ }
115
+ if (!qed_opts->has_table_size) {
116
+ qed_opts->table_size = QED_DEFAULT_TABLE_SIZE;
117
}
31
}
118
32
119
- blk = blk_new_open(filename, NULL, NULL,
33
s->supports_seek_data = qemu_gluster_test_seek(s->fd);
120
- BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
121
- &local_err);
122
- if (blk == NULL) {
123
- error_propagate(errp, local_err);
124
+ if (!qed_is_cluster_size_valid(qed_opts->cluster_size)) {
125
+ error_setg(errp, "QED cluster size must be within range [%u, %u] "
126
+ "and power of 2",
127
+ QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE);
128
+ return -EINVAL;
129
+ }
130
+ if (!qed_is_table_size_valid(qed_opts->table_size)) {
131
+ error_setg(errp, "QED table size must be within range [%u, %u] "
132
+ "and power of 2",
133
+ QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE);
134
+ return -EINVAL;
135
+ }
136
+ if (!qed_is_image_size_valid(qed_opts->size, qed_opts->cluster_size,
137
+ qed_opts->table_size))
138
+ {
139
+ error_setg(errp, "QED image size must be a non-zero multiple of "
140
+ "cluster size and less than %" PRIu64 " bytes",
141
+ qed_max_image_size(qed_opts->cluster_size,
142
+ qed_opts->table_size));
143
+ return -EINVAL;
144
+ }
145
+
146
+ /* Create BlockBackend to write to the image */
147
+ bs = bdrv_open_blockdev_ref(qed_opts->file, errp);
148
+ if (bs == NULL) {
149
return -EIO;
150
}
151
152
+ blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
153
+ ret = blk_insert_bs(blk, bs, errp);
154
+ if (ret < 0) {
155
+ goto out;
156
+ }
157
blk_set_allow_write_beyond_eof(blk, true);
158
159
+ /* Prepare image format */
160
+ header = (QEDHeader) {
161
+ .magic = QED_MAGIC,
162
+ .cluster_size = qed_opts->cluster_size,
163
+ .table_size = qed_opts->table_size,
164
+ .header_size = 1,
165
+ .features = 0,
166
+ .compat_features = 0,
167
+ .l1_table_offset = qed_opts->cluster_size,
168
+ .image_size = qed_opts->size,
169
+ };
170
+
171
+ l1_size = header.cluster_size * header.table_size;
172
+
173
/* File must start empty and grow, check truncate is supported */
174
ret = blk_truncate(blk, 0, PREALLOC_MODE_OFF, errp);
175
if (ret < 0) {
176
goto out;
177
}
178
179
- if (backing_file) {
180
+ if (qed_opts->has_backing_file) {
181
header.features |= QED_F_BACKING_FILE;
182
header.backing_filename_offset = sizeof(le_header);
183
- header.backing_filename_size = strlen(backing_file);
184
+ header.backing_filename_size = strlen(qed_opts->backing_file);
185
186
- if (qed_fmt_is_raw(backing_fmt)) {
187
- header.features |= QED_F_BACKING_FORMAT_NO_PROBE;
188
+ if (qed_opts->has_backing_fmt) {
189
+ const char *backing_fmt = BlockdevDriver_str(qed_opts->backing_fmt);
190
+ if (qed_fmt_is_raw(backing_fmt)) {
191
+ header.features |= QED_F_BACKING_FORMAT_NO_PROBE;
192
+ }
193
}
194
}
195
196
@@ -XXX,XX +XXX,XX @@ static int qed_create(const char *filename, uint32_t cluster_size,
197
if (ret < 0) {
198
goto out;
199
}
200
- ret = blk_pwrite(blk, sizeof(le_header), backing_file,
201
+ ret = blk_pwrite(blk, sizeof(le_header), qed_opts->backing_file,
202
header.backing_filename_size, 0);
203
if (ret < 0) {
204
goto out;
205
@@ -XXX,XX +XXX,XX @@ static int qed_create(const char *filename, uint32_t cluster_size,
206
out:
207
g_free(l1_table);
208
blk_unref(blk);
209
+ bdrv_unref(bs);
210
return ret;
211
}
212
213
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create_opts(const char *filename,
214
QemuOpts *opts,
215
Error **errp)
216
{
217
- uint64_t image_size = 0;
218
- uint32_t cluster_size = QED_DEFAULT_CLUSTER_SIZE;
219
- uint32_t table_size = QED_DEFAULT_TABLE_SIZE;
220
- char *backing_file = NULL;
221
- char *backing_fmt = NULL;
222
+ BlockdevCreateOptions *create_options = NULL;
223
+ QDict *qdict = NULL;
224
+ QObject *qobj;
225
+ Visitor *v;
226
+ BlockDriverState *bs = NULL;
227
+ Error *local_err = NULL;
228
int ret;
229
230
- image_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
231
- BDRV_SECTOR_SIZE);
232
- backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
233
- backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
234
- cluster_size = qemu_opt_get_size_del(opts,
235
- BLOCK_OPT_CLUSTER_SIZE,
236
- QED_DEFAULT_CLUSTER_SIZE);
237
- table_size = qemu_opt_get_size_del(opts, BLOCK_OPT_TABLE_SIZE,
238
- QED_DEFAULT_TABLE_SIZE);
239
-
240
- if (!qed_is_cluster_size_valid(cluster_size)) {
241
- error_setg(errp, "QED cluster size must be within range [%u, %u] "
242
- "and power of 2",
243
- QED_MIN_CLUSTER_SIZE, QED_MAX_CLUSTER_SIZE);
244
+ static const QDictRenames opt_renames[] = {
245
+ { BLOCK_OPT_BACKING_FILE, "backing-file" },
246
+ { BLOCK_OPT_BACKING_FMT, "backing-fmt" },
247
+ { BLOCK_OPT_CLUSTER_SIZE, "cluster-size" },
248
+ { BLOCK_OPT_TABLE_SIZE, "table-size" },
249
+ { NULL, NULL },
250
+ };
251
+
252
+ /* Parse options and convert legacy syntax */
253
+ qdict = qemu_opts_to_qdict_filtered(opts, NULL, &qed_create_opts, true);
254
+
255
+ if (!qdict_rename_keys(qdict, opt_renames, errp)) {
256
ret = -EINVAL;
257
- goto finish;
258
+ goto fail;
259
}
260
- if (!qed_is_table_size_valid(table_size)) {
261
- error_setg(errp, "QED table size must be within range [%u, %u] "
262
- "and power of 2",
263
- QED_MIN_TABLE_SIZE, QED_MAX_TABLE_SIZE);
264
+
265
+ /* Create and open the file (protocol layer) */
266
+ ret = bdrv_create_file(filename, opts, &local_err);
267
+ if (ret < 0) {
268
+ error_propagate(errp, local_err);
269
+ goto fail;
270
+ }
271
+
272
+ bs = bdrv_open(filename, NULL, NULL,
273
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
274
+ if (bs == NULL) {
275
+ ret = -EIO;
276
+ goto fail;
277
+ }
278
+
279
+ /* Now get the QAPI type BlockdevCreateOptions */
280
+ qdict_put_str(qdict, "driver", "qed");
281
+ qdict_put_str(qdict, "file", bs->node_name);
282
+
283
+ qobj = qdict_crumple(qdict, errp);
284
+ QDECREF(qdict);
285
+ qdict = qobject_to_qdict(qobj);
286
+ if (qdict == NULL) {
287
ret = -EINVAL;
288
- goto finish;
289
+ goto fail;
290
}
291
- if (!qed_is_image_size_valid(image_size, cluster_size, table_size)) {
292
- error_setg(errp, "QED image size must be a non-zero multiple of "
293
- "cluster size and less than %" PRIu64 " bytes",
294
- qed_max_image_size(cluster_size, table_size));
295
+
296
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
297
+ visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
298
+ visit_free(v);
299
+
300
+ if (local_err) {
301
+ error_propagate(errp, local_err);
302
ret = -EINVAL;
303
- goto finish;
304
+ goto fail;
305
}
306
307
- ret = qed_create(filename, cluster_size, image_size, table_size,
308
- backing_file, backing_fmt, opts, errp);
309
+ /* Silently round up size */
310
+ assert(create_options->driver == BLOCKDEV_DRIVER_QED);
311
+ create_options->u.qed.size =
312
+ ROUND_UP(create_options->u.qed.size, BDRV_SECTOR_SIZE);
313
+
314
+ /* Create the qed image (format layer) */
315
+ ret = bdrv_qed_co_create(create_options, errp);
316
317
-finish:
318
- g_free(backing_file);
319
- g_free(backing_fmt);
320
+fail:
321
+ QDECREF(qdict);
322
+ bdrv_unref(bs);
323
+ qapi_free_BlockdevCreateOptions(create_options);
324
return ret;
325
}
326
327
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_qed = {
328
.bdrv_close = bdrv_qed_close,
329
.bdrv_reopen_prepare = bdrv_qed_reopen_prepare,
330
.bdrv_child_perm = bdrv_format_default_perms,
331
+ .bdrv_co_create = bdrv_qed_co_create,
332
.bdrv_co_create_opts = bdrv_qed_co_create_opts,
333
.bdrv_has_zero_init = bdrv_has_zero_init_1,
334
.bdrv_co_block_status = bdrv_qed_co_block_status,
335
--
34
--
336
2.13.6
35
2.19.1
337
36
338
37
diff view generated by jsdifflib
1
Everything that refers to the protocol layer or QemuOpts is moved out of
1
If read-only=off, but auto-read-only=on is given, open the volume
2
block_crypto_create_generic(), so that the remaining function is
2
read-write if we have the permissions, but instead of erroring out for
3
suitable to be called by a .bdrv_co_create implementation.
3
read-only volumes, just degrade to read-only.
4
5
LUKS is the only driver that actually implements the old interface, and
6
we don't intend to use it in any new drivers, so put the moved out code
7
directly into a LUKS function rather than creating a generic
8
intermediate one.
9
4
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
13
---
7
---
14
block/crypto.c | 95 +++++++++++++++++++++++++++++++++++++---------------------
8
block/iscsi.c | 8 +++++---
15
1 file changed, 61 insertions(+), 34 deletions(-)
9
1 file changed, 5 insertions(+), 3 deletions(-)
16
10
17
diff --git a/block/crypto.c b/block/crypto.c
11
diff --git a/block/iscsi.c b/block/iscsi.c
18
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
19
--- a/block/crypto.c
13
--- a/block/iscsi.c
20
+++ b/block/crypto.c
14
+++ b/block/iscsi.c
21
@@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
15
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
22
}
16
/* Check the write protect flag of the LUN if we want to write */
23
17
if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) &&
24
18
iscsilun->write_protected) {
25
-static int block_crypto_create_generic(QCryptoBlockFormat format,
19
- error_setg(errp, "Cannot open a write protected LUN as read-write");
26
- const char *filename,
20
- ret = -EACCES;
27
- QemuOpts *opts,
21
- goto out;
28
- Error **errp)
22
+ ret = bdrv_apply_auto_read_only(bs, "LUN is write protected", errp);
29
+static int block_crypto_co_create_generic(BlockDriverState *bs,
23
+ if (ret < 0) {
30
+ int64_t size,
24
+ goto out;
31
+ QCryptoBlockCreateOptions *opts,
25
+ }
32
+ Error **errp)
26
+ flags &= ~BDRV_O_RDWR;
33
{
34
- int ret = -EINVAL;
35
- QCryptoBlockCreateOptions *create_opts = NULL;
36
+ int ret;
37
+ BlockBackend *blk;
38
QCryptoBlock *crypto = NULL;
39
- struct BlockCryptoCreateData data = {
40
- .size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
41
- BDRV_SECTOR_SIZE),
42
- };
43
- QDict *cryptoopts;
44
-
45
- /* Parse options */
46
- cryptoopts = qemu_opts_to_qdict(opts, NULL);
47
+ struct BlockCryptoCreateData data;
48
49
- create_opts = block_crypto_create_opts_init(format, cryptoopts, errp);
50
- if (!create_opts) {
51
- return -1;
52
- }
53
+ blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
54
55
- /* Create protocol layer */
56
- ret = bdrv_create_file(filename, opts, errp);
57
+ ret = blk_insert_bs(blk, bs, errp);
58
if (ret < 0) {
59
- return ret;
60
+ goto cleanup;
61
}
27
}
62
28
63
- data.blk = blk_new_open(filename, NULL, NULL,
29
iscsi_readcapacity_sync(iscsilun, &local_err);
64
- BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
65
- errp);
66
- if (!data.blk) {
67
- return -EINVAL;
68
- }
69
+ data = (struct BlockCryptoCreateData) {
70
+ .blk = blk,
71
+ .size = size,
72
+ };
73
74
- /* Create format layer */
75
- crypto = qcrypto_block_create(create_opts, NULL,
76
+ crypto = qcrypto_block_create(opts, NULL,
77
block_crypto_init_func,
78
block_crypto_write_func,
79
&data,
80
@@ -XXX,XX +XXX,XX @@ static int block_crypto_create_generic(QCryptoBlockFormat format,
81
82
ret = 0;
83
cleanup:
84
- QDECREF(cryptoopts);
85
qcrypto_block_free(crypto);
86
- blk_unref(data.blk);
87
- qapi_free_QCryptoBlockCreateOptions(create_opts);
88
+ blk_unref(blk);
89
return ret;
90
}
91
92
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
93
QemuOpts *opts,
94
Error **errp)
95
{
96
- return block_crypto_create_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
97
- filename, opts, errp);
98
+ QCryptoBlockCreateOptions *create_opts = NULL;
99
+ BlockDriverState *bs = NULL;
100
+ QDict *cryptoopts;
101
+ int64_t size;
102
+ int ret;
103
+
104
+ /* Parse options */
105
+ size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
106
+
107
+ cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL,
108
+ &block_crypto_create_opts_luks,
109
+ true);
110
+
111
+ create_opts = block_crypto_create_opts_init(Q_CRYPTO_BLOCK_FORMAT_LUKS,
112
+ cryptoopts, errp);
113
+ if (!create_opts) {
114
+ ret = -EINVAL;
115
+ goto fail;
116
+ }
117
+
118
+ /* Create protocol layer */
119
+ ret = bdrv_create_file(filename, opts, errp);
120
+ if (ret < 0) {
121
+ return ret;
122
+ }
123
+
124
+ bs = bdrv_open(filename, NULL, NULL,
125
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
126
+ if (!bs) {
127
+ ret = -EINVAL;
128
+ goto fail;
129
+ }
130
+
131
+ /* Create format layer */
132
+ ret = block_crypto_co_create_generic(bs, size, create_opts, errp);
133
+ if (ret < 0) {
134
+ goto fail;
135
+ }
136
+
137
+ ret = 0;
138
+fail:
139
+ bdrv_unref(bs);
140
+ qapi_free_QCryptoBlockCreateOptions(create_opts);
141
+ QDECREF(cryptoopts);
142
+ return ret;
143
}
144
145
static int block_crypto_get_info_luks(BlockDriverState *bs,
146
--
30
--
147
2.13.6
31
2.19.1
148
32
149
33
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
While we want machine interfaces like -blockdev and QMP blockdev-add to
2
add as little auto-detection as possible so that management tools are
3
explicit about their needs, -drive is a convenience option for human
4
users. Enabling auto-read-only=on by default there enables users to use
5
read-only images for read-only guest devices without having to specify
6
read-only=on explicitly. If they try to attach the image to a read-write
7
device, they will still get an error message.
2
8
3
Which commands ("verbs") are appropriate for jobs in which state is
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
also somewhat burdensome to keep track of.
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
---
12
blockdev.c | 1 +
13
1 file changed, 1 insertion(+)
5
14
6
As of this commit, it looks rather useless, but begins to look more
7
interesting the more states we add to the STM table.
8
9
A recurring theme is that no verb will apply to an 'undefined' job.
10
11
Further, it's not presently possible to restrict the "pause" or "resume"
12
verbs any more than they are in this commit because of the asynchronous
13
nature of how jobs enter the PAUSED state; justifications for some
14
seemingly erroneous applications are given below.
15
16
=====
17
Verbs
18
=====
19
20
Cancel: Any state except undefined.
21
Pause: Any state except undefined;
22
'created': Requests that the job pauses as it starts.
23
'running': Normal usage. (PAUSED)
24
'paused': The job may be paused for internal reasons,
25
but the user may wish to force an indefinite
26
user-pause, so this is allowed.
27
'ready': Normal usage. (STANDBY)
28
'standby': Same logic as above.
29
Resume: Any state except undefined;
30
'created': Will lift a user's pause-on-start request.
31
'running': Will lift a pause request before it takes effect.
32
'paused': Normal usage.
33
'ready': Will lift a pause request before it takes effect.
34
'standby': Normal usage.
35
Set-speed: Any state except undefined, though ready may not be meaningful.
36
Complete: Only a 'ready' job may accept a complete request.
37
38
=======
39
Changes
40
=======
41
42
(1)
43
44
To facilitate "nice" error checking, all five major block-job verb
45
interfaces in blockjob.c now support an errp parameter:
46
47
- block_job_user_cancel is added as a new interface.
48
- block_job_user_pause gains an errp paramter
49
- block_job_user_resume gains an errp parameter
50
- block_job_set_speed already had an errp parameter.
51
- block_job_complete already had an errp parameter.
52
53
(2)
54
55
block-job-pause and block-job-resume will no longer no-op when trying
56
to pause an already paused job, or trying to resume a job that isn't
57
paused. These functions will now report that they did not perform the
58
action requested because it was not possible.
59
60
iotests have been adjusted to address this new behavior.
61
62
(3)
63
64
block-job-complete doesn't worry about checking !block_job_started,
65
because the permission table guards against this.
66
67
(4)
68
69
test-bdrv-drain's job implementation needs to announce that it is
70
'ready' now, in order to be completed.
71
72
Signed-off-by: John Snow <jsnow@redhat.com>
73
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
74
Reviewed-by: Eric Blake <eblake@redhat.com>
75
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
76
---
77
qapi/block-core.json | 20 ++++++++++++++
78
include/block/blockjob.h | 13 +++++++--
79
blockdev.c | 10 +++----
80
blockjob.c | 71 ++++++++++++++++++++++++++++++++++++++++++------
81
tests/test-bdrv-drain.c | 1 +
82
block/trace-events | 1 +
83
6 files changed, 100 insertions(+), 16 deletions(-)
84
85
diff --git a/qapi/block-core.json b/qapi/block-core.json
86
index XXXXXXX..XXXXXXX 100644
87
--- a/qapi/block-core.json
88
+++ b/qapi/block-core.json
89
@@ -XXX,XX +XXX,XX @@
90
'data': ['commit', 'stream', 'mirror', 'backup'] }
91
92
##
93
+# @BlockJobVerb:
94
+#
95
+# Represents command verbs that can be applied to a blockjob.
96
+#
97
+# @cancel: see @block-job-cancel
98
+#
99
+# @pause: see @block-job-pause
100
+#
101
+# @resume: see @block-job-resume
102
+#
103
+# @set-speed: see @block-job-set-speed
104
+#
105
+# @complete: see @block-job-complete
106
+#
107
+# Since: 2.12
108
+##
109
+{ 'enum': 'BlockJobVerb',
110
+ 'data': ['cancel', 'pause', 'resume', 'set-speed', 'complete' ] }
111
+
112
+##
113
# @BlockJobStatus:
114
#
115
# Indicates the present state of a given blockjob in its lifetime.
116
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
117
index XXXXXXX..XXXXXXX 100644
118
--- a/include/block/blockjob.h
119
+++ b/include/block/blockjob.h
120
@@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp);
121
* Asynchronously pause the specified job.
122
* Do not allow a resume until a matching call to block_job_user_resume.
123
*/
124
-void block_job_user_pause(BlockJob *job);
125
+void block_job_user_pause(BlockJob *job, Error **errp);
126
127
/**
128
* block_job_paused:
129
@@ -XXX,XX +XXX,XX @@ bool block_job_user_paused(BlockJob *job);
130
* Resume the specified job.
131
* Must be paired with a preceding block_job_user_pause.
132
*/
133
-void block_job_user_resume(BlockJob *job);
134
+void block_job_user_resume(BlockJob *job, Error **errp);
135
+
136
+/**
137
+ * block_job_user_cancel:
138
+ * @job: The job to be cancelled.
139
+ *
140
+ * Cancels the specified job, but may refuse to do so if the
141
+ * operation isn't currently meaningful.
142
+ */
143
+void block_job_user_cancel(BlockJob *job, Error **errp);
144
145
/**
146
* block_job_cancel_sync:
147
diff --git a/blockdev.c b/blockdev.c
15
diff --git a/blockdev.c b/blockdev.c
148
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
149
--- a/blockdev.c
17
--- a/blockdev.c
150
+++ b/blockdev.c
18
+++ b/blockdev.c
151
@@ -XXX,XX +XXX,XX @@ void qmp_block_job_cancel(const char *device,
19
@@ -XXX,XX +XXX,XX @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
152
}
20
qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off");
153
21
qdict_set_default_str(bs_opts, BDRV_OPT_READ_ONLY,
154
trace_qmp_block_job_cancel(job);
22
read_only ? "on" : "off");
155
- block_job_cancel(job);
23
+ qdict_set_default_str(bs_opts, BDRV_OPT_AUTO_READ_ONLY, "on");
156
+ block_job_user_cancel(job, errp);
24
assert((bdrv_flags & BDRV_O_CACHE_MASK) == 0);
157
out:
25
158
aio_context_release(aio_context);
26
if (runstate_check(RUN_STATE_INMIGRATE)) {
159
}
160
@@ -XXX,XX +XXX,XX @@ void qmp_block_job_pause(const char *device, Error **errp)
161
AioContext *aio_context;
162
BlockJob *job = find_block_job(device, &aio_context, errp);
163
164
- if (!job || block_job_user_paused(job)) {
165
+ if (!job) {
166
return;
167
}
168
169
trace_qmp_block_job_pause(job);
170
- block_job_user_pause(job);
171
+ block_job_user_pause(job, errp);
172
aio_context_release(aio_context);
173
}
174
175
@@ -XXX,XX +XXX,XX @@ void qmp_block_job_resume(const char *device, Error **errp)
176
AioContext *aio_context;
177
BlockJob *job = find_block_job(device, &aio_context, errp);
178
179
- if (!job || !block_job_user_paused(job)) {
180
+ if (!job) {
181
return;
182
}
183
184
trace_qmp_block_job_resume(job);
185
- block_job_user_resume(job);
186
+ block_job_user_resume(job, errp);
187
aio_context_release(aio_context);
188
}
189
190
diff --git a/blockjob.c b/blockjob.c
191
index XXXXXXX..XXXXXXX 100644
192
--- a/blockjob.c
193
+++ b/blockjob.c
194
@@ -XXX,XX +XXX,XX @@ bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] = {
195
/* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0},
196
};
197
198
+bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] = {
199
+ /* U, C, R, P, Y, S */
200
+ [BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1},
201
+ [BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1},
202
+ [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1},
203
+ [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1},
204
+ [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0},
205
+};
206
+
207
static void block_job_state_transition(BlockJob *job, BlockJobStatus s1)
208
{
209
BlockJobStatus s0 = job->status;
210
@@ -XXX,XX +XXX,XX @@ static void block_job_state_transition(BlockJob *job, BlockJobStatus s1)
211
job->status = s1;
212
}
213
214
+static int block_job_apply_verb(BlockJob *job, BlockJobVerb bv, Error **errp)
215
+{
216
+ assert(bv >= 0 && bv <= BLOCK_JOB_VERB__MAX);
217
+ trace_block_job_apply_verb(job, qapi_enum_lookup(&BlockJobStatus_lookup,
218
+ job->status),
219
+ qapi_enum_lookup(&BlockJobVerb_lookup, bv),
220
+ BlockJobVerbTable[bv][job->status] ?
221
+ "allowed" : "prohibited");
222
+ if (BlockJobVerbTable[bv][job->status]) {
223
+ return 0;
224
+ }
225
+ error_setg(errp, "Job '%s' in state '%s' cannot accept command verb '%s'",
226
+ job->id, qapi_enum_lookup(&BlockJobStatus_lookup, job->status),
227
+ qapi_enum_lookup(&BlockJobVerb_lookup, bv));
228
+ return -EPERM;
229
+}
230
+
231
static void block_job_lock(void)
232
{
233
qemu_mutex_lock(&block_job_mutex);
234
@@ -XXX,XX +XXX,XX @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
235
error_setg(errp, QERR_UNSUPPORTED);
236
return;
237
}
238
+ if (block_job_apply_verb(job, BLOCK_JOB_VERB_SET_SPEED, errp)) {
239
+ return;
240
+ }
241
job->driver->set_speed(job, speed, &local_err);
242
if (local_err) {
243
error_propagate(errp, local_err);
244
@@ -XXX,XX +XXX,XX @@ void block_job_complete(BlockJob *job, Error **errp)
245
{
246
/* Should not be reachable via external interface for internal jobs */
247
assert(job->id);
248
- if (job->pause_count || job->cancelled ||
249
- !block_job_started(job) || !job->driver->complete) {
250
+ if (block_job_apply_verb(job, BLOCK_JOB_VERB_COMPLETE, errp)) {
251
+ return;
252
+ }
253
+ if (job->pause_count || job->cancelled || !job->driver->complete) {
254
error_setg(errp, "The active block job '%s' cannot be completed",
255
job->id);
256
return;
257
@@ -XXX,XX +XXX,XX @@ void block_job_complete(BlockJob *job, Error **errp)
258
job->driver->complete(job, errp);
259
}
260
261
-void block_job_user_pause(BlockJob *job)
262
+void block_job_user_pause(BlockJob *job, Error **errp)
263
{
264
+ if (block_job_apply_verb(job, BLOCK_JOB_VERB_PAUSE, errp)) {
265
+ return;
266
+ }
267
+ if (job->user_paused) {
268
+ error_setg(errp, "Job is already paused");
269
+ return;
270
+ }
271
job->user_paused = true;
272
block_job_pause(job);
273
}
274
@@ -XXX,XX +XXX,XX @@ bool block_job_user_paused(BlockJob *job)
275
return job->user_paused;
276
}
277
278
-void block_job_user_resume(BlockJob *job)
279
+void block_job_user_resume(BlockJob *job, Error **errp)
280
{
281
- if (job && job->user_paused && job->pause_count > 0) {
282
- block_job_iostatus_reset(job);
283
- job->user_paused = false;
284
- block_job_resume(job);
285
+ assert(job);
286
+ if (!job->user_paused || job->pause_count <= 0) {
287
+ error_setg(errp, "Can't resume a job that was not paused");
288
+ return;
289
+ }
290
+ if (block_job_apply_verb(job, BLOCK_JOB_VERB_RESUME, errp)) {
291
+ return;
292
}
293
+ block_job_iostatus_reset(job);
294
+ job->user_paused = false;
295
+ block_job_resume(job);
296
}
297
298
void block_job_cancel(BlockJob *job)
299
@@ -XXX,XX +XXX,XX @@ void block_job_cancel(BlockJob *job)
300
}
301
}
302
303
+void block_job_user_cancel(BlockJob *job, Error **errp)
304
+{
305
+ if (block_job_apply_verb(job, BLOCK_JOB_VERB_CANCEL, errp)) {
306
+ return;
307
+ }
308
+ block_job_cancel(job);
309
+}
310
+
311
/* A wrapper around block_job_cancel() taking an Error ** parameter so it may be
312
* used with block_job_finish_sync() without the need for (rather nasty)
313
* function pointer casts there. */
314
@@ -XXX,XX +XXX,XX @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
315
action, &error_abort);
316
}
317
if (action == BLOCK_ERROR_ACTION_STOP) {
318
+ block_job_pause(job);
319
/* make the pause user visible, which will be resumed from QMP. */
320
- block_job_user_pause(job);
321
+ job->user_paused = true;
322
block_job_iostatus_set_err(job, error);
323
}
324
return action;
325
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
326
index XXXXXXX..XXXXXXX 100644
327
--- a/tests/test-bdrv-drain.c
328
+++ b/tests/test-bdrv-drain.c
329
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_job_start(void *opaque)
330
{
331
TestBlockJob *s = opaque;
332
333
+ block_job_event_ready(&s->common);
334
while (!s->should_complete) {
335
block_job_sleep_ns(&s->common, 100000);
336
}
337
diff --git a/block/trace-events b/block/trace-events
338
index XXXXXXX..XXXXXXX 100644
339
--- a/block/trace-events
340
+++ b/block/trace-events
341
@@ -XXX,XX +XXX,XX @@ bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
342
343
# blockjob.c
344
block_job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)"
345
+block_job_apply_verb(void *job, const char *state, const char *verb, const char *legal) "job %p in state %s; applying verb %s (%s)"
346
347
# block/block-backend.c
348
blk_co_preadv(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x"
349
--
27
--
350
2.13.6
28
2.19.1
351
29
352
30
diff view generated by jsdifflib
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
3
---
3
---
4
tests/qemu-iotests/209 | 210 +++++++++++++++++++++++++++++++++++++++++++
4
tests/qemu-iotests/232 | 147 +++++++++++++++++++++++++++++++++++++
5
tests/qemu-iotests/209.out | 136 ++++++++++++++++++++++++++++
5
tests/qemu-iotests/232.out | 59 +++++++++++++++
6
tests/qemu-iotests/common.rc | 2 +-
6
tests/qemu-iotests/group | 1 +
7
tests/qemu-iotests/group | 1 +
7
3 files changed, 207 insertions(+)
8
4 files changed, 348 insertions(+), 1 deletion(-)
8
create mode 100755 tests/qemu-iotests/232
9
create mode 100755 tests/qemu-iotests/209
9
create mode 100644 tests/qemu-iotests/232.out
10
create mode 100644 tests/qemu-iotests/209.out
11
10
12
diff --git a/tests/qemu-iotests/209 b/tests/qemu-iotests/209
11
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
13
new file mode 100755
12
new file mode 100755
14
index XXXXXXX..XXXXXXX
13
index XXXXXXX..XXXXXXX
15
--- /dev/null
14
--- /dev/null
16
+++ b/tests/qemu-iotests/209
15
+++ b/tests/qemu-iotests/232
17
@@ -XXX,XX +XXX,XX @@
16
@@ -XXX,XX +XXX,XX @@
18
+#!/bin/bash
17
+#!/bin/bash
19
+#
18
+#
20
+# Test luks and file image creation
19
+# Test for auto-read-only
21
+#
20
+#
22
+# Copyright (C) 2018 Red Hat, Inc.
21
+# Copyright (C) 2018 Red Hat, Inc.
23
+#
22
+#
24
+# This program is free software; you can redistribute it and/or modify
23
+# This program is free software; you can redistribute it and/or modify
25
+# it under the terms of the GNU General Public License as published by
24
+# it under the terms of the GNU General Public License as published by
...
...
42
+echo "QA output created by $seq"
41
+echo "QA output created by $seq"
43
+
42
+
44
+here=`pwd`
43
+here=`pwd`
45
+status=1    # failure is the default!
44
+status=1    # failure is the default!
46
+
45
+
46
+_cleanup()
47
+{
48
+ _cleanup_test_img
49
+ rm -f $TEST_IMG.snap
50
+}
51
+trap "_cleanup; exit \$status" 0 1 2 3 15
52
+
47
+# get standard environment, filters and checks
53
+# get standard environment, filters and checks
48
+. ./common.rc
54
+. ./common.rc
49
+. ./common.filter
55
+. ./common.filter
50
+
56
+
51
+_supported_fmt luks
57
+_supported_fmt generic
52
+_supported_proto file
58
+_supported_proto file
53
+_supported_os Linux
59
+_supported_os Linux
54
+
60
+
55
+function do_run_qemu()
61
+function do_run_qemu()
56
+{
62
+{
57
+ echo Testing: "$@"
63
+ echo Testing: "$@"
58
+ $QEMU -nographic -qmp stdio -serial none "$@"
64
+ (
65
+ if ! test -t 0; then
66
+ while read cmd; do
67
+ echo $cmd
68
+ done
69
+ fi
70
+ echo quit
71
+ ) | $QEMU -nographic -monitor stdio -nodefaults "$@"
59
+ echo
72
+ echo
60
+}
73
+}
61
+
74
+
62
+function run_qemu()
75
+function run_qemu()
63
+{
76
+{
64
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \
77
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_hmp |
65
+ | _filter_qemu | _filter_imgfmt \
78
+ _filter_generated_node_ids | _filter_imgfmt
66
+ | _filter_actual_image_size
79
+}
67
+}
80
+
68
+
81
+function run_qemu_info_block()
69
+echo
82
+{
70
+echo "=== Successful image creation (defaults) ==="
83
+ echo "info block -n" | run_qemu "$@" | grep -e "(file" -e "QEMU_PROG"
71
+echo
84
+}
72
+
85
+
73
+size=$((128 * 1024 * 1024))
86
+size=128M
74
+
87
+
75
+run_qemu -object secret,id=keysec0,data="foo" <<EOF
88
+_make_test_img $size
76
+{ "execute": "qmp_capabilities" }
89
+
77
+{ "execute": "x-blockdev-create",
90
+echo
78
+ "arguments": {
91
+echo "=== -drive with read-write image: read-only/auto-read-only combinations ==="
79
+ "driver": "file",
92
+echo
80
+ "filename": "$TEST_IMG_FILE",
93
+
81
+ "size": 0
94
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=off
82
+ }
95
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=on
83
+}
96
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on
84
+{ "execute": "blockdev-add",
97
+echo
85
+ "arguments": {
98
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=off
86
+ "driver": "file",
99
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=on
87
+ "node-name": "imgfile",
100
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off
88
+ "filename": "$TEST_IMG_FILE"
101
+echo
89
+ }
102
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=off
90
+}
103
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=on
91
+{ "execute": "x-blockdev-create",
104
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none
92
+ "arguments": {
105
+
93
+ "driver": "$IMGFMT",
106
+echo
94
+ "file": "imgfile",
107
+echo "=== -drive with read-only image: read-only/auto-read-only combinations ==="
95
+ "key-secret": "keysec0",
108
+echo
96
+ "size": $size,
109
+
97
+ "iter-time": 10
110
+chmod a-w $TEST_IMG
98
+ }
111
+
99
+}
112
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=off
100
+{ "execute": "quit" }
113
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on,auto-read-only=on
101
+EOF
114
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=on
102
+
115
+echo
103
+_img_info --format-specific | _filter_img_info --format-specific
116
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=off
104
+
117
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off,auto-read-only=on
105
+echo
118
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,read-only=off
106
+echo "=== Successful image creation (with non-default options) ==="
119
+echo
107
+echo
120
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=off
108
+
121
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none,auto-read-only=on
109
+# Choose a different size to show that we got a new image
122
+run_qemu_info_block -drive driver=file,file="$TEST_IMG",if=none
110
+size=$((64 * 1024 * 1024))
123
+
111
+
124
+echo
112
+run_qemu -object secret,id=keysec0,data="foo" <<EOF
125
+echo "=== -blockdev with read-write image: read-only/auto-read-only combinations ==="
113
+{ "execute": "qmp_capabilities" }
126
+echo
114
+{ "execute": "x-blockdev-create",
127
+
115
+ "arguments": {
128
+chmod a+w $TEST_IMG
116
+ "driver": "file",
129
+
117
+ "filename": "$TEST_IMG_FILE",
130
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=off
118
+ "size": 0
131
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=on
119
+ }
132
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on
120
+}
133
+echo
121
+{ "execute": "x-blockdev-create",
134
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=off
122
+ "arguments": {
135
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=on
123
+ "driver": "$IMGFMT",
136
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off
124
+ "file": {
137
+echo
125
+ "driver": "file",
138
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=off
126
+ "filename": "$TEST_IMG_FILE"
139
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=on
127
+ },
140
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0
128
+ "size": $size,
141
+
129
+ "key-secret": "keysec0",
142
+echo
130
+ "cipher-alg": "twofish-128",
143
+echo "=== -blockdev with read-only image: read-only/auto-read-only combinations ==="
131
+ "cipher-mode": "ctr",
144
+echo
132
+ "ivgen-alg": "plain64",
145
+
133
+ "ivgen-hash-alg": "md5",
146
+chmod a-w $TEST_IMG
134
+ "hash-alg": "sha1",
147
+
135
+ "iter-time": 10
148
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=off
136
+ }
149
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on,auto-read-only=on
137
+}
150
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=on
138
+{ "execute": "quit" }
151
+echo
139
+EOF
152
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=off
140
+
153
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off,auto-read-only=on
141
+_img_info --format-specific | _filter_img_info --format-specific
154
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,read-only=off
142
+
155
+echo
143
+echo
156
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=off
144
+echo "=== Invalid BlockdevRef ==="
157
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=on
145
+echo
158
+run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0
146
+
147
+run_qemu <<EOF
148
+{ "execute": "qmp_capabilities" }
149
+{ "execute": "x-blockdev-create",
150
+ "arguments": {
151
+ "driver": "$IMGFMT",
152
+ "file": "this doesn't exist",
153
+ "size": $size
154
+ }
155
+}
156
+{ "execute": "quit" }
157
+EOF
158
+
159
+echo
160
+echo "=== Zero size ==="
161
+echo
162
+
163
+run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \
164
+ -object secret,id=keysec0,data="foo" <<EOF
165
+{ "execute": "qmp_capabilities" }
166
+{ "execute": "x-blockdev-create",
167
+ "arguments": {
168
+ "driver": "$IMGFMT",
169
+ "file": "node0",
170
+ "key-secret": "keysec0",
171
+ "size": 0,
172
+ "iter-time": 10
173
+ }
174
+}
175
+{ "execute": "quit" }
176
+EOF
177
+
178
+_img_info | _filter_img_info
179
+
180
+
181
+echo
182
+echo "=== Invalid sizes ==="
183
+echo
184
+
185
+# TODO Negative image sizes aren't handled correctly, but this is a problem
186
+# with QAPI's implementation of the 'size' type and affects other commands as
187
+# well. Once this is fixed, we may want to add a test case here.
188
+
189
+# 1. 2^64 - 512
190
+# 2. 2^63 = 8 EB (qemu-img enforces image sizes less than this)
191
+# 3. 2^63 - 512 (generally valid, but with the crypto header the file will
192
+# exceed 63 bits)
193
+
194
+run_qemu -blockdev driver=file,filename="$TEST_IMG_FILE",node-name=node0 \
195
+ -object secret,id=keysec0,data="foo" <<EOF
196
+{ "execute": "qmp_capabilities" }
197
+{ "execute": "x-blockdev-create",
198
+ "arguments": {
199
+ "driver": "$IMGFMT",
200
+ "file": "node0",
201
+ "key-secret": "keysec0",
202
+ "size": 18446744073709551104
203
+ }
204
+}
205
+{ "execute": "x-blockdev-create",
206
+ "arguments": {
207
+ "driver": "$IMGFMT",
208
+ "file": "node0",
209
+ "key-secret": "keysec0",
210
+ "size": 9223372036854775808
211
+ }
212
+}
213
+{ "execute": "x-blockdev-create",
214
+ "arguments": {
215
+ "driver": "$IMGFMT",
216
+ "file": "node0",
217
+ "key-secret": "keysec0",
218
+ "size": 9223372036854775296
219
+ }
220
+}
221
+{ "execute": "quit" }
222
+EOF
223
+
159
+
224
+# success, all done
160
+# success, all done
225
+echo "*** done"
161
+echo "*** done"
226
+rm -f $seq.full
162
+rm -f $seq.full
227
+status=0
163
+status=0
228
diff --git a/tests/qemu-iotests/209.out b/tests/qemu-iotests/209.out
164
diff --git a/tests/qemu-iotests/232.out b/tests/qemu-iotests/232.out
229
new file mode 100644
165
new file mode 100644
230
index XXXXXXX..XXXXXXX
166
index XXXXXXX..XXXXXXX
231
--- /dev/null
167
--- /dev/null
232
+++ b/tests/qemu-iotests/209.out
168
+++ b/tests/qemu-iotests/232.out
233
@@ -XXX,XX +XXX,XX @@
169
@@ -XXX,XX +XXX,XX @@
234
+QA output created by 209
170
+QA output created by 232
235
+
171
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
236
+=== Successful image creation (defaults) ===
172
+
237
+
173
+=== -drive with read-write image: read-only/auto-read-only combinations ===
238
+Testing: -object secret,id=keysec0,data=foo
174
+
239
+QMP_VERSION
175
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
240
+{"return": {}}
176
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
241
+{"return": {}}
177
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
242
+{"return": {}}
178
+
243
+{"return": {}}
179
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
244
+{"return": {}}
180
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
245
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
181
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
246
+
182
+
247
+image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"}
183
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
248
+file format: IMGFMT
184
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
249
+virtual size: 128M (134217728 bytes)
185
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
250
+Format specific information:
186
+
251
+ ivgen alg: plain64
187
+=== -drive with read-only image: read-only/auto-read-only combinations ===
252
+ hash alg: sha256
188
+
253
+ cipher alg: aes-256
189
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
254
+ uuid: 00000000-0000-0000-0000-000000000000
190
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
255
+ cipher mode: xts
191
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
256
+ slots:
192
+
257
+ [0]:
193
+QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
258
+ active: true
194
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
259
+ iters: 1024
195
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
260
+ key offset: 4096
196
+
261
+ stripes: 4000
197
+QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
262
+ [1]:
198
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
263
+ active: false
199
+NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
264
+ key offset: 262144
200
+
265
+ [2]:
201
+=== -blockdev with read-write image: read-only/auto-read-only combinations ===
266
+ active: false
202
+
267
+ key offset: 520192
203
+node0: TEST_DIR/t.IMGFMT (file, read-only)
268
+ [3]:
204
+node0: TEST_DIR/t.IMGFMT (file, read-only)
269
+ active: false
205
+node0: TEST_DIR/t.IMGFMT (file, read-only)
270
+ key offset: 778240
206
+
271
+ [4]:
207
+node0: TEST_DIR/t.IMGFMT (file)
272
+ active: false
208
+node0: TEST_DIR/t.IMGFMT (file)
273
+ key offset: 1036288
209
+node0: TEST_DIR/t.IMGFMT (file)
274
+ [5]:
210
+
275
+ active: false
211
+node0: TEST_DIR/t.IMGFMT (file)
276
+ key offset: 1294336
212
+node0: TEST_DIR/t.IMGFMT (file)
277
+ [6]:
213
+node0: TEST_DIR/t.IMGFMT (file)
278
+ active: false
214
+
279
+ key offset: 1552384
215
+=== -blockdev with read-only image: read-only/auto-read-only combinations ===
280
+ [7]:
216
+
281
+ active: false
217
+node0: TEST_DIR/t.IMGFMT (file, read-only)
282
+ key offset: 1810432
218
+node0: TEST_DIR/t.IMGFMT (file, read-only)
283
+ payload offset: 2068480
219
+node0: TEST_DIR/t.IMGFMT (file, read-only)
284
+ master key iters: 1024
220
+
285
+
221
+QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
286
+=== Successful image creation (with non-default options) ===
222
+node0: TEST_DIR/t.IMGFMT (file, read-only)
287
+
223
+QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
288
+Testing: -object secret,id=keysec0,data=foo
224
+
289
+QMP_VERSION
225
+QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
290
+{"return": {}}
226
+node0: TEST_DIR/t.IMGFMT (file, read-only)
291
+{"return": {}}
227
+QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
292
+{"return": {}}
293
+{"return": {}}
294
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
295
+
296
+image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"}
297
+file format: IMGFMT
298
+virtual size: 64M (67108864 bytes)
299
+Format specific information:
300
+ ivgen alg: plain64
301
+ hash alg: sha1
302
+ cipher alg: twofish-128
303
+ uuid: 00000000-0000-0000-0000-000000000000
304
+ cipher mode: ctr
305
+ slots:
306
+ [0]:
307
+ active: true
308
+ iters: 1024
309
+ key offset: 4096
310
+ stripes: 4000
311
+ [1]:
312
+ active: false
313
+ key offset: 69632
314
+ [2]:
315
+ active: false
316
+ key offset: 135168
317
+ [3]:
318
+ active: false
319
+ key offset: 200704
320
+ [4]:
321
+ active: false
322
+ key offset: 266240
323
+ [5]:
324
+ active: false
325
+ key offset: 331776
326
+ [6]:
327
+ active: false
328
+ key offset: 397312
329
+ [7]:
330
+ active: false
331
+ key offset: 462848
332
+ payload offset: 528384
333
+ master key iters: 1024
334
+
335
+=== Invalid BlockdevRef ===
336
+
337
+Testing:
338
+QMP_VERSION
339
+{"return": {}}
340
+{"error": {"class": "GenericError", "desc": "Cannot find device=this doesn't exist nor node_name=this doesn't exist"}}
341
+{"return": {}}
342
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
343
+
344
+
345
+=== Zero size ===
346
+
347
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 -object secret,id=keysec0,data=foo
348
+QMP_VERSION
349
+{"return": {}}
350
+{"return": {}}
351
+{"return": {}}
352
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
353
+
354
+image: json:{"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "key-secret": "keysec0"}
355
+file format: IMGFMT
356
+virtual size: 0 (0 bytes)
357
+
358
+=== Invalid sizes ===
359
+
360
+Testing: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0 -object secret,id=keysec0,data=foo
361
+QMP_VERSION
362
+{"return": {}}
363
+{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
364
+{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
365
+{"error": {"class": "GenericError", "desc": "The requested file size is too large"}}
366
+{"return": {}}
367
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
368
+
369
+*** done
228
+*** done
370
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
371
index XXXXXXX..XXXXXXX 100644
372
--- a/tests/qemu-iotests/common.rc
373
+++ b/tests/qemu-iotests/common.rc
374
@@ -XXX,XX +XXX,XX @@ _img_info()
375
376
discard=0
377
regex_json_spec_start='^ *"format-specific": \{'
378
- $QEMU_IMG info "$@" "$TEST_IMG" 2>&1 | \
379
+ $QEMU_IMG info $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" 2>&1 | \
380
sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
381
-e "s#$TEST_DIR#TEST_DIR#g" \
382
-e "s#$IMGFMT#IMGFMT#g" \
383
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
229
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
384
index XXXXXXX..XXXXXXX 100644
230
index XXXXXXX..XXXXXXX 100644
385
--- a/tests/qemu-iotests/group
231
--- a/tests/qemu-iotests/group
386
+++ b/tests/qemu-iotests/group
232
+++ b/tests/qemu-iotests/group
387
@@ -XXX,XX +XXX,XX @@
233
@@ -XXX,XX +XXX,XX @@
388
205 rw auto quick
234
227 auto quick
389
206 rw auto
235
229 auto quick
390
207 rw auto
236
231 auto quick
391
+209 rw auto
237
+232 auto quick
392
--
238
--
393
2.13.6
239
2.19.1
394
240
395
241
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
We're about to add several new states, and booleans are becoming
3
This adds some whitespace into the option help (including indentation)
4
unwieldly and difficult to reason about. It would help to have a
4
and puts angle brackets around the type names. Furthermore, the list
5
more explicit bookkeeping of the state of blockjobs. To this end,
5
name is no longer printed as part of every line, but only once in
6
add a new "status" field and add our existing states in a redundant
6
advance, and only if the caller did not print a caption already.
7
manner alongside the bools they are replacing:
8
7
9
UNDEFINED: Placeholder, default state. Not currently visible to QMP
8
This patch also restores the description alignment we had before commit
10
unless changes occur in the future to allow creating jobs
9
9cbef9d68ee1d8d0, just at 24 instead of 16 characters like we used to.
11
without starting them via QMP.
10
This increase is because now we have the type and two spaces of
12
CREATED: replaces !!job->co && paused && !busy
11
indentation before the description, and with a usual type name length of
13
RUNNING: replaces effectively (!paused && busy)
12
three chracters, this sums up to eight additional characters -- which
14
PAUSED: Nearly redundant with info->paused, which shows pause_count.
13
means that we now need 24 characters to get the same amount of padding
15
This reports the actual status of the job, which almost always
14
for most options. Also, 24 is a third of 80, which makes it kind of a
16
matches the paused request status. It differs in that it is
15
round number in terminal terms.
17
strictly only true when the job has actually gone dormant.
18
READY: replaces job->ready.
19
STANDBY: Paused, but job->ready is true.
20
16
21
New state additions in coming commits will not be quite so redundant:
17
Finally, this patch amends the reference output of iotest 082 to match
18
the changes (and thus makes it pass again).
22
19
23
WAITING: Waiting on transaction. This job has finished all the work
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
24
it can until the transaction converges, fails, or is canceled.
21
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
25
PENDING: Pending authorization from user. This job has finished all the
26
work it can until the job or transaction is finalized via
27
block_job_finalize. This implies the transaction has converged
28
and left the WAITING phase.
29
ABORTING: Job has encountered an error condition and is in the process
30
of aborting.
31
CONCLUDED: Job has ceased all operations and has a return code available
32
for query and may be dismissed via block_job_dismiss.
33
NULL: Job has been dismissed and (should) be destroyed. Should never
34
be visible to QMP.
35
36
Some of these states appear somewhat superfluous, but it helps define the
37
expected flow of a job; so some of the states wind up being synchronous
38
empty transitions. Importantly, jobs can be in only one of these states
39
at any given time, which helps code and external users alike reason about
40
the current condition of a job unambiguously.
41
42
Signed-off-by: John Snow <jsnow@redhat.com>
43
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
44
---
23
---
45
qapi/block-core.json | 31 ++++++++++++++++++++++++++++++-
24
include/qemu/option.h | 2 +-
46
include/block/blockjob.h | 3 +++
25
qemu-img.c | 4 +-
47
blockjob.c | 9 +++++++++
26
util/qemu-option.c | 32 +-
48
tests/qemu-iotests/109.out | 24 ++++++++++++------------
27
tests/qemu-iotests/082.out | 956 ++++++++++++++++++-------------------
49
4 files changed, 54 insertions(+), 13 deletions(-)
28
4 files changed, 507 insertions(+), 487 deletions(-)
50
29
51
diff --git a/qapi/block-core.json b/qapi/block-core.json
30
diff --git a/include/qemu/option.h b/include/qemu/option.h
52
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
53
--- a/qapi/block-core.json
32
--- a/include/qemu/option.h
54
+++ b/qapi/block-core.json
33
+++ b/include/qemu/option.h
55
@@ -XXX,XX +XXX,XX @@
34
@@ -XXX,XX +XXX,XX @@ typedef int (*qemu_opts_loopfunc)(void *opaque, QemuOpts *opts, Error **errp);
56
'data': ['commit', 'stream', 'mirror', 'backup'] }
35
int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func,
57
36
void *opaque, Error **errp);
58
##
37
void qemu_opts_print(QemuOpts *opts, const char *sep);
59
+# @BlockJobStatus:
38
-void qemu_opts_print_help(QemuOptsList *list);
60
+#
39
+void qemu_opts_print_help(QemuOptsList *list, bool print_caption);
61
+# Indicates the present state of a given blockjob in its lifetime.
40
void qemu_opts_free(QemuOptsList *list);
62
+#
41
QemuOptsList *qemu_opts_append(QemuOptsList *dst, QemuOptsList *list);
63
+# @undefined: Erroneous, default state. Should not ever be visible.
42
64
+#
43
diff --git a/qemu-img.c b/qemu-img.c
65
+# @created: The job has been created, but not yet started.
66
+#
67
+# @running: The job is currently running.
68
+#
69
+# @paused: The job is running, but paused. The pause may be requested by
70
+# either the QMP user or by internal processes.
71
+#
72
+# @ready: The job is running, but is ready for the user to signal completion.
73
+# This is used for long-running jobs like mirror that are designed to
74
+# run indefinitely.
75
+#
76
+# @standby: The job is ready, but paused. This is nearly identical to @paused.
77
+# The job may return to @ready or otherwise be canceled.
78
+#
79
+# Since: 2.12
80
+##
81
+{ 'enum': 'BlockJobStatus',
82
+ 'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby'] }
83
+
84
+##
85
# @BlockJobInfo:
86
#
87
# Information about a long-running block device operation.
88
@@ -XXX,XX +XXX,XX @@
89
#
90
# @ready: true if the job may be completed (since 2.2)
91
#
92
+# @status: Current job state/status (since 2.12)
93
+#
94
# Since: 1.1
95
##
96
{ 'struct': 'BlockJobInfo',
97
'data': {'type': 'str', 'device': 'str', 'len': 'int',
98
'offset': 'int', 'busy': 'bool', 'paused': 'bool', 'speed': 'int',
99
- 'io-status': 'BlockDeviceIoStatus', 'ready': 'bool'} }
100
+ 'io-status': 'BlockDeviceIoStatus', 'ready': 'bool',
101
+ 'status': 'BlockJobStatus' } }
102
103
##
104
# @query-block-jobs:
105
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
106
index XXXXXXX..XXXXXXX 100644
44
index XXXXXXX..XXXXXXX 100644
107
--- a/include/block/blockjob.h
45
--- a/qemu-img.c
108
+++ b/include/block/blockjob.h
46
+++ b/qemu-img.c
109
@@ -XXX,XX +XXX,XX @@ typedef struct BlockJob {
47
@@ -XXX,XX +XXX,XX @@ static int print_block_option_help(const char *filename, const char *fmt)
110
*/
48
}
111
QEMUTimer sleep_timer;
49
112
50
printf("Supported options:\n");
113
+ /** Current state; See @BlockJobStatus for details. */
51
- qemu_opts_print_help(create_opts);
114
+ BlockJobStatus status;
52
+ qemu_opts_print_help(create_opts, false);
115
+
53
qemu_opts_free(create_opts);
116
BlockJobTxn *txn;
54
return 0;
117
QLIST_ENTRY(BlockJob) txn_list;
55
}
118
} BlockJob;
56
@@ -XXX,XX +XXX,XX @@ static int print_amend_option_help(const char *format)
119
diff --git a/blockjob.c b/blockjob.c
57
assert(drv->create_opts);
58
59
printf("Creation options for '%s':\n", format);
60
- qemu_opts_print_help(drv->create_opts);
61
+ qemu_opts_print_help(drv->create_opts, false);
62
printf("\nNote that not all of these options may be amendable.\n");
63
return 0;
64
}
65
diff --git a/util/qemu-option.c b/util/qemu-option.c
120
index XXXXXXX..XXXXXXX 100644
66
index XXXXXXX..XXXXXXX 100644
121
--- a/blockjob.c
67
--- a/util/qemu-option.c
122
+++ b/blockjob.c
68
+++ b/util/qemu-option.c
123
@@ -XXX,XX +XXX,XX @@ void block_job_start(BlockJob *job)
69
@@ -XXX,XX +XXX,XX @@ static const char *opt_type_to_string(enum QemuOptType type)
124
job->pause_count--;
70
g_assert_not_reached();
125
job->busy = true;
126
job->paused = false;
127
+ job->status = BLOCK_JOB_STATUS_RUNNING;
128
bdrv_coroutine_enter(blk_bs(job->blk), job->co);
129
}
71
}
130
72
131
@@ -XXX,XX +XXX,XX @@ BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
73
-void qemu_opts_print_help(QemuOptsList *list)
132
info->speed = job->speed;
74
+/**
133
info->io_status = job->iostatus;
75
+ * Print the list of options available in the given list. If
134
info->ready = job->ready;
76
+ * @print_caption is true, a caption (including the list name, if it
135
+ info->status = job->status;
77
+ * exists) is printed. The options itself will be indented, so
136
return info;
78
+ * @print_caption should only be set to false if the caller prints its
137
}
79
+ * own custom caption (so that the indentation makes sense).
138
80
+ */
139
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
81
+void qemu_opts_print_help(QemuOptsList *list, bool print_caption)
140
job->paused = true;
82
{
141
job->pause_count = 1;
83
QemuOptDesc *desc;
142
job->refcnt = 1;
84
int i;
143
+ job->status = BLOCK_JOB_STATUS_CREATED;
85
@@ -XXX,XX +XXX,XX @@ void qemu_opts_print_help(QemuOptsList *list)
144
aio_timer_init(qemu_get_aio_context(), &job->sleep_timer,
86
desc = list->desc;
145
QEMU_CLOCK_REALTIME, SCALE_NS,
87
while (desc && desc->name) {
146
block_job_sleep_timer_cb, job);
88
GString *str = g_string_new(NULL);
147
@@ -XXX,XX +XXX,XX @@ void coroutine_fn block_job_pause_point(BlockJob *job)
89
- if (list->name) {
90
- g_string_append_printf(str, "%s.", list->name);
91
- }
92
- g_string_append_printf(str, "%s=%s", desc->name,
93
+ g_string_append_printf(str, " %s=<%s>", desc->name,
94
opt_type_to_string(desc->type));
95
if (desc->help) {
96
+ if (str->len < 24) {
97
+ g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
98
+ }
99
g_string_append_printf(str, " - %s", desc->help);
100
}
101
g_ptr_array_add(array, g_string_free(str, false));
102
@@ -XXX,XX +XXX,XX @@ void qemu_opts_print_help(QemuOptsList *list)
148
}
103
}
149
104
150
if (block_job_should_pause(job) && !block_job_is_cancelled(job)) {
105
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
151
+ BlockJobStatus status = job->status;
106
+ if (print_caption && array->len > 0) {
152
+ job->status = status == BLOCK_JOB_STATUS_READY ? \
107
+ if (list->name) {
153
+ BLOCK_JOB_STATUS_STANDBY : \
108
+ printf("%s options:\n", list->name);
154
+ BLOCK_JOB_STATUS_PAUSED;
109
+ } else {
155
job->paused = true;
110
+ printf("Options:\n");
156
block_job_do_yield(job, -1);
111
+ }
157
job->paused = false;
112
+ } else if (array->len == 0) {
158
+ job->status = status;
113
+ if (list->name) {
114
+ printf("There are no options for %s.\n", list->name);
115
+ } else {
116
+ printf("No options available.\n");
117
+ }
118
+ }
119
for (i = 0; i < array->len; i++) {
120
printf("%s\n", (char *)array->pdata[i]);
159
}
121
}
160
122
@@ -XXX,XX +XXX,XX @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
161
if (job->driver->resume) {
123
opts = opts_parse(list, params, permit_abbrev, false, &invalidp, &err);
162
@@ -XXX,XX +XXX,XX @@ void block_job_iostatus_reset(BlockJob *job)
124
if (err) {
163
125
if (invalidp && has_help_option(params)) {
164
void block_job_event_ready(BlockJob *job)
126
- qemu_opts_print_help(list);
165
{
127
+ qemu_opts_print_help(list, true);
166
+ job->status = BLOCK_JOB_STATUS_READY;
128
error_free(err);
167
job->ready = true;
129
} else {
168
130
error_report_err(err);
169
if (block_job_is_internal(job)) {
131
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
170
diff --git a/tests/qemu-iotests/109.out b/tests/qemu-iotests/109.out
171
index XXXXXXX..XXXXXXX 100644
132
index XXXXXXX..XXXXXXX 100644
172
--- a/tests/qemu-iotests/109.out
133
--- a/tests/qemu-iotests/082.out
173
+++ b/tests/qemu-iotests/109.out
134
+++ b/tests/qemu-iotests/082.out
174
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
135
@@ -XXX,XX +XXX,XX @@ cluster_size: 8192
175
{"return": {}}
136
176
{"return": {}}
137
Testing: create -f qcow2 -o help TEST_DIR/t.qcow2 128M
177
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
138
Supported options:
178
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 1024, "offset": 1024, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
139
-size Virtual disk size
179
+{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
140
-compat Compatibility level (0.10 or 1.1)
180
{"return": {}}
141
-backing_file File name of a base image
181
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
142
-backing_fmt Image format of the base image
182
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
143
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
183
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
144
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
184
{"return": {}}
145
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
185
{"return": {}}
146
-encrypt.cipher-alg Name of encryption cipher algorithm
186
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}}
147
-encrypt.cipher-mode Name of encryption cipher mode
187
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 197120, "offset": 197120, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
148
-encrypt.ivgen-alg Name of IV generator algorithm
188
+{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 197120, "offset": 197120, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
149
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
189
{"return": {}}
150
-encrypt.hash-alg Name of encryption hash algorithm
190
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
151
-encrypt.iter-time Time to spend in PBKDF in milliseconds
191
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}}
152
-cluster_size qcow2 cluster size
192
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
153
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
193
{"return": {}}
154
-lazy_refcounts Postpone refcount updates
194
{"return": {}}
155
-refcount_bits Width of a reference count entry in bits
195
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
156
-nocow Turn off copy-on-write (valid only on btrfs)
196
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 327680, "offset": 327680, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
157
+ backing_file=<str> - File name of a base image
197
+{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
158
+ backing_fmt=<str> - Image format of the base image
198
{"return": {}}
159
+ cluster_size=<size> - qcow2 cluster size
199
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
160
+ compat=<str> - Compatibility level (0.10 or 1.1)
200
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
161
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
201
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
162
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
202
{"return": {}}
163
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
203
{"return": {}}
164
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
204
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
165
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
205
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 1024, "offset": 1024, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
166
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
206
+{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
167
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
207
{"return": {}}
168
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
208
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
169
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
209
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
170
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
210
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
171
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
211
{"return": {}}
172
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
212
{"return": {}}
173
+ refcount_bits=<num> - Width of a reference count entry in bits
213
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
174
+ size=<size> - Virtual disk size
214
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 65536, "offset": 65536, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
175
215
+{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 65536, "offset": 65536, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
176
Testing: create -f qcow2 -o ? TEST_DIR/t.qcow2 128M
216
{"return": {}}
177
Supported options:
217
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
178
-size Virtual disk size
218
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
179
-compat Compatibility level (0.10 or 1.1)
219
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
180
-backing_file File name of a base image
220
{"return": {}}
181
-backing_fmt Image format of the base image
221
{"return": {}}
182
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
222
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
183
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
223
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 2560, "offset": 2560, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
184
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
224
+{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
185
-encrypt.cipher-alg Name of encryption cipher algorithm
225
{"return": {}}
186
-encrypt.cipher-mode Name of encryption cipher mode
226
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
187
-encrypt.ivgen-alg Name of IV generator algorithm
227
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
188
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
228
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
189
-encrypt.hash-alg Name of encryption hash algorithm
229
{"return": {}}
190
-encrypt.iter-time Time to spend in PBKDF in milliseconds
230
{"return": {}}
191
-cluster_size qcow2 cluster size
231
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
192
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
232
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 2560, "offset": 2560, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
193
-lazy_refcounts Postpone refcount updates
233
+{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
194
-refcount_bits Width of a reference count entry in bits
234
{"return": {}}
195
-nocow Turn off copy-on-write (valid only on btrfs)
235
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
196
+ backing_file=<str> - File name of a base image
236
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
197
+ backing_fmt=<str> - Image format of the base image
237
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
198
+ cluster_size=<size> - qcow2 cluster size
238
{"return": {}}
199
+ compat=<str> - Compatibility level (0.10 or 1.1)
239
{"return": {}}
200
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
240
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}}
201
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
241
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 31457280, "offset": 31457280, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
202
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
242
+{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 31457280, "offset": 31457280, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
203
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
243
{"return": {}}
204
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
244
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
205
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
245
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}}
206
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
246
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
207
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
247
{"return": {}}
208
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
248
{"return": {}}
209
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
249
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
210
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
250
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 327680, "offset": 327680, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
211
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
251
+{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
212
+ refcount_bits=<num> - Width of a reference count entry in bits
252
{"return": {}}
213
+ size=<size> - Virtual disk size
253
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
214
254
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
215
Testing: create -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 128M
255
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 0
216
Supported options:
256
{"return": {}}
217
-size Virtual disk size
257
{"return": {}}
218
-compat Compatibility level (0.10 or 1.1)
258
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}}
219
-backing_file File name of a base image
259
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 2048, "offset": 2048, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
220
-backing_fmt Image format of the base image
260
+{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 2048, "offset": 2048, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
221
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
261
{"return": {}}
222
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
262
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
223
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
263
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}}
224
-encrypt.cipher-alg Name of encryption cipher algorithm
264
@@ -XXX,XX +XXX,XX @@ Automatically detecting the format is dangerous for raw images, write operations
225
-encrypt.cipher-mode Name of encryption cipher mode
265
Specify the 'raw' format explicitly to remove the restrictions.
226
-encrypt.ivgen-alg Name of IV generator algorithm
266
{"return": {}}
227
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
267
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
228
-encrypt.hash-alg Name of encryption hash algorithm
268
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 512, "offset": 512, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
229
-encrypt.iter-time Time to spend in PBKDF in milliseconds
269
+{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
230
-cluster_size qcow2 cluster size
270
{"return": {}}
231
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
271
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
232
-lazy_refcounts Postpone refcount updates
272
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
233
-refcount_bits Width of a reference count entry in bits
273
@@ -XXX,XX +XXX,XX @@ Images are identical.
234
-nocow Turn off copy-on-write (valid only on btrfs)
274
{"return": {}}
235
+ backing_file=<str> - File name of a base image
275
{"return": {}}
236
+ backing_fmt=<str> - Image format of the base image
276
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
237
+ cluster_size=<size> - qcow2 cluster size
277
-{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 512, "offset": 512, "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
238
+ compat=<str> - Compatibility level (0.10 or 1.1)
278
+{"return": [{"io-status": "ok", "device": "src", "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
239
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
279
{"return": {}}
240
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
280
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false}}
241
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
281
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
242
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
243
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
244
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
245
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
246
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
247
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
248
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
249
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
250
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
251
+ refcount_bits=<num> - Width of a reference count entry in bits
252
+ size=<size> - Virtual disk size
253
254
Testing: create -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 128M
255
Supported options:
256
-size Virtual disk size
257
-compat Compatibility level (0.10 or 1.1)
258
-backing_file File name of a base image
259
-backing_fmt Image format of the base image
260
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
261
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
262
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
263
-encrypt.cipher-alg Name of encryption cipher algorithm
264
-encrypt.cipher-mode Name of encryption cipher mode
265
-encrypt.ivgen-alg Name of IV generator algorithm
266
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
267
-encrypt.hash-alg Name of encryption hash algorithm
268
-encrypt.iter-time Time to spend in PBKDF in milliseconds
269
-cluster_size qcow2 cluster size
270
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
271
-lazy_refcounts Postpone refcount updates
272
-refcount_bits Width of a reference count entry in bits
273
-nocow Turn off copy-on-write (valid only on btrfs)
274
+ backing_file=<str> - File name of a base image
275
+ backing_fmt=<str> - Image format of the base image
276
+ cluster_size=<size> - qcow2 cluster size
277
+ compat=<str> - Compatibility level (0.10 or 1.1)
278
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
279
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
280
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
281
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
282
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
283
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
284
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
285
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
286
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
287
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
288
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
289
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
290
+ refcount_bits=<num> - Width of a reference count entry in bits
291
+ size=<size> - Virtual disk size
292
293
Testing: create -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 128M
294
Supported options:
295
-size Virtual disk size
296
-compat Compatibility level (0.10 or 1.1)
297
-backing_file File name of a base image
298
-backing_fmt Image format of the base image
299
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
300
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
301
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
302
-encrypt.cipher-alg Name of encryption cipher algorithm
303
-encrypt.cipher-mode Name of encryption cipher mode
304
-encrypt.ivgen-alg Name of IV generator algorithm
305
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
306
-encrypt.hash-alg Name of encryption hash algorithm
307
-encrypt.iter-time Time to spend in PBKDF in milliseconds
308
-cluster_size qcow2 cluster size
309
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
310
-lazy_refcounts Postpone refcount updates
311
-refcount_bits Width of a reference count entry in bits
312
-nocow Turn off copy-on-write (valid only on btrfs)
313
+ backing_file=<str> - File name of a base image
314
+ backing_fmt=<str> - Image format of the base image
315
+ cluster_size=<size> - qcow2 cluster size
316
+ compat=<str> - Compatibility level (0.10 or 1.1)
317
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
318
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
319
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
320
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
321
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
322
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
323
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
324
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
325
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
326
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
327
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
328
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
329
+ refcount_bits=<num> - Width of a reference count entry in bits
330
+ size=<size> - Virtual disk size
331
332
Testing: create -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 128M
333
Supported options:
334
-size Virtual disk size
335
-compat Compatibility level (0.10 or 1.1)
336
-backing_file File name of a base image
337
-backing_fmt Image format of the base image
338
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
339
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
340
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
341
-encrypt.cipher-alg Name of encryption cipher algorithm
342
-encrypt.cipher-mode Name of encryption cipher mode
343
-encrypt.ivgen-alg Name of IV generator algorithm
344
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
345
-encrypt.hash-alg Name of encryption hash algorithm
346
-encrypt.iter-time Time to spend in PBKDF in milliseconds
347
-cluster_size qcow2 cluster size
348
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
349
-lazy_refcounts Postpone refcount updates
350
-refcount_bits Width of a reference count entry in bits
351
-nocow Turn off copy-on-write (valid only on btrfs)
352
+ backing_file=<str> - File name of a base image
353
+ backing_fmt=<str> - Image format of the base image
354
+ cluster_size=<size> - qcow2 cluster size
355
+ compat=<str> - Compatibility level (0.10 or 1.1)
356
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
357
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
358
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
359
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
360
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
361
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
362
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
363
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
364
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
365
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
366
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
367
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
368
+ refcount_bits=<num> - Width of a reference count entry in bits
369
+ size=<size> - Virtual disk size
370
371
Testing: create -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 128M
372
Supported options:
373
-size Virtual disk size
374
-compat Compatibility level (0.10 or 1.1)
375
-backing_file File name of a base image
376
-backing_fmt Image format of the base image
377
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
378
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
379
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
380
-encrypt.cipher-alg Name of encryption cipher algorithm
381
-encrypt.cipher-mode Name of encryption cipher mode
382
-encrypt.ivgen-alg Name of IV generator algorithm
383
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
384
-encrypt.hash-alg Name of encryption hash algorithm
385
-encrypt.iter-time Time to spend in PBKDF in milliseconds
386
-cluster_size qcow2 cluster size
387
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
388
-lazy_refcounts Postpone refcount updates
389
-refcount_bits Width of a reference count entry in bits
390
-nocow Turn off copy-on-write (valid only on btrfs)
391
+ backing_file=<str> - File name of a base image
392
+ backing_fmt=<str> - Image format of the base image
393
+ cluster_size=<size> - qcow2 cluster size
394
+ compat=<str> - Compatibility level (0.10 or 1.1)
395
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
396
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
397
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
398
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
399
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
400
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
401
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
402
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
403
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
404
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
405
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
406
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
407
+ refcount_bits=<num> - Width of a reference count entry in bits
408
+ size=<size> - Virtual disk size
409
410
Testing: create -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 128M
411
Supported options:
412
-size Virtual disk size
413
-compat Compatibility level (0.10 or 1.1)
414
-backing_file File name of a base image
415
-backing_fmt Image format of the base image
416
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
417
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
418
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
419
-encrypt.cipher-alg Name of encryption cipher algorithm
420
-encrypt.cipher-mode Name of encryption cipher mode
421
-encrypt.ivgen-alg Name of IV generator algorithm
422
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
423
-encrypt.hash-alg Name of encryption hash algorithm
424
-encrypt.iter-time Time to spend in PBKDF in milliseconds
425
-cluster_size qcow2 cluster size
426
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
427
-lazy_refcounts Postpone refcount updates
428
-refcount_bits Width of a reference count entry in bits
429
-nocow Turn off copy-on-write (valid only on btrfs)
430
+ backing_file=<str> - File name of a base image
431
+ backing_fmt=<str> - Image format of the base image
432
+ cluster_size=<size> - qcow2 cluster size
433
+ compat=<str> - Compatibility level (0.10 or 1.1)
434
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
435
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
436
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
437
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
438
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
439
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
440
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
441
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
442
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
443
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
444
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
445
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
446
+ refcount_bits=<num> - Width of a reference count entry in bits
447
+ size=<size> - Virtual disk size
448
449
Testing: create -f qcow2 -u -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M
450
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help cluster_size=65536 lazy_refcounts=off refcount_bits=16
451
@@ -XXX,XX +XXX,XX @@ qemu-img: Invalid option list: ,,
452
453
Testing: create -f qcow2 -o help
454
Supported options:
455
-size Virtual disk size
456
-compat Compatibility level (0.10 or 1.1)
457
-backing_file File name of a base image
458
-backing_fmt Image format of the base image
459
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
460
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
461
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
462
-encrypt.cipher-alg Name of encryption cipher algorithm
463
-encrypt.cipher-mode Name of encryption cipher mode
464
-encrypt.ivgen-alg Name of IV generator algorithm
465
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
466
-encrypt.hash-alg Name of encryption hash algorithm
467
-encrypt.iter-time Time to spend in PBKDF in milliseconds
468
-cluster_size qcow2 cluster size
469
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
470
-lazy_refcounts Postpone refcount updates
471
-refcount_bits Width of a reference count entry in bits
472
+ backing_file=<str> - File name of a base image
473
+ backing_fmt=<str> - Image format of the base image
474
+ cluster_size=<size> - qcow2 cluster size
475
+ compat=<str> - Compatibility level (0.10 or 1.1)
476
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
477
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
478
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
479
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
480
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
481
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
482
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
483
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
484
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
485
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
486
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
487
+ refcount_bits=<num> - Width of a reference count entry in bits
488
+ size=<size> - Virtual disk size
489
490
Testing: create -o help
491
Supported options:
492
-size Virtual disk size
493
+ size=<size> - Virtual disk size
494
495
Testing: create -f bochs -o help
496
qemu-img: Format driver 'bochs' does not support image creation
497
@@ -XXX,XX +XXX,XX @@ cluster_size: 8192
498
499
Testing: convert -O qcow2 -o help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
500
Supported options:
501
-size Virtual disk size
502
-compat Compatibility level (0.10 or 1.1)
503
-backing_file File name of a base image
504
-backing_fmt Image format of the base image
505
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
506
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
507
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
508
-encrypt.cipher-alg Name of encryption cipher algorithm
509
-encrypt.cipher-mode Name of encryption cipher mode
510
-encrypt.ivgen-alg Name of IV generator algorithm
511
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
512
-encrypt.hash-alg Name of encryption hash algorithm
513
-encrypt.iter-time Time to spend in PBKDF in milliseconds
514
-cluster_size qcow2 cluster size
515
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
516
-lazy_refcounts Postpone refcount updates
517
-refcount_bits Width of a reference count entry in bits
518
-nocow Turn off copy-on-write (valid only on btrfs)
519
+ backing_file=<str> - File name of a base image
520
+ backing_fmt=<str> - Image format of the base image
521
+ cluster_size=<size> - qcow2 cluster size
522
+ compat=<str> - Compatibility level (0.10 or 1.1)
523
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
524
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
525
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
526
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
527
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
528
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
529
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
530
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
531
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
532
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
533
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
534
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
535
+ refcount_bits=<num> - Width of a reference count entry in bits
536
+ size=<size> - Virtual disk size
537
538
Testing: convert -O qcow2 -o ? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
539
Supported options:
540
-size Virtual disk size
541
-compat Compatibility level (0.10 or 1.1)
542
-backing_file File name of a base image
543
-backing_fmt Image format of the base image
544
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
545
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
546
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
547
-encrypt.cipher-alg Name of encryption cipher algorithm
548
-encrypt.cipher-mode Name of encryption cipher mode
549
-encrypt.ivgen-alg Name of IV generator algorithm
550
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
551
-encrypt.hash-alg Name of encryption hash algorithm
552
-encrypt.iter-time Time to spend in PBKDF in milliseconds
553
-cluster_size qcow2 cluster size
554
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
555
-lazy_refcounts Postpone refcount updates
556
-refcount_bits Width of a reference count entry in bits
557
-nocow Turn off copy-on-write (valid only on btrfs)
558
+ backing_file=<str> - File name of a base image
559
+ backing_fmt=<str> - Image format of the base image
560
+ cluster_size=<size> - qcow2 cluster size
561
+ compat=<str> - Compatibility level (0.10 or 1.1)
562
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
563
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
564
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
565
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
566
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
567
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
568
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
569
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
570
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
571
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
572
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
573
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
574
+ refcount_bits=<num> - Width of a reference count entry in bits
575
+ size=<size> - Virtual disk size
576
577
Testing: convert -O qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
578
Supported options:
579
-size Virtual disk size
580
-compat Compatibility level (0.10 or 1.1)
581
-backing_file File name of a base image
582
-backing_fmt Image format of the base image
583
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
584
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
585
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
586
-encrypt.cipher-alg Name of encryption cipher algorithm
587
-encrypt.cipher-mode Name of encryption cipher mode
588
-encrypt.ivgen-alg Name of IV generator algorithm
589
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
590
-encrypt.hash-alg Name of encryption hash algorithm
591
-encrypt.iter-time Time to spend in PBKDF in milliseconds
592
-cluster_size qcow2 cluster size
593
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
594
-lazy_refcounts Postpone refcount updates
595
-refcount_bits Width of a reference count entry in bits
596
-nocow Turn off copy-on-write (valid only on btrfs)
597
+ backing_file=<str> - File name of a base image
598
+ backing_fmt=<str> - Image format of the base image
599
+ cluster_size=<size> - qcow2 cluster size
600
+ compat=<str> - Compatibility level (0.10 or 1.1)
601
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
602
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
603
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
604
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
605
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
606
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
607
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
608
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
609
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
610
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
611
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
612
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
613
+ refcount_bits=<num> - Width of a reference count entry in bits
614
+ size=<size> - Virtual disk size
615
616
Testing: convert -O qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
617
Supported options:
618
-size Virtual disk size
619
-compat Compatibility level (0.10 or 1.1)
620
-backing_file File name of a base image
621
-backing_fmt Image format of the base image
622
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
623
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
624
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
625
-encrypt.cipher-alg Name of encryption cipher algorithm
626
-encrypt.cipher-mode Name of encryption cipher mode
627
-encrypt.ivgen-alg Name of IV generator algorithm
628
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
629
-encrypt.hash-alg Name of encryption hash algorithm
630
-encrypt.iter-time Time to spend in PBKDF in milliseconds
631
-cluster_size qcow2 cluster size
632
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
633
-lazy_refcounts Postpone refcount updates
634
-refcount_bits Width of a reference count entry in bits
635
-nocow Turn off copy-on-write (valid only on btrfs)
636
+ backing_file=<str> - File name of a base image
637
+ backing_fmt=<str> - Image format of the base image
638
+ cluster_size=<size> - qcow2 cluster size
639
+ compat=<str> - Compatibility level (0.10 or 1.1)
640
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
641
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
642
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
643
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
644
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
645
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
646
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
647
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
648
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
649
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
650
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
651
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
652
+ refcount_bits=<num> - Width of a reference count entry in bits
653
+ size=<size> - Virtual disk size
654
655
Testing: convert -O qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
656
Supported options:
657
-size Virtual disk size
658
-compat Compatibility level (0.10 or 1.1)
659
-backing_file File name of a base image
660
-backing_fmt Image format of the base image
661
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
662
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
663
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
664
-encrypt.cipher-alg Name of encryption cipher algorithm
665
-encrypt.cipher-mode Name of encryption cipher mode
666
-encrypt.ivgen-alg Name of IV generator algorithm
667
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
668
-encrypt.hash-alg Name of encryption hash algorithm
669
-encrypt.iter-time Time to spend in PBKDF in milliseconds
670
-cluster_size qcow2 cluster size
671
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
672
-lazy_refcounts Postpone refcount updates
673
-refcount_bits Width of a reference count entry in bits
674
-nocow Turn off copy-on-write (valid only on btrfs)
675
+ backing_file=<str> - File name of a base image
676
+ backing_fmt=<str> - Image format of the base image
677
+ cluster_size=<size> - qcow2 cluster size
678
+ compat=<str> - Compatibility level (0.10 or 1.1)
679
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
680
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
681
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
682
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
683
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
684
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
685
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
686
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
687
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
688
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
689
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
690
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
691
+ refcount_bits=<num> - Width of a reference count entry in bits
692
+ size=<size> - Virtual disk size
693
694
Testing: convert -O qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
695
Supported options:
696
-size Virtual disk size
697
-compat Compatibility level (0.10 or 1.1)
698
-backing_file File name of a base image
699
-backing_fmt Image format of the base image
700
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
701
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
702
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
703
-encrypt.cipher-alg Name of encryption cipher algorithm
704
-encrypt.cipher-mode Name of encryption cipher mode
705
-encrypt.ivgen-alg Name of IV generator algorithm
706
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
707
-encrypt.hash-alg Name of encryption hash algorithm
708
-encrypt.iter-time Time to spend in PBKDF in milliseconds
709
-cluster_size qcow2 cluster size
710
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
711
-lazy_refcounts Postpone refcount updates
712
-refcount_bits Width of a reference count entry in bits
713
-nocow Turn off copy-on-write (valid only on btrfs)
714
+ backing_file=<str> - File name of a base image
715
+ backing_fmt=<str> - Image format of the base image
716
+ cluster_size=<size> - qcow2 cluster size
717
+ compat=<str> - Compatibility level (0.10 or 1.1)
718
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
719
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
720
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
721
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
722
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
723
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
724
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
725
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
726
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
727
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
728
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
729
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
730
+ refcount_bits=<num> - Width of a reference count entry in bits
731
+ size=<size> - Virtual disk size
732
733
Testing: convert -O qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
734
Supported options:
735
-size Virtual disk size
736
-compat Compatibility level (0.10 or 1.1)
737
-backing_file File name of a base image
738
-backing_fmt Image format of the base image
739
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
740
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
741
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
742
-encrypt.cipher-alg Name of encryption cipher algorithm
743
-encrypt.cipher-mode Name of encryption cipher mode
744
-encrypt.ivgen-alg Name of IV generator algorithm
745
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
746
-encrypt.hash-alg Name of encryption hash algorithm
747
-encrypt.iter-time Time to spend in PBKDF in milliseconds
748
-cluster_size qcow2 cluster size
749
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
750
-lazy_refcounts Postpone refcount updates
751
-refcount_bits Width of a reference count entry in bits
752
-nocow Turn off copy-on-write (valid only on btrfs)
753
+ backing_file=<str> - File name of a base image
754
+ backing_fmt=<str> - Image format of the base image
755
+ cluster_size=<size> - qcow2 cluster size
756
+ compat=<str> - Compatibility level (0.10 or 1.1)
757
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
758
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
759
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
760
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
761
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
762
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
763
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
764
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
765
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
766
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
767
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
768
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
769
+ refcount_bits=<num> - Width of a reference count entry in bits
770
+ size=<size> - Virtual disk size
771
772
Testing: convert -O qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
773
Supported options:
774
-size Virtual disk size
775
-compat Compatibility level (0.10 or 1.1)
776
-backing_file File name of a base image
777
-backing_fmt Image format of the base image
778
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
779
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
780
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
781
-encrypt.cipher-alg Name of encryption cipher algorithm
782
-encrypt.cipher-mode Name of encryption cipher mode
783
-encrypt.ivgen-alg Name of IV generator algorithm
784
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
785
-encrypt.hash-alg Name of encryption hash algorithm
786
-encrypt.iter-time Time to spend in PBKDF in milliseconds
787
-cluster_size qcow2 cluster size
788
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
789
-lazy_refcounts Postpone refcount updates
790
-refcount_bits Width of a reference count entry in bits
791
-nocow Turn off copy-on-write (valid only on btrfs)
792
+ backing_file=<str> - File name of a base image
793
+ backing_fmt=<str> - Image format of the base image
794
+ cluster_size=<size> - qcow2 cluster size
795
+ compat=<str> - Compatibility level (0.10 or 1.1)
796
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
797
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
798
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
799
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
800
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
801
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
802
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
803
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
804
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
805
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
806
+ nocow=<bool (on/off)> - Turn off copy-on-write (valid only on btrfs)
807
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
808
+ refcount_bits=<num> - Width of a reference count entry in bits
809
+ size=<size> - Virtual disk size
810
811
Testing: convert -O qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
812
qemu-img: Could not open 'TEST_DIR/t.qcow2.base': Could not open backing file: Could not open 'TEST_DIR/t.qcow2,help': No such file or directory
813
@@ -XXX,XX +XXX,XX @@ qemu-img: Invalid option list: ,,
814
815
Testing: convert -O qcow2 -o help
816
Supported options:
817
-size Virtual disk size
818
-compat Compatibility level (0.10 or 1.1)
819
-backing_file File name of a base image
820
-backing_fmt Image format of the base image
821
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
822
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
823
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
824
-encrypt.cipher-alg Name of encryption cipher algorithm
825
-encrypt.cipher-mode Name of encryption cipher mode
826
-encrypt.ivgen-alg Name of IV generator algorithm
827
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
828
-encrypt.hash-alg Name of encryption hash algorithm
829
-encrypt.iter-time Time to spend in PBKDF in milliseconds
830
-cluster_size qcow2 cluster size
831
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
832
-lazy_refcounts Postpone refcount updates
833
-refcount_bits Width of a reference count entry in bits
834
+ backing_file=<str> - File name of a base image
835
+ backing_fmt=<str> - Image format of the base image
836
+ cluster_size=<size> - qcow2 cluster size
837
+ compat=<str> - Compatibility level (0.10 or 1.1)
838
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
839
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
840
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
841
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
842
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
843
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
844
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
845
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
846
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
847
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
848
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
849
+ refcount_bits=<num> - Width of a reference count entry in bits
850
+ size=<size> - Virtual disk size
851
852
Testing: convert -o help
853
Supported options:
854
-size Virtual disk size
855
+ size=<size> - Virtual disk size
856
857
Testing: convert -O bochs -o help
858
qemu-img: Format driver 'bochs' does not support image creation
859
@@ -XXX,XX +XXX,XX @@ cluster_size: 65536
860
861
Testing: amend -f qcow2 -o help TEST_DIR/t.qcow2
862
Creation options for 'qcow2':
863
-size Virtual disk size
864
-compat Compatibility level (0.10 or 1.1)
865
-backing_file File name of a base image
866
-backing_fmt Image format of the base image
867
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
868
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
869
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
870
-encrypt.cipher-alg Name of encryption cipher algorithm
871
-encrypt.cipher-mode Name of encryption cipher mode
872
-encrypt.ivgen-alg Name of IV generator algorithm
873
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
874
-encrypt.hash-alg Name of encryption hash algorithm
875
-encrypt.iter-time Time to spend in PBKDF in milliseconds
876
-cluster_size qcow2 cluster size
877
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
878
-lazy_refcounts Postpone refcount updates
879
-refcount_bits Width of a reference count entry in bits
880
+ backing_file=<str> - File name of a base image
881
+ backing_fmt=<str> - Image format of the base image
882
+ cluster_size=<size> - qcow2 cluster size
883
+ compat=<str> - Compatibility level (0.10 or 1.1)
884
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
885
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
886
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
887
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
888
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
889
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
890
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
891
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
892
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
893
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
894
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
895
+ refcount_bits=<num> - Width of a reference count entry in bits
896
+ size=<size> - Virtual disk size
897
898
Note that not all of these options may be amendable.
899
900
Testing: amend -f qcow2 -o ? TEST_DIR/t.qcow2
901
Creation options for 'qcow2':
902
-size Virtual disk size
903
-compat Compatibility level (0.10 or 1.1)
904
-backing_file File name of a base image
905
-backing_fmt Image format of the base image
906
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
907
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
908
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
909
-encrypt.cipher-alg Name of encryption cipher algorithm
910
-encrypt.cipher-mode Name of encryption cipher mode
911
-encrypt.ivgen-alg Name of IV generator algorithm
912
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
913
-encrypt.hash-alg Name of encryption hash algorithm
914
-encrypt.iter-time Time to spend in PBKDF in milliseconds
915
-cluster_size qcow2 cluster size
916
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
917
-lazy_refcounts Postpone refcount updates
918
-refcount_bits Width of a reference count entry in bits
919
+ backing_file=<str> - File name of a base image
920
+ backing_fmt=<str> - Image format of the base image
921
+ cluster_size=<size> - qcow2 cluster size
922
+ compat=<str> - Compatibility level (0.10 or 1.1)
923
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
924
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
925
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
926
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
927
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
928
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
929
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
930
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
931
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
932
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
933
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
934
+ refcount_bits=<num> - Width of a reference count entry in bits
935
+ size=<size> - Virtual disk size
936
937
Note that not all of these options may be amendable.
938
939
Testing: amend -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2
940
Creation options for 'qcow2':
941
-size Virtual disk size
942
-compat Compatibility level (0.10 or 1.1)
943
-backing_file File name of a base image
944
-backing_fmt Image format of the base image
945
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
946
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
947
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
948
-encrypt.cipher-alg Name of encryption cipher algorithm
949
-encrypt.cipher-mode Name of encryption cipher mode
950
-encrypt.ivgen-alg Name of IV generator algorithm
951
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
952
-encrypt.hash-alg Name of encryption hash algorithm
953
-encrypt.iter-time Time to spend in PBKDF in milliseconds
954
-cluster_size qcow2 cluster size
955
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
956
-lazy_refcounts Postpone refcount updates
957
-refcount_bits Width of a reference count entry in bits
958
+ backing_file=<str> - File name of a base image
959
+ backing_fmt=<str> - Image format of the base image
960
+ cluster_size=<size> - qcow2 cluster size
961
+ compat=<str> - Compatibility level (0.10 or 1.1)
962
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
963
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
964
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
965
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
966
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
967
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
968
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
969
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
970
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
971
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
972
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
973
+ refcount_bits=<num> - Width of a reference count entry in bits
974
+ size=<size> - Virtual disk size
975
976
Note that not all of these options may be amendable.
977
978
Testing: amend -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2
979
Creation options for 'qcow2':
980
-size Virtual disk size
981
-compat Compatibility level (0.10 or 1.1)
982
-backing_file File name of a base image
983
-backing_fmt Image format of the base image
984
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
985
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
986
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
987
-encrypt.cipher-alg Name of encryption cipher algorithm
988
-encrypt.cipher-mode Name of encryption cipher mode
989
-encrypt.ivgen-alg Name of IV generator algorithm
990
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
991
-encrypt.hash-alg Name of encryption hash algorithm
992
-encrypt.iter-time Time to spend in PBKDF in milliseconds
993
-cluster_size qcow2 cluster size
994
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
995
-lazy_refcounts Postpone refcount updates
996
-refcount_bits Width of a reference count entry in bits
997
+ backing_file=<str> - File name of a base image
998
+ backing_fmt=<str> - Image format of the base image
999
+ cluster_size=<size> - qcow2 cluster size
1000
+ compat=<str> - Compatibility level (0.10 or 1.1)
1001
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1002
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1003
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1004
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1005
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1006
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1007
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1008
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1009
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1010
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1011
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1012
+ refcount_bits=<num> - Width of a reference count entry in bits
1013
+ size=<size> - Virtual disk size
1014
1015
Note that not all of these options may be amendable.
1016
1017
Testing: amend -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2
1018
Creation options for 'qcow2':
1019
-size Virtual disk size
1020
-compat Compatibility level (0.10 or 1.1)
1021
-backing_file File name of a base image
1022
-backing_fmt Image format of the base image
1023
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1024
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1025
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1026
-encrypt.cipher-alg Name of encryption cipher algorithm
1027
-encrypt.cipher-mode Name of encryption cipher mode
1028
-encrypt.ivgen-alg Name of IV generator algorithm
1029
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1030
-encrypt.hash-alg Name of encryption hash algorithm
1031
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1032
-cluster_size qcow2 cluster size
1033
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1034
-lazy_refcounts Postpone refcount updates
1035
-refcount_bits Width of a reference count entry in bits
1036
+ backing_file=<str> - File name of a base image
1037
+ backing_fmt=<str> - Image format of the base image
1038
+ cluster_size=<size> - qcow2 cluster size
1039
+ compat=<str> - Compatibility level (0.10 or 1.1)
1040
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1041
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1042
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1043
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1044
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1045
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1046
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1047
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1048
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1049
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1050
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1051
+ refcount_bits=<num> - Width of a reference count entry in bits
1052
+ size=<size> - Virtual disk size
1053
1054
Note that not all of these options may be amendable.
1055
1056
Testing: amend -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2
1057
Creation options for 'qcow2':
1058
-size Virtual disk size
1059
-compat Compatibility level (0.10 or 1.1)
1060
-backing_file File name of a base image
1061
-backing_fmt Image format of the base image
1062
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1063
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1064
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1065
-encrypt.cipher-alg Name of encryption cipher algorithm
1066
-encrypt.cipher-mode Name of encryption cipher mode
1067
-encrypt.ivgen-alg Name of IV generator algorithm
1068
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1069
-encrypt.hash-alg Name of encryption hash algorithm
1070
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1071
-cluster_size qcow2 cluster size
1072
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1073
-lazy_refcounts Postpone refcount updates
1074
-refcount_bits Width of a reference count entry in bits
1075
+ backing_file=<str> - File name of a base image
1076
+ backing_fmt=<str> - Image format of the base image
1077
+ cluster_size=<size> - qcow2 cluster size
1078
+ compat=<str> - Compatibility level (0.10 or 1.1)
1079
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1080
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1081
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1082
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1083
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1084
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1085
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1086
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1087
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1088
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1089
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1090
+ refcount_bits=<num> - Width of a reference count entry in bits
1091
+ size=<size> - Virtual disk size
1092
1093
Note that not all of these options may be amendable.
1094
1095
Testing: amend -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2
1096
Creation options for 'qcow2':
1097
-size Virtual disk size
1098
-compat Compatibility level (0.10 or 1.1)
1099
-backing_file File name of a base image
1100
-backing_fmt Image format of the base image
1101
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1102
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1103
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1104
-encrypt.cipher-alg Name of encryption cipher algorithm
1105
-encrypt.cipher-mode Name of encryption cipher mode
1106
-encrypt.ivgen-alg Name of IV generator algorithm
1107
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1108
-encrypt.hash-alg Name of encryption hash algorithm
1109
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1110
-cluster_size qcow2 cluster size
1111
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1112
-lazy_refcounts Postpone refcount updates
1113
-refcount_bits Width of a reference count entry in bits
1114
+ backing_file=<str> - File name of a base image
1115
+ backing_fmt=<str> - Image format of the base image
1116
+ cluster_size=<size> - qcow2 cluster size
1117
+ compat=<str> - Compatibility level (0.10 or 1.1)
1118
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1119
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1120
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1121
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1122
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1123
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1124
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1125
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1126
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1127
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1128
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1129
+ refcount_bits=<num> - Width of a reference count entry in bits
1130
+ size=<size> - Virtual disk size
1131
1132
Note that not all of these options may be amendable.
1133
1134
Testing: amend -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2
1135
Creation options for 'qcow2':
1136
-size Virtual disk size
1137
-compat Compatibility level (0.10 or 1.1)
1138
-backing_file File name of a base image
1139
-backing_fmt Image format of the base image
1140
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1141
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1142
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1143
-encrypt.cipher-alg Name of encryption cipher algorithm
1144
-encrypt.cipher-mode Name of encryption cipher mode
1145
-encrypt.ivgen-alg Name of IV generator algorithm
1146
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1147
-encrypt.hash-alg Name of encryption hash algorithm
1148
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1149
-cluster_size qcow2 cluster size
1150
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1151
-lazy_refcounts Postpone refcount updates
1152
-refcount_bits Width of a reference count entry in bits
1153
+ backing_file=<str> - File name of a base image
1154
+ backing_fmt=<str> - Image format of the base image
1155
+ cluster_size=<size> - qcow2 cluster size
1156
+ compat=<str> - Compatibility level (0.10 or 1.1)
1157
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1158
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1159
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1160
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1161
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1162
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1163
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1164
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1165
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1166
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1167
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1168
+ refcount_bits=<num> - Width of a reference count entry in bits
1169
+ size=<size> - Virtual disk size
1170
1171
Note that not all of these options may be amendable.
1172
1173
@@ -XXX,XX +XXX,XX @@ qemu-img: Invalid option list: ,,
1174
1175
Testing: amend -f qcow2 -o help
1176
Creation options for 'qcow2':
1177
-size Virtual disk size
1178
-compat Compatibility level (0.10 or 1.1)
1179
-backing_file File name of a base image
1180
-backing_fmt Image format of the base image
1181
-encryption Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1182
-encrypt.format Encrypt the image, format choices: 'aes', 'luks'
1183
-encrypt.key-secret ID of secret providing qcow AES key or LUKS passphrase
1184
-encrypt.cipher-alg Name of encryption cipher algorithm
1185
-encrypt.cipher-mode Name of encryption cipher mode
1186
-encrypt.ivgen-alg Name of IV generator algorithm
1187
-encrypt.ivgen-hash-alg Name of IV generator hash algorithm
1188
-encrypt.hash-alg Name of encryption hash algorithm
1189
-encrypt.iter-time Time to spend in PBKDF in milliseconds
1190
-cluster_size qcow2 cluster size
1191
-preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
1192
-lazy_refcounts Postpone refcount updates
1193
-refcount_bits Width of a reference count entry in bits
1194
+ backing_file=<str> - File name of a base image
1195
+ backing_fmt=<str> - Image format of the base image
1196
+ cluster_size=<size> - qcow2 cluster size
1197
+ compat=<str> - Compatibility level (0.10 or 1.1)
1198
+ encrypt.cipher-alg=<str> - Name of encryption cipher algorithm
1199
+ encrypt.cipher-mode=<str> - Name of encryption cipher mode
1200
+ encrypt.format=<str> - Encrypt the image, format choices: 'aes', 'luks'
1201
+ encrypt.hash-alg=<str> - Name of encryption hash algorithm
1202
+ encrypt.iter-time=<num> - Time to spend in PBKDF in milliseconds
1203
+ encrypt.ivgen-alg=<str> - Name of IV generator algorithm
1204
+ encrypt.ivgen-hash-alg=<str> - Name of IV generator hash algorithm
1205
+ encrypt.key-secret=<str> - ID of secret providing qcow AES key or LUKS passphrase
1206
+ encryption=<bool (on/off)> - Encrypt the image with format 'aes'. (Deprecated in favor of encrypt.format=aes)
1207
+ lazy_refcounts=<bool (on/off)> - Postpone refcount updates
1208
+ preallocation=<str> - Preallocation mode (allowed values: off, metadata, falloc, full)
1209
+ refcount_bits=<num> - Width of a reference count entry in bits
1210
+ size=<size> - Virtual disk size
1211
1212
Note that not all of these options may be amendable.
1213
1214
Testing: convert -o help
1215
Supported options:
1216
-size Virtual disk size
1217
+ size=<size> - Virtual disk size
1218
1219
Testing: amend -f bochs -o help
1220
qemu-img: Format driver 'bochs' does not support option amendment
282
--
1221
--
283
2.13.6
1222
2.19.1
284
1223
285
1224
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
The completed_single function is getting a little mucked up with
3
Following the example of qemu_opts_print_help(), indent all entries in
4
checking to see which callbacks exist, so let's factor them out.
4
the list of character devices.
5
5
6
Signed-off-by: John Snow <jsnow@redhat.com>
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
9
---
11
blockjob.c | 35 ++++++++++++++++++++++++++---------
10
chardev/char.c | 2 +-
12
1 file changed, 26 insertions(+), 9 deletions(-)
11
1 file changed, 1 insertion(+), 1 deletion(-)
13
12
14
diff --git a/blockjob.c b/blockjob.c
13
diff --git a/chardev/char.c b/chardev/char.c
15
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
16
--- a/blockjob.c
15
--- a/chardev/char.c
17
+++ b/blockjob.c
16
+++ b/chardev/char.c
18
@@ -XXX,XX +XXX,XX @@ static void block_job_update_rc(BlockJob *job)
17
@@ -XXX,XX +XXX,XX @@ help_string_append(const char *name, void *opaque)
19
}
18
{
19
GString *str = opaque;
20
21
- g_string_append_printf(str, "\n%s", name);
22
+ g_string_append_printf(str, "\n %s", name);
20
}
23
}
21
24
22
+static void block_job_commit(BlockJob *job)
25
static const char *chardev_alias_translate(const char *name)
23
+{
24
+ assert(!job->ret);
25
+ if (job->driver->commit) {
26
+ job->driver->commit(job);
27
+ }
28
+}
29
+
30
+static void block_job_abort(BlockJob *job)
31
+{
32
+ assert(job->ret);
33
+ if (job->driver->abort) {
34
+ job->driver->abort(job);
35
+ }
36
+}
37
+
38
+static void block_job_clean(BlockJob *job)
39
+{
40
+ if (job->driver->clean) {
41
+ job->driver->clean(job);
42
+ }
43
+}
44
+
45
static void block_job_completed_single(BlockJob *job)
46
{
47
assert(job->completed);
48
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_single(BlockJob *job)
49
block_job_update_rc(job);
50
51
if (!job->ret) {
52
- if (job->driver->commit) {
53
- job->driver->commit(job);
54
- }
55
+ block_job_commit(job);
56
} else {
57
- if (job->driver->abort) {
58
- job->driver->abort(job);
59
- }
60
- }
61
- if (job->driver->clean) {
62
- job->driver->clean(job);
63
+ block_job_abort(job);
64
}
65
+ block_job_clean(job);
66
67
if (job->cb) {
68
job->cb(job->opaque, job->ret);
69
--
26
--
70
2.13.6
27
2.19.1
71
28
72
29
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
Just like in qemu_opts_print_help(), print the device name as a caption
4
instead of on every single line, indent all options, add angle brackets
5
around types, and align the descriptions after 24 characters. Also,
6
separate the descriptions with " - " instead of putting them in
7
parentheses, because that is what we do everywhere else. This does look
8
a bit funny here because basically all bits have the description
9
"on/off", but funny does not mean it is less readable.
10
3
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
14
---
6
qapi/block-core.json | 2 +-
15
qdev-monitor.c | 13 +++++++++++--
7
block/vdi.c | 24 +++++++++++++++++++-----
16
1 file changed, 11 insertions(+), 2 deletions(-)
8
2 files changed, 20 insertions(+), 6 deletions(-)
9
17
10
diff --git a/qapi/block-core.json b/qapi/block-core.json
18
diff --git a/qdev-monitor.c b/qdev-monitor.c
11
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
12
--- a/qapi/block-core.json
20
--- a/qdev-monitor.c
13
+++ b/qapi/block-core.json
21
+++ b/qdev-monitor.c
14
@@ -XXX,XX +XXX,XX @@
22
@@ -XXX,XX +XXX,XX @@ int qdev_device_help(QemuOpts *opts)
15
'sheepdog': 'BlockdevCreateOptionsSheepdog',
23
goto error;
16
'ssh': 'BlockdevCreateOptionsSsh',
17
'throttle': 'BlockdevCreateNotSupported',
18
- 'vdi': 'BlockdevCreateNotSupported',
19
+ 'vdi': 'BlockdevCreateOptionsVdi',
20
'vhdx': 'BlockdevCreateNotSupported',
21
'vmdk': 'BlockdevCreateNotSupported',
22
'vpc': 'BlockdevCreateNotSupported',
23
diff --git a/block/vdi.c b/block/vdi.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block/vdi.c
26
+++ b/block/vdi.c
27
@@ -XXX,XX +XXX,XX @@ nonallocating_write:
28
return ret;
29
}
30
31
-static int coroutine_fn vdi_co_do_create(BlockdevCreateOptionsVdi *vdi_opts,
32
+static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
33
size_t block_size, Error **errp)
34
{
35
+ BlockdevCreateOptionsVdi *vdi_opts;
36
int ret = 0;
37
uint64_t bytes = 0;
38
uint32_t blocks;
39
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptionsVdi *vdi_opts,
40
BlockBackend *blk = NULL;
41
uint32_t *bmap = NULL;
42
43
+ assert(create_options->driver == BLOCKDEV_DRIVER_VDI);
44
+ vdi_opts = &create_options->u.vdi;
45
+
46
logout("\n");
47
48
/* Read out options. */
49
@@ -XXX,XX +XXX,XX @@ exit:
50
return ret;
51
}
52
53
+static int coroutine_fn vdi_co_create(BlockdevCreateOptions *create_options,
54
+ Error **errp)
55
+{
56
+ return vdi_co_do_create(create_options, DEFAULT_CLUSTER_SIZE, errp);
57
+}
58
+
59
static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
60
Error **errp)
61
{
62
QDict *qdict = NULL;
63
- BlockdevCreateOptionsVdi *create_options = NULL;
64
+ BlockdevCreateOptions *create_options = NULL;
65
BlockDriverState *bs_file = NULL;
66
uint64_t block_size = DEFAULT_CLUSTER_SIZE;
67
Visitor *v;
68
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
69
goto done;
70
}
24
}
71
25
72
+ qdict_put_str(qdict, "driver", "vdi");
26
+ if (prop_list) {
73
qdict_put_str(qdict, "file", bs_file->node_name);
27
+ out_printf("%s options:\n", driver);
74
28
+ } else {
75
/* Get the QAPI object */
29
+ out_printf("There are no options for %s.\n", driver);
76
v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
30
+ }
77
- visit_type_BlockdevCreateOptionsVdi(v, NULL, &create_options, &local_err);
31
for (prop = prop_list; prop; prop = prop->next) {
78
+ visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
32
- out_printf("%s.%s=%s", driver, prop->value->name, prop->value->type);
79
visit_free(v);
33
+ int len;
80
34
+ out_printf(" %s=<%s>%n", prop->value->name, prop->value->type, &len);
81
if (local_err) {
35
if (prop->value->has_description) {
82
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
36
- out_printf(" (%s)\n", prop->value->description);
83
goto done;
37
+ if (len < 24) {
84
}
38
+ out_printf("%*s", 24 - len, "");
85
39
+ }
86
- create_options->size = ROUND_UP(create_options->size, BDRV_SECTOR_SIZE);
40
+ out_printf(" - %s\n", prop->value->description);
87
+ assert(create_options->driver == BLOCKDEV_DRIVER_VDI);
41
} else {
88
+ create_options->u.vdi.size = ROUND_UP(create_options->u.vdi.size,
42
out_printf("\n");
89
+ BDRV_SECTOR_SIZE);
43
}
90
91
ret = vdi_co_do_create(create_options, block_size, errp);
92
done:
93
QDECREF(qdict);
94
- qapi_free_BlockdevCreateOptionsVdi(create_options);
95
+ qapi_free_BlockdevCreateOptions(create_options);
96
bdrv_unref(bs_file);
97
return ret;
98
}
99
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vdi = {
100
.bdrv_reopen_prepare = vdi_reopen_prepare,
101
.bdrv_child_perm = bdrv_format_default_perms,
102
.bdrv_co_create_opts = vdi_co_create_opts,
103
+ .bdrv_co_create = vdi_co_create,
104
.bdrv_has_zero_init = bdrv_has_zero_init_1,
105
.bdrv_co_block_status = vdi_co_block_status,
106
.bdrv_make_empty = vdi_make_empty,
107
--
44
--
108
2.13.6
45
2.19.1
109
46
110
47
diff view generated by jsdifflib
1
From: Max Reitz <mreitz@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
In preparation of QAPI-fying VDI image creation, we have to create a
3
Just like in qemu_opts_print_help(), print the object name as a caption
4
BlockdevCreateOptionsVdi type which is received by a (future)
4
instead of on every single line, indent all options, add angle brackets
5
vdi_co_create().
5
around types, and align the descriptions after 24 characters.
6
6
7
vdi_co_create_opts() now converts the QemuOpts object into such a
7
Also, indent every object name in the list of available objects.
8
BlockdevCreateOptionsVdi object. The protocol-layer file is still
9
created in vdi_co_do_create() (and BlockdevCreateOptionsVdi.file is set
10
to an empty string), but that will be addressed by a follow-up patch.
11
12
Note that cluster-size is not part of the QAPI schema because it is not
13
supported by default.
14
8
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
12
---
18
qapi/block-core.json | 18 +++++++++++
13
vl.c | 13 ++++++++++---
19
block/vdi.c | 91 ++++++++++++++++++++++++++++++++++++++++++++--------
14
1 file changed, 10 insertions(+), 3 deletions(-)
20
2 files changed, 95 insertions(+), 14 deletions(-)
21
15
22
diff --git a/qapi/block-core.json b/qapi/block-core.json
16
diff --git a/vl.c b/vl.c
23
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
24
--- a/qapi/block-core.json
18
--- a/vl.c
25
+++ b/qapi/block-core.json
19
+++ b/vl.c
26
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ static bool object_create_initial(const char *type, QemuOpts *opts)
27
'size': 'size' } }
21
list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
28
22
for (l = list; l != NULL; l = l->next) {
29
##
23
ObjectClass *oc = OBJECT_CLASS(l->data);
30
+# @BlockdevCreateOptionsVdi:
24
- printf("%s\n", object_class_get_name(oc));
31
+#
25
+ printf(" %s\n", object_class_get_name(oc));
32
+# Driver specific image creation options for VDI.
26
}
33
+#
27
g_slist_free(list);
34
+# @file Node to create the image format on
28
exit(0);
35
+# @size Size of the virtual disk in bytes
29
@@ -XXX,XX +XXX,XX @@ static bool object_create_initial(const char *type, QemuOpts *opts)
36
+# @static Whether to create a statically (true) or
30
}
37
+# dynamically (false) allocated image
31
38
+# (default: false, i.e. dynamic)
32
str = g_string_new(NULL);
39
+#
33
- g_string_append_printf(str, "%s.%s=%s", type,
40
+# Since: 2.12
34
- prop->name, prop->type);
41
+##
35
+ g_string_append_printf(str, " %s=<%s>", prop->name, prop->type);
42
+{ 'struct': 'BlockdevCreateOptionsVdi',
36
if (prop->description) {
43
+ 'data': { 'file': 'BlockdevRef',
37
+ if (str->len < 24) {
44
+ 'size': 'size',
38
+ g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
45
+ '*static': 'bool' } }
39
+ }
46
+
40
g_string_append_printf(str, " - %s", prop->description);
47
+##
41
}
48
# @BlockdevCreateNotSupported:
42
g_ptr_array_add(array, g_string_free(str, false));
49
#
43
}
50
# This is used for all drivers that don't support creating images.
44
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
51
diff --git a/block/vdi.c b/block/vdi.c
45
+ if (array->len > 0) {
52
index XXXXXXX..XXXXXXX 100644
46
+ printf("%s options:\n", type);
53
--- a/block/vdi.c
47
+ } else {
54
+++ b/block/vdi.c
48
+ printf("There are no options for %s.\n", type);
55
@@ -XXX,XX +XXX,XX @@
49
+ }
56
50
for (i = 0; i < array->len; i++) {
57
#include "qemu/osdep.h"
51
printf("%s\n", (char *)array->pdata[i]);
58
#include "qapi/error.h"
52
}
59
+#include "qapi/qmp/qdict.h"
60
+#include "qapi/qobject-input-visitor.h"
61
+#include "qapi/qapi-visit-block-core.h"
62
#include "block/block_int.h"
63
#include "sysemu/block-backend.h"
64
#include "qemu/module.h"
65
@@ -XXX,XX +XXX,XX @@
66
#define VDI_DISK_SIZE_MAX ((uint64_t)VDI_BLOCKS_IN_IMAGE_MAX * \
67
(uint64_t)DEFAULT_CLUSTER_SIZE)
68
69
+static QemuOptsList vdi_create_opts;
70
+
71
typedef struct {
72
char text[0x40];
73
uint32_t signature;
74
@@ -XXX,XX +XXX,XX @@ nonallocating_write:
75
return ret;
76
}
77
78
-static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
79
- Error **errp)
80
+static int coroutine_fn vdi_co_do_create(const char *filename,
81
+ QemuOpts *file_opts,
82
+ BlockdevCreateOptionsVdi *vdi_opts,
83
+ size_t block_size, Error **errp)
84
{
85
int ret = 0;
86
uint64_t bytes = 0;
87
uint32_t blocks;
88
- size_t block_size = DEFAULT_CLUSTER_SIZE;
89
uint32_t image_type = VDI_TYPE_DYNAMIC;
90
VdiHeader header;
91
size_t i;
92
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
93
logout("\n");
94
95
/* Read out options. */
96
- bytes = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
97
- BDRV_SECTOR_SIZE);
98
-#if defined(CONFIG_VDI_BLOCK_SIZE)
99
- /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
100
- block_size = qemu_opt_get_size_del(opts,
101
- BLOCK_OPT_CLUSTER_SIZE,
102
- DEFAULT_CLUSTER_SIZE);
103
-#endif
104
-#if defined(CONFIG_VDI_STATIC_IMAGE)
105
- if (qemu_opt_get_bool_del(opts, BLOCK_OPT_STATIC, false)) {
106
+ bytes = vdi_opts->size;
107
+ if (vdi_opts->q_static) {
108
image_type = VDI_TYPE_STATIC;
109
}
110
+#ifndef CONFIG_VDI_STATIC_IMAGE
111
+ if (image_type == VDI_TYPE_STATIC) {
112
+ ret = -ENOTSUP;
113
+ error_setg(errp, "Statically allocated images cannot be created in "
114
+ "this build");
115
+ goto exit;
116
+ }
117
+#endif
118
+#ifndef CONFIG_VDI_BLOCK_SIZE
119
+ if (block_size != DEFAULT_CLUSTER_SIZE) {
120
+ ret = -ENOTSUP;
121
+ error_setg(errp,
122
+ "A non-default cluster size is not supported in this build");
123
+ goto exit;
124
+ }
125
#endif
126
127
if (bytes > VDI_DISK_SIZE_MAX) {
128
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
129
goto exit;
130
}
131
132
- ret = bdrv_create_file(filename, opts, &local_err);
133
+ ret = bdrv_create_file(filename, file_opts, &local_err);
134
if (ret < 0) {
135
error_propagate(errp, local_err);
136
goto exit;
137
@@ -XXX,XX +XXX,XX @@ exit:
138
return ret;
139
}
140
141
+static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
142
+ Error **errp)
143
+{
144
+ QDict *qdict = NULL;
145
+ BlockdevCreateOptionsVdi *create_options = NULL;
146
+ uint64_t block_size = DEFAULT_CLUSTER_SIZE;
147
+ Visitor *v;
148
+ Error *local_err = NULL;
149
+ int ret;
150
+
151
+ /* Since CONFIG_VDI_BLOCK_SIZE is disabled by default,
152
+ * cluster-size is not part of the QAPI schema; therefore we have
153
+ * to parse it before creating the QAPI object. */
154
+#if defined(CONFIG_VDI_BLOCK_SIZE)
155
+ block_size = qemu_opt_get_size_del(opts,
156
+ BLOCK_OPT_CLUSTER_SIZE,
157
+ DEFAULT_CLUSTER_SIZE);
158
+ if (block_size < BDRV_SECTOR_SIZE || block_size > UINT32_MAX ||
159
+ !is_power_of_2(block_size))
160
+ {
161
+ error_setg(errp, "Invalid cluster size");
162
+ ret = -EINVAL;
163
+ goto done;
164
+ }
165
+#endif
166
+
167
+ qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vdi_create_opts, true);
168
+
169
+ qdict_put_str(qdict, "file", ""); /* FIXME */
170
+
171
+ /* Get the QAPI object */
172
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
173
+ visit_type_BlockdevCreateOptionsVdi(v, NULL, &create_options, &local_err);
174
+ visit_free(v);
175
+
176
+ if (local_err) {
177
+ error_propagate(errp, local_err);
178
+ ret = -EINVAL;
179
+ goto done;
180
+ }
181
+
182
+ create_options->size = ROUND_UP(create_options->size, BDRV_SECTOR_SIZE);
183
+
184
+ ret = vdi_co_do_create(filename, opts, create_options, block_size, errp);
185
+done:
186
+ QDECREF(qdict);
187
+ qapi_free_BlockdevCreateOptionsVdi(create_options);
188
+ return ret;
189
+}
190
+
191
static void vdi_close(BlockDriverState *bs)
192
{
193
BDRVVdiState *s = bs->opaque;
194
--
53
--
195
2.13.6
54
2.19.1
196
55
197
56
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Max Reitz <mreitz@redhat.com>
2
2
3
If speed is '0' it's not actually "less than" the previous speed.
3
There is no good reason why there should be a newline in this
4
Kick the job in this case too.
4
description, so remove it.
5
5
6
Signed-off-by: John Snow <jsnow@redhat.com>
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
8
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
10
---
11
blockjob.c | 2 +-
11
vl.c | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
12
1 file changed, 1 insertion(+), 1 deletion(-)
13
13
14
diff --git a/blockjob.c b/blockjob.c
14
diff --git a/vl.c b/vl.c
15
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
16
--- a/blockjob.c
16
--- a/vl.c
17
+++ b/blockjob.c
17
+++ b/vl.c
18
@@ -XXX,XX +XXX,XX @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
18
@@ -XXX,XX +XXX,XX @@ static QemuOptsList qemu_fw_cfg_opts = {
19
}
19
}, {
20
20
.name = "file",
21
job->speed = speed;
21
.type = QEMU_OPT_STRING,
22
- if (speed <= old_speed) {
22
- .help = "Sets the name of the file from which\n"
23
+ if (speed && speed <= old_speed) {
23
+ .help = "Sets the name of the file from which "
24
return;
24
"the fw_cfg blob will be loaded",
25
}
25
}, {
26
26
.name = "string",
27
--
27
--
28
2.13.6
28
2.19.1
29
29
30
30
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
Trivial; Document what the job creation flags do,
4
and some general tidying.
5
6
Signed-off-by: John Snow <jsnow@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
include/block/blockjob.h | 8 ++++----
10
include/block/blockjob_int.h | 4 +++-
11
2 files changed, 7 insertions(+), 5 deletions(-)
12
13
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/include/block/blockjob.h
16
+++ b/include/block/blockjob.h
17
@@ -XXX,XX +XXX,XX @@ typedef struct BlockJob {
18
/** Reference count of the block job */
19
int refcnt;
20
21
- /* True if this job has reported completion by calling block_job_completed.
22
- */
23
+ /** True when job has reported completion by calling block_job_completed. */
24
bool completed;
25
26
- /* ret code passed to block_job_completed.
27
- */
28
+ /** ret code passed to block_job_completed. */
29
int ret;
30
31
/**
32
@@ -XXX,XX +XXX,XX @@ typedef struct BlockJob {
33
} BlockJob;
34
35
typedef enum BlockJobCreateFlags {
36
+ /* Default behavior */
37
BLOCK_JOB_DEFAULT = 0x00,
38
+ /* BlockJob is not QMP-created and should not send QMP events */
39
BLOCK_JOB_INTERNAL = 0x01,
40
} BlockJobCreateFlags;
41
42
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
43
index XXXXXXX..XXXXXXX 100644
44
--- a/include/block/blockjob_int.h
45
+++ b/include/block/blockjob_int.h
46
@@ -XXX,XX +XXX,XX @@ struct BlockJobDriver {
47
* block_job_create:
48
* @job_id: The id of the newly-created job, or %NULL to have one
49
* generated automatically.
50
- * @job_type: The class object for the newly-created job.
51
+ * @driver: The class object for the newly-created job.
52
* @txn: The transaction this job belongs to, if any. %NULL otherwise.
53
* @bs: The block
54
* @perm, @shared_perm: Permissions to request for @bs
55
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
56
+ * @flags: Creation flags for the Block Job.
57
+ * See @BlockJobCreateFlags
58
* @cb: Completion function for the job.
59
* @opaque: Opaque pointer value passed to @cb.
60
* @errp: Error object.
61
--
62
2.13.6
63
64
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
The state transition table has mostly been implied. We're about to make
4
it a bit more complex, so let's make the STM explicit instead.
5
6
Perform state transitions with a function that for now just asserts the
7
transition is appropriate.
8
9
Transitions:
10
Undefined -> Created: During job initialization.
11
Created -> Running: Once the job is started.
12
Jobs cannot transition from "Created" to "Paused"
13
directly, but will instead synchronously transition
14
to running to paused immediately.
15
Running -> Paused: Normal workflow for pauses.
16
Running -> Ready: Normal workflow for jobs reaching their sync point.
17
(e.g. mirror)
18
Ready -> Standby: Normal workflow for pausing ready jobs.
19
Paused -> Running: Normal resume.
20
Standby -> Ready: Resume of a Standby job.
21
22
+---------+
23
|UNDEFINED|
24
+--+------+
25
|
26
+--v----+
27
|CREATED|
28
+--+----+
29
|
30
+--v----+ +------+
31
|RUNNING<----->PAUSED|
32
+--+----+ +------+
33
|
34
+--v--+ +-------+
35
|READY<------->STANDBY|
36
+-----+ +-------+
37
38
Notably, there is no state presently defined as of this commit that
39
deals with a job after the "running" or "ready" states, so this table
40
will be adjusted alongside the commits that introduce those states.
41
42
Signed-off-by: John Snow <jsnow@redhat.com>
43
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
44
---
45
blockjob.c | 40 +++++++++++++++++++++++++++++++++-------
46
block/trace-events | 3 +++
47
2 files changed, 36 insertions(+), 7 deletions(-)
48
49
diff --git a/blockjob.c b/blockjob.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/blockjob.c
52
+++ b/blockjob.c
53
@@ -XXX,XX +XXX,XX @@
54
#include "block/block.h"
55
#include "block/blockjob_int.h"
56
#include "block/block_int.h"
57
+#include "block/trace.h"
58
#include "sysemu/block-backend.h"
59
#include "qapi/error.h"
60
#include "qapi/qapi-events-block-core.h"
61
@@ -XXX,XX +XXX,XX @@
62
* block_job_enter. */
63
static QemuMutex block_job_mutex;
64
65
+/* BlockJob State Transition Table */
66
+bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] = {
67
+ /* U, C, R, P, Y, S */
68
+ /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0},
69
+ /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0},
70
+ /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0},
71
+ /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0},
72
+ /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1},
73
+ /* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0},
74
+};
75
+
76
+static void block_job_state_transition(BlockJob *job, BlockJobStatus s1)
77
+{
78
+ BlockJobStatus s0 = job->status;
79
+ assert(s1 >= 0 && s1 <= BLOCK_JOB_STATUS__MAX);
80
+ trace_block_job_state_transition(job, job->ret, BlockJobSTT[s0][s1] ?
81
+ "allowed" : "disallowed",
82
+ qapi_enum_lookup(&BlockJobStatus_lookup,
83
+ s0),
84
+ qapi_enum_lookup(&BlockJobStatus_lookup,
85
+ s1));
86
+ assert(BlockJobSTT[s0][s1]);
87
+ job->status = s1;
88
+}
89
+
90
static void block_job_lock(void)
91
{
92
qemu_mutex_lock(&block_job_mutex);
93
@@ -XXX,XX +XXX,XX @@ void block_job_start(BlockJob *job)
94
job->pause_count--;
95
job->busy = true;
96
job->paused = false;
97
- job->status = BLOCK_JOB_STATUS_RUNNING;
98
+ block_job_state_transition(job, BLOCK_JOB_STATUS_RUNNING);
99
bdrv_coroutine_enter(blk_bs(job->blk), job->co);
100
}
101
102
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
103
job->paused = true;
104
job->pause_count = 1;
105
job->refcnt = 1;
106
- job->status = BLOCK_JOB_STATUS_CREATED;
107
+ block_job_state_transition(job, BLOCK_JOB_STATUS_CREATED);
108
aio_timer_init(qemu_get_aio_context(), &job->sleep_timer,
109
QEMU_CLOCK_REALTIME, SCALE_NS,
110
block_job_sleep_timer_cb, job);
111
@@ -XXX,XX +XXX,XX @@ void coroutine_fn block_job_pause_point(BlockJob *job)
112
113
if (block_job_should_pause(job) && !block_job_is_cancelled(job)) {
114
BlockJobStatus status = job->status;
115
- job->status = status == BLOCK_JOB_STATUS_READY ? \
116
- BLOCK_JOB_STATUS_STANDBY : \
117
- BLOCK_JOB_STATUS_PAUSED;
118
+ block_job_state_transition(job, status == BLOCK_JOB_STATUS_READY ? \
119
+ BLOCK_JOB_STATUS_STANDBY : \
120
+ BLOCK_JOB_STATUS_PAUSED);
121
job->paused = true;
122
block_job_do_yield(job, -1);
123
job->paused = false;
124
- job->status = status;
125
+ block_job_state_transition(job, status);
126
}
127
128
if (job->driver->resume) {
129
@@ -XXX,XX +XXX,XX @@ void block_job_iostatus_reset(BlockJob *job)
130
131
void block_job_event_ready(BlockJob *job)
132
{
133
- job->status = BLOCK_JOB_STATUS_READY;
134
+ block_job_state_transition(job, BLOCK_JOB_STATUS_READY);
135
job->ready = true;
136
137
if (block_job_is_internal(job)) {
138
diff --git a/block/trace-events b/block/trace-events
139
index XXXXXXX..XXXXXXX 100644
140
--- a/block/trace-events
141
+++ b/block/trace-events
142
@@ -XXX,XX +XXX,XX @@
143
bdrv_open_common(void *bs, const char *filename, int flags, const char *format_name) "bs %p filename \"%s\" flags 0x%x format_name \"%s\""
144
bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
145
146
+# blockjob.c
147
+block_job_state_transition(void *job, int ret, const char *legal, const char *s0, const char *s1) "job %p (ret: %d) attempting %s transition (%s-->%s)"
148
+
149
# block/block-backend.c
150
blk_co_preadv(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x"
151
blk_co_pwritev(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x"
152
--
153
2.13.6
154
155
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
Split out the pause command into the actual pause and the wait.
4
Not every usage presently needs to resubmit a pause request.
5
6
The intent with the next commit will be to explicitly disallow
7
redundant or meaningless pause/resume requests, so the tests
8
need to become more judicious to reflect that.
9
10
Signed-off-by: John Snow <jsnow@redhat.com>
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Reviewed-by: Eric Blake <eblake@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
tests/qemu-iotests/030 | 6 ++----
16
tests/qemu-iotests/055 | 17 ++++++-----------
17
tests/qemu-iotests/iotests.py | 12 ++++++++----
18
3 files changed, 16 insertions(+), 19 deletions(-)
19
20
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
21
index XXXXXXX..XXXXXXX 100755
22
--- a/tests/qemu-iotests/030
23
+++ b/tests/qemu-iotests/030
24
@@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase):
25
result = self.vm.qmp('block-stream', device='drive0')
26
self.assert_qmp(result, 'return', {})
27
28
- result = self.vm.qmp('block-job-pause', device='drive0')
29
- self.assert_qmp(result, 'return', {})
30
-
31
+ self.pause_job('drive0', wait=False)
32
self.vm.resume_drive('drive0')
33
- self.pause_job('drive0')
34
+ self.pause_wait('drive0')
35
36
result = self.vm.qmp('query-block-jobs')
37
offset = self.dictpath(result, 'return[0]/offset')
38
diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055
39
index XXXXXXX..XXXXXXX 100755
40
--- a/tests/qemu-iotests/055
41
+++ b/tests/qemu-iotests/055
42
@@ -XXX,XX +XXX,XX @@ class TestSingleDrive(iotests.QMPTestCase):
43
target=target, sync='full')
44
self.assert_qmp(result, 'return', {})
45
46
- result = self.vm.qmp('block-job-pause', device='drive0')
47
- self.assert_qmp(result, 'return', {})
48
-
49
+ self.pause_job('drive0', wait=False)
50
self.vm.resume_drive('drive0')
51
- self.pause_job('drive0')
52
+ self.pause_wait('drive0')
53
54
result = self.vm.qmp('query-block-jobs')
55
offset = self.dictpath(result, 'return[0]/offset')
56
@@ -XXX,XX +XXX,XX @@ class TestSingleTransaction(iotests.QMPTestCase):
57
])
58
self.assert_qmp(result, 'return', {})
59
60
- result = self.vm.qmp('block-job-pause', device='drive0')
61
- self.assert_qmp(result, 'return', {})
62
+ self.pause_job('drive0', wait=False)
63
64
result = self.vm.qmp('block-job-set-speed', device='drive0', speed=0)
65
self.assert_qmp(result, 'return', {})
66
67
- self.pause_job('drive0')
68
+ self.pause_wait('drive0')
69
70
result = self.vm.qmp('query-block-jobs')
71
offset = self.dictpath(result, 'return[0]/offset')
72
@@ -XXX,XX +XXX,XX @@ class TestDriveCompression(iotests.QMPTestCase):
73
result = self.vm.qmp(cmd, device='drive0', sync='full', compress=True, **args)
74
self.assert_qmp(result, 'return', {})
75
76
- result = self.vm.qmp('block-job-pause', device='drive0')
77
- self.assert_qmp(result, 'return', {})
78
-
79
+ self.pause_job('drive0', wait=False)
80
self.vm.resume_drive('drive0')
81
- self.pause_job('drive0')
82
+ self.pause_wait('drive0')
83
84
result = self.vm.qmp('query-block-jobs')
85
offset = self.dictpath(result, 'return[0]/offset')
86
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
87
index XXXXXXX..XXXXXXX 100644
88
--- a/tests/qemu-iotests/iotests.py
89
+++ b/tests/qemu-iotests/iotests.py
90
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
91
event = self.wait_until_completed(drive=drive)
92
self.assert_qmp(event, 'data/type', 'mirror')
93
94
- def pause_job(self, job_id='job0'):
95
- result = self.vm.qmp('block-job-pause', device=job_id)
96
- self.assert_qmp(result, 'return', {})
97
-
98
+ def pause_wait(self, job_id='job0'):
99
with Timeout(1, "Timeout waiting for job to pause"):
100
while True:
101
result = self.vm.qmp('query-block-jobs')
102
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
103
if job['device'] == job_id and job['paused'] == True and job['busy'] == False:
104
return job
105
106
+ def pause_job(self, job_id='job0', wait=True):
107
+ result = self.vm.qmp('block-job-pause', device=job_id)
108
+ self.assert_qmp(result, 'return', {})
109
+ if wait:
110
+ return self.pause_wait(job_id)
111
+ return result
112
+
113
114
def notrun(reason):
115
'''Skip this test suite'''
116
--
117
2.13.6
118
119
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
Add a new state ABORTING.
4
5
This makes transitions from normative states to error states explicit
6
in the STM, and serves as a disambiguation for which states may complete
7
normally when normal end-states (CONCLUDED) are added in future commits.
8
9
Notably, Paused/Standby jobs do not transition directly to aborting,
10
as they must wake up first and cooperate in their cancellation.
11
12
Transitions:
13
Created -> Aborting: can be cancelled (by the system)
14
Running -> Aborting: can be cancelled or encounter an error
15
Ready -> Aborting: can be cancelled or encounter an error
16
17
Verbs:
18
None. The job must finish cleaning itself up and report its final status.
19
20
+---------+
21
|UNDEFINED|
22
+--+------+
23
|
24
+--v----+
25
+---------+CREATED|
26
| +--+----+
27
| |
28
| +--v----+ +------+
29
+---------+RUNNING<----->PAUSED|
30
| +--+----+ +------+
31
| |
32
| +--v--+ +-------+
33
+---------+READY<------->STANDBY|
34
| +-----+ +-------+
35
|
36
+--v-----+
37
|ABORTING|
38
+--------+
39
40
Signed-off-by: John Snow <jsnow@redhat.com>
41
Reviewed-by: Eric Blake <eblake@redhat.com>
42
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
43
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
44
---
45
qapi/block-core.json | 7 ++++++-
46
blockjob.c | 31 ++++++++++++++++++-------------
47
2 files changed, 24 insertions(+), 14 deletions(-)
48
49
diff --git a/qapi/block-core.json b/qapi/block-core.json
50
index XXXXXXX..XXXXXXX 100644
51
--- a/qapi/block-core.json
52
+++ b/qapi/block-core.json
53
@@ -XXX,XX +XXX,XX @@
54
# @standby: The job is ready, but paused. This is nearly identical to @paused.
55
# The job may return to @ready or otherwise be canceled.
56
#
57
+# @aborting: The job is in the process of being aborted, and will finish with
58
+# an error.
59
+# This status may not be visible to the management process.
60
+#
61
# Since: 2.12
62
##
63
{ 'enum': 'BlockJobStatus',
64
- 'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby'] }
65
+ 'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby',
66
+ 'aborting' ] }
67
68
##
69
# @BlockJobInfo:
70
diff --git a/blockjob.c b/blockjob.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/blockjob.c
73
+++ b/blockjob.c
74
@@ -XXX,XX +XXX,XX @@ static QemuMutex block_job_mutex;
75
76
/* BlockJob State Transition Table */
77
bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] = {
78
- /* U, C, R, P, Y, S */
79
- /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0},
80
- /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0},
81
- /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0},
82
- /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0},
83
- /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1},
84
- /* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0},
85
+ /* U, C, R, P, Y, S, X */
86
+ /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0},
87
+ /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 1},
88
+ /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1},
89
+ /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0},
90
+ /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1},
91
+ /* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0},
92
+ /* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0},
93
};
94
95
bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] = {
96
- /* U, C, R, P, Y, S */
97
- [BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1},
98
- [BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1},
99
- [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1},
100
- [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1},
101
- [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0},
102
+ /* U, C, R, P, Y, S, X */
103
+ [BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 0},
104
+ [BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0},
105
+ [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0},
106
+ [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0},
107
+ [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0},
108
};
109
110
static void block_job_state_transition(BlockJob *job, BlockJobStatus s1)
111
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_single(BlockJob *job)
112
{
113
assert(job->completed);
114
115
+ if (job->ret || block_job_is_cancelled(job)) {
116
+ block_job_state_transition(job, BLOCK_JOB_STATUS_ABORTING);
117
+ }
118
+
119
if (!job->ret) {
120
if (job->driver->commit) {
121
job->driver->commit(job);
122
--
123
2.13.6
124
125
diff view generated by jsdifflib
1
This makes the .bdrv_co_create(_opts) implementation of vdi look more
1
From: Leonid Bloch <lbloch@janustech.com>
2
like the other recently converted block drivers.
3
2
3
If an expression is used to define DEFAULT_CLUSTER_SIZE, when compiled,
4
it will be embedded as a literal expression in the binary (as the
5
default value) because it is stringified to mark the size of the default
6
value. Now this is fixed by using a defined number to define this value.
7
8
Signed-off-by: Leonid Bloch <lbloch@janustech.com>
9
Reviewed-by: Stefan Weil <sw@weilnetz.de>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
6
---
11
---
7
block/vdi.c | 12 +++++++++---
12
block/vdi.c | 4 ++--
8
1 file changed, 9 insertions(+), 3 deletions(-)
13
1 file changed, 2 insertions(+), 2 deletions(-)
9
14
10
diff --git a/block/vdi.c b/block/vdi.c
15
diff --git a/block/vdi.c b/block/vdi.c
11
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
12
--- a/block/vdi.c
17
--- a/block/vdi.c
13
+++ b/block/vdi.c
18
+++ b/block/vdi.c
14
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
19
@@ -XXX,XX +XXX,XX @@
15
20
#define BLOCK_OPT_STATIC "static"
16
logout("\n");
21
17
22
#define SECTOR_SIZE 512
18
- /* Read out options. */
23
-#define DEFAULT_CLUSTER_SIZE (1 * MiB)
19
+ /* Validate options and set default values */
24
+#define DEFAULT_CLUSTER_SIZE S_1MiB
20
bytes = vdi_opts->size;
25
21
if (vdi_opts->q_static) {
26
#if defined(CONFIG_VDI_DEBUG)
22
image_type = VDI_TYPE_STATIC;
27
#define VDI_DEBUG 1
23
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
28
@@ -XXX,XX +XXX,XX @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
24
goto exit;
29
goto fail;
25
}
30
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
26
31
error_setg(errp, "unsupported VDI image (block size %" PRIu32
27
+ /* Create BlockBackend to write to the image */
32
- " is not %" PRIu64 ")",
28
bs_file = bdrv_open_blockdev_ref(vdi_opts->file, errp);
33
+ " is not %" PRIu32 ")",
29
if (!bs_file) {
34
header.block_size, DEFAULT_CLUSTER_SIZE);
30
ret = -EIO;
35
ret = -ENOTSUP;
31
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
36
goto fail;
32
Error *local_err = NULL;
33
int ret;
34
35
- /* Since CONFIG_VDI_BLOCK_SIZE is disabled by default,
36
+ /* Parse options and convert legacy syntax.
37
+ *
38
+ * Since CONFIG_VDI_BLOCK_SIZE is disabled by default,
39
* cluster-size is not part of the QAPI schema; therefore we have
40
* to parse it before creating the QAPI object. */
41
#if defined(CONFIG_VDI_BLOCK_SIZE)
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
43
44
qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vdi_create_opts, true);
45
46
+ /* Create and open the file (protocol layer) */
47
ret = bdrv_create_file(filename, opts, errp);
48
if (ret < 0) {
49
goto done;
50
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
51
goto done;
52
}
53
54
+ /* Silently round up size */
55
assert(create_options->driver == BLOCKDEV_DRIVER_VDI);
56
create_options->u.vdi.size = ROUND_UP(create_options->u.vdi.size,
57
BDRV_SECTOR_SIZE);
58
59
+ /* Create the vdi image (format layer) */
60
ret = vdi_co_do_create(create_options, block_size, errp);
61
done:
62
QDECREF(qdict);
63
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_vdi = {
64
.bdrv_close = vdi_close,
65
.bdrv_reopen_prepare = vdi_reopen_prepare,
66
.bdrv_child_perm = bdrv_format_default_perms,
67
- .bdrv_co_create_opts = vdi_co_create_opts,
68
.bdrv_co_create = vdi_co_create,
69
+ .bdrv_co_create_opts = vdi_co_create_opts,
70
.bdrv_has_zero_init = bdrv_has_zero_init_1,
71
.bdrv_co_block_status = vdi_co_block_status,
72
.bdrv_make_empty = vdi_make_empty,
73
--
37
--
74
2.13.6
38
2.19.1
75
39
76
40
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Leonid Bloch <lbloch@janustech.com>
2
2
3
Add a new state that specifically demarcates when we begin to permanently
3
The lookup table for power-of-two sizes was added in commit 540b8492618eb
4
demolish a job after it has performed all work. This makes the transition
4
for the purpose of having convenient shortcuts for these sizes in cases
5
explicit in the STM table and highlights conditions under which a job may
5
when the literal number has to be present at compile time, and
6
be demolished.
6
expressions as '(1 * KiB)' can not be used. One such case is the
7
stringification of sizes. Beyond that, it is convenient to use these
8
shortcuts for all power-of-two sizes, even if they don't have to be
9
literal numbers.
7
10
8
Alongside this state, add a new helper command "block_job_decommission",
11
Despite its convenience, this table introduced 55 lines of "dumb" code,
9
which transitions to the NULL state and puts down our implicit reference.
12
the purpose and origin of which are obscure without reading the message
10
This separates instances in the code for "block_job_unref" which merely
13
of the commit which introduced it. This patch fixes that by adding a
11
undo a matching "block_job_ref" with instances intended to initiate the
14
comment to the code itself with a brief explanation for the reasoning
12
full destruction of the object.
15
behind this table. This comment includes the short AWK script that
16
generated the table, so that anyone who's interested could make sure
17
that the values in it are correct (otherwise these values look as if
18
they were typed manually).
13
19
14
This decommission action also sets a number of fields to make sure that
20
Signed-off-by: Leonid Bloch <lbloch@janustech.com>
15
block internals or external users that are holding a reference to a job
16
to see when it "finishes" are convinced that the job object is "done."
17
This is necessary, for instance, to do a block_job_cancel_sync on a
18
created object which will not make any progress.
19
20
Now, all jobs must go through block_job_decommission prior to being
21
freed, giving us start-to-finish state machine coverage for jobs.
22
23
Transitions:
24
Created -> Null: Early failure event before the job is started
25
Concluded -> Null: Standard transition.
26
27
Verbs:
28
None. This should not ever be visible to the monitor.
29
30
+---------+
31
|UNDEFINED|
32
+--+------+
33
|
34
+--v----+
35
+---------+CREATED+------------------+
36
| +--+----+ |
37
| | |
38
| +--v----+ +------+ |
39
+---------+RUNNING<----->PAUSED| |
40
| +--+-+--+ +------+ |
41
| | | |
42
| | +------------------+ |
43
| | | |
44
| +--v--+ +-------+ | |
45
+---------+READY<------->STANDBY| | |
46
| +--+--+ +-------+ | |
47
| | | |
48
+--v-----+ +--v------+ | |
49
|ABORTING+--->CONCLUDED<-------------+ |
50
+--------+ +--+------+ |
51
| |
52
+--v-+ |
53
|NULL<---------------------+
54
+----+
55
56
Signed-off-by: John Snow <jsnow@redhat.com>
57
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
58
---
22
---
59
qapi/block-core.json | 5 ++++-
23
include/qemu/units.h | 18 ++++++++++++++++++
60
blockjob.c | 50 ++++++++++++++++++++++++++++++++------------------
24
1 file changed, 18 insertions(+)
61
2 files changed, 36 insertions(+), 19 deletions(-)
62
25
63
diff --git a/qapi/block-core.json b/qapi/block-core.json
26
diff --git a/include/qemu/units.h b/include/qemu/units.h
64
index XXXXXXX..XXXXXXX 100644
27
index XXXXXXX..XXXXXXX 100644
65
--- a/qapi/block-core.json
28
--- a/include/qemu/units.h
66
+++ b/qapi/block-core.json
29
+++ b/include/qemu/units.h
67
@@ -XXX,XX +XXX,XX @@
30
@@ -XXX,XX +XXX,XX @@
68
# @concluded: The job has finished all work. If manual was set to true, the job
31
#define PiB (INT64_C(1) << 50)
69
# will remain in the query list until it is dismissed.
32
#define EiB (INT64_C(1) << 60)
70
#
33
71
+# @null: The job is in the process of being dismantled. This state should not
34
+/*
72
+# ever be visible externally.
35
+ * The following lookup table is intended to be used when a literal string of
73
+#
36
+ * the number of bytes is required (for example if it needs to be stringified).
74
# Since: 2.12
37
+ * It can also be used for generic shortcuts of power-of-two sizes.
75
##
38
+ * This table is generated using the AWK script below:
76
{ 'enum': 'BlockJobStatus',
39
+ *
77
'data': ['undefined', 'created', 'running', 'paused', 'ready', 'standby',
40
+ * BEGIN {
78
- 'aborting', 'concluded' ] }
41
+ * suffix="KMGTPE";
79
+ 'aborting', 'concluded', 'null' ] }
42
+ * for(i=10; i<64; i++) {
80
43
+ * val=2**i;
81
##
44
+ * s=substr(suffix, int(i/10), 1);
82
# @BlockJobInfo:
45
+ * n=2**(i%10);
83
diff --git a/blockjob.c b/blockjob.c
46
+ * pad=21-int(log(n)/log(10));
84
index XXXXXXX..XXXXXXX 100644
47
+ * printf("#define S_%d%siB %*d\n", n, s, pad, val);
85
--- a/blockjob.c
48
+ * }
86
+++ b/blockjob.c
49
+ * }
87
@@ -XXX,XX +XXX,XX @@ static QemuMutex block_job_mutex;
50
+ */
88
89
/* BlockJob State Transition Table */
90
bool BlockJobSTT[BLOCK_JOB_STATUS__MAX][BLOCK_JOB_STATUS__MAX] = {
91
- /* U, C, R, P, Y, S, X, E */
92
- /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0},
93
- /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 1, 0},
94
- /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1, 1},
95
- /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0},
96
- /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 1},
97
- /* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0},
98
- /* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0, 1},
99
- /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0},
100
+ /* U, C, R, P, Y, S, X, E, N */
101
+ /* U: */ [BLOCK_JOB_STATUS_UNDEFINED] = {0, 1, 0, 0, 0, 0, 0, 0, 0},
102
+ /* C: */ [BLOCK_JOB_STATUS_CREATED] = {0, 0, 1, 0, 0, 0, 1, 0, 1},
103
+ /* R: */ [BLOCK_JOB_STATUS_RUNNING] = {0, 0, 0, 1, 1, 0, 1, 1, 0},
104
+ /* P: */ [BLOCK_JOB_STATUS_PAUSED] = {0, 0, 1, 0, 0, 0, 0, 0, 0},
105
+ /* Y: */ [BLOCK_JOB_STATUS_READY] = {0, 0, 0, 0, 0, 1, 1, 1, 0},
106
+ /* S: */ [BLOCK_JOB_STATUS_STANDBY] = {0, 0, 0, 0, 1, 0, 0, 0, 0},
107
+ /* X: */ [BLOCK_JOB_STATUS_ABORTING] = {0, 0, 0, 0, 0, 0, 0, 1, 0},
108
+ /* E: */ [BLOCK_JOB_STATUS_CONCLUDED] = {0, 0, 0, 0, 0, 0, 0, 0, 1},
109
+ /* N: */ [BLOCK_JOB_STATUS_NULL] = {0, 0, 0, 0, 0, 0, 0, 0, 0},
110
};
111
112
bool BlockJobVerbTable[BLOCK_JOB_VERB__MAX][BLOCK_JOB_STATUS__MAX] = {
113
- /* U, C, R, P, Y, S, X, E */
114
- [BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 0, 0},
115
- [BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0, 0},
116
- [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0},
117
- [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0},
118
- [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0},
119
+ /* U, C, R, P, Y, S, X, E, N */
120
+ [BLOCK_JOB_VERB_CANCEL] = {0, 1, 1, 1, 1, 1, 0, 0, 0},
121
+ [BLOCK_JOB_VERB_PAUSE] = {0, 1, 1, 1, 1, 1, 0, 0, 0},
122
+ [BLOCK_JOB_VERB_RESUME] = {0, 1, 1, 1, 1, 1, 0, 0, 0},
123
+ [BLOCK_JOB_VERB_SET_SPEED] = {0, 1, 1, 1, 1, 1, 0, 0, 0},
124
+ [BLOCK_JOB_VERB_COMPLETE] = {0, 0, 0, 0, 1, 0, 0, 0, 0},
125
};
126
127
static void block_job_state_transition(BlockJob *job, BlockJobStatus s1)
128
@@ -XXX,XX +XXX,XX @@ static void block_job_detach_aio_context(void *opaque);
129
void block_job_unref(BlockJob *job)
130
{
131
if (--job->refcnt == 0) {
132
+ assert(job->status == BLOCK_JOB_STATUS_NULL);
133
BlockDriverState *bs = blk_bs(job->blk);
134
QLIST_REMOVE(job, job_list);
135
bs->job = NULL;
136
@@ -XXX,XX +XXX,XX @@ void block_job_start(BlockJob *job)
137
bdrv_coroutine_enter(blk_bs(job->blk), job->co);
138
}
139
140
+static void block_job_decommission(BlockJob *job)
141
+{
142
+ assert(job);
143
+ job->completed = true;
144
+ job->busy = false;
145
+ job->paused = false;
146
+ job->deferred_to_main_loop = true;
147
+ block_job_state_transition(job, BLOCK_JOB_STATUS_NULL);
148
+ block_job_unref(job);
149
+}
150
+
51
+
151
static void block_job_conclude(BlockJob *job)
52
#define S_1KiB 1024
152
{
53
#define S_2KiB 2048
153
block_job_state_transition(job, BLOCK_JOB_STATUS_CONCLUDED);
54
#define S_4KiB 4096
154
@@ -XXX,XX +XXX,XX @@ static void block_job_completed_single(BlockJob *job)
155
QLIST_REMOVE(job, txn_list);
156
block_job_txn_unref(job->txn);
157
block_job_conclude(job);
158
- block_job_unref(job);
159
+ block_job_decommission(job);
160
}
161
162
static void block_job_cancel_async(BlockJob *job)
163
@@ -XXX,XX +XXX,XX @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
164
165
block_job_set_speed(job, speed, &local_err);
166
if (local_err) {
167
- block_job_unref(job);
168
+ block_job_early_fail(job);
169
error_propagate(errp, local_err);
170
return NULL;
171
}
172
@@ -XXX,XX +XXX,XX @@ void block_job_pause_all(void)
173
174
void block_job_early_fail(BlockJob *job)
175
{
176
- block_job_unref(job);
177
+ assert(job->status == BLOCK_JOB_STATUS_CREATED);
178
+ block_job_decommission(job);
179
}
180
181
void block_job_completed(BlockJob *job, int ret)
182
--
55
--
183
2.13.6
56
2.19.1
184
57
185
58
diff view generated by jsdifflib
Deleted patch
1
The .bdrv_getlength implementation of the crypto block driver asserted
2
that the payload offset isn't after EOF. This is an invalid assertion to
3
make as the image file could be corrupted. Instead, check it and return
4
-EIO if the file is too small for the payload offset.
5
1
6
Zero length images are fine, so trigger -EIO only on offset > len, not
7
on offset >= len as the assertion did before.
8
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
11
---
12
block/crypto.c | 5 ++++-
13
1 file changed, 4 insertions(+), 1 deletion(-)
14
15
diff --git a/block/crypto.c b/block/crypto.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/crypto.c
18
+++ b/block/crypto.c
19
@@ -XXX,XX +XXX,XX @@ static int64_t block_crypto_getlength(BlockDriverState *bs)
20
21
uint64_t offset = qcrypto_block_get_payload_offset(crypto->block);
22
assert(offset < INT64_MAX);
23
- assert(offset < len);
24
+
25
+ if (offset > len) {
26
+ return -EIO;
27
+ }
28
29
len -= offset;
30
31
--
32
2.13.6
33
34
diff view generated by jsdifflib