1
The following changes since commit 16aaacb307ed607b9780c12702c44f0fe52edc7e:
1
The following changes since commit 6972ef1440a9d685482d78672620a7482f2bd09a:
2
2
3
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20200430' into staging (2020-04-30 14:00:36 +0100)
3
Merge tag 'pull-tcg-20230516-3' of https://gitlab.com/rth7680/qemu into staging (2023-05-16 21:30:27 -0700)
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
https://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to eaae29ef89d498d0eac553c77b554f310a47f809:
9
for you to fetch changes up to 75b2591bbce5dc9f3da89f140b7bdc00e92fa8ec:
10
10
11
qemu-storage-daemon: Fix non-string --object properties (2020-04-30 17:51:07 +0200)
11
tested: add test for nested aio_poll() in poll handlers (2023-05-17 18:01:22 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches
15
15
16
- Fix resize (extending) of short overlays
16
- qcow2 spec: Rename "zlib" compression to "deflate"
17
- nvme: introduce PMR support from NVMe 1.4 spec
17
- Honour graph read lock even in the main thread + prerequisite fixes
18
- qemu-storage-daemon: Fix non-string --object properties
18
- aio-posix: do not nest poll handlers (fixes infinite recursion)
19
- Refactor QMP blockdev transactions
20
- iotests/245: Check if 'compress' driver is available
19
21
20
----------------------------------------------------------------
22
----------------------------------------------------------------
21
Alberto Garcia (1):
23
Akihiro Suda (1):
22
qcow2: Add incompatibility note between backing files and raw external data files
24
docs/interop/qcow2.txt: fix description about "zlib" clusters
23
25
24
Andrzej Jakowski (1):
26
Kevin Wolf (9):
25
nvme: introduce PMR support from NVMe 1.4 spec
27
block: Call .bdrv_co_create(_opts) unlocked
28
block/export: Fix null pointer dereference in error path
29
qcow2: Unlock the graph in qcow2_do_open() where necessary
30
qemu-img: Take graph lock more selectively
31
test-bdrv-drain: Take graph lock more selectively
32
test-bdrv-drain: Call bdrv_co_unref() in coroutine context
33
blockjob: Adhere to rate limit even when reentered early
34
graph-lock: Honour read locks even in the main thread
35
iotests/245: Check if 'compress' driver is available
26
36
27
Kevin Wolf (12):
37
Stefan Hajnoczi (2):
28
block: Add flags to BlockDriver.bdrv_co_truncate()
38
aio-posix: do not nest poll handlers
29
block: Add flags to bdrv(_co)_truncate()
39
tested: add test for nested aio_poll() in poll handlers
30
block-backend: Add flags to blk_truncate()
31
qcow2: Support BDRV_REQ_ZERO_WRITE for truncate
32
raw-format: Support BDRV_REQ_ZERO_WRITE for truncate
33
file-posix: Support BDRV_REQ_ZERO_WRITE for truncate
34
block: truncate: Don't make backing file data visible
35
iotests: Filter testfiles out in filter_img_info()
36
iotests: Test committing to short backing file
37
qcow2: Forward ZERO_WRITE flag for full preallocation
38
qom: Factor out user_creatable_add_dict()
39
qemu-storage-daemon: Fix non-string --object properties
40
40
41
Paolo Bonzini (1):
41
Vladimir Sementsov-Ogievskiy (6):
42
qemu-iotests: allow qcow2 external discarded clusters to contain stale data
42
blockdev: refactor transaction to use Transaction API
43
blockdev: transactions: rename some things
44
blockdev: qmp_transaction: refactor loop to classic for
45
blockdev: transaction: refactor handling transaction properties
46
blockdev: use state.bitmap in block-dirty-bitmap-add action
47
blockdev: qmp_transaction: drop extra generic layer
43
48
44
docs/interop/qcow2.txt | 3 +
49
docs/interop/qcow2.txt | 10 +-
45
hw/block/nvme.h | 2 +
50
include/block/block-global-state.h | 8 +-
46
include/block/block.h | 5 +-
51
include/block/block_int-common.h | 4 +-
47
include/block/block_int.h | 10 +-
52
include/block/blockjob_int.h | 14 +-
48
include/block/nvme.h | 172 ++++++++++++++++++++++++++
53
block.c | 1 -
49
include/qom/object_interfaces.h | 16 +++
54
block/commit.c | 7 +-
50
include/sysemu/block-backend.h | 2 +-
55
block/create.c | 1 -
51
block.c | 3 +-
56
block/crypto.c | 25 +-
52
block/block-backend.c | 4 +-
57
block/export/export.c | 6 +-
53
block/commit.c | 4 +-
58
block/graph-lock.c | 10 -
54
block/crypto.c | 7 +-
59
block/mirror.c | 23 +-
55
block/file-posix.c | 6 +-
60
block/parallels.c | 6 +-
56
block/file-win32.c | 2 +-
61
block/qcow.c | 6 +-
57
block/gluster.c | 1 +
62
block/qcow2.c | 43 ++-
58
block/io.c | 43 ++++++-
63
block/qed.c | 6 +-
59
block/iscsi.c | 2 +-
64
block/raw-format.c | 2 +-
60
block/mirror.c | 2 +-
65
block/stream.c | 7 +-
61
block/nfs.c | 3 +-
66
block/vdi.c | 11 +-
62
block/parallels.c | 6 +-
67
block/vhdx.c | 8 +-
63
block/qcow.c | 4 +-
68
block/vmdk.c | 27 +-
64
block/qcow2-cluster.c | 2 +-
69
block/vpc.c | 6 +-
65
block/qcow2-refcount.c | 2 +-
70
blockdev.c | 606 +++++++++++++++----------------------
66
block/qcow2.c | 73 +++++++++--
71
blockjob.c | 22 +-
67
block/qed.c | 3 +-
72
qemu-img.c | 5 +-
68
block/raw-format.c | 6 +-
73
tests/unit/test-bdrv-drain.c | 6 +-
69
block/rbd.c | 1 +
74
tests/unit/test-nested-aio-poll.c | 130 ++++++++
70
block/sheepdog.c | 4 +-
75
util/aio-posix.c | 11 +
71
block/ssh.c | 2 +-
76
tests/qemu-iotests/245 | 7 +-
72
block/vdi.c | 2 +-
77
tests/qemu-iotests/245.out | 9 +-
73
block/vhdx-log.c | 2 +-
78
tests/unit/meson.build | 1 +
74
block/vhdx.c | 6 +-
79
30 files changed, 541 insertions(+), 487 deletions(-)
75
block/vmdk.c | 8 +-
80
create mode 100644 tests/unit/test-nested-aio-poll.c
76
block/vpc.c | 2 +-
77
blockdev.c | 2 +-
78
hw/block/nvme.c | 109 ++++++++++++++++
79
qemu-img.c | 2 +-
80
qemu-io-cmds.c | 2 +-
81
qemu-storage-daemon.c | 4 +-
82
qom/object_interfaces.c | 31 +++++
83
qom/qom-qmp-cmds.c | 24 +---
84
tests/test-block-iothread.c | 9 +-
85
tests/qemu-iotests/iotests.py | 5 +-
86
hw/block/Makefile.objs | 2 +-
87
hw/block/trace-events | 4 +
88
tests/qemu-iotests/244 | 10 +-
89
tests/qemu-iotests/244.out | 9 +-
90
tests/qemu-iotests/274 | 155 +++++++++++++++++++++++
91
tests/qemu-iotests/274.out | 268 ++++++++++++++++++++++++++++++++++++++++
92
tests/qemu-iotests/group | 1 +
93
49 files changed, 951 insertions(+), 96 deletions(-)
94
create mode 100755 tests/qemu-iotests/274
95
create mode 100644 tests/qemu-iotests/274.out
96
97
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
1
2
3
We are going to add more block-graph modifying transaction actions,
4
and block-graph modifying functions are already based on Transaction
5
API.
6
7
Next, we'll need to separately update permissions after several
8
graph-modifying actions, and this would be simple with help of
9
Transaction API.
10
11
So, now let's just transform what we have into new-style transaction
12
actions.
13
14
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
15
Message-Id: <20230510150624.310640-2-vsementsov@yandex-team.ru>
16
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
19
blockdev.c | 309 ++++++++++++++++++++++++++++++-----------------------
20
1 file changed, 178 insertions(+), 131 deletions(-)
21
22
diff --git a/blockdev.c b/blockdev.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/blockdev.c
25
+++ b/blockdev.c
26
@@ -XXX,XX +XXX,XX @@ typedef struct BlkActionState BlkActionState;
27
*/
28
typedef struct BlkActionOps {
29
size_t instance_size;
30
- void (*prepare)(BlkActionState *common, Error **errp);
31
- void (*commit)(BlkActionState *common);
32
- void (*abort)(BlkActionState *common);
33
- void (*clean)(BlkActionState *common);
34
+ void (*action)(BlkActionState *common, Transaction *tran, Error **errp);
35
} BlkActionOps;
36
37
/**
38
@@ -XXX,XX +XXX,XX @@ typedef struct InternalSnapshotState {
39
bool created;
40
} InternalSnapshotState;
41
42
+static void internal_snapshot_abort(void *opaque);
43
+static void internal_snapshot_clean(void *opaque);
44
+TransactionActionDrv internal_snapshot_drv = {
45
+ .abort = internal_snapshot_abort,
46
+ .clean = internal_snapshot_clean,
47
+};
48
49
static int action_check_completion_mode(BlkActionState *s, Error **errp)
50
{
51
@@ -XXX,XX +XXX,XX @@ static int action_check_completion_mode(BlkActionState *s, Error **errp)
52
return 0;
53
}
54
55
-static void internal_snapshot_prepare(BlkActionState *common,
56
- Error **errp)
57
+static void internal_snapshot_action(BlkActionState *common,
58
+ Transaction *tran, Error **errp)
59
{
60
Error *local_err = NULL;
61
const char *device;
62
@@ -XXX,XX +XXX,XX @@ static void internal_snapshot_prepare(BlkActionState *common,
63
internal = common->action->u.blockdev_snapshot_internal_sync.data;
64
state = DO_UPCAST(InternalSnapshotState, common, common);
65
66
+ tran_add(tran, &internal_snapshot_drv, state);
67
+
68
/* 1. parse input */
69
device = internal->device;
70
name = internal->name;
71
@@ -XXX,XX +XXX,XX @@ out:
72
aio_context_release(aio_context);
73
}
74
75
-static void internal_snapshot_abort(BlkActionState *common)
76
+static void internal_snapshot_abort(void *opaque)
77
{
78
- InternalSnapshotState *state =
79
- DO_UPCAST(InternalSnapshotState, common, common);
80
+ InternalSnapshotState *state = opaque;
81
BlockDriverState *bs = state->bs;
82
QEMUSnapshotInfo *sn = &state->sn;
83
AioContext *aio_context;
84
@@ -XXX,XX +XXX,XX @@ static void internal_snapshot_abort(BlkActionState *common)
85
aio_context_release(aio_context);
86
}
87
88
-static void internal_snapshot_clean(BlkActionState *common)
89
+static void internal_snapshot_clean(void *opaque)
90
{
91
- InternalSnapshotState *state = DO_UPCAST(InternalSnapshotState,
92
- common, common);
93
+ g_autofree InternalSnapshotState *state = opaque;
94
AioContext *aio_context;
95
96
if (!state->bs) {
97
@@ -XXX,XX +XXX,XX @@ typedef struct ExternalSnapshotState {
98
bool overlay_appended;
99
} ExternalSnapshotState;
100
101
-static void external_snapshot_prepare(BlkActionState *common,
102
- Error **errp)
103
+static void external_snapshot_commit(void *opaque);
104
+static void external_snapshot_abort(void *opaque);
105
+static void external_snapshot_clean(void *opaque);
106
+TransactionActionDrv external_snapshot_drv = {
107
+ .commit = external_snapshot_commit,
108
+ .abort = external_snapshot_abort,
109
+ .clean = external_snapshot_clean,
110
+};
111
+
112
+static void external_snapshot_action(BlkActionState *common, Transaction *tran,
113
+ Error **errp)
114
{
115
int ret;
116
int flags = 0;
117
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
118
AioContext *aio_context;
119
uint64_t perm, shared;
120
121
+ tran_add(tran, &external_snapshot_drv, state);
122
+
123
/* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
124
* purpose but a different set of parameters */
125
switch (action->type) {
126
@@ -XXX,XX +XXX,XX @@ out:
127
aio_context_release(aio_context);
128
}
129
130
-static void external_snapshot_commit(BlkActionState *common)
131
+static void external_snapshot_commit(void *opaque)
132
{
133
- ExternalSnapshotState *state =
134
- DO_UPCAST(ExternalSnapshotState, common, common);
135
+ ExternalSnapshotState *state = opaque;
136
AioContext *aio_context;
137
138
aio_context = bdrv_get_aio_context(state->old_bs);
139
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_commit(BlkActionState *common)
140
aio_context_release(aio_context);
141
}
142
143
-static void external_snapshot_abort(BlkActionState *common)
144
+static void external_snapshot_abort(void *opaque)
145
{
146
- ExternalSnapshotState *state =
147
- DO_UPCAST(ExternalSnapshotState, common, common);
148
+ ExternalSnapshotState *state = opaque;
149
if (state->new_bs) {
150
if (state->overlay_appended) {
151
AioContext *aio_context;
152
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_abort(BlkActionState *common)
153
}
154
}
155
156
-static void external_snapshot_clean(BlkActionState *common)
157
+static void external_snapshot_clean(void *opaque)
158
{
159
- ExternalSnapshotState *state =
160
- DO_UPCAST(ExternalSnapshotState, common, common);
161
+ g_autofree ExternalSnapshotState *state = opaque;
162
AioContext *aio_context;
163
164
if (!state->old_bs) {
165
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_backup_common(BackupCommon *backup,
166
AioContext *aio_context,
167
JobTxn *txn, Error **errp);
168
169
-static void drive_backup_prepare(BlkActionState *common, Error **errp)
170
+static void drive_backup_commit(void *opaque);
171
+static void drive_backup_abort(void *opaque);
172
+static void drive_backup_clean(void *opaque);
173
+TransactionActionDrv drive_backup_drv = {
174
+ .commit = drive_backup_commit,
175
+ .abort = drive_backup_abort,
176
+ .clean = drive_backup_clean,
177
+};
178
+
179
+static void drive_backup_action(BlkActionState *common, Transaction *tran,
180
+ Error **errp)
181
{
182
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
183
DriveBackup *backup;
184
@@ -XXX,XX +XXX,XX @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
185
bool set_backing_hd = false;
186
int ret;
187
188
+ tran_add(tran, &drive_backup_drv, state);
189
+
190
assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
191
backup = common->action->u.drive_backup.data;
192
193
@@ -XXX,XX +XXX,XX @@ out:
194
aio_context_release(aio_context);
195
}
196
197
-static void drive_backup_commit(BlkActionState *common)
198
+static void drive_backup_commit(void *opaque)
199
{
200
- DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
201
+ DriveBackupState *state = opaque;
202
AioContext *aio_context;
203
204
aio_context = bdrv_get_aio_context(state->bs);
205
@@ -XXX,XX +XXX,XX @@ static void drive_backup_commit(BlkActionState *common)
206
aio_context_release(aio_context);
207
}
208
209
-static void drive_backup_abort(BlkActionState *common)
210
+static void drive_backup_abort(void *opaque)
211
{
212
- DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
213
+ DriveBackupState *state = opaque;
214
215
if (state->job) {
216
job_cancel_sync(&state->job->job, true);
217
}
218
}
219
220
-static void drive_backup_clean(BlkActionState *common)
221
+static void drive_backup_clean(void *opaque)
222
{
223
- DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
224
+ g_autofree DriveBackupState *state = opaque;
225
AioContext *aio_context;
226
227
if (!state->bs) {
228
@@ -XXX,XX +XXX,XX @@ typedef struct BlockdevBackupState {
229
BlockJob *job;
230
} BlockdevBackupState;
231
232
-static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
233
+static void blockdev_backup_commit(void *opaque);
234
+static void blockdev_backup_abort(void *opaque);
235
+static void blockdev_backup_clean(void *opaque);
236
+TransactionActionDrv blockdev_backup_drv = {
237
+ .commit = blockdev_backup_commit,
238
+ .abort = blockdev_backup_abort,
239
+ .clean = blockdev_backup_clean,
240
+};
241
+
242
+static void blockdev_backup_action(BlkActionState *common, Transaction *tran,
243
+ Error **errp)
244
{
245
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
246
BlockdevBackup *backup;
247
@@ -XXX,XX +XXX,XX @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
248
AioContext *old_context;
249
int ret;
250
251
+ tran_add(tran, &blockdev_backup_drv, state);
252
+
253
assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
254
backup = common->action->u.blockdev_backup.data;
255
256
@@ -XXX,XX +XXX,XX @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
257
aio_context_release(aio_context);
258
}
259
260
-static void blockdev_backup_commit(BlkActionState *common)
261
+static void blockdev_backup_commit(void *opaque)
262
{
263
- BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
264
+ BlockdevBackupState *state = opaque;
265
AioContext *aio_context;
266
267
aio_context = bdrv_get_aio_context(state->bs);
268
@@ -XXX,XX +XXX,XX @@ static void blockdev_backup_commit(BlkActionState *common)
269
aio_context_release(aio_context);
270
}
271
272
-static void blockdev_backup_abort(BlkActionState *common)
273
+static void blockdev_backup_abort(void *opaque)
274
{
275
- BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
276
+ BlockdevBackupState *state = opaque;
277
278
if (state->job) {
279
job_cancel_sync(&state->job->job, true);
280
}
281
}
282
283
-static void blockdev_backup_clean(BlkActionState *common)
284
+static void blockdev_backup_clean(void *opaque)
285
{
286
- BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
287
+ g_autofree BlockdevBackupState *state = opaque;
288
AioContext *aio_context;
289
290
if (!state->bs) {
291
@@ -XXX,XX +XXX,XX @@ typedef struct BlockDirtyBitmapState {
292
bool was_enabled;
293
} BlockDirtyBitmapState;
294
295
-static void block_dirty_bitmap_add_prepare(BlkActionState *common,
296
- Error **errp)
297
+static void block_dirty_bitmap_add_abort(void *opaque);
298
+TransactionActionDrv block_dirty_bitmap_add_drv = {
299
+ .abort = block_dirty_bitmap_add_abort,
300
+ .clean = g_free,
301
+};
302
+
303
+static void block_dirty_bitmap_add_action(BlkActionState *common,
304
+ Transaction *tran, Error **errp)
305
{
306
Error *local_err = NULL;
307
BlockDirtyBitmapAdd *action;
308
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
309
common, common);
310
311
+ tran_add(tran, &block_dirty_bitmap_add_drv, state);
312
+
313
if (action_check_completion_mode(common, errp) < 0) {
314
return;
315
}
316
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common,
317
}
318
}
319
320
-static void block_dirty_bitmap_add_abort(BlkActionState *common)
321
+static void block_dirty_bitmap_add_abort(void *opaque)
322
{
323
BlockDirtyBitmapAdd *action;
324
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
325
- common, common);
326
+ BlockDirtyBitmapState *state = opaque;
327
328
- action = common->action->u.block_dirty_bitmap_add.data;
329
+ action = state->common.action->u.block_dirty_bitmap_add.data;
330
/* Should not be able to fail: IF the bitmap was added via .prepare(),
331
* then the node reference and bitmap name must have been valid.
332
*/
333
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_add_abort(BlkActionState *common)
334
}
335
}
336
337
-static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
338
- Error **errp)
339
+static void block_dirty_bitmap_restore(void *opaque);
340
+static void block_dirty_bitmap_free_backup(void *opaque);
341
+TransactionActionDrv block_dirty_bitmap_clear_drv = {
342
+ .abort = block_dirty_bitmap_restore,
343
+ .commit = block_dirty_bitmap_free_backup,
344
+ .clean = g_free,
345
+};
346
+
347
+static void block_dirty_bitmap_clear_action(BlkActionState *common,
348
+ Transaction *tran, Error **errp)
349
{
350
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
351
common, common);
352
BlockDirtyBitmap *action;
353
354
+ tran_add(tran, &block_dirty_bitmap_clear_drv, state);
355
+
356
if (action_check_completion_mode(common, errp) < 0) {
357
return;
358
}
359
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
360
bdrv_clear_dirty_bitmap(state->bitmap, &state->backup);
361
}
362
363
-static void block_dirty_bitmap_restore(BlkActionState *common)
364
+static void block_dirty_bitmap_restore(void *opaque)
365
{
366
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
367
- common, common);
368
+ BlockDirtyBitmapState *state = opaque;
369
370
if (state->backup) {
371
bdrv_restore_dirty_bitmap(state->bitmap, state->backup);
372
}
373
}
374
375
-static void block_dirty_bitmap_free_backup(BlkActionState *common)
376
+static void block_dirty_bitmap_free_backup(void *opaque)
377
{
378
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
379
- common, common);
380
+ BlockDirtyBitmapState *state = opaque;
381
382
hbitmap_free(state->backup);
383
}
384
385
-static void block_dirty_bitmap_enable_prepare(BlkActionState *common,
386
- Error **errp)
387
+static void block_dirty_bitmap_enable_abort(void *opaque);
388
+TransactionActionDrv block_dirty_bitmap_enable_drv = {
389
+ .abort = block_dirty_bitmap_enable_abort,
390
+ .clean = g_free,
391
+};
392
+
393
+static void block_dirty_bitmap_enable_action(BlkActionState *common,
394
+ Transaction *tran, Error **errp)
395
{
396
BlockDirtyBitmap *action;
397
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
398
common, common);
399
400
+ tran_add(tran, &block_dirty_bitmap_enable_drv, state);
401
+
402
if (action_check_completion_mode(common, errp) < 0) {
403
return;
404
}
405
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_enable_prepare(BlkActionState *common,
406
bdrv_enable_dirty_bitmap(state->bitmap);
407
}
408
409
-static void block_dirty_bitmap_enable_abort(BlkActionState *common)
410
+static void block_dirty_bitmap_enable_abort(void *opaque)
411
{
412
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
413
- common, common);
414
+ BlockDirtyBitmapState *state = opaque;
415
416
if (!state->was_enabled) {
417
bdrv_disable_dirty_bitmap(state->bitmap);
418
}
419
}
420
421
-static void block_dirty_bitmap_disable_prepare(BlkActionState *common,
422
- Error **errp)
423
+static void block_dirty_bitmap_disable_abort(void *opaque);
424
+TransactionActionDrv block_dirty_bitmap_disable_drv = {
425
+ .abort = block_dirty_bitmap_disable_abort,
426
+ .clean = g_free,
427
+};
428
+
429
+static void block_dirty_bitmap_disable_action(BlkActionState *common,
430
+ Transaction *tran, Error **errp)
431
{
432
BlockDirtyBitmap *action;
433
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
434
common, common);
435
436
+ tran_add(tran, &block_dirty_bitmap_disable_drv, state);
437
+
438
if (action_check_completion_mode(common, errp) < 0) {
439
return;
440
}
441
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_disable_prepare(BlkActionState *common,
442
bdrv_disable_dirty_bitmap(state->bitmap);
443
}
444
445
-static void block_dirty_bitmap_disable_abort(BlkActionState *common)
446
+static void block_dirty_bitmap_disable_abort(void *opaque)
447
{
448
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
449
- common, common);
450
+ BlockDirtyBitmapState *state = opaque;
451
452
if (state->was_enabled) {
453
bdrv_enable_dirty_bitmap(state->bitmap);
454
}
455
}
456
457
-static void block_dirty_bitmap_merge_prepare(BlkActionState *common,
458
- Error **errp)
459
+TransactionActionDrv block_dirty_bitmap_merge_drv = {
460
+ .commit = block_dirty_bitmap_free_backup,
461
+ .abort = block_dirty_bitmap_restore,
462
+ .clean = g_free,
463
+};
464
+
465
+static void block_dirty_bitmap_merge_action(BlkActionState *common,
466
+ Transaction *tran, Error **errp)
467
{
468
BlockDirtyBitmapMerge *action;
469
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
470
common, common);
471
472
+ tran_add(tran, &block_dirty_bitmap_merge_drv, state);
473
+
474
if (action_check_completion_mode(common, errp) < 0) {
475
return;
476
}
477
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_merge_prepare(BlkActionState *common,
478
errp);
479
}
480
481
-static void block_dirty_bitmap_remove_prepare(BlkActionState *common,
482
- Error **errp)
483
+static void block_dirty_bitmap_remove_commit(void *opaque);
484
+static void block_dirty_bitmap_remove_abort(void *opaque);
485
+TransactionActionDrv block_dirty_bitmap_remove_drv = {
486
+ .commit = block_dirty_bitmap_remove_commit,
487
+ .abort = block_dirty_bitmap_remove_abort,
488
+ .clean = g_free,
489
+};
490
+
491
+static void block_dirty_bitmap_remove_action(BlkActionState *common,
492
+ Transaction *tran, Error **errp)
493
{
494
BlockDirtyBitmap *action;
495
BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
496
common, common);
497
498
+ tran_add(tran, &block_dirty_bitmap_remove_drv, state);
499
+
500
if (action_check_completion_mode(common, errp) < 0) {
501
return;
502
}
503
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_remove_prepare(BlkActionState *common,
504
}
505
}
506
507
-static void block_dirty_bitmap_remove_abort(BlkActionState *common)
508
+static void block_dirty_bitmap_remove_abort(void *opaque)
509
{
510
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
511
- common, common);
512
+ BlockDirtyBitmapState *state = opaque;
513
514
if (state->bitmap) {
515
bdrv_dirty_bitmap_skip_store(state->bitmap, false);
516
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_remove_abort(BlkActionState *common)
517
}
518
}
519
520
-static void block_dirty_bitmap_remove_commit(BlkActionState *common)
521
+static void block_dirty_bitmap_remove_commit(void *opaque)
522
{
523
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
524
- common, common);
525
+ BlockDirtyBitmapState *state = opaque;
526
527
bdrv_dirty_bitmap_set_busy(state->bitmap, false);
528
bdrv_release_dirty_bitmap(state->bitmap);
529
}
530
531
-static void abort_prepare(BlkActionState *common, Error **errp)
532
+static void abort_commit(void *opaque);
533
+TransactionActionDrv abort_drv = {
534
+ .commit = abort_commit,
535
+ .clean = g_free,
536
+};
537
+
538
+static void abort_action(BlkActionState *common, Transaction *tran,
539
+ Error **errp)
540
{
541
+ tran_add(tran, &abort_drv, common);
542
error_setg(errp, "Transaction aborted using Abort action");
543
}
544
545
-static void abort_commit(BlkActionState *common)
546
+static void abort_commit(void *opaque)
547
{
548
g_assert_not_reached(); /* this action never succeeds */
549
}
550
@@ -XXX,XX +XXX,XX @@ static void abort_commit(BlkActionState *common)
551
static const BlkActionOps actions[] = {
552
[TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT] = {
553
.instance_size = sizeof(ExternalSnapshotState),
554
- .prepare = external_snapshot_prepare,
555
- .commit = external_snapshot_commit,
556
- .abort = external_snapshot_abort,
557
- .clean = external_snapshot_clean,
558
+ .action = external_snapshot_action,
559
},
560
[TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC] = {
561
.instance_size = sizeof(ExternalSnapshotState),
562
- .prepare = external_snapshot_prepare,
563
- .commit = external_snapshot_commit,
564
- .abort = external_snapshot_abort,
565
- .clean = external_snapshot_clean,
566
+ .action = external_snapshot_action,
567
},
568
[TRANSACTION_ACTION_KIND_DRIVE_BACKUP] = {
569
.instance_size = sizeof(DriveBackupState),
570
- .prepare = drive_backup_prepare,
571
- .commit = drive_backup_commit,
572
- .abort = drive_backup_abort,
573
- .clean = drive_backup_clean,
574
+ .action = drive_backup_action,
575
},
576
[TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP] = {
577
.instance_size = sizeof(BlockdevBackupState),
578
- .prepare = blockdev_backup_prepare,
579
- .commit = blockdev_backup_commit,
580
- .abort = blockdev_backup_abort,
581
- .clean = blockdev_backup_clean,
582
+ .action = blockdev_backup_action,
583
},
584
[TRANSACTION_ACTION_KIND_ABORT] = {
585
.instance_size = sizeof(BlkActionState),
586
- .prepare = abort_prepare,
587
- .commit = abort_commit,
588
+ .action = abort_action,
589
},
590
[TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC] = {
591
.instance_size = sizeof(InternalSnapshotState),
592
- .prepare = internal_snapshot_prepare,
593
- .abort = internal_snapshot_abort,
594
- .clean = internal_snapshot_clean,
595
+ .action = internal_snapshot_action,
596
},
597
[TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ADD] = {
598
.instance_size = sizeof(BlockDirtyBitmapState),
599
- .prepare = block_dirty_bitmap_add_prepare,
600
- .abort = block_dirty_bitmap_add_abort,
601
+ .action = block_dirty_bitmap_add_action,
602
},
603
[TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_CLEAR] = {
604
.instance_size = sizeof(BlockDirtyBitmapState),
605
- .prepare = block_dirty_bitmap_clear_prepare,
606
- .commit = block_dirty_bitmap_free_backup,
607
- .abort = block_dirty_bitmap_restore,
608
+ .action = block_dirty_bitmap_clear_action,
609
},
610
[TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ENABLE] = {
611
.instance_size = sizeof(BlockDirtyBitmapState),
612
- .prepare = block_dirty_bitmap_enable_prepare,
613
- .abort = block_dirty_bitmap_enable_abort,
614
+ .action = block_dirty_bitmap_enable_action,
615
},
616
[TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_DISABLE] = {
617
.instance_size = sizeof(BlockDirtyBitmapState),
618
- .prepare = block_dirty_bitmap_disable_prepare,
619
- .abort = block_dirty_bitmap_disable_abort,
620
+ .action = block_dirty_bitmap_disable_action,
621
},
622
[TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_MERGE] = {
623
.instance_size = sizeof(BlockDirtyBitmapState),
624
- .prepare = block_dirty_bitmap_merge_prepare,
625
- .commit = block_dirty_bitmap_free_backup,
626
- .abort = block_dirty_bitmap_restore,
627
+ .action = block_dirty_bitmap_merge_action,
628
},
629
[TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_REMOVE] = {
630
.instance_size = sizeof(BlockDirtyBitmapState),
631
- .prepare = block_dirty_bitmap_remove_prepare,
632
- .commit = block_dirty_bitmap_remove_commit,
633
- .abort = block_dirty_bitmap_remove_abort,
634
+ .action = block_dirty_bitmap_remove_action,
635
},
636
/* Where are transactions for MIRROR, COMMIT and STREAM?
637
* Although these blockjobs use transaction callbacks like the backup job,
638
@@ -XXX,XX +XXX,XX @@ void qmp_transaction(TransactionActionList *dev_list,
639
TransactionActionList *dev_entry = dev_list;
640
bool has_props = !!props;
641
JobTxn *block_job_txn = NULL;
642
- BlkActionState *state, *next;
643
Error *local_err = NULL;
644
+ Transaction *tran = tran_new();
645
646
GLOBAL_STATE_CODE();
647
648
- QTAILQ_HEAD(, BlkActionState) snap_bdrv_states;
649
- QTAILQ_INIT(&snap_bdrv_states);
650
-
651
/* Does this transaction get canceled as a group on failure?
652
* If not, we don't really need to make a JobTxn.
653
*/
654
@@ -XXX,XX +XXX,XX @@ void qmp_transaction(TransactionActionList *dev_list,
655
while (NULL != dev_entry) {
656
TransactionAction *dev_info = NULL;
657
const BlkActionOps *ops;
658
+ BlkActionState *state;
659
660
dev_info = dev_entry->value;
661
dev_entry = dev_entry->next;
662
@@ -XXX,XX +XXX,XX @@ void qmp_transaction(TransactionActionList *dev_list,
663
state->action = dev_info;
664
state->block_job_txn = block_job_txn;
665
state->txn_props = props;
666
- QTAILQ_INSERT_TAIL(&snap_bdrv_states, state, entry);
667
668
- state->ops->prepare(state, &local_err);
669
+ state->ops->action(state, tran, &local_err);
670
if (local_err) {
671
error_propagate(errp, local_err);
672
goto delete_and_fail;
673
}
674
}
675
676
- QTAILQ_FOREACH(state, &snap_bdrv_states, entry) {
677
- if (state->ops->commit) {
678
- state->ops->commit(state);
679
- }
680
- }
681
+ tran_commit(tran);
682
683
/* success */
684
goto exit;
685
686
delete_and_fail:
687
/* failure, and it is all-or-none; roll back all operations */
688
- QTAILQ_FOREACH_REVERSE(state, &snap_bdrv_states, entry) {
689
- if (state->ops->abort) {
690
- state->ops->abort(state);
691
- }
692
- }
693
+ tran_abort(tran);
694
exit:
695
- QTAILQ_FOREACH_SAFE(state, &snap_bdrv_states, entry, next) {
696
- if (state->ops->clean) {
697
- state->ops->clean(state);
698
- }
699
- g_free(state);
700
- }
701
if (!has_props) {
702
qapi_free_TransactionProperties(props);
703
}
704
--
705
2.40.1
diff view generated by jsdifflib
1
This adds a new BdrvRequestFlags parameter to the .bdrv_co_truncate()
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
2
driver callbacks, and a supported_truncate_flags field in
3
BlockDriverState that allows drivers to advertise support for request
4
flags in the context of truncate.
5
2
6
For now, we always pass 0 and no drivers declare support for any flag.
3
Look at qmp_transaction(): dev_list is not obvious name for list of
4
actions. Let's look at qapi spec, this argument is "actions". Let's
5
follow the common practice of using same argument names in qapi scheme
6
and code.
7
7
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
To be honest, rename props to properties for same reason.
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
Next, we have to rename global map of actions, to not conflict with new
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
name for function argument.
12
Message-Id: <20200424125448.63318-2-kwolf@redhat.com>
12
13
Rename also dev_entry loop variable accordingly to new name of the
14
list.
15
16
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
17
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
18
Message-Id: <20230510150624.310640-3-vsementsov@yandex-team.ru>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
20
---
15
include/block/block_int.h | 10 +++++++++-
21
blockdev.c | 30 +++++++++++++++---------------
16
block/crypto.c | 3 ++-
22
1 file changed, 15 insertions(+), 15 deletions(-)
17
block/file-posix.c | 2 +-
18
block/file-win32.c | 2 +-
19
block/gluster.c | 1 +
20
block/io.c | 8 +++++++-
21
block/iscsi.c | 2 +-
22
block/nfs.c | 3 ++-
23
block/qcow2.c | 2 +-
24
block/qed.c | 1 +
25
block/raw-format.c | 2 +-
26
block/rbd.c | 1 +
27
block/sheepdog.c | 4 ++--
28
block/ssh.c | 2 +-
29
tests/test-block-iothread.c | 3 ++-
30
15 files changed, 33 insertions(+), 13 deletions(-)
31
23
32
diff --git a/include/block/block_int.h b/include/block/block_int.h
24
diff --git a/blockdev.c b/blockdev.c
33
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
34
--- a/include/block/block_int.h
26
--- a/blockdev.c
35
+++ b/include/block/block_int.h
27
+++ b/blockdev.c
36
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
28
@@ -XXX,XX +XXX,XX @@ static void abort_commit(void *opaque)
29
g_assert_not_reached(); /* this action never succeeds */
30
}
31
32
-static const BlkActionOps actions[] = {
33
+static const BlkActionOps actions_map[] = {
34
[TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT] = {
35
.instance_size = sizeof(ExternalSnapshotState),
36
.action = external_snapshot_action,
37
@@ -XXX,XX +XXX,XX @@ static TransactionProperties *get_transaction_properties(
38
*
39
* Always run under BQL.
40
*/
41
-void qmp_transaction(TransactionActionList *dev_list,
42
- struct TransactionProperties *props,
43
+void qmp_transaction(TransactionActionList *actions,
44
+ struct TransactionProperties *properties,
45
Error **errp)
46
{
47
- TransactionActionList *dev_entry = dev_list;
48
- bool has_props = !!props;
49
+ TransactionActionList *act = actions;
50
+ bool has_properties = !!properties;
51
JobTxn *block_job_txn = NULL;
52
Error *local_err = NULL;
53
Transaction *tran = tran_new();
54
@@ -XXX,XX +XXX,XX @@ void qmp_transaction(TransactionActionList *dev_list,
55
/* Does this transaction get canceled as a group on failure?
56
* If not, we don't really need to make a JobTxn.
37
*/
57
*/
38
int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset,
58
- props = get_transaction_properties(props);
39
bool exact, PreallocMode prealloc,
59
- if (props->completion_mode != ACTION_COMPLETION_MODE_INDIVIDUAL) {
40
- Error **errp);
60
+ properties = get_transaction_properties(properties);
41
+ BdrvRequestFlags flags, Error **errp);
61
+ if (properties->completion_mode != ACTION_COMPLETION_MODE_INDIVIDUAL) {
42
62
block_job_txn = job_txn_new();
43
int64_t (*bdrv_getlength)(BlockDriverState *bs);
44
bool has_variable_length;
45
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
46
/* Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA,
47
* BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */
48
unsigned int supported_zero_flags;
49
+ /*
50
+ * Flags honoured during truncate (so far: BDRV_REQ_ZERO_WRITE).
51
+ *
52
+ * If BDRV_REQ_ZERO_WRITE is given, the truncate operation must make sure
53
+ * that any added space reads as all zeros. If this can't be guaranteed,
54
+ * the operation must fail.
55
+ */
56
+ unsigned int supported_truncate_flags;
57
58
/* the following member gives a name to every node on the bs graph. */
59
char node_name[32];
60
diff --git a/block/crypto.c b/block/crypto.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/block/crypto.c
63
+++ b/block/crypto.c
64
@@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
65
66
static int coroutine_fn
67
block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
68
- PreallocMode prealloc, Error **errp)
69
+ PreallocMode prealloc, BdrvRequestFlags flags,
70
+ Error **errp)
71
{
72
BlockCrypto *crypto = bs->opaque;
73
uint64_t payload_offset =
74
diff --git a/block/file-posix.c b/block/file-posix.c
75
index XXXXXXX..XXXXXXX 100644
76
--- a/block/file-posix.c
77
+++ b/block/file-posix.c
78
@@ -XXX,XX +XXX,XX @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset,
79
80
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
81
bool exact, PreallocMode prealloc,
82
- Error **errp)
83
+ BdrvRequestFlags flags, Error **errp)
84
{
85
BDRVRawState *s = bs->opaque;
86
struct stat st;
87
diff --git a/block/file-win32.c b/block/file-win32.c
88
index XXXXXXX..XXXXXXX 100644
89
--- a/block/file-win32.c
90
+++ b/block/file-win32.c
91
@@ -XXX,XX +XXX,XX @@ static void raw_close(BlockDriverState *bs)
92
93
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
94
bool exact, PreallocMode prealloc,
95
- Error **errp)
96
+ BdrvRequestFlags flags, Error **errp)
97
{
98
BDRVRawState *s = bs->opaque;
99
LONG low, high;
100
diff --git a/block/gluster.c b/block/gluster.c
101
index XXXXXXX..XXXXXXX 100644
102
--- a/block/gluster.c
103
+++ b/block/gluster.c
104
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
105
int64_t offset,
106
bool exact,
107
PreallocMode prealloc,
108
+ BdrvRequestFlags flags,
109
Error **errp)
110
{
111
BDRVGlusterState *s = bs->opaque;
112
diff --git a/block/io.c b/block/io.c
113
index XXXXXXX..XXXXXXX 100644
114
--- a/block/io.c
115
+++ b/block/io.c
116
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
117
BlockDriverState *bs = child->bs;
118
BlockDriver *drv = bs->drv;
119
BdrvTrackedRequest req;
120
+ BdrvRequestFlags flags = 0;
121
int64_t old_size, new_bytes;
122
int ret;
123
124
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
125
}
63
}
126
64
127
if (drv->bdrv_co_truncate) {
65
@@ -XXX,XX +XXX,XX @@ void qmp_transaction(TransactionActionList *dev_list,
128
- ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, errp);
66
bdrv_drain_all();
129
+ if (flags & ~bs->supported_truncate_flags) {
67
130
+ error_setg(errp, "Block driver does not support requested flags");
68
/* We don't do anything in this loop that commits us to the operations */
131
+ ret = -ENOTSUP;
69
- while (NULL != dev_entry) {
132
+ goto out;
70
+ while (NULL != act) {
133
+ }
71
TransactionAction *dev_info = NULL;
134
+ ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
72
const BlkActionOps *ops;
135
} else if (bs->file && drv->is_filter) {
73
BlkActionState *state;
136
ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
74
137
} else {
75
- dev_info = dev_entry->value;
138
diff --git a/block/iscsi.c b/block/iscsi.c
76
- dev_entry = dev_entry->next;
139
index XXXXXXX..XXXXXXX 100644
77
+ dev_info = act->value;
140
--- a/block/iscsi.c
78
+ act = act->next;
141
+++ b/block/iscsi.c
79
142
@@ -XXX,XX +XXX,XX @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
80
- assert(dev_info->type < ARRAY_SIZE(actions));
143
81
+ assert(dev_info->type < ARRAY_SIZE(actions_map));
144
static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
82
145
bool exact, PreallocMode prealloc,
83
- ops = &actions[dev_info->type];
146
- Error **errp)
84
+ ops = &actions_map[dev_info->type];
147
+ BdrvRequestFlags flags, Error **errp)
85
assert(ops->instance_size > 0);
148
{
86
149
IscsiLun *iscsilun = bs->opaque;
87
state = g_malloc0(ops->instance_size);
150
int64_t cur_length;
88
state->ops = ops;
151
diff --git a/block/nfs.c b/block/nfs.c
89
state->action = dev_info;
152
index XXXXXXX..XXXXXXX 100644
90
state->block_job_txn = block_job_txn;
153
--- a/block/nfs.c
91
- state->txn_props = props;
154
+++ b/block/nfs.c
92
+ state->txn_props = properties;
155
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
93
156
94
state->ops->action(state, tran, &local_err);
157
static int coroutine_fn
95
if (local_err) {
158
nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
96
@@ -XXX,XX +XXX,XX @@ delete_and_fail:
159
- PreallocMode prealloc, Error **errp)
97
/* failure, and it is all-or-none; roll back all operations */
160
+ PreallocMode prealloc, BdrvRequestFlags flags,
98
tran_abort(tran);
161
+ Error **errp)
99
exit:
162
{
100
- if (!has_props) {
163
NFSClient *client = bs->opaque;
101
- qapi_free_TransactionProperties(props);
164
int ret;
102
+ if (!has_properties) {
165
diff --git a/block/qcow2.c b/block/qcow2.c
103
+ qapi_free_TransactionProperties(properties);
166
index XXXXXXX..XXXXXXX 100644
104
}
167
--- a/block/qcow2.c
105
job_txn_unref(block_job_txn);
168
+++ b/block/qcow2.c
169
@@ -XXX,XX +XXX,XX @@ fail:
170
171
static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
172
bool exact, PreallocMode prealloc,
173
- Error **errp)
174
+ BdrvRequestFlags flags, Error **errp)
175
{
176
BDRVQcow2State *s = bs->opaque;
177
uint64_t old_length;
178
diff --git a/block/qed.c b/block/qed.c
179
index XXXXXXX..XXXXXXX 100644
180
--- a/block/qed.c
181
+++ b/block/qed.c
182
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs,
183
int64_t offset,
184
bool exact,
185
PreallocMode prealloc,
186
+ BdrvRequestFlags flags,
187
Error **errp)
188
{
189
BDRVQEDState *s = bs->opaque;
190
diff --git a/block/raw-format.c b/block/raw-format.c
191
index XXXXXXX..XXXXXXX 100644
192
--- a/block/raw-format.c
193
+++ b/block/raw-format.c
194
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
195
196
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
197
bool exact, PreallocMode prealloc,
198
- Error **errp)
199
+ BdrvRequestFlags flags, Error **errp)
200
{
201
BDRVRawState *s = bs->opaque;
202
203
diff --git a/block/rbd.c b/block/rbd.c
204
index XXXXXXX..XXXXXXX 100644
205
--- a/block/rbd.c
206
+++ b/block/rbd.c
207
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs,
208
int64_t offset,
209
bool exact,
210
PreallocMode prealloc,
211
+ BdrvRequestFlags flags,
212
Error **errp)
213
{
214
int r;
215
diff --git a/block/sheepdog.c b/block/sheepdog.c
216
index XXXXXXX..XXXXXXX 100644
217
--- a/block/sheepdog.c
218
+++ b/block/sheepdog.c
219
@@ -XXX,XX +XXX,XX @@ static int64_t sd_getlength(BlockDriverState *bs)
220
221
static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset,
222
bool exact, PreallocMode prealloc,
223
- Error **errp)
224
+ BdrvRequestFlags flags, Error **errp)
225
{
226
BDRVSheepdogState *s = bs->opaque;
227
int ret, fd;
228
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
229
230
assert(!flags);
231
if (offset > s->inode.vdi_size) {
232
- ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, NULL);
233
+ ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, 0, NULL);
234
if (ret < 0) {
235
return ret;
236
}
237
diff --git a/block/ssh.c b/block/ssh.c
238
index XXXXXXX..XXXXXXX 100644
239
--- a/block/ssh.c
240
+++ b/block/ssh.c
241
@@ -XXX,XX +XXX,XX @@ static int64_t ssh_getlength(BlockDriverState *bs)
242
243
static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
244
bool exact, PreallocMode prealloc,
245
- Error **errp)
246
+ BdrvRequestFlags flags, Error **errp)
247
{
248
BDRVSSHState *s = bs->opaque;
249
250
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
251
index XXXXXXX..XXXXXXX 100644
252
--- a/tests/test-block-iothread.c
253
+++ b/tests/test-block-iothread.c
254
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs,
255
256
static int coroutine_fn
257
bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
258
- PreallocMode prealloc, Error **errp)
259
+ PreallocMode prealloc, BdrvRequestFlags flags,
260
+ Error **errp)
261
{
262
return 0;
263
}
106
}
264
--
107
--
265
2.25.3
108
2.40.1
266
267
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
1
2
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
4
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
5
Message-Id: <20230510150624.310640-4-vsementsov@yandex-team.ru>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
8
blockdev.c | 9 +++------
9
1 file changed, 3 insertions(+), 6 deletions(-)
10
11
diff --git a/blockdev.c b/blockdev.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/blockdev.c
14
+++ b/blockdev.c
15
@@ -XXX,XX +XXX,XX @@ void qmp_transaction(TransactionActionList *actions,
16
struct TransactionProperties *properties,
17
Error **errp)
18
{
19
- TransactionActionList *act = actions;
20
+ TransactionActionList *act;
21
bool has_properties = !!properties;
22
JobTxn *block_job_txn = NULL;
23
Error *local_err = NULL;
24
@@ -XXX,XX +XXX,XX @@ void qmp_transaction(TransactionActionList *actions,
25
bdrv_drain_all();
26
27
/* We don't do anything in this loop that commits us to the operations */
28
- while (NULL != act) {
29
- TransactionAction *dev_info = NULL;
30
+ for (act = actions; act; act = act->next) {
31
+ TransactionAction *dev_info = act->value;
32
const BlkActionOps *ops;
33
BlkActionState *state;
34
35
- dev_info = act->value;
36
- act = act->next;
37
-
38
assert(dev_info->type < ARRAY_SIZE(actions_map));
39
40
ops = &actions_map[dev_info->type];
41
--
42
2.40.1
diff view generated by jsdifflib
1
When extending the size of an image that has a backing file larger than
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
2
its old size, make sure that the backing file data doesn't become
3
visible in the guest, but the added area is properly zeroed out.
4
2
5
Consider the following scenario where the overlay is shorter than its
3
Only backup supports GROUPED mode. Make this logic more clear. And
6
backing file:
4
avoid passing extra thing to each action.
7
5
8
base.qcow2: AAAAAAAA
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
9
overlay.qcow2: BBBB
7
Message-Id: <20230510150624.310640-5-vsementsov@yandex-team.ru>
10
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
When resizing (extending) overlay.qcow2, the new blocks should not stay
12
unallocated and make the additional As from base.qcow2 visible like
13
before this patch, but zeros should be read.
14
15
A similar case happens with the various variants of a commit job when an
16
intermediate file is short (- for unallocated):
17
18
base.qcow2: A-A-AAAA
19
mid.qcow2: BB-B
20
top.qcow2: C--C--C-
21
22
After commit top.qcow2 to mid.qcow2, the following happens:
23
24
mid.qcow2: CB-C00C0 (correct result)
25
mid.qcow2: CB-C--C- (before this fix)
26
27
Without the fix, blocks that previously read as zeros on top.qcow2
28
suddenly turn into A.
29
30
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
31
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
32
Message-Id: <20200424125448.63318-8-kwolf@redhat.com>
33
Reviewed-by: Max Reitz <mreitz@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
35
---
10
---
36
block/io.c | 25 +++++++++++++++++++++++++
11
blockdev.c | 96 +++++++++++++-----------------------------------------
37
1 file changed, 25 insertions(+)
12
1 file changed, 22 insertions(+), 74 deletions(-)
38
13
39
diff --git a/block/io.c b/block/io.c
14
diff --git a/blockdev.c b/blockdev.c
40
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
41
--- a/block/io.c
16
--- a/blockdev.c
42
+++ b/block/io.c
17
+++ b/blockdev.c
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
18
@@ -XXX,XX +XXX,XX @@ struct BlkActionState {
44
goto out;
19
TransactionAction *action;
20
const BlkActionOps *ops;
21
JobTxn *block_job_txn;
22
- TransactionProperties *txn_props;
23
QTAILQ_ENTRY(BlkActionState) entry;
24
};
25
26
@@ -XXX,XX +XXX,XX @@ TransactionActionDrv internal_snapshot_drv = {
27
.clean = internal_snapshot_clean,
28
};
29
30
-static int action_check_completion_mode(BlkActionState *s, Error **errp)
31
-{
32
- if (s->txn_props->completion_mode != ACTION_COMPLETION_MODE_INDIVIDUAL) {
33
- error_setg(errp,
34
- "Action '%s' does not support Transaction property "
35
- "completion-mode = %s",
36
- TransactionActionKind_str(s->action->type),
37
- ActionCompletionMode_str(s->txn_props->completion_mode));
38
- return -1;
39
- }
40
- return 0;
41
-}
42
-
43
static void internal_snapshot_action(BlkActionState *common,
44
Transaction *tran, Error **errp)
45
{
46
@@ -XXX,XX +XXX,XX @@ static void internal_snapshot_action(BlkActionState *common,
47
48
tran_add(tran, &internal_snapshot_drv, state);
49
50
- /* 1. parse input */
51
device = internal->device;
52
name = internal->name;
53
54
- /* 2. check for validation */
55
- if (action_check_completion_mode(common, errp) < 0) {
56
- return;
57
- }
58
-
59
bs = qmp_get_root_bs(device, errp);
60
if (!bs) {
61
return;
62
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_action(BlkActionState *common, Transaction *tran,
45
}
63
}
46
64
47
+ /*
65
/* start processing */
48
+ * If the image has a backing file that is large enough that it would
66
- if (action_check_completion_mode(common, errp) < 0) {
49
+ * provide data for the new area, we cannot leave it unallocated because
67
- return;
50
+ * then the backing file content would become visible. Instead, zero-fill
68
- }
51
+ * the new area.
69
52
+ *
70
state->old_bs = bdrv_lookup_bs(device, node_name, errp);
53
+ * Note that if the image has a backing file, but was opened without the
71
if (!state->old_bs) {
54
+ * backing file, taking care of keeping things consistent with that backing
72
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_add_action(BlkActionState *common,
55
+ * file is the user's responsibility.
73
56
+ */
74
tran_add(tran, &block_dirty_bitmap_add_drv, state);
57
+ if (new_bytes && bs->backing) {
75
58
+ int64_t backing_len;
76
- if (action_check_completion_mode(common, errp) < 0) {
77
- return;
78
- }
79
-
80
action = common->action->u.block_dirty_bitmap_add.data;
81
/* AIO context taken and released within qmp_block_dirty_bitmap_add */
82
qmp_block_dirty_bitmap_add(action->node, action->name,
83
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_clear_action(BlkActionState *common,
84
85
tran_add(tran, &block_dirty_bitmap_clear_drv, state);
86
87
- if (action_check_completion_mode(common, errp) < 0) {
88
- return;
89
- }
90
-
91
action = common->action->u.block_dirty_bitmap_clear.data;
92
state->bitmap = block_dirty_bitmap_lookup(action->node,
93
action->name,
94
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_enable_action(BlkActionState *common,
95
96
tran_add(tran, &block_dirty_bitmap_enable_drv, state);
97
98
- if (action_check_completion_mode(common, errp) < 0) {
99
- return;
100
- }
101
-
102
action = common->action->u.block_dirty_bitmap_enable.data;
103
state->bitmap = block_dirty_bitmap_lookup(action->node,
104
action->name,
105
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_disable_action(BlkActionState *common,
106
107
tran_add(tran, &block_dirty_bitmap_disable_drv, state);
108
109
- if (action_check_completion_mode(common, errp) < 0) {
110
- return;
111
- }
112
-
113
action = common->action->u.block_dirty_bitmap_disable.data;
114
state->bitmap = block_dirty_bitmap_lookup(action->node,
115
action->name,
116
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_merge_action(BlkActionState *common,
117
118
tran_add(tran, &block_dirty_bitmap_merge_drv, state);
119
120
- if (action_check_completion_mode(common, errp) < 0) {
121
- return;
122
- }
123
-
124
action = common->action->u.block_dirty_bitmap_merge.data;
125
126
state->bitmap = block_dirty_bitmap_merge(action->node, action->target,
127
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_remove_action(BlkActionState *common,
128
129
tran_add(tran, &block_dirty_bitmap_remove_drv, state);
130
131
- if (action_check_completion_mode(common, errp) < 0) {
132
- return;
133
- }
134
-
135
action = common->action->u.block_dirty_bitmap_remove.data;
136
137
state->bitmap = block_dirty_bitmap_remove(action->node, action->name,
138
@@ -XXX,XX +XXX,XX @@ static const BlkActionOps actions_map[] = {
139
*/
140
};
141
142
-/**
143
- * Allocate a TransactionProperties structure if necessary, and fill
144
- * that structure with desired defaults if they are unset.
145
- */
146
-static TransactionProperties *get_transaction_properties(
147
- TransactionProperties *props)
148
-{
149
- if (!props) {
150
- props = g_new0(TransactionProperties, 1);
151
- }
152
-
153
- if (!props->has_completion_mode) {
154
- props->has_completion_mode = true;
155
- props->completion_mode = ACTION_COMPLETION_MODE_INDIVIDUAL;
156
- }
157
-
158
- return props;
159
-}
160
-
161
/*
162
* 'Atomic' group operations. The operations are performed as a set, and if
163
* any fail then we roll back all operations in the group.
164
@@ -XXX,XX +XXX,XX @@ void qmp_transaction(TransactionActionList *actions,
165
Error **errp)
166
{
167
TransactionActionList *act;
168
- bool has_properties = !!properties;
169
JobTxn *block_job_txn = NULL;
170
Error *local_err = NULL;
171
- Transaction *tran = tran_new();
172
+ Transaction *tran;
173
+ ActionCompletionMode comp_mode =
174
+ properties ? properties->completion_mode :
175
+ ACTION_COMPLETION_MODE_INDIVIDUAL;
176
177
GLOBAL_STATE_CODE();
178
179
/* Does this transaction get canceled as a group on failure?
180
* If not, we don't really need to make a JobTxn.
181
*/
182
- properties = get_transaction_properties(properties);
183
- if (properties->completion_mode != ACTION_COMPLETION_MODE_INDIVIDUAL) {
184
+ if (comp_mode != ACTION_COMPLETION_MODE_INDIVIDUAL) {
185
+ for (act = actions; act; act = act->next) {
186
+ TransactionActionKind type = act->value->type;
59
+
187
+
60
+ backing_len = bdrv_getlength(backing_bs(bs));
188
+ if (type != TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP &&
61
+ if (backing_len < 0) {
189
+ type != TRANSACTION_ACTION_KIND_DRIVE_BACKUP)
62
+ ret = backing_len;
190
+ {
63
+ error_setg_errno(errp, -ret, "Could not get backing file size");
191
+ error_setg(errp,
64
+ goto out;
192
+ "Action '%s' does not support transaction property "
193
+ "completion-mode = %s",
194
+ TransactionActionKind_str(type),
195
+ ActionCompletionMode_str(comp_mode));
196
+ return;
197
+ }
65
+ }
198
+ }
66
+
199
+
67
+ if (backing_len > old_size) {
200
block_job_txn = job_txn_new();
68
+ flags |= BDRV_REQ_ZERO_WRITE;
201
}
69
+ }
202
70
+ }
203
/* drain all i/o before any operations */
204
bdrv_drain_all();
205
206
+ tran = tran_new();
71
+
207
+
72
if (drv->bdrv_co_truncate) {
208
/* We don't do anything in this loop that commits us to the operations */
73
if (flags & ~bs->supported_truncate_flags) {
209
for (act = actions; act; act = act->next) {
74
error_setg(errp, "Block driver does not support requested flags");
210
TransactionAction *dev_info = act->value;
211
@@ -XXX,XX +XXX,XX @@ void qmp_transaction(TransactionActionList *actions,
212
state->ops = ops;
213
state->action = dev_info;
214
state->block_job_txn = block_job_txn;
215
- state->txn_props = properties;
216
217
state->ops->action(state, tran, &local_err);
218
if (local_err) {
219
@@ -XXX,XX +XXX,XX @@ delete_and_fail:
220
/* failure, and it is all-or-none; roll back all operations */
221
tran_abort(tran);
222
exit:
223
- if (!has_properties) {
224
- qapi_free_TransactionProperties(properties);
225
- }
226
job_txn_unref(block_job_txn);
227
}
228
75
--
229
--
76
2.25.3
230
2.40.1
77
78
diff view generated by jsdifflib
1
After processing the option string with the keyval parser, we get a
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
2
QDict that contains only strings. This QDict must be fed to a keyval
3
visitor which converts the strings into the right data types.
4
2
5
qmp_object_add(), however, uses the normal QObject input visitor, which
3
Other bitmap related actions use the .bitmap pointer in .abort action,
6
expects a QDict where all properties already have the QType that matches
4
let's do same here:
7
the data type required by the QOM object type.
8
5
9
Change the --object implementation in qemu-storage-daemon so that it
6
1. It helps further refactoring, as bitmap-add is the only bitmap
10
doesn't call qmp_object_add(), but calls user_creatable_add_dict()
7
action that uses state.action in .abort
11
directly instead and pass it a new keyval boolean that decides which
12
visitor must be used.
13
8
14
Reported-by: Coiby Xu <coiby.xu@gmail.com>
9
2. It must be safe: transaction actions rely on the fact that on
10
.abort() the state is the same as at the end of .prepare(), so that
11
in .abort() we could precisely rollback the changes done by
12
.prepare().
13
The only way to remove the bitmap during transaction should be
14
block-dirty-bitmap-remove action, but it postpones actual removal to
15
.commit(), so we are OK on any rollback path. (Note also that
16
bitmap-remove is the only bitmap action that has .commit() phase,
17
except for simple g_free the state on .clean())
18
19
3. Again, other bitmap actions behave this way: keep the bitmap pointer
20
during the transaction.
21
22
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
23
Message-Id: <20230510150624.310640-6-vsementsov@yandex-team.ru>
24
[kwolf: Also remove the now unused BlockDirtyBitmapState.prepared]
25
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
27
---
17
include/qom/object_interfaces.h | 6 +++++-
28
blockdev.c | 13 ++++---------
18
qemu-storage-daemon.c | 4 +---
29
1 file changed, 4 insertions(+), 9 deletions(-)
19
qom/object_interfaces.c | 8 ++++++--
20
qom/qom-qmp-cmds.c | 2 +-
21
4 files changed, 13 insertions(+), 7 deletions(-)
22
30
23
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
31
diff --git a/blockdev.c b/blockdev.c
24
index XXXXXXX..XXXXXXX 100644
32
index XXXXXXX..XXXXXXX 100644
25
--- a/include/qom/object_interfaces.h
33
--- a/blockdev.c
26
+++ b/include/qom/object_interfaces.h
34
+++ b/blockdev.c
27
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
35
@@ -XXX,XX +XXX,XX @@ typedef struct BlockDirtyBitmapState {
28
/**
36
BdrvDirtyBitmap *bitmap;
29
* user_creatable_add_dict:
37
BlockDriverState *bs;
30
* @qdict: the object definition
38
HBitmap *backup;
31
+ * @keyval: if true, use a keyval visitor for processing @qdict (i.e.
39
- bool prepared;
32
+ * assume that all @qdict values are strings); otherwise, use
40
bool was_enabled;
33
+ * the normal QObject visitor (i.e. assume all @qdict values
41
} BlockDirtyBitmapState;
34
+ * have the QType expected by the QOM object type)
42
35
* @errp: if an error occurs, a pointer to an area to store the error
43
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_add_action(BlkActionState *common,
36
*
44
&local_err);
37
* Create an instance of the user creatable object that is defined by
45
38
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
46
if (!local_err) {
39
* ID from the key 'id'. The remaining entries in @qdict are used to
47
- state->prepared = true;
40
* initialize the object properties.
48
+ state->bitmap = block_dirty_bitmap_lookup(action->node, action->name,
41
*/
49
+ NULL, &error_abort);
42
-void user_creatable_add_dict(QDict *qdict, Error **errp);
50
} else {
43
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp);
51
error_propagate(errp, local_err);
44
52
}
45
/**
53
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_add_action(BlkActionState *common,
46
* user_creatable_add_opts:
54
47
diff --git a/qemu-storage-daemon.c b/qemu-storage-daemon.c
55
static void block_dirty_bitmap_add_abort(void *opaque)
48
index XXXXXXX..XXXXXXX 100644
56
{
49
--- a/qemu-storage-daemon.c
57
- BlockDirtyBitmapAdd *action;
50
+++ b/qemu-storage-daemon.c
58
BlockDirtyBitmapState *state = opaque;
51
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
59
52
QemuOpts *opts;
60
- action = state->common.action->u.block_dirty_bitmap_add.data;
53
const char *type;
61
- /* Should not be able to fail: IF the bitmap was added via .prepare(),
54
QDict *args;
62
- * then the node reference and bitmap name must have been valid.
55
- QObject *ret_data = NULL;
63
- */
56
64
- if (state->prepared) {
57
/* FIXME The keyval parser rejects 'help' arguments, so we must
65
- qmp_block_dirty_bitmap_remove(action->node, action->name, &error_abort);
58
* unconditionall try QemuOpts first. */
66
+ if (state->bitmap) {
59
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
67
+ bdrv_release_dirty_bitmap(state->bitmap);
60
qemu_opts_del(opts);
68
}
61
62
args = keyval_parse(optarg, "qom-type", &error_fatal);
63
- qmp_object_add(args, &ret_data, &error_fatal);
64
+ user_creatable_add_dict(args, true, &error_fatal);
65
qobject_unref(args);
66
- qobject_unref(ret_data);
67
break;
68
}
69
default:
70
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/qom/object_interfaces.c
73
+++ b/qom/object_interfaces.c
74
@@ -XXX,XX +XXX,XX @@ out:
75
return obj;
76
}
69
}
77
70
78
-void user_creatable_add_dict(QDict *qdict, Error **errp)
79
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp)
80
{
81
Visitor *v;
82
Object *obj;
83
@@ -XXX,XX +XXX,XX @@ void user_creatable_add_dict(QDict *qdict, Error **errp)
84
}
85
qdict_del(qdict, "id");
86
87
- v = qobject_input_visitor_new(QOBJECT(qdict));
88
+ if (keyval) {
89
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
90
+ } else {
91
+ v = qobject_input_visitor_new(QOBJECT(qdict));
92
+ }
93
obj = user_creatable_add_type(type, id, qdict, v, errp);
94
visit_free(v);
95
object_unref(obj);
96
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/qom/qom-qmp-cmds.c
99
+++ b/qom/qom-qmp-cmds.c
100
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
101
qobject_unref(pdict);
102
}
103
104
- user_creatable_add_dict(qdict, errp);
105
+ user_creatable_add_dict(qdict, false, errp);
106
}
107
108
void qmp_object_del(const char *id, Error **errp)
109
--
71
--
110
2.25.3
72
2.40.1
111
112
diff view generated by jsdifflib
New patch
1
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
2
3
Let's simplify things:
4
5
First, actions generally don't need access to common BlkActionState
6
structure. The only exclusion are backup actions that need
7
block_job_txn.
8
9
Next, for transaction actions of Transaction API is more native to
10
allocated state structure in the action itself.
11
12
So, do the following transformation:
13
14
1. Let all actions be represented by a function with corresponding
15
structure as arguments.
16
17
2. Instead of array-map marshaller, let's make a function, that calls
18
corresponding action directly.
19
20
3. BlkActionOps and BlkActionState structures become unused
21
22
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
23
Message-Id: <20230510150624.310640-7-vsementsov@yandex-team.ru>
24
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26
---
27
blockdev.c | 265 +++++++++++++++++------------------------------------
28
1 file changed, 85 insertions(+), 180 deletions(-)
29
30
diff --git a/blockdev.c b/blockdev.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/blockdev.c
33
+++ b/blockdev.c
34
@@ -XXX,XX +XXX,XX @@ out_aio_context:
35
return NULL;
36
}
37
38
-/* New and old BlockDriverState structs for atomic group operations */
39
-
40
-typedef struct BlkActionState BlkActionState;
41
-
42
-/**
43
- * BlkActionOps:
44
- * Table of operations that define an Action.
45
- *
46
- * @instance_size: Size of state struct, in bytes.
47
- * @prepare: Prepare the work, must NOT be NULL.
48
- * @commit: Commit the changes, can be NULL.
49
- * @abort: Abort the changes on fail, can be NULL.
50
- * @clean: Clean up resources after all transaction actions have called
51
- * commit() or abort(). Can be NULL.
52
- *
53
- * Only prepare() may fail. In a single transaction, only one of commit() or
54
- * abort() will be called. clean() will always be called if it is present.
55
- *
56
- * Always run under BQL.
57
- */
58
-typedef struct BlkActionOps {
59
- size_t instance_size;
60
- void (*action)(BlkActionState *common, Transaction *tran, Error **errp);
61
-} BlkActionOps;
62
-
63
-/**
64
- * BlkActionState:
65
- * Describes one Action's state within a Transaction.
66
- *
67
- * @action: QAPI-defined enum identifying which Action to perform.
68
- * @ops: Table of ActionOps this Action can perform.
69
- * @block_job_txn: Transaction which this action belongs to.
70
- * @entry: List membership for all Actions in this Transaction.
71
- *
72
- * This structure must be arranged as first member in a subclassed type,
73
- * assuming that the compiler will also arrange it to the same offsets as the
74
- * base class.
75
- */
76
-struct BlkActionState {
77
- TransactionAction *action;
78
- const BlkActionOps *ops;
79
- JobTxn *block_job_txn;
80
- QTAILQ_ENTRY(BlkActionState) entry;
81
-};
82
-
83
/* internal snapshot private data */
84
typedef struct InternalSnapshotState {
85
- BlkActionState common;
86
BlockDriverState *bs;
87
QEMUSnapshotInfo sn;
88
bool created;
89
@@ -XXX,XX +XXX,XX @@ TransactionActionDrv internal_snapshot_drv = {
90
.clean = internal_snapshot_clean,
91
};
92
93
-static void internal_snapshot_action(BlkActionState *common,
94
+static void internal_snapshot_action(BlockdevSnapshotInternal *internal,
95
Transaction *tran, Error **errp)
96
{
97
Error *local_err = NULL;
98
@@ -XXX,XX +XXX,XX @@ static void internal_snapshot_action(BlkActionState *common,
99
QEMUSnapshotInfo old_sn, *sn;
100
bool ret;
101
int64_t rt;
102
- BlockdevSnapshotInternal *internal;
103
- InternalSnapshotState *state;
104
+ InternalSnapshotState *state = g_new0(InternalSnapshotState, 1);
105
AioContext *aio_context;
106
int ret1;
107
108
- g_assert(common->action->type ==
109
- TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC);
110
- internal = common->action->u.blockdev_snapshot_internal_sync.data;
111
- state = DO_UPCAST(InternalSnapshotState, common, common);
112
-
113
tran_add(tran, &internal_snapshot_drv, state);
114
115
device = internal->device;
116
@@ -XXX,XX +XXX,XX @@ static void internal_snapshot_clean(void *opaque)
117
118
/* external snapshot private data */
119
typedef struct ExternalSnapshotState {
120
- BlkActionState common;
121
BlockDriverState *old_bs;
122
BlockDriverState *new_bs;
123
bool overlay_appended;
124
@@ -XXX,XX +XXX,XX @@ TransactionActionDrv external_snapshot_drv = {
125
.clean = external_snapshot_clean,
126
};
127
128
-static void external_snapshot_action(BlkActionState *common, Transaction *tran,
129
- Error **errp)
130
+static void external_snapshot_action(TransactionAction *action,
131
+ Transaction *tran, Error **errp)
132
{
133
int ret;
134
int flags = 0;
135
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_action(BlkActionState *common, Transaction *tran,
136
const char *snapshot_ref;
137
/* File name of the new image (for 'blockdev-snapshot-sync') */
138
const char *new_image_file;
139
- ExternalSnapshotState *state =
140
- DO_UPCAST(ExternalSnapshotState, common, common);
141
- TransactionAction *action = common->action;
142
+ ExternalSnapshotState *state = g_new0(ExternalSnapshotState, 1);
143
AioContext *aio_context;
144
uint64_t perm, shared;
145
146
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_clean(void *opaque)
147
}
148
149
typedef struct DriveBackupState {
150
- BlkActionState common;
151
BlockDriverState *bs;
152
BlockJob *job;
153
} DriveBackupState;
154
@@ -XXX,XX +XXX,XX @@ TransactionActionDrv drive_backup_drv = {
155
.clean = drive_backup_clean,
156
};
157
158
-static void drive_backup_action(BlkActionState *common, Transaction *tran,
159
- Error **errp)
160
+static void drive_backup_action(DriveBackup *backup,
161
+ JobTxn *block_job_txn,
162
+ Transaction *tran, Error **errp)
163
{
164
- DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
165
- DriveBackup *backup;
166
+ DriveBackupState *state = g_new0(DriveBackupState, 1);
167
BlockDriverState *bs;
168
BlockDriverState *target_bs;
169
BlockDriverState *source = NULL;
170
@@ -XXX,XX +XXX,XX @@ static void drive_backup_action(BlkActionState *common, Transaction *tran,
171
172
tran_add(tran, &drive_backup_drv, state);
173
174
- assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
175
- backup = common->action->u.drive_backup.data;
176
-
177
if (!backup->has_mode) {
178
backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
179
}
180
@@ -XXX,XX +XXX,XX @@ static void drive_backup_action(BlkActionState *common, Transaction *tran,
181
182
state->job = do_backup_common(qapi_DriveBackup_base(backup),
183
bs, target_bs, aio_context,
184
- common->block_job_txn, errp);
185
+ block_job_txn, errp);
186
187
unref:
188
bdrv_unref(target_bs);
189
@@ -XXX,XX +XXX,XX @@ static void drive_backup_clean(void *opaque)
190
}
191
192
typedef struct BlockdevBackupState {
193
- BlkActionState common;
194
BlockDriverState *bs;
195
BlockJob *job;
196
} BlockdevBackupState;
197
@@ -XXX,XX +XXX,XX @@ TransactionActionDrv blockdev_backup_drv = {
198
.clean = blockdev_backup_clean,
199
};
200
201
-static void blockdev_backup_action(BlkActionState *common, Transaction *tran,
202
- Error **errp)
203
+static void blockdev_backup_action(BlockdevBackup *backup,
204
+ JobTxn *block_job_txn,
205
+ Transaction *tran, Error **errp)
206
{
207
- BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
208
- BlockdevBackup *backup;
209
+ BlockdevBackupState *state = g_new0(BlockdevBackupState, 1);
210
BlockDriverState *bs;
211
BlockDriverState *target_bs;
212
AioContext *aio_context;
213
@@ -XXX,XX +XXX,XX @@ static void blockdev_backup_action(BlkActionState *common, Transaction *tran,
214
215
tran_add(tran, &blockdev_backup_drv, state);
216
217
- assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
218
- backup = common->action->u.blockdev_backup.data;
219
-
220
bs = bdrv_lookup_bs(backup->device, backup->device, errp);
221
if (!bs) {
222
return;
223
@@ -XXX,XX +XXX,XX @@ static void blockdev_backup_action(BlkActionState *common, Transaction *tran,
224
225
state->job = do_backup_common(qapi_BlockdevBackup_base(backup),
226
bs, target_bs, aio_context,
227
- common->block_job_txn, errp);
228
+ block_job_txn, errp);
229
230
aio_context_release(aio_context);
231
}
232
@@ -XXX,XX +XXX,XX @@ static void blockdev_backup_clean(void *opaque)
233
}
234
235
typedef struct BlockDirtyBitmapState {
236
- BlkActionState common;
237
BdrvDirtyBitmap *bitmap;
238
BlockDriverState *bs;
239
HBitmap *backup;
240
@@ -XXX,XX +XXX,XX @@ TransactionActionDrv block_dirty_bitmap_add_drv = {
241
.clean = g_free,
242
};
243
244
-static void block_dirty_bitmap_add_action(BlkActionState *common,
245
+static void block_dirty_bitmap_add_action(BlockDirtyBitmapAdd *action,
246
Transaction *tran, Error **errp)
247
{
248
Error *local_err = NULL;
249
- BlockDirtyBitmapAdd *action;
250
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
251
- common, common);
252
+ BlockDirtyBitmapState *state = g_new0(BlockDirtyBitmapState, 1);
253
254
tran_add(tran, &block_dirty_bitmap_add_drv, state);
255
256
- action = common->action->u.block_dirty_bitmap_add.data;
257
/* AIO context taken and released within qmp_block_dirty_bitmap_add */
258
qmp_block_dirty_bitmap_add(action->node, action->name,
259
action->has_granularity, action->granularity,
260
@@ -XXX,XX +XXX,XX @@ TransactionActionDrv block_dirty_bitmap_clear_drv = {
261
.clean = g_free,
262
};
263
264
-static void block_dirty_bitmap_clear_action(BlkActionState *common,
265
+static void block_dirty_bitmap_clear_action(BlockDirtyBitmap *action,
266
Transaction *tran, Error **errp)
267
{
268
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
269
- common, common);
270
- BlockDirtyBitmap *action;
271
+ BlockDirtyBitmapState *state = g_new0(BlockDirtyBitmapState, 1);
272
273
tran_add(tran, &block_dirty_bitmap_clear_drv, state);
274
275
- action = common->action->u.block_dirty_bitmap_clear.data;
276
state->bitmap = block_dirty_bitmap_lookup(action->node,
277
action->name,
278
&state->bs,
279
@@ -XXX,XX +XXX,XX @@ TransactionActionDrv block_dirty_bitmap_enable_drv = {
280
.clean = g_free,
281
};
282
283
-static void block_dirty_bitmap_enable_action(BlkActionState *common,
284
+static void block_dirty_bitmap_enable_action(BlockDirtyBitmap *action,
285
Transaction *tran, Error **errp)
286
{
287
- BlockDirtyBitmap *action;
288
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
289
- common, common);
290
+ BlockDirtyBitmapState *state = g_new0(BlockDirtyBitmapState, 1);
291
292
tran_add(tran, &block_dirty_bitmap_enable_drv, state);
293
294
- action = common->action->u.block_dirty_bitmap_enable.data;
295
state->bitmap = block_dirty_bitmap_lookup(action->node,
296
action->name,
297
NULL,
298
@@ -XXX,XX +XXX,XX @@ TransactionActionDrv block_dirty_bitmap_disable_drv = {
299
.clean = g_free,
300
};
301
302
-static void block_dirty_bitmap_disable_action(BlkActionState *common,
303
+static void block_dirty_bitmap_disable_action(BlockDirtyBitmap *action,
304
Transaction *tran, Error **errp)
305
{
306
- BlockDirtyBitmap *action;
307
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
308
- common, common);
309
+ BlockDirtyBitmapState *state = g_new0(BlockDirtyBitmapState, 1);
310
311
tran_add(tran, &block_dirty_bitmap_disable_drv, state);
312
313
- action = common->action->u.block_dirty_bitmap_disable.data;
314
state->bitmap = block_dirty_bitmap_lookup(action->node,
315
action->name,
316
NULL,
317
@@ -XXX,XX +XXX,XX @@ TransactionActionDrv block_dirty_bitmap_merge_drv = {
318
.clean = g_free,
319
};
320
321
-static void block_dirty_bitmap_merge_action(BlkActionState *common,
322
+static void block_dirty_bitmap_merge_action(BlockDirtyBitmapMerge *action,
323
Transaction *tran, Error **errp)
324
{
325
- BlockDirtyBitmapMerge *action;
326
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
327
- common, common);
328
+ BlockDirtyBitmapState *state = g_new0(BlockDirtyBitmapState, 1);
329
330
tran_add(tran, &block_dirty_bitmap_merge_drv, state);
331
332
- action = common->action->u.block_dirty_bitmap_merge.data;
333
-
334
state->bitmap = block_dirty_bitmap_merge(action->node, action->target,
335
action->bitmaps, &state->backup,
336
errp);
337
@@ -XXX,XX +XXX,XX @@ TransactionActionDrv block_dirty_bitmap_remove_drv = {
338
.clean = g_free,
339
};
340
341
-static void block_dirty_bitmap_remove_action(BlkActionState *common,
342
+static void block_dirty_bitmap_remove_action(BlockDirtyBitmap *action,
343
Transaction *tran, Error **errp)
344
{
345
- BlockDirtyBitmap *action;
346
- BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
347
- common, common);
348
+ BlockDirtyBitmapState *state = g_new0(BlockDirtyBitmapState, 1);
349
350
tran_add(tran, &block_dirty_bitmap_remove_drv, state);
351
352
- action = common->action->u.block_dirty_bitmap_remove.data;
353
354
state->bitmap = block_dirty_bitmap_remove(action->node, action->name,
355
false, &state->bs, errp);
356
@@ -XXX,XX +XXX,XX @@ static void block_dirty_bitmap_remove_commit(void *opaque)
357
static void abort_commit(void *opaque);
358
TransactionActionDrv abort_drv = {
359
.commit = abort_commit,
360
- .clean = g_free,
361
};
362
363
-static void abort_action(BlkActionState *common, Transaction *tran,
364
- Error **errp)
365
+static void abort_action(Transaction *tran, Error **errp)
366
{
367
- tran_add(tran, &abort_drv, common);
368
+ tran_add(tran, &abort_drv, NULL);
369
error_setg(errp, "Transaction aborted using Abort action");
370
}
371
372
@@ -XXX,XX +XXX,XX @@ static void abort_commit(void *opaque)
373
g_assert_not_reached(); /* this action never succeeds */
374
}
375
376
-static const BlkActionOps actions_map[] = {
377
- [TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT] = {
378
- .instance_size = sizeof(ExternalSnapshotState),
379
- .action = external_snapshot_action,
380
- },
381
- [TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC] = {
382
- .instance_size = sizeof(ExternalSnapshotState),
383
- .action = external_snapshot_action,
384
- },
385
- [TRANSACTION_ACTION_KIND_DRIVE_BACKUP] = {
386
- .instance_size = sizeof(DriveBackupState),
387
- .action = drive_backup_action,
388
- },
389
- [TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP] = {
390
- .instance_size = sizeof(BlockdevBackupState),
391
- .action = blockdev_backup_action,
392
- },
393
- [TRANSACTION_ACTION_KIND_ABORT] = {
394
- .instance_size = sizeof(BlkActionState),
395
- .action = abort_action,
396
- },
397
- [TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC] = {
398
- .instance_size = sizeof(InternalSnapshotState),
399
- .action = internal_snapshot_action,
400
- },
401
- [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ADD] = {
402
- .instance_size = sizeof(BlockDirtyBitmapState),
403
- .action = block_dirty_bitmap_add_action,
404
- },
405
- [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_CLEAR] = {
406
- .instance_size = sizeof(BlockDirtyBitmapState),
407
- .action = block_dirty_bitmap_clear_action,
408
- },
409
- [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ENABLE] = {
410
- .instance_size = sizeof(BlockDirtyBitmapState),
411
- .action = block_dirty_bitmap_enable_action,
412
- },
413
- [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_DISABLE] = {
414
- .instance_size = sizeof(BlockDirtyBitmapState),
415
- .action = block_dirty_bitmap_disable_action,
416
- },
417
- [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_MERGE] = {
418
- .instance_size = sizeof(BlockDirtyBitmapState),
419
- .action = block_dirty_bitmap_merge_action,
420
- },
421
- [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_REMOVE] = {
422
- .instance_size = sizeof(BlockDirtyBitmapState),
423
- .action = block_dirty_bitmap_remove_action,
424
- },
425
- /* Where are transactions for MIRROR, COMMIT and STREAM?
426
+static void transaction_action(TransactionAction *act, JobTxn *block_job_txn,
427
+ Transaction *tran, Error **errp)
428
+{
429
+ switch (act->type) {
430
+ case TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT:
431
+ case TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC:
432
+ external_snapshot_action(act, tran, errp);
433
+ return;
434
+ case TRANSACTION_ACTION_KIND_DRIVE_BACKUP:
435
+ drive_backup_action(act->u.drive_backup.data,
436
+ block_job_txn, tran, errp);
437
+ return;
438
+ case TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP:
439
+ blockdev_backup_action(act->u.blockdev_backup.data,
440
+ block_job_txn, tran, errp);
441
+ return;
442
+ case TRANSACTION_ACTION_KIND_ABORT:
443
+ abort_action(tran, errp);
444
+ return;
445
+ case TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC:
446
+ internal_snapshot_action(act->u.blockdev_snapshot_internal_sync.data,
447
+ tran, errp);
448
+ return;
449
+ case TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ADD:
450
+ block_dirty_bitmap_add_action(act->u.block_dirty_bitmap_add.data,
451
+ tran, errp);
452
+ return;
453
+ case TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_CLEAR:
454
+ block_dirty_bitmap_clear_action(act->u.block_dirty_bitmap_clear.data,
455
+ tran, errp);
456
+ return;
457
+ case TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ENABLE:
458
+ block_dirty_bitmap_enable_action(act->u.block_dirty_bitmap_enable.data,
459
+ tran, errp);
460
+ return;
461
+ case TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_DISABLE:
462
+ block_dirty_bitmap_disable_action(
463
+ act->u.block_dirty_bitmap_disable.data, tran, errp);
464
+ return;
465
+ case TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_MERGE:
466
+ block_dirty_bitmap_merge_action(act->u.block_dirty_bitmap_merge.data,
467
+ tran, errp);
468
+ return;
469
+ case TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_REMOVE:
470
+ block_dirty_bitmap_remove_action(act->u.block_dirty_bitmap_remove.data,
471
+ tran, errp);
472
+ return;
473
+ /*
474
+ * Where are transactions for MIRROR, COMMIT and STREAM?
475
* Although these blockjobs use transaction callbacks like the backup job,
476
* these jobs do not necessarily adhere to transaction semantics.
477
* These jobs may not fully undo all of their actions on abort, nor do they
478
* necessarily work in transactions with more than one job in them.
479
*/
480
-};
481
+ case TRANSACTION_ACTION_KIND__MAX:
482
+ default:
483
+ g_assert_not_reached();
484
+ };
485
+}
486
+
487
488
/*
489
* 'Atomic' group operations. The operations are performed as a set, and if
490
@@ -XXX,XX +XXX,XX @@ void qmp_transaction(TransactionActionList *actions,
491
492
/* We don't do anything in this loop that commits us to the operations */
493
for (act = actions; act; act = act->next) {
494
- TransactionAction *dev_info = act->value;
495
- const BlkActionOps *ops;
496
- BlkActionState *state;
497
-
498
- assert(dev_info->type < ARRAY_SIZE(actions_map));
499
-
500
- ops = &actions_map[dev_info->type];
501
- assert(ops->instance_size > 0);
502
-
503
- state = g_malloc0(ops->instance_size);
504
- state->ops = ops;
505
- state->action = dev_info;
506
- state->block_job_txn = block_job_txn;
507
-
508
- state->ops->action(state, tran, &local_err);
509
+ transaction_action(act->value, block_job_txn, tran, &local_err);
510
if (local_err) {
511
error_propagate(errp, local_err);
512
goto delete_and_fail;
513
--
514
2.40.1
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
2
2
3
Backing files and raw external data files are mutually exclusive.
3
"zlib" clusters are actually raw deflate (RFC1951) clusters without
4
The documentation of the raw external data bit (in autoclear_features)
4
zlib headers.
5
already indicates that, but we should also mention it on the other
6
side.
7
5
8
Suggested-by: Eric Blake <eblake@redhat.com>
6
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Message-Id: <168424874322.11954.1340942046351859521-0@git.sr.ht>
10
Message-Id: <20200410121816.8334-1-berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
11
---
14
docs/interop/qcow2.txt | 3 +++
12
docs/interop/qcow2.txt | 10 +++++++---
15
1 file changed, 3 insertions(+)
13
1 file changed, 7 insertions(+), 3 deletions(-)
16
14
17
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
15
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
18
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
19
--- a/docs/interop/qcow2.txt
17
--- a/docs/interop/qcow2.txt
20
+++ b/docs/interop/qcow2.txt
18
+++ b/docs/interop/qcow2.txt
21
@@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header:
19
@@ -XXX,XX +XXX,XX @@ version 2.
22
is stored (NB: The string is not null terminated). 0 if the
20
type.
23
image doesn't have a backing file.
21
24
22
If the incompatible bit "Compression type" is set: the field
25
+ Note: backing files are incompatible with raw external data
23
- must be present and non-zero (which means non-zlib
26
+ files (auto-clear feature bit 1).
24
+ must be present and non-zero (which means non-deflate
25
compression type). Otherwise, this field must not be present
26
- or must be zero (which means zlib).
27
+ or must be zero (which means deflate).
28
29
Available compression type values:
30
- 0: zlib <https://www.zlib.net/>
31
+ 0: deflate <https://www.ietf.org/rfc/rfc1951.txt>
32
1: zstd <http://github.com/facebook/zstd>
33
34
+ The deflate compression type is called "zlib"
35
+ <https://www.zlib.net/> in QEMU. However, clusters with the
36
+ deflate compression type do not have zlib headers.
27
+
37
+
28
16 - 19: backing_file_size
38
29
Length of the backing file name in bytes. Must not be
39
=== Header padding ===
30
longer than 1023 bytes. Undefined if the image doesn't have
40
31
--
41
--
32
2.25.3
42
2.40.1
33
34
diff view generated by jsdifflib
1
Now that block drivers can support flags for .bdrv_co_truncate, expose
1
These are functions that modify the graph, so they must be able to take
2
the parameter in the node level interfaces bdrv_co_truncate() and
2
a writer lock. This is impossible if they already hold the reader lock.
3
bdrv_truncate().
3
If they need a reader lock for some of their operations, they should
4
take it internally.
5
6
Many of them go through blk_*(), which will always take the lock itself.
7
Direct calls of bdrv_*() need to take the reader lock. Note that while
8
locking for bdrv_co_*() calls is checked by TSA, this is not the case
9
for the mixed_coroutine_fns bdrv_*(). Holding the lock is still required
10
when they are called from coroutine context like here!
11
12
This effectively reverts 4ec8df0183, but adds some internal locking
13
instead.
4
14
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Message-Id: <20230510203601.418015-2-kwolf@redhat.com>
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
17
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-Id: <20200424125448.63318-3-kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
19
---
12
include/block/block.h | 5 +++--
20
include/block/block-global-state.h | 8 +++----
13
block/block-backend.c | 2 +-
21
include/block/block_int-common.h | 4 ++--
14
block/crypto.c | 2 +-
22
block.c | 1 -
15
block/io.c | 12 +++++++-----
23
block/create.c | 1 -
16
block/parallels.c | 6 +++---
24
block/crypto.c | 25 ++++++++++----------
17
block/qcow.c | 4 ++--
25
block/parallels.c | 6 ++---
18
block/qcow2-refcount.c | 2 +-
26
block/qcow.c | 6 ++---
19
block/qcow2.c | 15 +++++++++------
27
block/qcow2.c | 37 +++++++++++++++++++-----------
20
block/raw-format.c | 2 +-
28
block/qed.c | 6 ++---
21
block/vhdx-log.c | 2 +-
29
block/raw-format.c | 2 +-
22
block/vhdx.c | 2 +-
30
block/vdi.c | 11 +++++----
23
block/vmdk.c | 2 +-
31
block/vhdx.c | 8 ++++---
24
tests/test-block-iothread.c | 6 +++---
32
block/vmdk.c | 27 ++++++++++------------
25
13 files changed, 34 insertions(+), 28 deletions(-)
33
block/vpc.c | 6 ++---
34
14 files changed, 78 insertions(+), 70 deletions(-)
26
35
27
diff --git a/include/block/block.h b/include/block/block.h
36
diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h
28
index XXXXXXX..XXXXXXX 100644
37
index XXXXXXX..XXXXXXX 100644
29
--- a/include/block/block.h
38
--- a/include/block/block-global-state.h
30
+++ b/include/block/block.h
39
+++ b/include/block/block-global-state.h
31
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
40
@@ -XXX,XX +XXX,XX @@ BlockDriver *bdrv_find_protocol(const char *filename,
32
void bdrv_refresh_filename(BlockDriverState *bs);
41
Error **errp);
33
42
BlockDriver *bdrv_find_format(const char *format_name);
34
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
43
35
- PreallocMode prealloc, Error **errp);
44
-int coroutine_fn GRAPH_RDLOCK
36
+ PreallocMode prealloc, BdrvRequestFlags flags,
45
+int coroutine_fn GRAPH_UNLOCKED
37
+ Error **errp);
46
bdrv_co_create(BlockDriver *drv, const char *filename, QemuOpts *opts,
38
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
47
Error **errp);
39
- PreallocMode prealloc, Error **errp);
48
40
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
49
-int co_wrapper_bdrv_rdlock bdrv_create(BlockDriver *drv, const char *filename,
41
50
- QemuOpts *opts, Error **errp);
42
int64_t bdrv_nb_sectors(BlockDriverState *bs);
51
+int co_wrapper bdrv_create(BlockDriver *drv, const char *filename,
43
int64_t bdrv_getlength(BlockDriverState *bs);
52
+ QemuOpts *opts, Error **errp);
44
diff --git a/block/block-backend.c b/block/block-backend.c
53
45
index XXXXXXX..XXXXXXX 100644
54
-int coroutine_fn GRAPH_RDLOCK
46
--- a/block/block-backend.c
55
+int coroutine_fn GRAPH_UNLOCKED
47
+++ b/block/block-backend.c
56
bdrv_co_create_file(const char *filename, QemuOpts *opts, Error **errp);
48
@@ -XXX,XX +XXX,XX @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
57
49
return -ENOMEDIUM;
58
BlockDriverState *bdrv_new(void);
50
}
59
diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
51
60
index XXXXXXX..XXXXXXX 100644
52
- return bdrv_truncate(blk->root, offset, exact, prealloc, errp);
61
--- a/include/block/block_int-common.h
53
+ return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
62
+++ b/include/block/block_int-common.h
54
}
63
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
55
64
BlockDriverState *bs, QDict *options, int flags, Error **errp);
56
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
65
void (*bdrv_close)(BlockDriverState *bs);
66
67
- int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_create)(
68
+ int coroutine_fn GRAPH_UNLOCKED_PTR (*bdrv_co_create)(
69
BlockdevCreateOptions *opts, Error **errp);
70
71
- int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_create_opts)(
72
+ int coroutine_fn GRAPH_UNLOCKED_PTR (*bdrv_co_create_opts)(
73
BlockDriver *drv, const char *filename, QemuOpts *opts, Error **errp);
74
75
int (*bdrv_amend_options)(BlockDriverState *bs,
76
diff --git a/block.c b/block.c
77
index XXXXXXX..XXXXXXX 100644
78
--- a/block.c
79
+++ b/block.c
80
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_create(BlockDriver *drv, const char *filename,
81
int ret;
82
GLOBAL_STATE_CODE();
83
ERRP_GUARD();
84
- assert_bdrv_graph_readable();
85
86
if (!drv->bdrv_co_create_opts) {
87
error_setg(errp, "Driver '%s' does not support image creation",
88
diff --git a/block/create.c b/block/create.c
89
index XXXXXXX..XXXXXXX 100644
90
--- a/block/create.c
91
+++ b/block/create.c
92
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blockdev_create_run(Job *job, Error **errp)
93
int ret;
94
95
GLOBAL_STATE_CODE();
96
- GRAPH_RDLOCK_GUARD();
97
98
job_progress_set_remaining(&s->common, 1);
99
ret = s->drv->bdrv_co_create(s->opts, errp);
57
diff --git a/block/crypto.c b/block/crypto.c
100
diff --git a/block/crypto.c b/block/crypto.c
58
index XXXXXXX..XXXXXXX 100644
101
index XXXXXXX..XXXXXXX 100644
59
--- a/block/crypto.c
102
--- a/block/crypto.c
60
+++ b/block/crypto.c
103
+++ b/block/crypto.c
61
@@ -XXX,XX +XXX,XX @@ block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
104
@@ -XXX,XX +XXX,XX @@ struct BlockCryptoCreateData {
62
105
};
63
offset += payload_offset;
106
64
107
65
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
108
-static int block_crypto_create_write_func(QCryptoBlock *block,
66
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
109
- size_t offset,
67
}
110
- const uint8_t *buf,
68
111
- size_t buflen,
69
static void block_crypto_close(BlockDriverState *bs)
112
- void *opaque,
70
diff --git a/block/io.c b/block/io.c
113
- Error **errp)
71
index XXXXXXX..XXXXXXX 100644
114
+static int coroutine_fn GRAPH_UNLOCKED
72
--- a/block/io.c
115
+block_crypto_create_write_func(QCryptoBlock *block, size_t offset,
73
+++ b/block/io.c
116
+ const uint8_t *buf, size_t buflen, void *opaque,
74
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
117
+ Error **errp)
75
* 'offset' bytes in length.
118
{
76
*/
119
struct BlockCryptoCreateData *data = opaque;
77
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
120
ssize_t ret;
78
- PreallocMode prealloc, Error **errp)
121
@@ -XXX,XX +XXX,XX @@ static int block_crypto_create_write_func(QCryptoBlock *block,
79
+ PreallocMode prealloc, BdrvRequestFlags flags,
122
return 0;
80
+ Error **errp)
123
}
81
{
124
82
BlockDriverState *bs = child->bs;
125
-static int block_crypto_create_init_func(QCryptoBlock *block,
83
BlockDriver *drv = bs->drv;
126
- size_t headerlen,
84
BdrvTrackedRequest req;
127
- void *opaque,
85
- BdrvRequestFlags flags = 0;
128
- Error **errp)
86
int64_t old_size, new_bytes;
129
+static int coroutine_fn GRAPH_UNLOCKED
87
int ret;
130
+block_crypto_create_init_func(QCryptoBlock *block, size_t headerlen,
88
131
+ void *opaque, Error **errp)
89
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
132
{
90
}
133
struct BlockCryptoCreateData *data = opaque;
91
ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
134
Error *local_error = NULL;
92
} else if (bs->file && drv->is_filter) {
135
@@ -XXX,XX +XXX,XX @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
93
- ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
136
}
94
+ ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
137
95
} else {
138
96
error_setg(errp, "Image format driver does not support resize");
139
-static int coroutine_fn
97
ret = -ENOTSUP;
140
+static int coroutine_fn GRAPH_UNLOCKED
98
@@ -XXX,XX +XXX,XX @@ typedef struct TruncateCo {
141
block_crypto_co_create_generic(BlockDriverState *bs, int64_t size,
99
int64_t offset;
142
QCryptoBlockCreateOptions *opts,
100
bool exact;
143
PreallocMode prealloc, Error **errp)
101
PreallocMode prealloc;
144
@@ -XXX,XX +XXX,XX @@ static int block_crypto_open_luks(BlockDriverState *bs,
102
+ BdrvRequestFlags flags;
145
bs, options, flags, errp);
103
Error **errp;
146
}
104
int ret;
147
105
} TruncateCo;
148
-static int coroutine_fn
106
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
149
+static int coroutine_fn GRAPH_UNLOCKED
107
{
150
block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp)
108
TruncateCo *tco = opaque;
151
{
109
tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->exact,
152
BlockdevCreateOptionsLUKS *luks_opts;
110
- tco->prealloc, tco->errp);
153
@@ -XXX,XX +XXX,XX @@ fail:
111
+ tco->prealloc, tco->flags, tco->errp);
154
return ret;
112
aio_wait_kick();
155
}
113
}
156
114
157
-static int coroutine_fn GRAPH_RDLOCK
115
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
158
+static int coroutine_fn GRAPH_UNLOCKED
116
- PreallocMode prealloc, Error **errp)
159
block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename,
117
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
160
QemuOpts *opts, Error **errp)
118
{
161
{
119
Coroutine *co;
162
@@ -XXX,XX +XXX,XX @@ fail:
120
TruncateCo tco = {
163
* beforehand, it has been truncated and corrupted in the process.
121
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
164
*/
122
.offset = offset,
165
if (ret) {
123
.exact = exact,
166
+ bdrv_graph_co_rdlock();
124
.prealloc = prealloc,
167
bdrv_co_delete_file_noerr(bs);
125
+ .flags = flags,
168
+ bdrv_graph_co_rdunlock();
126
.errp = errp,
169
}
127
.ret = NOT_DONE,
170
128
};
171
bdrv_co_unref(bs);
129
diff --git a/block/parallels.c b/block/parallels.c
172
diff --git a/block/parallels.c b/block/parallels.c
130
index XXXXXXX..XXXXXXX 100644
173
index XXXXXXX..XXXXXXX 100644
131
--- a/block/parallels.c
174
--- a/block/parallels.c
132
+++ b/block/parallels.c
175
+++ b/block/parallels.c
133
@@ -XXX,XX +XXX,XX @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
176
@@ -XXX,XX +XXX,XX @@ out:
134
} else {
177
}
135
ret = bdrv_truncate(bs->file,
178
136
(s->data_end + space) << BDRV_SECTOR_BITS,
179
137
- false, PREALLOC_MODE_OFF, NULL);
180
-static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts,
138
+ false, PREALLOC_MODE_OFF, 0, NULL);
181
- Error **errp)
139
}
182
+static int coroutine_fn GRAPH_UNLOCKED
140
if (ret < 0) {
183
+parallels_co_create(BlockdevCreateOptions* opts, Error **errp)
141
return ret;
184
{
142
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
185
BlockdevCreateOptionsParallels *parallels_opts;
143
* That means we have to pass exact=true.
186
BlockDriverState *bs;
144
*/
187
@@ -XXX,XX +XXX,XX @@ exit:
145
ret = bdrv_truncate(bs->file, res->image_end_offset, true,
188
goto out;
146
- PREALLOC_MODE_OFF, &local_err);
189
}
147
+ PREALLOC_MODE_OFF, 0, &local_err);
190
148
if (ret < 0) {
191
-static int coroutine_fn GRAPH_RDLOCK
149
error_report_err(local_err);
192
+static int coroutine_fn GRAPH_UNLOCKED
150
res->check_errors++;
193
parallels_co_create_opts(BlockDriver *drv, const char *filename,
151
@@ -XXX,XX +XXX,XX @@ static void parallels_close(BlockDriverState *bs)
194
QemuOpts *opts, Error **errp)
152
195
{
153
/* errors are ignored, so we might as well pass exact=true */
154
bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, true,
155
- PREALLOC_MODE_OFF, NULL);
156
+ PREALLOC_MODE_OFF, 0, NULL);
157
}
158
159
g_free(s->bat_dirty_bmap);
160
diff --git a/block/qcow.c b/block/qcow.c
196
diff --git a/block/qcow.c b/block/qcow.c
161
index XXXXXXX..XXXXXXX 100644
197
index XXXXXXX..XXXXXXX 100644
162
--- a/block/qcow.c
198
--- a/block/qcow.c
163
+++ b/block/qcow.c
199
+++ b/block/qcow.c
164
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
200
@@ -XXX,XX +XXX,XX @@ static void qcow_close(BlockDriverState *bs)
165
return -E2BIG;
201
error_free(s->migration_blocker);
166
}
202
}
167
ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
203
168
- false, PREALLOC_MODE_OFF, NULL);
204
-static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
169
+ false, PREALLOC_MODE_OFF, 0, NULL);
205
- Error **errp)
170
if (ret < 0) {
206
+static int coroutine_fn GRAPH_UNLOCKED
171
return ret;
207
+qcow_co_create(BlockdevCreateOptions *opts, Error **errp)
172
}
208
{
173
@@ -XXX,XX +XXX,XX @@ static int qcow_make_empty(BlockDriverState *bs)
209
BlockdevCreateOptionsQcow *qcow_opts;
174
l1_length) < 0)
210
int header_size, backing_filename_len, l1_size, shift, i;
175
return -1;
211
@@ -XXX,XX +XXX,XX @@ exit:
176
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, false,
212
return ret;
177
- PREALLOC_MODE_OFF, NULL);
213
}
178
+ PREALLOC_MODE_OFF, 0, NULL);
214
179
if (ret < 0)
215
-static int coroutine_fn GRAPH_RDLOCK
180
return ret;
216
+static int coroutine_fn GRAPH_UNLOCKED
181
217
qcow_co_create_opts(BlockDriver *drv, const char *filename,
182
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
218
QemuOpts *opts, Error **errp)
183
index XXXXXXX..XXXXXXX 100644
219
{
184
--- a/block/qcow2-refcount.c
185
+++ b/block/qcow2-refcount.c
186
@@ -XXX,XX +XXX,XX @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
187
}
188
189
ret = bdrv_truncate(bs->file, offset + s->cluster_size, false,
190
- PREALLOC_MODE_OFF, &local_err);
191
+ PREALLOC_MODE_OFF, 0, &local_err);
192
if (ret < 0) {
193
error_report_err(local_err);
194
goto resize_fail;
195
diff --git a/block/qcow2.c b/block/qcow2.c
220
diff --git a/block/qcow2.c b/block/qcow2.c
196
index XXXXXXX..XXXXXXX 100644
221
index XXXXXXX..XXXXXXX 100644
197
--- a/block/qcow2.c
222
--- a/block/qcow2.c
198
+++ b/block/qcow2.c
223
+++ b/block/qcow2.c
199
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
224
@@ -XXX,XX +XXX,XX @@ static int qcow2_crypto_hdr_read_func(QCryptoBlock *block, size_t offset,
200
mode = PREALLOC_MODE_OFF;
225
}
226
227
228
-static int qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen,
229
- void *opaque, Error **errp)
230
+static int coroutine_fn GRAPH_RDLOCK
231
+qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, void *opaque,
232
+ Error **errp)
233
{
234
BlockDriverState *bs = opaque;
235
BDRVQcow2State *s = bs->opaque;
236
@@ -XXX,XX +XXX,XX @@ static int qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen,
237
*/
238
clusterlen = size_to_clusters(s, headerlen) * s->cluster_size;
239
assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen, false) == 0);
240
- ret = bdrv_pwrite_zeroes(bs->file,
241
- ret,
242
- clusterlen, 0);
243
+ ret = bdrv_co_pwrite_zeroes(bs->file, ret, clusterlen, 0);
244
if (ret < 0) {
245
error_setg_errno(errp, -ret, "Could not zero fill encryption header");
246
return -1;
247
@@ -XXX,XX +XXX,XX @@ static int qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen,
248
}
249
250
251
-static int qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset,
252
- const uint8_t *buf, size_t buflen,
253
- void *opaque, Error **errp)
254
+/* The graph lock must be held when called in coroutine context */
255
+static int coroutine_mixed_fn
256
+qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset,
257
+ const uint8_t *buf, size_t buflen,
258
+ void *opaque, Error **errp)
259
{
260
BlockDriverState *bs = opaque;
261
BDRVQcow2State *s = bs->opaque;
262
@@ -XXX,XX +XXX,XX @@ static int qcow2_change_backing_file(BlockDriverState *bs,
263
return qcow2_update_header(bs);
264
}
265
266
-static int qcow2_set_up_encryption(BlockDriverState *bs,
267
- QCryptoBlockCreateOptions *cryptoopts,
268
- Error **errp)
269
+static int coroutine_fn GRAPH_RDLOCK
270
+qcow2_set_up_encryption(BlockDriverState *bs,
271
+ QCryptoBlockCreateOptions *cryptoopts,
272
+ Error **errp)
273
{
274
BDRVQcow2State *s = bs->opaque;
275
QCryptoBlock *crypto = NULL;
276
@@ -XXX,XX +XXX,XX @@ static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int version,
277
return refcount_bits;
278
}
279
280
-static int coroutine_fn
281
+static int coroutine_fn GRAPH_UNLOCKED
282
qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
283
{
284
BlockdevCreateOptionsQcow2 *qcow2_opts;
285
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
286
goto out;
287
}
288
289
+ bdrv_graph_co_rdlock();
290
ret = qcow2_alloc_clusters(blk_bs(blk), 3 * cluster_size);
291
if (ret < 0) {
292
+ bdrv_graph_co_rdunlock();
293
error_setg_errno(errp, -ret, "Could not allocate clusters for qcow2 "
294
"header and refcount table");
295
goto out;
296
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
297
298
/* Create a full header (including things like feature table) */
299
ret = qcow2_update_header(blk_bs(blk));
300
+ bdrv_graph_co_rdunlock();
301
+
302
if (ret < 0) {
303
error_setg_errno(errp, -ret, "Could not update qcow2 header");
304
goto out;
305
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
306
307
/* Want encryption? There you go. */
308
if (qcow2_opts->encrypt) {
309
+ bdrv_graph_co_rdlock();
310
ret = qcow2_set_up_encryption(blk_bs(blk), qcow2_opts->encrypt, errp);
311
+ bdrv_graph_co_rdunlock();
312
+
313
if (ret < 0) {
314
goto out;
201
}
315
}
202
ret = bdrv_co_truncate(s->data_file, host_offset + cur_bytes, false,
316
@@ -XXX,XX +XXX,XX @@ out:
203
- mode, errp);
317
return ret;
204
+ mode, 0, errp);
318
}
205
if (ret < 0) {
319
206
return ret;
320
-static int coroutine_fn GRAPH_RDLOCK
207
}
321
+static int coroutine_fn GRAPH_UNLOCKED
208
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
322
qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts,
209
* always fulfilled, so there is no need to pass it on.)
323
Error **errp)
210
*/
324
{
211
bdrv_co_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
325
@@ -XXX,XX +XXX,XX @@ qcow2_co_create_opts(BlockDriver *drv, const char *filename, QemuOpts *opts,
212
- false, PREALLOC_MODE_OFF, &local_err);
326
ret = qcow2_co_create(create_options, errp);
213
+ false, PREALLOC_MODE_OFF, 0, &local_err);
327
finish:
214
if (local_err) {
328
if (ret < 0) {
215
warn_reportf_err(local_err,
329
+ bdrv_graph_co_rdlock();
216
"Failed to truncate the tail of the image: ");
330
bdrv_co_delete_file_noerr(bs);
217
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
331
bdrv_co_delete_file_noerr(data_bs);
218
* file should be resized to the exact target size, too,
332
+ bdrv_graph_co_rdunlock();
219
* so we pass @exact here.
333
} else {
220
*/
334
ret = 0;
221
- ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, errp);
222
+ ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, 0,
223
+ errp);
224
if (ret < 0) {
225
goto fail;
226
}
227
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
228
new_file_size = allocation_start +
229
nb_new_data_clusters * s->cluster_size;
230
/* Image file grows, so @exact does not matter */
231
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, errp);
232
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
233
+ errp);
234
if (ret < 0) {
235
error_prepend(errp, "Failed to resize underlying file: ");
236
qcow2_free_clusters(bs, allocation_start,
237
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
238
if (len < 0) {
239
return len;
240
}
241
- return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
242
+ return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, 0,
243
+ NULL);
244
}
335
}
245
336
diff --git a/block/qed.c b/block/qed.c
246
if (offset_into_cluster(s, offset)) {
337
index XXXXXXX..XXXXXXX 100644
247
@@ -XXX,XX +XXX,XX @@ static int make_completely_empty(BlockDriverState *bs)
338
--- a/block/qed.c
248
}
339
+++ b/block/qed.c
249
340
@@ -XXX,XX +XXX,XX @@ static void bdrv_qed_close(BlockDriverState *bs)
250
ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size, false,
341
qemu_vfree(s->l1_table);
251
- PREALLOC_MODE_OFF, &local_err);
342
}
252
+ PREALLOC_MODE_OFF, 0, &local_err);
343
253
if (ret < 0) {
344
-static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
254
error_report_err(local_err);
345
- Error **errp)
255
goto fail;
346
+static int coroutine_fn GRAPH_UNLOCKED
347
+bdrv_qed_co_create(BlockdevCreateOptions *opts, Error **errp)
348
{
349
BlockdevCreateOptionsQed *qed_opts;
350
BlockBackend *blk = NULL;
351
@@ -XXX,XX +XXX,XX @@ out:
352
return ret;
353
}
354
355
-static int coroutine_fn GRAPH_RDLOCK
356
+static int coroutine_fn GRAPH_UNLOCKED
357
bdrv_qed_co_create_opts(BlockDriver *drv, const char *filename,
358
QemuOpts *opts, Error **errp)
359
{
256
diff --git a/block/raw-format.c b/block/raw-format.c
360
diff --git a/block/raw-format.c b/block/raw-format.c
257
index XXXXXXX..XXXXXXX 100644
361
index XXXXXXX..XXXXXXX 100644
258
--- a/block/raw-format.c
362
--- a/block/raw-format.c
259
+++ b/block/raw-format.c
363
+++ b/block/raw-format.c
260
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
364
@@ -XXX,XX +XXX,XX @@ static int raw_has_zero_init(BlockDriverState *bs)
261
365
return bdrv_has_zero_init(bs->file->bs);
262
s->size = offset;
366
}
263
offset += s->offset;
367
264
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
368
-static int coroutine_fn GRAPH_RDLOCK
265
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
369
+static int coroutine_fn GRAPH_UNLOCKED
266
}
370
raw_co_create_opts(BlockDriver *drv, const char *filename,
267
371
QemuOpts *opts, Error **errp)
268
static void raw_eject(BlockDriverState *bs, bool eject_flag)
372
{
269
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
373
diff --git a/block/vdi.c b/block/vdi.c
270
index XXXXXXX..XXXXXXX 100644
374
index XXXXXXX..XXXXXXX 100644
271
--- a/block/vhdx-log.c
375
--- a/block/vdi.c
272
+++ b/block/vhdx-log.c
376
+++ b/block/vdi.c
273
@@ -XXX,XX +XXX,XX @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
377
@@ -XXX,XX +XXX,XX @@ nonallocating_write:
274
goto exit;
378
return ret;
275
}
379
}
276
ret = bdrv_truncate(bs->file, new_file_size, false,
380
277
- PREALLOC_MODE_OFF, NULL);
381
-static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
278
+ PREALLOC_MODE_OFF, 0, NULL);
382
- size_t block_size, Error **errp)
279
if (ret < 0) {
383
+static int coroutine_fn GRAPH_UNLOCKED
280
goto exit;
384
+vdi_co_do_create(BlockdevCreateOptions *create_options, size_t block_size,
281
}
385
+ Error **errp)
386
{
387
BlockdevCreateOptionsVdi *vdi_opts;
388
int ret = 0;
389
@@ -XXX,XX +XXX,XX @@ exit:
390
return ret;
391
}
392
393
-static int coroutine_fn vdi_co_create(BlockdevCreateOptions *create_options,
394
- Error **errp)
395
+static int coroutine_fn GRAPH_UNLOCKED
396
+vdi_co_create(BlockdevCreateOptions *create_options, Error **errp)
397
{
398
return vdi_co_do_create(create_options, DEFAULT_CLUSTER_SIZE, errp);
399
}
400
401
-static int coroutine_fn GRAPH_RDLOCK
402
+static int coroutine_fn GRAPH_UNLOCKED
403
vdi_co_create_opts(BlockDriver *drv, const char *filename,
404
QemuOpts *opts, Error **errp)
405
{
282
diff --git a/block/vhdx.c b/block/vhdx.c
406
diff --git a/block/vhdx.c b/block/vhdx.c
283
index XXXXXXX..XXXXXXX 100644
407
index XXXXXXX..XXXXXXX 100644
284
--- a/block/vhdx.c
408
--- a/block/vhdx.c
285
+++ b/block/vhdx.c
409
+++ b/block/vhdx.c
286
@@ -XXX,XX +XXX,XX @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
410
@@ -XXX,XX +XXX,XX @@ exit:
287
}
411
* There are 2 headers, and the highest sequence number will represent
288
412
* the active header
289
return bdrv_truncate(bs->file, *new_offset + s->block_size, false,
413
*/
290
- PREALLOC_MODE_OFF, NULL);
414
-static int coroutine_fn GRAPH_RDLOCK
291
+ PREALLOC_MODE_OFF, 0, NULL);
415
+static int coroutine_fn GRAPH_UNLOCKED
292
}
416
vhdx_create_new_headers(BlockBackend *blk, uint64_t image_size,
293
417
uint32_t log_size)
294
/*
418
{
419
@@ -XXX,XX +XXX,XX @@ vhdx_create_new_headers(BlockBackend *blk, uint64_t image_size,
420
int ret = 0;
421
VHDXHeader *hdr = NULL;
422
423
+ GRAPH_RDLOCK_GUARD();
424
+
425
hdr = g_new0(VHDXHeader, 1);
426
427
hdr->signature = VHDX_HEADER_SIGNATURE;
428
@@ -XXX,XX +XXX,XX @@ exit:
429
* .---- ~ ----------- ~ ------------ ~ ---------------- ~ -----------.
430
* 1MB
431
*/
432
-static int coroutine_fn GRAPH_RDLOCK
433
+static int coroutine_fn GRAPH_UNLOCKED
434
vhdx_co_create(BlockdevCreateOptions *opts, Error **errp)
435
{
436
BlockdevCreateOptionsVhdx *vhdx_opts;
437
@@ -XXX,XX +XXX,XX @@ delete_and_exit:
438
return ret;
439
}
440
441
-static int coroutine_fn GRAPH_RDLOCK
442
+static int coroutine_fn GRAPH_UNLOCKED
443
vhdx_co_create_opts(BlockDriver *drv, const char *filename,
444
QemuOpts *opts, Error **errp)
445
{
295
diff --git a/block/vmdk.c b/block/vmdk.c
446
diff --git a/block/vmdk.c b/block/vmdk.c
296
index XXXXXXX..XXXXXXX 100644
447
index XXXXXXX..XXXXXXX 100644
297
--- a/block/vmdk.c
448
--- a/block/vmdk.c
298
+++ b/block/vmdk.c
449
+++ b/block/vmdk.c
299
@@ -XXX,XX +XXX,XX @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
450
@@ -XXX,XX +XXX,XX @@ vmdk_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
300
}
451
return ret;
301
length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE);
452
}
302
ret = bdrv_truncate(s->extents[i].file, length, false,
453
303
- PREALLOC_MODE_OFF, NULL);
454
-static int vmdk_init_extent(BlockBackend *blk,
304
+ PREALLOC_MODE_OFF, 0, NULL);
455
- int64_t filesize, bool flat,
305
if (ret < 0) {
456
- bool compress, bool zeroed_grain,
306
return ret;
457
- Error **errp)
307
}
458
+static int GRAPH_UNLOCKED
308
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
459
+vmdk_init_extent(BlockBackend *blk, int64_t filesize, bool flat, bool compress,
309
index XXXXXXX..XXXXXXX 100644
460
+ bool zeroed_grain, Error **errp)
310
--- a/tests/test-block-iothread.c
461
{
311
+++ b/tests/test-block-iothread.c
462
int ret, i;
312
@@ -XXX,XX +XXX,XX @@ static void test_sync_op_truncate(BdrvChild *c)
463
VMDK4Header header;
464
@@ -XXX,XX +XXX,XX @@ exit:
465
return ret;
466
}
467
468
-static int coroutine_fn GRAPH_RDLOCK
469
+static int coroutine_fn GRAPH_UNLOCKED
470
vmdk_create_extent(const char *filename, int64_t filesize, bool flat,
471
bool compress, bool zeroed_grain, BlockBackend **pbb,
472
QemuOpts *opts, Error **errp)
473
@@ -XXX,XX +XXX,XX @@ static int filename_decompose(const char *filename, char *path, char *prefix,
474
* non-split format.
475
* idx >= 1: get the n-th extent if in a split subformat
476
*/
477
-typedef BlockBackend * coroutine_fn /* GRAPH_RDLOCK */
478
+typedef BlockBackend * coroutine_fn GRAPH_UNLOCKED_PTR
479
(*vmdk_create_extent_fn)(int64_t size, int idx, bool flat, bool split,
480
bool compress, bool zeroed_grain, void *opaque,
481
Error **errp);
482
@@ -XXX,XX +XXX,XX @@ static void vmdk_desc_add_extent(GString *desc,
483
g_free(basename);
484
}
485
486
-static int coroutine_fn GRAPH_RDLOCK
487
+static int coroutine_fn GRAPH_UNLOCKED
488
vmdk_co_do_create(int64_t size,
489
BlockdevVmdkSubformat subformat,
490
BlockdevVmdkAdapterType adapter_type,
491
@@ -XXX,XX +XXX,XX @@ typedef struct {
492
QemuOpts *opts;
493
} VMDKCreateOptsData;
494
495
-static BlockBackend * coroutine_fn GRAPH_RDLOCK
496
+static BlockBackend * coroutine_fn GRAPH_UNLOCKED
497
vmdk_co_create_opts_cb(int64_t size, int idx, bool flat, bool split,
498
bool compress, bool zeroed_grain, void *opaque,
499
Error **errp)
500
@@ -XXX,XX +XXX,XX @@ exit:
501
return blk;
502
}
503
504
-static int coroutine_fn GRAPH_RDLOCK
505
+static int coroutine_fn GRAPH_UNLOCKED
506
vmdk_co_create_opts(BlockDriver *drv, const char *filename,
507
QemuOpts *opts, Error **errp)
508
{
509
@@ -XXX,XX +XXX,XX @@ exit:
510
return ret;
511
}
512
513
-static BlockBackend * coroutine_fn vmdk_co_create_cb(int64_t size, int idx,
514
- bool flat, bool split,
515
- bool compress,
516
- bool zeroed_grain,
517
- void *opaque, Error **errp)
518
+static BlockBackend * coroutine_fn GRAPH_UNLOCKED
519
+vmdk_co_create_cb(int64_t size, int idx, bool flat, bool split, bool compress,
520
+ bool zeroed_grain, void *opaque, Error **errp)
521
{
313
int ret;
522
int ret;
314
523
BlockDriverState *bs;
315
/* Normal success path */
524
@@ -XXX,XX +XXX,XX @@ static BlockBackend * coroutine_fn vmdk_co_create_cb(int64_t size, int idx,
316
- ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL);
525
return blk;
317
+ ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
526
}
318
g_assert_cmpint(ret, ==, 0);
527
319
528
-static int coroutine_fn GRAPH_RDLOCK
320
/* Early error: Negative offset */
529
+static int coroutine_fn GRAPH_UNLOCKED
321
- ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, NULL);
530
vmdk_co_create(BlockdevCreateOptions *create_options, Error **errp)
322
+ ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, 0, NULL);
531
{
323
g_assert_cmpint(ret, ==, -EINVAL);
532
BlockdevCreateOptionsVmdk *opts;
324
533
diff --git a/block/vpc.c b/block/vpc.c
325
/* Error: Read-only image */
534
index XXXXXXX..XXXXXXX 100644
326
c->bs->read_only = true;
535
--- a/block/vpc.c
327
c->bs->open_flags &= ~BDRV_O_RDWR;
536
+++ b/block/vpc.c
328
537
@@ -XXX,XX +XXX,XX @@ static int calculate_rounded_image_size(BlockdevCreateOptionsVpc *vpc_opts,
329
- ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL);
538
return 0;
330
+ ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
539
}
331
g_assert_cmpint(ret, ==, -EACCES);
540
332
541
-static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
333
c->bs->read_only = false;
542
- Error **errp)
543
+static int coroutine_fn GRAPH_UNLOCKED
544
+vpc_co_create(BlockdevCreateOptions *opts, Error **errp)
545
{
546
BlockdevCreateOptionsVpc *vpc_opts;
547
BlockBackend *blk = NULL;
548
@@ -XXX,XX +XXX,XX @@ out:
549
return ret;
550
}
551
552
-static int coroutine_fn GRAPH_RDLOCK
553
+static int coroutine_fn GRAPH_UNLOCKED
554
vpc_co_create_opts(BlockDriver *drv, const char *filename,
555
QemuOpts *opts, Error **errp)
556
{
334
--
557
--
335
2.25.3
558
2.40.1
336
337
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
There are some error paths in blk_exp_add() that jump to 'fail:' before
2
'exp' is even created. So we can't just unconditionally access exp->blk.
2
3
3
Test 244 checks the expected behavior of qcow2 external data files
4
Add a NULL check, and switch from exp->blk to blk, which is available
4
with respect to zero and discarded clusters. Filesystems however
5
earlier, just to be extra sure that we really cover all cases where
5
are free to ignore discard requests, and this seems to be the
6
BlockDevOps could have been set for it (in practice, this only happens
6
case for overlayfs. Relax the tests to skip checks on the
7
in drv->create() today, so this part of the change isn't strictly
7
external data file for discarded areas, which implies not using
8
necessary).
8
qemu-img compare in the data_file_raw=on case.
9
9
10
This fixes docker tests on RHEL8.
10
Fixes: Coverity CID 1509238
11
11
Fixes: de79b52604e43fdeba6cee4f5af600b62169f2d2
12
Cc: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Cc: qemu-block@nongnu.org
13
Message-Id: <20230510203601.418015-3-kwolf@redhat.com>
14
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
14
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Message-Id: <20200409191006.24429-1-pbonzini@redhat.com>
15
Tested-by: Eric Blake <eblake@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
17
---
18
tests/qemu-iotests/244 | 10 ++++++++--
18
block/export/export.c | 6 ++++--
19
tests/qemu-iotests/244.out | 9 ++++++---
19
1 file changed, 4 insertions(+), 2 deletions(-)
20
2 files changed, 14 insertions(+), 5 deletions(-)
21
20
22
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
21
diff --git a/block/export/export.c b/block/export/export.c
23
index XXXXXXX..XXXXXXX 100755
24
--- a/tests/qemu-iotests/244
25
+++ b/tests/qemu-iotests/244
26
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'read -P 0 0 1M' \
27
echo
28
$QEMU_IO -c 'read -P 0 0 1M' \
29
-c 'read -P 0x11 1M 1M' \
30
- -c 'read -P 0 2M 2M' \
31
-c 'read -P 0x11 4M 1M' \
32
-c 'read -P 0 5M 1M' \
33
-f raw "$TEST_IMG.data" |
34
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'read -P 0 0 1M' \
35
-f $IMGFMT "$TEST_IMG" |
36
_filter_qemu_io
37
38
+# Discarded clusters are only marked as such in the qcow2 metadata, but
39
+# they can contain stale data in the external data file. Instead, zero
40
+# clusters must be zeroed in the external data file too.
41
echo
42
-$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.data"
43
+$QEMU_IO -c 'read -P 0 0 1M' \
44
+ -c 'read -P 0x11 1M 1M' \
45
+ -c 'read -P 0 3M 3M' \
46
+ -f raw "$TEST_IMG".data |
47
+ _filter_qemu_io
48
49
echo -n "qcow2 file size after I/O: "
50
du -b $TEST_IMG | cut -f1
51
diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out
52
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
53
--- a/tests/qemu-iotests/244.out
23
--- a/block/export/export.c
54
+++ b/tests/qemu-iotests/244.out
24
+++ b/block/export/export.c
55
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0
25
@@ -XXX,XX +XXX,XX @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
56
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
26
return exp;
57
read 1048576/1048576 bytes at offset 1048576
27
58
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
28
fail:
59
-read 2097152/2097152 bytes at offset 2097152
29
- blk_set_dev_ops(exp->blk, NULL, NULL);
60
-2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
30
- blk_unref(blk);
61
read 1048576/1048576 bytes at offset 4194304
31
+ if (blk) {
62
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
32
+ blk_set_dev_ops(blk, NULL, NULL);
63
read 1048576/1048576 bytes at offset 5242880
33
+ blk_unref(blk);
64
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
34
+ }
65
read 4194304/4194304 bytes at offset 2097152
35
aio_context_release(ctx);
66
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
36
if (exp) {
67
37
g_free(exp->id);
68
-Images are identical.
69
+read 1048576/1048576 bytes at offset 0
70
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
71
+read 1048576/1048576 bytes at offset 1048576
72
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
73
+read 3145728/3145728 bytes at offset 3145728
74
+3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
75
qcow2 file size after I/O: 327680
76
77
=== bdrv_co_block_status test for file and offset=0 ===
78
--
38
--
79
2.25.3
39
2.40.1
80
81
diff view generated by jsdifflib
1
The BDRV_REQ_ZERO_WRITE is currently implemented in a way that first the
1
qcow2_do_open() calls a few no_co_wrappers that wrap functions taking
2
image is possibly preallocated and then the zero flag is added to all
2
the graph lock internally as a writer. Therefore, it can't hold the
3
clusters. This means that a copy-on-write operation may be needed when
3
reader lock across these calls, it causes deadlocks. Drop the lock
4
writing to these clusters, despite having used preallocation, negating
4
temporarily around the calls.
5
one of the major benefits of preallocation.
6
7
Instead, try to forward the BDRV_REQ_ZERO_WRITE to the protocol driver,
8
and if the protocol driver can ensure that the new area reads as zeros,
9
we can skip setting the zero flag in the qcow2 layer.
10
11
Unfortunately, the same approach doesn't work for metadata
12
preallocation, so we'll still set the zero flag there.
13
5
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Message-Id: <20230510203601.418015-4-kwolf@redhat.com>
16
Message-Id: <20200424142701.67053-1-kwolf@redhat.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
17
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
10
---
20
block/qcow2.c | 22 +++++++++++++++++++---
11
block/qcow2.c | 6 ++++++
21
tests/qemu-iotests/274.out | 4 ++--
12
1 file changed, 6 insertions(+)
22
2 files changed, 21 insertions(+), 5 deletions(-)
23
13
24
diff --git a/block/qcow2.c b/block/qcow2.c
14
diff --git a/block/qcow2.c b/block/qcow2.c
25
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
26
--- a/block/qcow2.c
16
--- a/block/qcow2.c
27
+++ b/block/qcow2.c
17
+++ b/block/qcow2.c
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
18
@@ -XXX,XX +XXX,XX @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
29
/* Allocate the data area */
19
30
new_file_size = allocation_start +
20
if (open_data_file) {
31
nb_new_data_clusters * s->cluster_size;
21
/* Open external data file */
32
- /* Image file grows, so @exact does not matter */
22
+ bdrv_graph_co_rdunlock();
33
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
23
s->data_file = bdrv_co_open_child(NULL, options, "data-file", bs,
34
- errp);
24
&child_of_bds, BDRV_CHILD_DATA,
35
+ /*
25
true, errp);
36
+ * Image file grows, so @exact does not matter.
26
+ bdrv_graph_co_rdlock();
37
+ *
27
if (*errp) {
38
+ * If we need to zero out the new area, try first whether the protocol
28
ret = -EINVAL;
39
+ * driver can already take care of this.
29
goto fail;
40
+ */
30
@@ -XXX,XX +XXX,XX @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
41
+ if (flags & BDRV_REQ_ZERO_WRITE) {
31
42
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc,
32
if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) {
43
+ BDRV_REQ_ZERO_WRITE, NULL);
33
if (!s->data_file && s->image_data_file) {
44
+ if (ret >= 0) {
34
+ bdrv_graph_co_rdunlock();
45
+ flags &= ~BDRV_REQ_ZERO_WRITE;
35
s->data_file = bdrv_co_open_child(s->image_data_file, options,
46
+ }
36
"data-file", bs,
47
+ } else {
37
&child_of_bds,
48
+ ret = -1;
38
BDRV_CHILD_DATA, false, errp);
49
+ }
39
+ bdrv_graph_co_rdlock();
50
+ if (ret < 0) {
40
if (!s->data_file) {
51
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
41
ret = -EINVAL;
52
+ errp);
42
goto fail;
53
+ }
43
@@ -XXX,XX +XXX,XX @@ qcow2_do_open(BlockDriverState *bs, QDict *options, int flags,
54
if (ret < 0) {
44
fail:
55
error_prepend(errp, "Failed to resize underlying file: ");
45
g_free(s->image_data_file);
56
qcow2_free_clusters(bs, allocation_start,
46
if (open_data_file && has_data_file(bs)) {
57
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
47
+ bdrv_graph_co_rdunlock();
58
index XXXXXXX..XXXXXXX 100644
48
bdrv_unref_child(bs, s->data_file);
59
--- a/tests/qemu-iotests/274.out
49
+ bdrv_graph_co_rdlock();
60
+++ b/tests/qemu-iotests/274.out
50
s->data_file = NULL;
61
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184
51
}
62
10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
52
g_free(s->unknown_header_fields);
63
64
[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
65
-{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
66
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}]
67
68
=== preallocation=full ===
69
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
70
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 11534336
71
4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
72
73
[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
74
-{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
75
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}]
76
77
=== preallocation=off ===
78
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
79
--
53
--
80
2.25.3
54
2.40.1
81
82
diff view generated by jsdifflib
1
We want to keep TEST_IMG for the full path of the main test image, but
1
If we take a reader lock, we can't call any functions that take a writer
2
filter_testfiles() must be called for other test images before replacing
2
lock internally without causing deadlocks once the reader lock is
3
other things like the image format because the test directory path could
3
actually enforced in the main thread, too. Take the reader lock only
4
contain the format as a substring.
4
where it is actually needed.
5
6
Insert a filter_testfiles() call between both.
7
5
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Message-Id: <20230510203601.418015-5-kwolf@redhat.com>
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Message-Id: <20200424125448.63318-9-kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
10
---
14
tests/qemu-iotests/iotests.py | 5 +++--
11
qemu-img.c | 5 +++--
15
1 file changed, 3 insertions(+), 2 deletions(-)
12
1 file changed, 3 insertions(+), 2 deletions(-)
16
13
17
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
14
diff --git a/qemu-img.c b/qemu-img.c
18
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/iotests.py
16
--- a/qemu-img.c
20
+++ b/tests/qemu-iotests/iotests.py
17
+++ b/qemu-img.c
21
@@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename):
18
@@ -XXX,XX +XXX,XX @@ static BlockGraphInfoList *collect_image_info_list(bool image_opts,
22
for line in output.split('\n'):
19
}
23
if 'disk size' in line or 'actual-size' in line:
20
bs = blk_bs(blk);
24
continue
21
25
- line = line.replace(filename, 'TEST_IMG') \
22
- GRAPH_RDLOCK_GUARD_MAINLOOP();
26
- .replace(imgfmt, 'IMGFMT')
23
-
27
+ line = line.replace(filename, 'TEST_IMG')
24
/*
28
+ line = filter_testfiles(line)
25
* Note that the returned BlockGraphInfo object will not have
29
+ line = line.replace(imgfmt, 'IMGFMT')
26
* information about this image's backing node, because we have opened
30
line = re.sub('iters: [0-9]+', 'iters: XXX', line)
27
@@ -XXX,XX +XXX,XX @@ static BlockGraphInfoList *collect_image_info_list(bool image_opts,
31
line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line)
28
* duplicate the backing chain information that we obtain by walking
32
line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line)
29
* the chain manually here.
30
*/
31
+ bdrv_graph_rdlock_main_loop();
32
bdrv_query_block_graph_info(bs, &info, &err);
33
+ bdrv_graph_rdunlock_main_loop();
34
+
35
if (err) {
36
error_report_err(err);
37
blk_unref(blk);
33
--
38
--
34
2.25.3
39
2.40.1
35
36
diff view generated by jsdifflib
1
For regular files, we always get BDRV_REQ_ZERO_WRITE behaviour from the
1
If we take a reader lock, we can't call any functions that take a writer
2
OS, so we can advertise the flag and just ignore it.
2
lock internally without causing deadlocks once the reader lock is
3
actually enforced in the main thread, too. Take the reader lock only
4
where it is actually needed.
3
5
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Message-Id: <20230510203601.418015-6-kwolf@redhat.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20200424125448.63318-7-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
10
---
11
block/file-posix.c | 4 ++++
11
tests/unit/test-bdrv-drain.c | 4 ++--
12
1 file changed, 4 insertions(+)
12
1 file changed, 2 insertions(+), 2 deletions(-)
13
13
14
diff --git a/block/file-posix.c b/block/file-posix.c
14
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
15
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/file-posix.c
16
--- a/tests/unit/test-bdrv-drain.c
17
+++ b/block/file-posix.c
17
+++ b/tests/unit/test-bdrv-drain.c
18
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
18
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque)
19
#endif
19
void *buffer = g_malloc(65536);
20
20
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buffer, 65536);
21
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
21
22
+ if (S_ISREG(st.st_mode)) {
22
- GRAPH_RDLOCK_GUARD();
23
+ /* When extending regular files, we get zeros from the OS */
23
-
24
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
24
/* Pretend some internal write operation from parent to child.
25
+ }
25
* Important: We have to read from the child, not from the parent!
26
ret = 0;
26
* Draining works by first propagating it all up the tree to the
27
fail:
27
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque)
28
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
28
* everything will be drained before we go back down the tree, but
29
* we do not want that. We want to be in the middle of draining
30
* when this following requests returns. */
31
+ bdrv_graph_co_rdlock();
32
bdrv_co_preadv(tts->wait_child, 0, 65536, &qiov, 0);
33
+ bdrv_graph_co_rdunlock();
34
35
g_assert_cmpint(bs->refcnt, ==, 1);
36
29
--
37
--
30
2.25.3
38
2.40.1
31
32
diff view generated by jsdifflib
1
The raw format driver can simply forward the flag and let its bs->file
1
bdrv_unref() is a no_coroutine_fn, so calling it from coroutine context
2
child take care of actually providing the zeros.
2
is invalid. Use bdrv_co_unref() instead.
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
Message-Id: <20230510203601.418015-7-kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Message-Id: <20200424125448.63318-6-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
8
---
11
block/raw-format.c | 4 +++-
9
tests/unit/test-bdrv-drain.c | 2 +-
12
1 file changed, 3 insertions(+), 1 deletion(-)
10
1 file changed, 1 insertion(+), 1 deletion(-)
13
11
14
diff --git a/block/raw-format.c b/block/raw-format.c
12
diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
15
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
16
--- a/block/raw-format.c
14
--- a/tests/unit/test-bdrv-drain.c
17
+++ b/block/raw-format.c
15
+++ b/tests/unit/test-bdrv-drain.c
18
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
16
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn test_co_delete_by_drain(void *opaque)
19
17
g_assert_cmpint(bs->refcnt, ==, 1);
20
s->size = offset;
18
21
offset += s->offset;
19
if (!dbdd->detach_instead_of_delete) {
22
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
20
- blk_unref(blk);
23
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
21
+ blk_co_unref(blk);
24
}
22
} else {
25
23
BdrvChild *c, *next_c;
26
static void raw_eject(BlockDriverState *bs, bool eject_flag)
24
QLIST_FOREACH_SAFE(c, &bs->children, next, next_c) {
27
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
28
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
29
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
30
bs->file->bs->supported_zero_flags);
31
+ bs->supported_truncate_flags = bs->file->bs->supported_truncate_flags &
32
+ BDRV_REQ_ZERO_WRITE;
33
34
if (bs->probed && !bdrv_is_read_only(bs)) {
35
bdrv_refresh_filename(bs->file->bs);
36
--
25
--
37
2.25.3
26
2.40.1
38
39
diff view generated by jsdifflib
1
Now that node level interface bdrv_truncate() supports passing request
1
When jobs are sleeping, for example to enforce a given rate limit, they
2
flags to the block driver, expose this on the BlockBackend level, too.
2
can be reentered early, in particular in order to get paused, to update
3
the rate limit or to get cancelled.
4
5
Before this patch, they behave in this case as if they had fully
6
completed their rate limiting delay. This means that requests are sped
7
up beyond their limit, violating the constraints that the user gave us.
8
9
Change the block jobs to sleep in a loop until the necessary delay is
10
completed, while still allowing cancelling them immediately as well
11
pausing (handled by the pause point in job_sleep_ns()) and updating the
12
rate limit.
13
14
This change is also motivated by iotests cases being prone to fail
15
because drain operations pause and unpause them so often that block jobs
16
complete earlier than they are supposed to. In particular, the next
17
commit would fail iotests 030 without this change.
3
18
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
20
Message-Id: <20230510203601.418015-8-kwolf@redhat.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
21
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20200424125448.63318-4-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
23
---
11
include/sysemu/block-backend.h | 2 +-
24
include/block/blockjob_int.h | 14 ++++++++++----
12
block.c | 3 ++-
25
block/commit.c | 7 ++-----
13
block/block-backend.c | 4 ++--
26
block/mirror.c | 23 ++++++++++-------------
14
block/commit.c | 4 ++--
27
block/stream.c | 7 ++-----
15
block/crypto.c | 2 +-
28
blockjob.c | 22 ++++++++++++++++++++--
16
block/mirror.c | 2 +-
29
5 files changed, 44 insertions(+), 29 deletions(-)
17
block/qcow2.c | 4 ++--
30
18
block/qed.c | 2 +-
31
diff --git a/include/block/blockjob_int.h b/include/block/blockjob_int.h
19
block/vdi.c | 2 +-
32
index XXXXXXX..XXXXXXX 100644
20
block/vhdx.c | 4 ++--
33
--- a/include/block/blockjob_int.h
21
block/vmdk.c | 6 +++---
34
+++ b/include/block/blockjob_int.h
22
block/vpc.c | 2 +-
35
@@ -XXX,XX +XXX,XX @@ void block_job_user_resume(Job *job);
23
blockdev.c | 2 +-
36
*/
24
qemu-img.c | 2 +-
37
25
qemu-io-cmds.c | 2 +-
38
/**
26
15 files changed, 22 insertions(+), 21 deletions(-)
39
- * block_job_ratelimit_get_delay:
27
40
+ * block_job_ratelimit_processed_bytes:
28
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
41
*
29
index XXXXXXX..XXXXXXX 100644
42
- * Calculate and return delay for the next request in ns. See the documentation
30
--- a/include/sysemu/block-backend.h
43
- * of ratelimit_calculate_delay() for details.
31
+++ b/include/sysemu/block-backend.h
44
+ * To be called after some work has been done. Adjusts the delay for the next
32
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
45
+ * request. See the documentation of ratelimit_calculate_delay() for details.
33
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
46
*/
34
int bytes);
47
-int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n);
35
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
48
+void block_job_ratelimit_processed_bytes(BlockJob *job, uint64_t n);
36
- PreallocMode prealloc, Error **errp);
49
+
37
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
50
+/**
38
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
51
+ * Put the job to sleep (assuming that it wasn't canceled) to throttle it to the
39
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
52
+ * right speed according to its rate limiting.
40
int64_t pos, int size);
53
+ */
41
diff --git a/block.c b/block.c
54
+void block_job_ratelimit_sleep(BlockJob *job);
42
index XXXXXXX..XXXXXXX 100644
55
43
--- a/block.c
56
/**
44
+++ b/block.c
57
* block_job_error_action:
45
@@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk,
46
int64_t size;
47
int ret;
48
49
- ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err);
50
+ ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
51
+ &local_err);
52
if (ret < 0 && ret != -ENOTSUP) {
53
error_propagate(errp, local_err);
54
return ret;
55
diff --git a/block/block-backend.c b/block/block-backend.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block/block-backend.c
58
+++ b/block/block-backend.c
59
@@ -XXX,XX +XXX,XX @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
60
}
61
62
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
63
- PreallocMode prealloc, Error **errp)
64
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
65
{
66
if (!blk_is_available(blk)) {
67
error_setg(errp, "No medium inserted");
68
return -ENOMEDIUM;
69
}
70
71
- return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
72
+ return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp);
73
}
74
75
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
76
diff --git a/block/commit.c b/block/commit.c
58
diff --git a/block/commit.c b/block/commit.c
77
index XXXXXXX..XXXXXXX 100644
59
index XXXXXXX..XXXXXXX 100644
78
--- a/block/commit.c
60
--- a/block/commit.c
79
+++ b/block/commit.c
61
+++ b/block/commit.c
80
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp)
62
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp)
81
}
63
{
82
64
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
83
if (base_len < len) {
65
int64_t offset;
84
- ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, NULL);
66
- uint64_t delay_ns = 0;
85
+ ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL);
67
int ret = 0;
86
if (ret) {
68
int64_t n = 0; /* bytes */
87
goto out;
69
QEMU_AUTO_VFREE void *buf = NULL;
88
}
70
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp)
89
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
71
/* Note that even when no rate limit is applied we need to yield
90
* grow the backing file image if possible. If not possible,
72
* with no pending I/O here so that bdrv_drain_all() returns.
91
* we must return an error */
73
*/
92
if (length > backing_length) {
74
- job_sleep_ns(&s->common.job, delay_ns);
93
- ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF,
75
+ block_job_ratelimit_sleep(&s->common);
94
+ ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, 0,
76
if (job_is_cancelled(&s->common.job)) {
95
&local_err);
77
break;
96
if (ret < 0) {
78
}
97
error_report_err(local_err);
79
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp)
98
diff --git a/block/crypto.c b/block/crypto.c
80
job_progress_update(&s->common.job, n);
99
index XXXXXXX..XXXXXXX 100644
81
100
--- a/block/crypto.c
82
if (copy) {
101
+++ b/block/crypto.c
83
- delay_ns = block_job_ratelimit_get_delay(&s->common, n);
102
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_init_func(QCryptoBlock *block,
84
- } else {
103
* which will be used by the crypto header
85
- delay_ns = 0;
104
*/
86
+ block_job_ratelimit_processed_bytes(&s->common, n);
105
return blk_truncate(data->blk, data->size + headerlen, false,
87
}
106
- data->prealloc, errp);
88
}
107
+ data->prealloc, 0, errp);
108
}
109
110
89
111
diff --git a/block/mirror.c b/block/mirror.c
90
diff --git a/block/mirror.c b/block/mirror.c
112
index XXXXXXX..XXXXXXX 100644
91
index XXXXXXX..XXXXXXX 100644
113
--- a/block/mirror.c
92
--- a/block/mirror.c
114
+++ b/block/mirror.c
93
+++ b/block/mirror.c
94
@@ -XXX,XX +XXX,XX @@ static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset,
95
return bytes_handled;
96
}
97
98
-static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
99
+static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
100
{
101
BlockDriverState *source = s->mirror_top_bs->backing->bs;
102
MirrorOp *pseudo_op;
103
int64_t offset;
104
- uint64_t delay_ns = 0, ret = 0;
105
/* At least the first dirty chunk is mirrored in one iteration. */
106
int nb_chunks = 1;
107
bool write_zeroes_ok = bdrv_can_write_zeroes_with_unmap(blk_bs(s->target));
108
@@ -XXX,XX +XXX,XX @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
109
assert(io_bytes);
110
offset += io_bytes;
111
nb_chunks -= DIV_ROUND_UP(io_bytes, s->granularity);
112
- delay_ns = block_job_ratelimit_get_delay(&s->common, io_bytes_acct);
113
+ block_job_ratelimit_processed_bytes(&s->common, io_bytes_acct);
114
}
115
116
- ret = delay_ns;
117
fail:
118
QTAILQ_REMOVE(&s->ops_in_flight, pseudo_op, next);
119
qemu_co_queue_restart_all(&pseudo_op->waiting_requests);
120
g_free(pseudo_op);
121
-
122
- return ret;
123
}
124
125
static void mirror_free_init(MirrorBlockJob *s)
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
126
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
116
127
assert(!s->dbi);
117
if (s->bdev_length > base_length) {
128
s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap);
118
ret = blk_truncate(s->target, s->bdev_length, false,
129
for (;;) {
119
- PREALLOC_MODE_OFF, NULL);
130
- uint64_t delay_ns = 0;
120
+ PREALLOC_MODE_OFF, 0, NULL);
131
int64_t cnt, delta;
121
if (ret < 0) {
132
bool should_complete;
122
goto immediate_exit;
133
134
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
135
mirror_wait_for_free_in_flight_slot(s);
136
continue;
137
} else if (cnt != 0) {
138
- delay_ns = mirror_iteration(s);
139
+ mirror_iteration(s);
123
}
140
}
124
diff --git a/block/qcow2.c b/block/qcow2.c
141
}
125
index XXXXXXX..XXXXXXX 100644
142
126
--- a/block/qcow2.c
143
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
127
+++ b/block/qcow2.c
144
}
128
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
145
129
146
if (job_is_ready(&s->common.job) && !should_complete) {
130
/* Okay, now that we have a valid image, let's give it the right size */
147
- delay_ns = (s->in_flight == 0 &&
131
ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation,
148
- cnt == 0 ? BLOCK_JOB_SLICE_TIME : 0);
132
- errp);
149
+ if (s->in_flight == 0 && cnt == 0) {
133
+ 0, errp);
150
+ trace_mirror_before_sleep(s, cnt, job_is_ready(&s->common.job),
134
if (ret < 0) {
151
+ BLOCK_JOB_SLICE_TIME);
135
error_prepend(errp, "Could not resize image: ");
152
+ job_sleep_ns(&s->common.job, BLOCK_JOB_SLICE_TIME);
136
goto out;
153
+ }
137
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
154
+ } else {
138
* Amending image options should ensure that the image has
155
+ block_job_ratelimit_sleep(&s->common);
139
* exactly the given new values, so pass exact=true here.
156
}
157
- trace_mirror_before_sleep(s, cnt, job_is_ready(&s->common.job),
158
- delay_ns);
159
- job_sleep_ns(&s->common.job, delay_ns);
160
s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
161
}
162
163
diff --git a/block/stream.c b/block/stream.c
164
index XXXXXXX..XXXXXXX 100644
165
--- a/block/stream.c
166
+++ b/block/stream.c
167
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_run(Job *job, Error **errp)
168
BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs);
169
int64_t len;
170
int64_t offset = 0;
171
- uint64_t delay_ns = 0;
172
int error = 0;
173
int64_t n = 0; /* bytes */
174
175
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_run(Job *job, Error **errp)
176
/* Note that even when no rate limit is applied we need to yield
177
* with no pending I/O here so that bdrv_drain_all() returns.
140
*/
178
*/
141
- ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, errp);
179
- job_sleep_ns(&s->common.job, delay_ns);
142
+ ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, 0, errp);
180
+ block_job_ratelimit_sleep(&s->common);
143
blk_unref(blk);
181
if (job_is_cancelled(&s->common.job)) {
144
if (ret < 0) {
182
break;
145
return ret;
183
}
146
diff --git a/block/qed.c b/block/qed.c
184
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_run(Job *job, Error **errp)
147
index XXXXXXX..XXXXXXX 100644
185
/* Publish progress */
148
--- a/block/qed.c
186
job_progress_update(&s->common.job, n);
149
+++ b/block/qed.c
187
if (copy) {
150
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
188
- delay_ns = block_job_ratelimit_get_delay(&s->common, n);
151
* The QED format associates file length with allocation status,
189
- } else {
152
* so a new file (which is empty) must have a length of 0.
190
- delay_ns = 0;
153
*/
191
+ block_job_ratelimit_processed_bytes(&s->common, n);
154
- ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, errp);
192
}
155
+ ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, 0, errp);
193
}
156
if (ret < 0) {
194
157
goto out;
195
diff --git a/blockjob.c b/blockjob.c
158
}
196
index XXXXXXX..XXXXXXX 100644
159
diff --git a/block/vdi.c b/block/vdi.c
197
--- a/blockjob.c
160
index XXXXXXX..XXXXXXX 100644
198
+++ b/blockjob.c
161
--- a/block/vdi.c
199
@@ -XXX,XX +XXX,XX @@ static bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
162
+++ b/block/vdi.c
200
return block_job_set_speed_locked(job, speed, errp);
163
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
201
}
164
202
165
if (image_type == VDI_TYPE_STATIC) {
203
-int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n)
166
ret = blk_truncate(blk, offset + blocks * block_size, false,
204
+void block_job_ratelimit_processed_bytes(BlockJob *job, uint64_t n)
167
- PREALLOC_MODE_OFF, errp);
205
{
168
+ PREALLOC_MODE_OFF, 0, errp);
206
IO_CODE();
169
if (ret < 0) {
207
- return ratelimit_calculate_delay(&job->limit, n);
170
error_prepend(errp, "Failed to statically allocate file");
208
+ ratelimit_calculate_delay(&job->limit, n);
171
goto exit;
209
+}
172
diff --git a/block/vhdx.c b/block/vhdx.c
210
+
173
index XXXXXXX..XXXXXXX 100644
211
+void block_job_ratelimit_sleep(BlockJob *job)
174
--- a/block/vhdx.c
212
+{
175
+++ b/block/vhdx.c
213
+ uint64_t delay_ns;
176
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
214
+
177
/* All zeroes, so we can just extend the file - the end of the BAT
215
+ /*
178
* is the furthest thing we have written yet */
216
+ * Sleep at least once. If the job is reentered early, keep waiting until
179
ret = blk_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF,
217
+ * we've waited for the full time that is necessary to keep the job at the
180
- errp);
218
+ * right speed.
181
+ 0, errp);
219
+ *
182
if (ret < 0) {
220
+ * Make sure to recalculate the delay after each (possibly interrupted)
183
goto exit;
221
+ * sleep because the speed can change while the job has yielded.
184
}
222
+ */
185
} else if (type == VHDX_TYPE_FIXED) {
223
+ do {
186
ret = blk_truncate(blk, data_file_offset + image_size, false,
224
+ delay_ns = ratelimit_calculate_delay(&job->limit, 0);
187
- PREALLOC_MODE_OFF, errp);
225
+ job_sleep_ns(&job->job, delay_ns);
188
+ PREALLOC_MODE_OFF, 0, errp);
226
+ } while (delay_ns && !job_is_cancelled(&job->job));
189
if (ret < 0) {
227
}
190
goto exit;
228
191
}
229
BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp)
192
diff --git a/block/vmdk.c b/block/vmdk.c
193
index XXXXXXX..XXXXXXX 100644
194
--- a/block/vmdk.c
195
+++ b/block/vmdk.c
196
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk,
197
int gd_buf_size;
198
199
if (flat) {
200
- ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, errp);
201
+ ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, 0, errp);
202
goto exit;
203
}
204
magic = cpu_to_be32(VMDK4_MAGIC);
205
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk,
206
}
207
208
ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false,
209
- PREALLOC_MODE_OFF, errp);
210
+ PREALLOC_MODE_OFF, 0, errp);
211
if (ret < 0) {
212
goto exit;
213
}
214
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
215
/* bdrv_pwrite write padding zeros to align to sector, we don't need that
216
* for description file */
217
if (desc_offset == 0) {
218
- ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, errp);
219
+ ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, 0, errp);
220
if (ret < 0) {
221
goto exit;
222
}
223
diff --git a/block/vpc.c b/block/vpc.c
224
index XXXXXXX..XXXXXXX 100644
225
--- a/block/vpc.c
226
+++ b/block/vpc.c
227
@@ -XXX,XX +XXX,XX @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
228
/* Add footer to total size */
229
total_size += HEADER_SIZE;
230
231
- ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, errp);
232
+ ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, 0, errp);
233
if (ret < 0) {
234
return ret;
235
}
236
diff --git a/blockdev.c b/blockdev.c
237
index XXXXXXX..XXXXXXX 100644
238
--- a/blockdev.c
239
+++ b/blockdev.c
240
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
241
}
242
243
bdrv_drained_begin(bs);
244
- ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, errp);
245
+ ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp);
246
bdrv_drained_end(bs);
247
248
out:
249
diff --git a/qemu-img.c b/qemu-img.c
250
index XXXXXXX..XXXXXXX 100644
251
--- a/qemu-img.c
252
+++ b/qemu-img.c
253
@@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv)
254
* resizing, so pass @exact=true. It is of no use to report
255
* success when the image has not actually been resized.
256
*/
257
- ret = blk_truncate(blk, total_size, true, prealloc, &err);
258
+ ret = blk_truncate(blk, total_size, true, prealloc, 0, &err);
259
if (!ret) {
260
qprintf(quiet, "Image resized.\n");
261
} else {
262
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
263
index XXXXXXX..XXXXXXX 100644
264
--- a/qemu-io-cmds.c
265
+++ b/qemu-io-cmds.c
266
@@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv)
267
* exact=true. It is better to err on the "emit more errors" side
268
* than to be overly permissive.
269
*/
270
- ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, &local_err);
271
+ ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, 0, &local_err);
272
if (ret < 0) {
273
error_report_err(local_err);
274
return ret;
275
--
230
--
276
2.25.3
231
2.40.1
277
278
diff view generated by jsdifflib
1
The QMP handler qmp_object_add() and the implementation of --object in
1
There are some conditions under which we don't actually need to do
2
qemu-storage-daemon can share most of the code. Currently,
2
anything for taking a reader lock: Writing the graph is only possible
3
qemu-storage-daemon calls qmp_object_add(), but this is not correct
3
from the main context while holding the BQL. So if a reader is running
4
because different visitors need to be used.
4
in the main context under the BQL and knows that it won't be interrupted
5
until the next writer runs, we don't actually need to do anything.
5
6
6
As a first step towards a fix, make qmp_object_add() a wrapper around a
7
This is the case if the reader code neither has a nested event loop
7
new function user_creatable_add_dict() that can get an additional
8
(this is forbidden anyway while you hold the lock) nor is a coroutine
8
parameter. The handling of "props" is only required for compatibility
9
(because a writer could run when the coroutine has yielded).
9
and not required for the qemu-storage-daemon command line, so it stays
10
in qmp_object_add().
11
10
11
These conditions are exactly what bdrv_graph_rdlock_main_loop() asserts.
12
They are not fulfilled in bdrv_graph_co_rdlock(), which always runs in a
13
coroutine.
14
15
This deletes the shortcuts in bdrv_graph_co_rdlock() that skip taking
16
the reader lock in the main thread.
17
18
Reported-by: Fiona Ebner <f.ebner@proxmox.com>
19
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
20
Message-Id: <20230510203601.418015-9-kwolf@redhat.com>
21
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
23
---
14
include/qom/object_interfaces.h | 12 ++++++++++++
24
block/graph-lock.c | 10 ----------
15
qom/object_interfaces.c | 27 +++++++++++++++++++++++++++
25
1 file changed, 10 deletions(-)
16
qom/qom-qmp-cmds.c | 24 +-----------------------
17
3 files changed, 40 insertions(+), 23 deletions(-)
18
26
19
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
27
diff --git a/block/graph-lock.c b/block/graph-lock.c
20
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
21
--- a/include/qom/object_interfaces.h
29
--- a/block/graph-lock.c
22
+++ b/include/qom/object_interfaces.h
30
+++ b/block/graph-lock.c
23
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
31
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_graph_co_rdlock(void)
24
const QDict *qdict,
32
BdrvGraphRWlock *bdrv_graph;
25
Visitor *v, Error **errp);
33
bdrv_graph = qemu_get_current_aio_context()->bdrv_graph;
26
34
27
+/**
35
- /* Do not lock if in main thread */
28
+ * user_creatable_add_dict:
36
- if (qemu_in_main_thread()) {
29
+ * @qdict: the object definition
30
+ * @errp: if an error occurs, a pointer to an area to store the error
31
+ *
32
+ * Create an instance of the user creatable object that is defined by
33
+ * @qdict. The object type is taken from the QDict key 'qom-type', its
34
+ * ID from the key 'id'. The remaining entries in @qdict are used to
35
+ * initialize the object properties.
36
+ */
37
+void user_creatable_add_dict(QDict *qdict, Error **errp);
38
+
39
/**
40
* user_creatable_add_opts:
41
* @opts: the object definition
42
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/qom/object_interfaces.c
45
+++ b/qom/object_interfaces.c
46
@@ -XXX,XX +XXX,XX @@
47
#include "qapi/qmp/qerror.h"
48
#include "qapi/qmp/qjson.h"
49
#include "qapi/qmp/qstring.h"
50
+#include "qapi/qobject-input-visitor.h"
51
#include "qom/object_interfaces.h"
52
#include "qemu/help_option.h"
53
#include "qemu/module.h"
54
@@ -XXX,XX +XXX,XX @@ out:
55
return obj;
56
}
57
58
+void user_creatable_add_dict(QDict *qdict, Error **errp)
59
+{
60
+ Visitor *v;
61
+ Object *obj;
62
+ g_autofree char *type = NULL;
63
+ g_autofree char *id = NULL;
64
+
65
+ type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
66
+ if (!type) {
67
+ error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
68
+ return;
69
+ }
70
+ qdict_del(qdict, "qom-type");
71
+
72
+ id = g_strdup(qdict_get_try_str(qdict, "id"));
73
+ if (!id) {
74
+ error_setg(errp, QERR_MISSING_PARAMETER, "id");
75
+ return;
76
+ }
77
+ qdict_del(qdict, "id");
78
+
79
+ v = qobject_input_visitor_new(QOBJECT(qdict));
80
+ obj = user_creatable_add_type(type, id, qdict, v, errp);
81
+ visit_free(v);
82
+ object_unref(obj);
83
+}
84
85
Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
86
{
87
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
88
index XXXXXXX..XXXXXXX 100644
89
--- a/qom/qom-qmp-cmds.c
90
+++ b/qom/qom-qmp-cmds.c
91
@@ -XXX,XX +XXX,XX @@
92
#include "qapi/qapi-commands-qom.h"
93
#include "qapi/qmp/qdict.h"
94
#include "qapi/qmp/qerror.h"
95
-#include "qapi/qobject-input-visitor.h"
96
#include "qemu/cutils.h"
97
#include "qom/object_interfaces.h"
98
#include "qom/qom-qobject.h"
99
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
100
{
101
QObject *props;
102
QDict *pdict;
103
- Visitor *v;
104
- Object *obj;
105
- g_autofree char *type = NULL;
106
- g_autofree char *id = NULL;
107
-
108
- type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
109
- if (!type) {
110
- error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
111
- return;
37
- return;
112
- }
38
- }
113
- qdict_del(qdict, "qom-type");
114
-
39
-
115
- id = g_strdup(qdict_get_try_str(qdict, "id"));
40
for (;;) {
116
- if (!id) {
41
qatomic_set(&bdrv_graph->reader_count,
117
- error_setg(errp, QERR_MISSING_PARAMETER, "id");
42
bdrv_graph->reader_count + 1);
43
@@ -XXX,XX +XXX,XX @@ void coroutine_fn bdrv_graph_co_rdunlock(void)
44
BdrvGraphRWlock *bdrv_graph;
45
bdrv_graph = qemu_get_current_aio_context()->bdrv_graph;
46
47
- /* Do not lock if in main thread */
48
- if (qemu_in_main_thread()) {
118
- return;
49
- return;
119
- }
50
- }
120
- qdict_del(qdict, "id");
51
-
121
52
qatomic_store_release(&bdrv_graph->reader_count,
122
props = qdict_get(qdict, "props");
53
bdrv_graph->reader_count - 1);
123
if (props) {
54
/* make sure writer sees reader_count before we check has_writer */
124
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
125
qobject_unref(pdict);
126
}
127
128
- v = qobject_input_visitor_new(QOBJECT(qdict));
129
- obj = user_creatable_add_type(type, id, qdict, v, errp);
130
- visit_free(v);
131
- object_unref(obj);
132
+ user_creatable_add_dict(qdict, errp);
133
}
134
135
void qmp_object_del(const char *id, Error **errp)
136
--
55
--
137
2.25.3
56
2.40.1
138
139
diff view generated by jsdifflib
1
If BDRV_REQ_ZERO_WRITE is set and we're extending the image, calling
1
Skip TestBlockdevReopen.test_insert_compress_filter() if the 'compress'
2
qcow2_cluster_zeroize() with flags=0 does the right thing: It doesn't
2
driver isn't available.
3
undo any previous preallocation, but just adds the zero flag to all
3
4
relevant L2 entries. If an external data file is in use, a write_zeroes
4
In order to make the test succeed when the case is skipped, we also need
5
request to the data file is made instead.
5
to remove any output from it (which would be missing in the case where
6
we skip it). This is done by replacing qemu_io_log() with qemu_io(). In
7
case of failure, qemu_io() raises an exception with the output of the
8
qemu-io binary in its message, so we don't actually lose anything.
6
9
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Message-Id: <20200424125448.63318-5-kwolf@redhat.com>
11
Message-Id: <20230511143801.255021-1-kwolf@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
---
13
block/qcow2-cluster.c | 2 +-
14
tests/qemu-iotests/245 | 7 ++++---
14
block/qcow2.c | 34 ++++++++++++++++++++++++++++++++++
15
tests/qemu-iotests/245.out | 9 +--------
15
2 files changed, 35 insertions(+), 1 deletion(-)
16
2 files changed, 5 insertions(+), 11 deletions(-)
16
17
17
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
18
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
19
index XXXXXXX..XXXXXXX 100755
20
--- a/tests/qemu-iotests/245
21
+++ b/tests/qemu-iotests/245
22
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
23
self.reopen(hd0_opts, {'file': 'hd0-file'})
24
25
# Insert (and remove) a compress filter
26
+ @iotests.skip_if_unsupported(['compress'])
27
def test_insert_compress_filter(self):
28
# Add an image to the VM: hd (raw) -> hd0 (qcow2) -> hd0-file (file)
29
opts = {'driver': 'raw', 'node-name': 'hd', 'file': hd_opts(0)}
30
@@ -XXX,XX +XXX,XX @@ class TestBlockdevReopen(iotests.QMPTestCase):
31
32
# Check the first byte of the first three L2 entries and verify that
33
# the second one is compressed (0x40) while the others are not (0x80)
34
- iotests.qemu_io_log('-f', 'raw', '-c', 'read -P 0x80 0x40000 1',
35
- '-c', 'read -P 0x40 0x40008 1',
36
- '-c', 'read -P 0x80 0x40010 1', hd_path[0])
37
+ iotests.qemu_io('-f', 'raw', '-c', 'read -P 0x80 0x40000 1',
38
+ '-c', 'read -P 0x40 0x40008 1',
39
+ '-c', 'read -P 0x80 0x40010 1', hd_path[0])
40
41
# Swap the disk images of two active block devices
42
def test_swap_files(self):
43
diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out
18
index XXXXXXX..XXXXXXX 100644
44
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2-cluster.c
45
--- a/tests/qemu-iotests/245.out
20
+++ b/block/qcow2-cluster.c
46
+++ b/tests/qemu-iotests/245.out
21
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
47
@@ -XXX,XX +XXX,XX @@
22
/* Caller must pass aligned values, except at image end */
48
{"return": {}}
23
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
49
{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
24
assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
50
{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
25
- end_offset == bs->total_sectors << BDRV_SECTOR_BITS);
51
-....read 1/1 bytes at offset 262144
26
+ end_offset >= bs->total_sectors << BDRV_SECTOR_BITS);
52
-1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
27
53
-read 1/1 bytes at offset 262152
28
/* The zero flag is only supported by version 3 and newer */
54
-1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
29
if (s->qcow_version < 3) {
55
-read 1/1 bytes at offset 262160
30
diff --git a/block/qcow2.c b/block/qcow2.c
56
-1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
31
index XXXXXXX..XXXXXXX 100644
57
-
32
--- a/block/qcow2.c
58
-................
33
+++ b/block/qcow2.c
59
+....................
34
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
60
----------------------------------------------------------------------
35
61
Ran 26 tests
36
bs->supported_zero_flags = header.version >= 3 ?
62
37
BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0;
38
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
39
40
/* Repair image if dirty */
41
if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
43
g_assert_not_reached();
44
}
45
46
+ if ((flags & BDRV_REQ_ZERO_WRITE) && offset > old_length) {
47
+ uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size);
48
+
49
+ /*
50
+ * Use zero clusters as much as we can. qcow2_cluster_zeroize()
51
+ * requires a cluster-aligned start. The end may be unaligned if it is
52
+ * at the end of the image (which it is here).
53
+ */
54
+ ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0);
55
+ if (ret < 0) {
56
+ error_setg_errno(errp, -ret, "Failed to zero out new clusters");
57
+ goto fail;
58
+ }
59
+
60
+ /* Write explicit zeros for the unaligned head */
61
+ if (zero_start > old_length) {
62
+ uint64_t len = zero_start - old_length;
63
+ uint8_t *buf = qemu_blockalign0(bs, len);
64
+ QEMUIOVector qiov;
65
+ qemu_iovec_init_buf(&qiov, buf, len);
66
+
67
+ qemu_co_mutex_unlock(&s->lock);
68
+ ret = qcow2_co_pwritev_part(bs, old_length, len, &qiov, 0, 0);
69
+ qemu_co_mutex_lock(&s->lock);
70
+
71
+ qemu_vfree(buf);
72
+ if (ret < 0) {
73
+ error_setg_errno(errp, -ret, "Failed to zero out the new area");
74
+ goto fail;
75
+ }
76
+ }
77
+ }
78
+
79
if (prealloc != PREALLOC_MODE_OFF) {
80
/* Flush metadata before actually changing the image size */
81
ret = qcow2_write_caches(bs);
82
--
63
--
83
2.25.3
64
2.40.1
84
85
diff view generated by jsdifflib
1
From: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
2
3
This patch introduces support for PMR that has been defined as part of NVMe 1.4
3
QEMU's event loop supports nesting, which means that event handler
4
spec. User can now specify a pmrdev option that should point to HostMemoryBackend.
4
functions may themselves call aio_poll(). The condition that triggered a
5
pmrdev memory region will subsequently be exposed as PCI BAR 2 in emulated NVMe
5
handler must be reset before the nested aio_poll() call, otherwise the
6
device. Guest OS can perform mmio read and writes to the PMR region that will stay
6
same handler will be called and immediately re-enter aio_poll. This
7
persistent across system reboot.
7
leads to an infinite loop and stack exhaustion.
8
8
9
Signed-off-by: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
9
Poll handlers are especially prone to this issue, because they typically
10
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
10
reset their condition by finishing the processing of pending work.
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Unfortunately it is during the processing of pending work that nested
12
Message-Id: <20200330164656.9348-1-andrzej.jakowski@linux.intel.com>
12
aio_poll() calls typically occur and the condition has not yet been
13
Reviewed-by: Keith Busch <kbusch@kernel.org>
13
reset.
14
15
Disable a poll handler during ->io_poll_ready() so that a nested
16
aio_poll() call cannot invoke ->io_poll_ready() again. As a result, the
17
disabled poll handler and its associated fd handler do not run during
18
the nested aio_poll(). Calling aio_set_fd_handler() from inside nested
19
aio_poll() could cause it to run again. If the fd handler is pending
20
inside nested aio_poll(), then it will also run again.
21
22
In theory fd handlers can be affected by the same issue, but they are
23
more likely to reset the condition before calling nested aio_poll().
24
25
This is a special case and it's somewhat complex, but I don't see a way
26
around it as long as nested aio_poll() is supported.
27
28
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2186181
29
Fixes: c38270692593 ("block: Mark bdrv_co_io_(un)plug() and callers GRAPH_RDLOCK")
30
Cc: Kevin Wolf <kwolf@redhat.com>
31
Cc: Emanuele Giuseppe Esposito <eesposit@redhat.com>
32
Cc: Paolo Bonzini <pbonzini@redhat.com>
33
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
34
Message-Id: <20230502184134.534703-2-stefanha@redhat.com>
35
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
36
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
37
---
16
hw/block/nvme.h | 2 +
38
util/aio-posix.c | 11 +++++++++++
17
include/block/nvme.h | 172 +++++++++++++++++++++++++++++++++++++++++
39
1 file changed, 11 insertions(+)
18
hw/block/nvme.c | 109 ++++++++++++++++++++++++++
19
hw/block/Makefile.objs | 2 +-
20
hw/block/trace-events | 4 +
21
5 files changed, 288 insertions(+), 1 deletion(-)
22
40
23
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
41
diff --git a/util/aio-posix.c b/util/aio-posix.c
24
index XXXXXXX..XXXXXXX 100644
42
index XXXXXXX..XXXXXXX 100644
25
--- a/hw/block/nvme.h
43
--- a/util/aio-posix.c
26
+++ b/hw/block/nvme.h
44
+++ b/util/aio-posix.c
27
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeCtrl {
45
@@ -XXX,XX +XXX,XX @@ static bool aio_dispatch_handler(AioContext *ctx, AioHandler *node)
28
uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
46
poll_ready && revents == 0 &&
29
47
aio_node_check(ctx, node->is_external) &&
30
char *serial;
48
node->io_poll_ready) {
31
+ HostMemoryBackend *pmrdev;
49
+ /*
50
+ * Remove temporarily to avoid infinite loops when ->io_poll_ready()
51
+ * calls aio_poll() before clearing the condition that made the poll
52
+ * handler become ready.
53
+ */
54
+ QLIST_SAFE_REMOVE(node, node_poll);
32
+
55
+
33
NvmeNamespace *namespaces;
56
node->io_poll_ready(node->opaque);
34
NvmeSQueue **sq;
57
35
NvmeCQueue **cq;
58
+ if (!QLIST_IS_INSERTED(node, node_poll)) {
36
diff --git a/include/block/nvme.h b/include/block/nvme.h
59
+ QLIST_INSERT_HEAD(&ctx->poll_aio_handlers, node, node_poll);
37
index XXXXXXX..XXXXXXX 100644
38
--- a/include/block/nvme.h
39
+++ b/include/block/nvme.h
40
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeBar {
41
uint64_t acq;
42
uint32_t cmbloc;
43
uint32_t cmbsz;
44
+ uint8_t padding[3520]; /* not used by QEMU */
45
+ uint32_t pmrcap;
46
+ uint32_t pmrctl;
47
+ uint32_t pmrsts;
48
+ uint32_t pmrebs;
49
+ uint32_t pmrswtp;
50
+ uint32_t pmrmsc;
51
} NvmeBar;
52
53
enum NvmeCapShift {
54
@@ -XXX,XX +XXX,XX @@ enum NvmeCapShift {
55
CAP_CSS_SHIFT = 37,
56
CAP_MPSMIN_SHIFT = 48,
57
CAP_MPSMAX_SHIFT = 52,
58
+ CAP_PMR_SHIFT = 56,
59
};
60
61
enum NvmeCapMask {
62
@@ -XXX,XX +XXX,XX @@ enum NvmeCapMask {
63
CAP_CSS_MASK = 0xff,
64
CAP_MPSMIN_MASK = 0xf,
65
CAP_MPSMAX_MASK = 0xf,
66
+ CAP_PMR_MASK = 0x1,
67
};
68
69
#define NVME_CAP_MQES(cap) (((cap) >> CAP_MQES_SHIFT) & CAP_MQES_MASK)
70
@@ -XXX,XX +XXX,XX @@ enum NvmeCapMask {
71
<< CAP_MPSMIN_SHIFT)
72
#define NVME_CAP_SET_MPSMAX(cap, val) (cap |= (uint64_t)(val & CAP_MPSMAX_MASK)\
73
<< CAP_MPSMAX_SHIFT)
74
+#define NVME_CAP_SET_PMRS(cap, val) (cap |= (uint64_t)(val & CAP_PMR_MASK)\
75
+ << CAP_PMR_SHIFT)
76
77
enum NvmeCcShift {
78
CC_EN_SHIFT = 0,
79
@@ -XXX,XX +XXX,XX @@ enum NvmeCmbszMask {
80
#define NVME_CMBSZ_GETSIZE(cmbsz) \
81
(NVME_CMBSZ_SZ(cmbsz) * (1 << (12 + 4 * NVME_CMBSZ_SZU(cmbsz))))
82
83
+enum NvmePmrcapShift {
84
+ PMRCAP_RDS_SHIFT = 3,
85
+ PMRCAP_WDS_SHIFT = 4,
86
+ PMRCAP_BIR_SHIFT = 5,
87
+ PMRCAP_PMRTU_SHIFT = 8,
88
+ PMRCAP_PMRWBM_SHIFT = 10,
89
+ PMRCAP_PMRTO_SHIFT = 16,
90
+ PMRCAP_CMSS_SHIFT = 24,
91
+};
92
+
93
+enum NvmePmrcapMask {
94
+ PMRCAP_RDS_MASK = 0x1,
95
+ PMRCAP_WDS_MASK = 0x1,
96
+ PMRCAP_BIR_MASK = 0x7,
97
+ PMRCAP_PMRTU_MASK = 0x3,
98
+ PMRCAP_PMRWBM_MASK = 0xf,
99
+ PMRCAP_PMRTO_MASK = 0xff,
100
+ PMRCAP_CMSS_MASK = 0x1,
101
+};
102
+
103
+#define NVME_PMRCAP_RDS(pmrcap) \
104
+ ((pmrcap >> PMRCAP_RDS_SHIFT) & PMRCAP_RDS_MASK)
105
+#define NVME_PMRCAP_WDS(pmrcap) \
106
+ ((pmrcap >> PMRCAP_WDS_SHIFT) & PMRCAP_WDS_MASK)
107
+#define NVME_PMRCAP_BIR(pmrcap) \
108
+ ((pmrcap >> PMRCAP_BIR_SHIFT) & PMRCAP_BIR_MASK)
109
+#define NVME_PMRCAP_PMRTU(pmrcap) \
110
+ ((pmrcap >> PMRCAP_PMRTU_SHIFT) & PMRCAP_PMRTU_MASK)
111
+#define NVME_PMRCAP_PMRWBM(pmrcap) \
112
+ ((pmrcap >> PMRCAP_PMRWBM_SHIFT) & PMRCAP_PMRWBM_MASK)
113
+#define NVME_PMRCAP_PMRTO(pmrcap) \
114
+ ((pmrcap >> PMRCAP_PMRTO_SHIFT) & PMRCAP_PMRTO_MASK)
115
+#define NVME_PMRCAP_CMSS(pmrcap) \
116
+ ((pmrcap >> PMRCAP_CMSS_SHIFT) & PMRCAP_CMSS_MASK)
117
+
118
+#define NVME_PMRCAP_SET_RDS(pmrcap, val) \
119
+ (pmrcap |= (uint64_t)(val & PMRCAP_RDS_MASK) << PMRCAP_RDS_SHIFT)
120
+#define NVME_PMRCAP_SET_WDS(pmrcap, val) \
121
+ (pmrcap |= (uint64_t)(val & PMRCAP_WDS_MASK) << PMRCAP_WDS_SHIFT)
122
+#define NVME_PMRCAP_SET_BIR(pmrcap, val) \
123
+ (pmrcap |= (uint64_t)(val & PMRCAP_BIR_MASK) << PMRCAP_BIR_SHIFT)
124
+#define NVME_PMRCAP_SET_PMRTU(pmrcap, val) \
125
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRTU_MASK) << PMRCAP_PMRTU_SHIFT)
126
+#define NVME_PMRCAP_SET_PMRWBM(pmrcap, val) \
127
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRWBM_MASK) << PMRCAP_PMRWBM_SHIFT)
128
+#define NVME_PMRCAP_SET_PMRTO(pmrcap, val) \
129
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRTO_MASK) << PMRCAP_PMRTO_SHIFT)
130
+#define NVME_PMRCAP_SET_CMSS(pmrcap, val) \
131
+ (pmrcap |= (uint64_t)(val & PMRCAP_CMSS_MASK) << PMRCAP_CMSS_SHIFT)
132
+
133
+enum NvmePmrctlShift {
134
+ PMRCTL_EN_SHIFT = 0,
135
+};
136
+
137
+enum NvmePmrctlMask {
138
+ PMRCTL_EN_MASK = 0x1,
139
+};
140
+
141
+#define NVME_PMRCTL_EN(pmrctl) ((pmrctl >> PMRCTL_EN_SHIFT) & PMRCTL_EN_MASK)
142
+
143
+#define NVME_PMRCTL_SET_EN(pmrctl, val) \
144
+ (pmrctl |= (uint64_t)(val & PMRCTL_EN_MASK) << PMRCTL_EN_SHIFT)
145
+
146
+enum NvmePmrstsShift {
147
+ PMRSTS_ERR_SHIFT = 0,
148
+ PMRSTS_NRDY_SHIFT = 8,
149
+ PMRSTS_HSTS_SHIFT = 9,
150
+ PMRSTS_CBAI_SHIFT = 12,
151
+};
152
+
153
+enum NvmePmrstsMask {
154
+ PMRSTS_ERR_MASK = 0xff,
155
+ PMRSTS_NRDY_MASK = 0x1,
156
+ PMRSTS_HSTS_MASK = 0x7,
157
+ PMRSTS_CBAI_MASK = 0x1,
158
+};
159
+
160
+#define NVME_PMRSTS_ERR(pmrsts) \
161
+ ((pmrsts >> PMRSTS_ERR_SHIFT) & PMRSTS_ERR_MASK)
162
+#define NVME_PMRSTS_NRDY(pmrsts) \
163
+ ((pmrsts >> PMRSTS_NRDY_SHIFT) & PMRSTS_NRDY_MASK)
164
+#define NVME_PMRSTS_HSTS(pmrsts) \
165
+ ((pmrsts >> PMRSTS_HSTS_SHIFT) & PMRSTS_HSTS_MASK)
166
+#define NVME_PMRSTS_CBAI(pmrsts) \
167
+ ((pmrsts >> PMRSTS_CBAI_SHIFT) & PMRSTS_CBAI_MASK)
168
+
169
+#define NVME_PMRSTS_SET_ERR(pmrsts, val) \
170
+ (pmrsts |= (uint64_t)(val & PMRSTS_ERR_MASK) << PMRSTS_ERR_SHIFT)
171
+#define NVME_PMRSTS_SET_NRDY(pmrsts, val) \
172
+ (pmrsts |= (uint64_t)(val & PMRSTS_NRDY_MASK) << PMRSTS_NRDY_SHIFT)
173
+#define NVME_PMRSTS_SET_HSTS(pmrsts, val) \
174
+ (pmrsts |= (uint64_t)(val & PMRSTS_HSTS_MASK) << PMRSTS_HSTS_SHIFT)
175
+#define NVME_PMRSTS_SET_CBAI(pmrsts, val) \
176
+ (pmrsts |= (uint64_t)(val & PMRSTS_CBAI_MASK) << PMRSTS_CBAI_SHIFT)
177
+
178
+enum NvmePmrebsShift {
179
+ PMREBS_PMRSZU_SHIFT = 0,
180
+ PMREBS_RBB_SHIFT = 4,
181
+ PMREBS_PMRWBZ_SHIFT = 8,
182
+};
183
+
184
+enum NvmePmrebsMask {
185
+ PMREBS_PMRSZU_MASK = 0xf,
186
+ PMREBS_RBB_MASK = 0x1,
187
+ PMREBS_PMRWBZ_MASK = 0xffffff,
188
+};
189
+
190
+#define NVME_PMREBS_PMRSZU(pmrebs) \
191
+ ((pmrebs >> PMREBS_PMRSZU_SHIFT) & PMREBS_PMRSZU_MASK)
192
+#define NVME_PMREBS_RBB(pmrebs) \
193
+ ((pmrebs >> PMREBS_RBB_SHIFT) & PMREBS_RBB_MASK)
194
+#define NVME_PMREBS_PMRWBZ(pmrebs) \
195
+ ((pmrebs >> PMREBS_PMRWBZ_SHIFT) & PMREBS_PMRWBZ_MASK)
196
+
197
+#define NVME_PMREBS_SET_PMRSZU(pmrebs, val) \
198
+ (pmrebs |= (uint64_t)(val & PMREBS_PMRSZU_MASK) << PMREBS_PMRSZU_SHIFT)
199
+#define NVME_PMREBS_SET_RBB(pmrebs, val) \
200
+ (pmrebs |= (uint64_t)(val & PMREBS_RBB_MASK) << PMREBS_RBB_SHIFT)
201
+#define NVME_PMREBS_SET_PMRWBZ(pmrebs, val) \
202
+ (pmrebs |= (uint64_t)(val & PMREBS_PMRWBZ_MASK) << PMREBS_PMRWBZ_SHIFT)
203
+
204
+enum NvmePmrswtpShift {
205
+ PMRSWTP_PMRSWTU_SHIFT = 0,
206
+ PMRSWTP_PMRSWTV_SHIFT = 8,
207
+};
208
+
209
+enum NvmePmrswtpMask {
210
+ PMRSWTP_PMRSWTU_MASK = 0xf,
211
+ PMRSWTP_PMRSWTV_MASK = 0xffffff,
212
+};
213
+
214
+#define NVME_PMRSWTP_PMRSWTU(pmrswtp) \
215
+ ((pmrswtp >> PMRSWTP_PMRSWTU_SHIFT) & PMRSWTP_PMRSWTU_MASK)
216
+#define NVME_PMRSWTP_PMRSWTV(pmrswtp) \
217
+ ((pmrswtp >> PMRSWTP_PMRSWTV_SHIFT) & PMRSWTP_PMRSWTV_MASK)
218
+
219
+#define NVME_PMRSWTP_SET_PMRSWTU(pmrswtp, val) \
220
+ (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTU_MASK) << PMRSWTP_PMRSWTU_SHIFT)
221
+#define NVME_PMRSWTP_SET_PMRSWTV(pmrswtp, val) \
222
+ (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTV_MASK) << PMRSWTP_PMRSWTV_SHIFT)
223
+
224
+enum NvmePmrmscShift {
225
+ PMRMSC_CMSE_SHIFT = 1,
226
+ PMRMSC_CBA_SHIFT = 12,
227
+};
228
+
229
+enum NvmePmrmscMask {
230
+ PMRMSC_CMSE_MASK = 0x1,
231
+ PMRMSC_CBA_MASK = 0xfffffffffffff,
232
+};
233
+
234
+#define NVME_PMRMSC_CMSE(pmrmsc) \
235
+ ((pmrmsc >> PMRMSC_CMSE_SHIFT) & PMRMSC_CMSE_MASK)
236
+#define NVME_PMRMSC_CBA(pmrmsc) \
237
+ ((pmrmsc >> PMRMSC_CBA_SHIFT) & PMRMSC_CBA_MASK)
238
+
239
+#define NVME_PMRMSC_SET_CMSE(pmrmsc, val) \
240
+ (pmrmsc |= (uint64_t)(val & PMRMSC_CMSE_MASK) << PMRMSC_CMSE_SHIFT)
241
+#define NVME_PMRMSC_SET_CBA(pmrmsc, val) \
242
+ (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT)
243
+
244
typedef struct NvmeCmd {
245
uint8_t opcode;
246
uint8_t fuse;
247
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
248
index XXXXXXX..XXXXXXX 100644
249
--- a/hw/block/nvme.c
250
+++ b/hw/block/nvme.c
251
@@ -XXX,XX +XXX,XX @@
252
* -drive file=<file>,if=none,id=<drive_id>
253
* -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]>, \
254
* cmb_size_mb=<cmb_size_mb[optional]>, \
255
+ * [pmrdev=<mem_backend_file_id>,] \
256
* num_queues=<N[optional]>
257
*
258
* Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at
259
* offset 0 in BAR2 and supports only WDS, RDS and SQS for now.
260
+ *
261
+ * cmb_size_mb= and pmrdev= options are mutually exclusive due to limitation
262
+ * in available BAR's. cmb_size_mb= will take precedence over pmrdev= when
263
+ * both provided.
264
+ * Enabling pmr emulation can be achieved by pointing to memory-backend-file.
265
+ * For example:
266
+ * -object memory-backend-file,id=<mem_id>,share=on,mem-path=<file_path>, \
267
+ * size=<size> .... -device nvme,...,pmrdev=<mem_id>
268
*/
269
270
#include "qemu/osdep.h"
271
@@ -XXX,XX +XXX,XX @@
272
#include "sysemu/sysemu.h"
273
#include "qapi/error.h"
274
#include "qapi/visitor.h"
275
+#include "sysemu/hostmem.h"
276
#include "sysemu/block-backend.h"
277
+#include "exec/ram_addr.h"
278
279
#include "qemu/log.h"
280
#include "qemu/module.h"
281
@@ -XXX,XX +XXX,XX @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
282
NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly,
283
"invalid write to read only CMBSZ, ignored");
284
return;
285
+ case 0xE00: /* PMRCAP */
286
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrcap_readonly,
287
+ "invalid write to PMRCAP register, ignored");
288
+ return;
289
+ case 0xE04: /* TODO PMRCTL */
290
+ break;
291
+ case 0xE08: /* PMRSTS */
292
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrsts_readonly,
293
+ "invalid write to PMRSTS register, ignored");
294
+ return;
295
+ case 0xE0C: /* PMREBS */
296
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrebs_readonly,
297
+ "invalid write to PMREBS register, ignored");
298
+ return;
299
+ case 0xE10: /* PMRSWTP */
300
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrswtp_readonly,
301
+ "invalid write to PMRSWTP register, ignored");
302
+ return;
303
+ case 0xE14: /* TODO PMRMSC */
304
+ break;
305
default:
306
NVME_GUEST_ERR(nvme_ub_mmiowr_invalid,
307
"invalid MMIO write,"
308
@@ -XXX,XX +XXX,XX @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
309
}
310
311
if (addr < sizeof(n->bar)) {
312
+ /*
313
+ * When PMRWBM bit 1 is set then read from
314
+ * from PMRSTS should ensure prior writes
315
+ * made it to persistent media
316
+ */
317
+ if (addr == 0xE08 &&
318
+ (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) {
319
+ qemu_ram_writeback(n->pmrdev->mr.ram_block,
320
+ 0, n->pmrdev->size);
321
+ }
322
memcpy(&val, ptr + addr, size);
323
} else {
324
NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs,
325
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
326
error_setg(errp, "serial property not set");
327
return;
328
}
329
+
330
+ if (!n->cmb_size_mb && n->pmrdev) {
331
+ if (host_memory_backend_is_mapped(n->pmrdev)) {
332
+ char *path = object_get_canonical_path_component(OBJECT(n->pmrdev));
333
+ error_setg(errp, "can't use already busy memdev: %s", path);
334
+ g_free(path);
335
+ return;
336
+ }
60
+ }
337
+
61
+
338
+ if (!is_power_of_2(n->pmrdev->size)) {
62
/*
339
+ error_setg(errp, "pmr backend size needs to be power of 2 in size");
63
* Return early since revents was zero. aio_notify() does not count as
340
+ return;
64
* progress.
341
+ }
342
+
343
+ host_memory_backend_set_mapped(n->pmrdev, true);
344
+ }
345
+
346
blkconf_blocksizes(&n->conf);
347
if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
348
false, errp)) {
349
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
350
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
351
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem);
352
353
+ } else if (n->pmrdev) {
354
+ /* Controller Capabilities register */
355
+ NVME_CAP_SET_PMRS(n->bar.cap, 1);
356
+
357
+ /* PMR Capabities register */
358
+ n->bar.pmrcap = 0;
359
+ NVME_PMRCAP_SET_RDS(n->bar.pmrcap, 0);
360
+ NVME_PMRCAP_SET_WDS(n->bar.pmrcap, 0);
361
+ NVME_PMRCAP_SET_BIR(n->bar.pmrcap, 2);
362
+ NVME_PMRCAP_SET_PMRTU(n->bar.pmrcap, 0);
363
+ /* Turn on bit 1 support */
364
+ NVME_PMRCAP_SET_PMRWBM(n->bar.pmrcap, 0x02);
365
+ NVME_PMRCAP_SET_PMRTO(n->bar.pmrcap, 0);
366
+ NVME_PMRCAP_SET_CMSS(n->bar.pmrcap, 0);
367
+
368
+ /* PMR Control register */
369
+ n->bar.pmrctl = 0;
370
+ NVME_PMRCTL_SET_EN(n->bar.pmrctl, 0);
371
+
372
+ /* PMR Status register */
373
+ n->bar.pmrsts = 0;
374
+ NVME_PMRSTS_SET_ERR(n->bar.pmrsts, 0);
375
+ NVME_PMRSTS_SET_NRDY(n->bar.pmrsts, 0);
376
+ NVME_PMRSTS_SET_HSTS(n->bar.pmrsts, 0);
377
+ NVME_PMRSTS_SET_CBAI(n->bar.pmrsts, 0);
378
+
379
+ /* PMR Elasticity Buffer Size register */
380
+ n->bar.pmrebs = 0;
381
+ NVME_PMREBS_SET_PMRSZU(n->bar.pmrebs, 0);
382
+ NVME_PMREBS_SET_RBB(n->bar.pmrebs, 0);
383
+ NVME_PMREBS_SET_PMRWBZ(n->bar.pmrebs, 0);
384
+
385
+ /* PMR Sustained Write Throughput register */
386
+ n->bar.pmrswtp = 0;
387
+ NVME_PMRSWTP_SET_PMRSWTU(n->bar.pmrswtp, 0);
388
+ NVME_PMRSWTP_SET_PMRSWTV(n->bar.pmrswtp, 0);
389
+
390
+ /* PMR Memory Space Control register */
391
+ n->bar.pmrmsc = 0;
392
+ NVME_PMRMSC_SET_CMSE(n->bar.pmrmsc, 0);
393
+ NVME_PMRMSC_SET_CBA(n->bar.pmrmsc, 0);
394
+
395
+ pci_register_bar(pci_dev, NVME_PMRCAP_BIR(n->bar.pmrcap),
396
+ PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
397
+ PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmrdev->mr);
398
}
399
400
for (i = 0; i < n->num_namespaces; i++) {
401
@@ -XXX,XX +XXX,XX @@ static void nvme_exit(PCIDevice *pci_dev)
402
if (n->cmb_size_mb) {
403
g_free(n->cmbuf);
404
}
405
+
406
+ if (n->pmrdev) {
407
+ host_memory_backend_set_mapped(n->pmrdev, false);
408
+ }
409
msix_uninit_exclusive_bar(pci_dev);
410
}
411
412
static Property nvme_props[] = {
413
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
414
+ DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmrdev, TYPE_MEMORY_BACKEND,
415
+ HostMemoryBackend *),
416
DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
417
DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0),
418
DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64),
419
diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs
420
index XXXXXXX..XXXXXXX 100644
421
--- a/hw/block/Makefile.objs
422
+++ b/hw/block/Makefile.objs
423
@@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
424
common-obj-$(CONFIG_XEN) += xen-block.o
425
common-obj-$(CONFIG_ECC) += ecc.o
426
common-obj-$(CONFIG_ONENAND) += onenand.o
427
-common-obj-$(CONFIG_NVME_PCI) += nvme.o
428
common-obj-$(CONFIG_SWIM) += swim.o
429
430
common-obj-$(CONFIG_SH4) += tc58128.o
431
432
obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o
433
obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o
434
+obj-$(CONFIG_NVME_PCI) += nvme.o
435
436
obj-y += dataplane/
437
diff --git a/hw/block/trace-events b/hw/block/trace-events
438
index XXXXXXX..XXXXXXX 100644
439
--- a/hw/block/trace-events
440
+++ b/hw/block/trace-events
441
@@ -XXX,XX +XXX,XX @@ nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CA
442
nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
443
nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
444
nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
445
+nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored"
446
+nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored"
447
+nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored"
448
+nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored"
449
nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
450
nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
451
nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
452
--
65
--
453
2.25.3
66
2.40.1
454
455
diff view generated by jsdifflib
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1
From: Stefan Hajnoczi <stefanha@redhat.com>
2
Message-Id: <20200424125448.63318-10-kwolf@redhat.com>
2
3
Reviewed-by: Max Reitz <mreitz@redhat.com>
3
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
Message-Id: <20230502184134.534703-3-stefanha@redhat.com>
5
Tested-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
---
7
tests/qemu-iotests/274 | 155 +++++++++++++++++++++
8
tests/unit/test-nested-aio-poll.c | 130 ++++++++++++++++++++++++++++++
8
tests/qemu-iotests/274.out | 268 +++++++++++++++++++++++++++++++++++++
9
tests/unit/meson.build | 1 +
9
tests/qemu-iotests/group | 1 +
10
2 files changed, 131 insertions(+)
10
3 files changed, 424 insertions(+)
11
create mode 100644 tests/unit/test-nested-aio-poll.c
11
create mode 100755 tests/qemu-iotests/274
12
create mode 100644 tests/qemu-iotests/274.out
13
12
14
diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274
13
diff --git a/tests/unit/test-nested-aio-poll.c b/tests/unit/test-nested-aio-poll.c
15
new file mode 100755
16
index XXXXXXX..XXXXXXX
17
--- /dev/null
18
+++ b/tests/qemu-iotests/274
19
@@ -XXX,XX +XXX,XX @@
20
+#!/usr/bin/env python3
21
+#
22
+# Copyright (C) 2019 Red Hat, Inc.
23
+#
24
+# 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
26
+# the Free Software Foundation; either version 2 of the License, or
27
+# (at your option) any later version.
28
+#
29
+# This program is distributed in the hope that it will be useful,
30
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
31
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32
+# GNU General Public License for more details.
33
+#
34
+# You should have received a copy of the GNU General Public License
35
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
36
+#
37
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
38
+#
39
+# Some tests for short backing files and short overlays
40
+
41
+import iotests
42
+
43
+iotests.verify_image_format(supported_fmts=['qcow2'])
44
+iotests.verify_platform(['linux'])
45
+
46
+size_short = 1 * 1024 * 1024
47
+size_long = 2 * 1024 * 1024
48
+size_diff = size_long - size_short
49
+
50
+def create_chain() -> None:
51
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base,
52
+ str(size_long))
53
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, mid,
54
+ str(size_short))
55
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, top,
56
+ str(size_long))
57
+
58
+ iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base)
59
+
60
+def create_vm() -> iotests.VM:
61
+ vm = iotests.VM()
62
+ vm.add_blockdev('file,filename=%s,node-name=base-file' % base)
63
+ vm.add_blockdev('%s,file=base-file,node-name=base' % iotests.imgfmt)
64
+ vm.add_blockdev('file,filename=%s,node-name=mid-file' % mid)
65
+ vm.add_blockdev('%s,file=mid-file,node-name=mid,backing=base'
66
+ % iotests.imgfmt)
67
+ vm.add_drive(top, 'backing=mid,node-name=top')
68
+ return vm
69
+
70
+with iotests.FilePath('base') as base, \
71
+ iotests.FilePath('mid') as mid, \
72
+ iotests.FilePath('top') as top:
73
+
74
+ iotests.log('== Commit tests ==')
75
+
76
+ create_chain()
77
+
78
+ iotests.log('=== Check visible data ===')
79
+
80
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, top)
81
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), top)
82
+
83
+ iotests.log('=== Checking allocation status ===')
84
+
85
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
86
+ '-c', 'alloc %d %d' % (size_short, size_diff),
87
+ base)
88
+
89
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
90
+ '-c', 'alloc %d %d' % (size_short, size_diff),
91
+ mid)
92
+
93
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
94
+ '-c', 'alloc %d %d' % (size_short, size_diff),
95
+ top)
96
+
97
+ iotests.log('=== Checking map ===')
98
+
99
+ iotests.qemu_img_log('map', '--output=json', base)
100
+ iotests.qemu_img_log('map', '--output=human', base)
101
+ iotests.qemu_img_log('map', '--output=json', mid)
102
+ iotests.qemu_img_log('map', '--output=human', mid)
103
+ iotests.qemu_img_log('map', '--output=json', top)
104
+ iotests.qemu_img_log('map', '--output=human', top)
105
+
106
+ iotests.log('=== Testing qemu-img commit (top -> mid) ===')
107
+
108
+ iotests.qemu_img_log('commit', top)
109
+ iotests.img_info_log(mid)
110
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
111
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
112
+
113
+ iotests.log('=== Testing HMP commit (top -> mid) ===')
114
+
115
+ create_chain()
116
+ with create_vm() as vm:
117
+ vm.launch()
118
+ vm.qmp_log('human-monitor-command', command_line='commit drive0')
119
+
120
+ iotests.img_info_log(mid)
121
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
122
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
123
+
124
+ iotests.log('=== Testing QMP active commit (top -> mid) ===')
125
+
126
+ create_chain()
127
+ with create_vm() as vm:
128
+ vm.launch()
129
+ vm.qmp_log('block-commit', device='top', base_node='mid',
130
+ job_id='job0', auto_dismiss=False)
131
+ vm.run_job('job0', wait=5)
132
+
133
+ iotests.img_info_log(mid)
134
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
135
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
136
+
137
+
138
+ iotests.log('== Resize tests ==')
139
+
140
+ # Use different sizes for different allocation modes:
141
+ #
142
+ # We want to have at least one test where 32 bit truncation in the size of
143
+ # the overlapping area becomes visible. This is covered by the
144
+ # prealloc='off' case (1G to 6G is an overlap of 5G).
145
+ #
146
+ # However, we can only do this for modes that don't preallocate data
147
+ # because otherwise we might run out of space on the test host.
148
+ #
149
+ # We also want to test some unaligned combinations.
150
+ for (prealloc, base_size, top_size_old, top_size_new, off) in [
151
+ ('off', '6G', '1G', '8G', '5G'),
152
+ ('metadata', '32G', '30G', '33G', '31G'),
153
+ ('falloc', '10M', '5M', '15M', '9M'),
154
+ ('full', '16M', '8M', '12M', '11M'),
155
+ ('off', '384k', '253k', '512k', '253k'),
156
+ ('off', '400k', '256k', '512k', '336k'),
157
+ ('off', '512k', '256k', '500k', '436k')]:
158
+
159
+ iotests.log('=== preallocation=%s ===' % prealloc)
160
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, base_size)
161
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, top,
162
+ top_size_old)
163
+ iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base)
164
+
165
+ # After this, top_size_old to base_size should be allocated/zeroed.
166
+ #
167
+ # In theory, leaving base_size to top_size_new unallocated would be
168
+ # correct, but in practice, if we zero out anything, we zero out
169
+ # everything up to top_size_new.
170
+ iotests.qemu_img_log('resize', '-f', iotests.imgfmt,
171
+ '--preallocation', prealloc, top, top_size_new)
172
+ iotests.qemu_io_log('-c', 'read -P 0 %s 64k' % off, top)
173
+ iotests.qemu_io_log('-c', 'map', top)
174
+ iotests.qemu_img_log('map', '--output=json', top)
175
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
176
new file mode 100644
14
new file mode 100644
177
index XXXXXXX..XXXXXXX
15
index XXXXXXX..XXXXXXX
178
--- /dev/null
16
--- /dev/null
179
+++ b/tests/qemu-iotests/274.out
17
+++ b/tests/unit/test-nested-aio-poll.c
180
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@
181
+== Commit tests ==
19
+/* SPDX-License-Identifier: GPL-2.0-or-later */
182
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
20
+/*
21
+ * Test that poll handlers are not re-entrant in nested aio_poll()
22
+ *
23
+ * Copyright Red Hat
24
+ *
25
+ * Poll handlers are usually level-triggered. That means they continue firing
26
+ * until the condition is reset (e.g. a virtqueue becomes empty). If a poll
27
+ * handler calls nested aio_poll() before the condition is reset, then infinite
28
+ * recursion occurs.
29
+ *
30
+ * aio_poll() is supposed to prevent this by disabling poll handlers in nested
31
+ * aio_poll() calls. This test case checks that this is indeed what happens.
32
+ */
33
+#include "qemu/osdep.h"
34
+#include "block/aio.h"
35
+#include "qapi/error.h"
183
+
36
+
184
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
37
+typedef struct {
38
+ AioContext *ctx;
185
+
39
+
186
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
40
+ /* This is the EventNotifier that drives the test */
41
+ EventNotifier poll_notifier;
187
+
42
+
188
+wrote 2097152/2097152 bytes at offset 0
43
+ /* This EventNotifier is only used to wake aio_poll() */
189
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
44
+ EventNotifier dummy_notifier;
190
+
45
+
191
+=== Check visible data ===
46
+ bool nested;
192
+read 1048576/1048576 bytes at offset 0
47
+} TestData;
193
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
194
+
48
+
195
+read 1048576/1048576 bytes at offset 1048576
49
+static void io_read(EventNotifier *notifier)
196
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
50
+{
51
+ fprintf(stderr, "%s %p\n", __func__, notifier);
52
+ event_notifier_test_and_clear(notifier);
53
+}
197
+
54
+
198
+=== Checking allocation status ===
55
+static bool io_poll_true(void *opaque)
199
+1048576/1048576 bytes allocated at offset 0 bytes
56
+{
200
+1048576/1048576 bytes allocated at offset 1 MiB
57
+ fprintf(stderr, "%s %p\n", __func__, opaque);
58
+ return true;
59
+}
201
+
60
+
202
+0/1048576 bytes allocated at offset 0 bytes
61
+static bool io_poll_false(void *opaque)
203
+0/0 bytes allocated at offset 1 MiB
62
+{
63
+ fprintf(stderr, "%s %p\n", __func__, opaque);
64
+ return false;
65
+}
204
+
66
+
205
+0/1048576 bytes allocated at offset 0 bytes
67
+static void io_poll_ready(EventNotifier *notifier)
206
+0/1048576 bytes allocated at offset 1 MiB
68
+{
69
+ TestData *td = container_of(notifier, TestData, poll_notifier);
207
+
70
+
208
+=== Checking map ===
71
+ fprintf(stderr, "> %s\n", __func__);
209
+[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}]
210
+
72
+
211
+Offset Length Mapped to File
73
+ g_assert(!td->nested);
212
+0 0x200000 0x50000 TEST_DIR/PID-base
74
+ td->nested = true;
213
+
75
+
214
+[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}]
76
+ /* Wake the following nested aio_poll() call */
77
+ event_notifier_set(&td->dummy_notifier);
215
+
78
+
216
+Offset Length Mapped to File
79
+ /* This nested event loop must not call io_poll()/io_poll_ready() */
217
+0 0x100000 0x50000 TEST_DIR/PID-base
80
+ g_assert(aio_poll(td->ctx, true));
218
+
81
+
219
+[{ "start": 0, "length": 1048576, "depth": 2, "zero": false, "data": true, "offset": 327680},
82
+ td->nested = false;
220
+{ "start": 1048576, "length": 1048576, "depth": 0, "zero": true, "data": false}]
221
+
83
+
222
+Offset Length Mapped to File
84
+ fprintf(stderr, "< %s\n", __func__);
223
+0 0x100000 0x50000 TEST_DIR/PID-base
85
+}
224
+
86
+
225
+=== Testing qemu-img commit (top -> mid) ===
87
+/* dummy_notifier never triggers */
226
+Image committed.
88
+static void io_poll_never_ready(EventNotifier *notifier)
89
+{
90
+ g_assert_not_reached();
91
+}
227
+
92
+
228
+image: TEST_IMG
93
+static void test(void)
229
+file format: IMGFMT
94
+{
230
+virtual size: 2 MiB (2097152 bytes)
95
+ TestData td = {
231
+cluster_size: 65536
96
+ .ctx = aio_context_new(&error_abort),
232
+backing file: TEST_DIR/PID-base
97
+ };
233
+Format specific information:
234
+ compat: 1.1
235
+ lazy refcounts: false
236
+ refcount bits: 16
237
+ corrupt: false
238
+
98
+
239
+read 1048576/1048576 bytes at offset 0
99
+ qemu_set_current_aio_context(td.ctx);
240
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
241
+
100
+
242
+read 1048576/1048576 bytes at offset 1048576
101
+ /* Enable polling */
243
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
102
+ aio_context_set_poll_params(td.ctx, 1000000, 2, 2, &error_abort);
244
+
103
+
245
+=== Testing HMP commit (top -> mid) ===
104
+ /*
246
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
105
+ * The GSource is unused but this has the side-effect of changing the fdmon
106
+ * that AioContext uses.
107
+ */
108
+ aio_get_g_source(td.ctx);
247
+
109
+
248
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
110
+ /* Make the event notifier active (set) right away */
111
+ event_notifier_init(&td.poll_notifier, 1);
112
+ aio_set_event_notifier(td.ctx, &td.poll_notifier, false,
113
+ io_read, io_poll_true, io_poll_ready);
249
+
114
+
250
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
115
+ /* This event notifier will be used later */
116
+ event_notifier_init(&td.dummy_notifier, 0);
117
+ aio_set_event_notifier(td.ctx, &td.dummy_notifier, false,
118
+ io_read, io_poll_false, io_poll_never_ready);
251
+
119
+
252
+wrote 2097152/2097152 bytes at offset 0
120
+ /* Consume aio_notify() */
253
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
121
+ g_assert(!aio_poll(td.ctx, false));
254
+
122
+
255
+{"execute": "human-monitor-command", "arguments": {"command-line": "commit drive0"}}
123
+ /*
256
+{"return": ""}
124
+ * Run the io_read() handler. This has the side-effect of activating
257
+image: TEST_IMG
125
+ * polling in future aio_poll() calls.
258
+file format: IMGFMT
126
+ */
259
+virtual size: 2 MiB (2097152 bytes)
127
+ g_assert(aio_poll(td.ctx, true));
260
+cluster_size: 65536
261
+backing file: TEST_DIR/PID-base
262
+Format specific information:
263
+ compat: 1.1
264
+ lazy refcounts: false
265
+ refcount bits: 16
266
+ corrupt: false
267
+
128
+
268
+read 1048576/1048576 bytes at offset 0
129
+ /* The second time around the io_poll()/io_poll_ready() handler runs */
269
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
130
+ g_assert(aio_poll(td.ctx, true));
270
+
131
+
271
+read 1048576/1048576 bytes at offset 1048576
132
+ /* Run io_poll()/io_poll_ready() one more time to show it keeps working */
272
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
133
+ g_assert(aio_poll(td.ctx, true));
273
+
134
+
274
+=== Testing QMP active commit (top -> mid) ===
135
+ aio_set_event_notifier(td.ctx, &td.dummy_notifier, false,
275
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
136
+ NULL, NULL, NULL);
137
+ aio_set_event_notifier(td.ctx, &td.poll_notifier, false, NULL, NULL, NULL);
138
+ event_notifier_cleanup(&td.dummy_notifier);
139
+ event_notifier_cleanup(&td.poll_notifier);
140
+ aio_context_unref(td.ctx);
141
+}
276
+
142
+
277
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
143
+int main(int argc, char **argv)
278
+
144
+{
279
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
145
+ g_test_init(&argc, &argv, NULL);
280
+
146
+ g_test_add_func("/nested-aio-poll", test);
281
+wrote 2097152/2097152 bytes at offset 0
147
+ return g_test_run();
282
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
148
+}
283
+
149
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
284
+{"execute": "block-commit", "arguments": {"auto-dismiss": false, "base-node": "mid", "device": "top", "job-id": "job0"}}
285
+{"return": {}}
286
+{"execute": "job-complete", "arguments": {"id": "job0"}}
287
+{"return": {}}
288
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
289
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
290
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
291
+{"return": {}}
292
+image: TEST_IMG
293
+file format: IMGFMT
294
+virtual size: 2 MiB (2097152 bytes)
295
+cluster_size: 65536
296
+backing file: TEST_DIR/PID-base
297
+Format specific information:
298
+ compat: 1.1
299
+ lazy refcounts: false
300
+ refcount bits: 16
301
+ corrupt: false
302
+
303
+read 1048576/1048576 bytes at offset 0
304
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
305
+
306
+read 1048576/1048576 bytes at offset 1048576
307
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
308
+
309
+== Resize tests ==
310
+=== preallocation=off ===
311
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16
312
+
313
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=1073741824 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
314
+
315
+wrote 65536/65536 bytes at offset 5368709120
316
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
317
+
318
+Image resized.
319
+
320
+read 65536/65536 bytes at offset 5368709120
321
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
322
+
323
+1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0)
324
+7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000)
325
+
326
+[{ "start": 0, "length": 1073741824, "depth": 1, "zero": true, "data": false},
327
+{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}]
328
+
329
+=== preallocation=metadata ===
330
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16
331
+
332
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=32212254720 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
333
+
334
+wrote 65536/65536 bytes at offset 33285996544
335
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
336
+
337
+Image resized.
338
+
339
+read 65536/65536 bytes at offset 33285996544
340
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
341
+
342
+30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0)
343
+3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000)
344
+
345
+[{ "start": 0, "length": 32212254720, "depth": 1, "zero": true, "data": false},
346
+{ "start": 32212254720, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 327680},
347
+{ "start": 32749125632, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 537264128},
348
+{ "start": 33285996544, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1074200576},
349
+{ "start": 33822867456, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1611137024},
350
+{ "start": 34359738368, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2148139008},
351
+{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}]
352
+
353
+=== preallocation=falloc ===
354
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16
355
+
356
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=5242880 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
357
+
358
+wrote 65536/65536 bytes at offset 9437184
359
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
360
+
361
+Image resized.
362
+
363
+read 65536/65536 bytes at offset 9437184
364
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
365
+
366
+5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0)
367
+10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
368
+
369
+[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
370
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
371
+
372
+=== preallocation=full ===
373
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
374
+
375
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=8388608 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
376
+
377
+wrote 65536/65536 bytes at offset 11534336
378
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
379
+
380
+Image resized.
381
+
382
+read 65536/65536 bytes at offset 11534336
383
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
384
+
385
+8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0)
386
+4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
387
+
388
+[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
389
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
390
+
391
+=== preallocation=off ===
392
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
393
+
394
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=259072 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
395
+
396
+wrote 65536/65536 bytes at offset 259072
397
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
398
+
399
+Image resized.
400
+
401
+read 65536/65536 bytes at offset 259072
402
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
403
+
404
+192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0)
405
+320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000)
406
+
407
+[{ "start": 0, "length": 196608, "depth": 1, "zero": true, "data": false},
408
+{ "start": 196608, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": 327680},
409
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
410
+
411
+=== preallocation=off ===
412
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16
413
+
414
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
415
+
416
+wrote 65536/65536 bytes at offset 344064
417
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
418
+
419
+Image resized.
420
+
421
+read 65536/65536 bytes at offset 344064
422
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
423
+
424
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
425
+256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000)
426
+
427
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
428
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
429
+
430
+=== preallocation=off ===
431
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16
432
+
433
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
434
+
435
+wrote 65536/65536 bytes at offset 446464
436
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
437
+
438
+Image resized.
439
+
440
+read 65536/65536 bytes at offset 446464
441
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
442
+
443
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
444
+244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000)
445
+
446
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
447
+{ "start": 262144, "length": 249856, "depth": 0, "zero": true, "data": false}]
448
+
449
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
450
index XXXXXXX..XXXXXXX 100644
150
index XXXXXXX..XXXXXXX 100644
451
--- a/tests/qemu-iotests/group
151
--- a/tests/unit/meson.build
452
+++ b/tests/qemu-iotests/group
152
+++ b/tests/unit/meson.build
453
@@ -XXX,XX +XXX,XX @@
153
@@ -XXX,XX +XXX,XX @@ if have_block
454
270 rw backing quick
154
'test-coroutine': [testblock],
455
272 rw
155
'test-aio': [testblock],
456
273 backing quick
156
'test-aio-multithread': [testblock],
457
+274 rw backing
157
+ 'test-nested-aio-poll': [testblock],
458
277 rw quick
158
'test-throttle': [testblock],
459
279 rw backing quick
159
'test-thread-pool': [testblock],
460
280 rw migration quick
160
'test-hbitmap': [testblock],
461
--
161
--
462
2.25.3
162
2.40.1
463
464
diff view generated by jsdifflib