1
The following changes since commit 5ec2eca83dc478ddf24077e02a8b34dd26cd3ff9:
1
The following changes since commit 418fa86dd465b4fd8394373cf83db8fa65d7611c:
2
2
3
Merge remote-tracking branch 'remotes/awilliam/tags/vfio-updates-20190613.0' into staging (2019-06-14 09:33:55 +0100)
3
Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-040220-1' into staging (2020-02-04 18:55:06 +0000)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://github.com/XanClic/qemu.git tags/pull-block-2019-06-14
7
https://github.com/XanClic/qemu.git tags/pull-block-2020-02-06
8
8
9
for you to fetch changes up to 21c1ce592a144188dfe59b9e156a97da412a59a2:
9
for you to fetch changes up to a541fcc27c98b96da187c7d4573f3270f3ddd283:
10
10
11
iotests: Test qemu-img convert -C --salvage (2019-06-14 15:09:42 +0200)
11
iotests: add test for backup-top failure on permission activation (2020-02-06 13:47:45 +0100)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
14
Block patches:
15
- Allow blockdev-backup from nodes that are not in qemu's main AIO
15
- Drop BDRV_SECTOR_SIZE from qcow2
16
context to newly added nodes
16
- Allow Python iotests to be added to the auto group
17
- Add salvaging mode to qemu-img convert
17
(and add some)
18
- Minor fixes to tests, documentation, and for less Valgrind annoyance
18
- Fix for the backup job
19
- Fix memleak in bdrv_refresh_filename()
20
- Use GStrings in two places for greater efficiency (than manually
21
handling string allocation)
19
22
20
----------------------------------------------------------------
23
----------------------------------------------------------------
21
Andrey Shinkevich (1):
24
Alberto Garcia (8):
22
hw/block/fdc: floppy command FIFO memory initialization
25
qcow2: Assert that host cluster offsets fit in L2 table entries
26
block: Use a GString in bdrv_perm_names()
27
qcow2: Use a GString in report_unsupported_feature()
28
qcow2: Don't round the L1 table allocation up to the sector size
29
qcow2: Tighten cluster_offset alignment assertions
30
qcow2: Use bs->bl.request_alignment when updating an L1 entry
31
qcow2: Don't require aligned offsets in qcow2_co_copy_range_from()
32
qcow2: Use BDRV_SECTOR_SIZE instead of the hardcoded value
23
33
24
John Snow (6):
34
John Snow (1):
25
blockdev-backup: don't check aio_context too early
35
iotests: remove 'linux' from default supported platforms
26
iotests.py: do not use infinite waits
27
QEMUMachine: add events_wait method
28
iotests.py: rewrite run_job to be pickier
29
iotests: add iotest 256 for testing blockdev-backup across iothread
30
contexts
31
event_match: always match on None value
32
36
33
Max Reitz (12):
37
Pan Nengyuan (1):
34
iotests: Filter 175's allocation information
38
block: fix memleaks in bdrv_refresh_filename
35
iotests: Fix intermittent failure in 219
36
qemu-img: Fix options leakage in img_rebase()
37
qapi/block-core: Overlays are not snapshots
38
blockdev: Overlays are not snapshots
39
qemu-img: Move quiet into ImgConvertState
40
qemu-img: Add salvaging mode to convert
41
blkdebug: Add @iotype error option
42
blkdebug: Add "none" event
43
blkdebug: Inject errors on .bdrv_co_block_status()
44
iotests: Test qemu-img convert --salvage
45
iotests: Test qemu-img convert -C --salvage
46
39
47
Vladimir Sementsov-Ogievskiy (1):
40
Thomas Huth (5):
48
iotests: restrict 254 to support only qcow2
41
iotests: Test 041 only works on certain systems
42
iotests: Test 183 does not work on macOS and OpenBSD
43
iotests: Check for the availability of the required devices in 267 and
44
127
45
iotests: Skip Python-based tests if QEMU does not support virtio-blk
46
iotests: Enable more tests in the 'auto' group to improve test
47
coverage
49
48
50
qapi/block-core.json | 53 ++++++++---
49
Vladimir Sementsov-Ogievskiy (2):
51
block/blkdebug.c | 60 ++++++++++--
50
block/backup-top: fix failure path
52
blockdev.c | 14 +--
51
iotests: add test for backup-top failure on permission activation
53
hw/block/fdc.c | 1 +
52
54
qemu-img.c | 106 +++++++++++++++------
53
block.c | 12 +++--
55
python/qemu/__init__.py | 67 ++++++++++----
54
block/backup-top.c | 21 ++++----
56
qemu-img-cmds.hx | 4 +-
55
block/qcow2-cluster.c | 44 +++++++++++------
57
qemu-img.texi | 4 +
56
block/qcow2-refcount.c | 2 +-
58
tests/qemu-iotests/082 | 1 +
57
block/qcow2-snapshot.c | 3 +-
59
tests/qemu-iotests/082.out | 3 +
58
block/qcow2.c | 46 ++++++++----------
60
tests/qemu-iotests/085.out | 10 +-
59
tests/qemu-iotests/041 | 3 +-
61
tests/qemu-iotests/175 | 26 +++++-
60
tests/qemu-iotests/127 | 2 +
62
tests/qemu-iotests/175.out | 8 +-
61
tests/qemu-iotests/183 | 1 +
63
tests/qemu-iotests/219 | 13 ++-
62
tests/qemu-iotests/267 | 2 +
64
tests/qemu-iotests/251 | 170 ++++++++++++++++++++++++++++++++++
63
tests/qemu-iotests/283 | 92 +++++++++++++++++++++++++++++++++++
65
tests/qemu-iotests/251.out | 43 +++++++++
64
tests/qemu-iotests/283.out | 8 +++
66
tests/qemu-iotests/254 | 2 +
65
tests/qemu-iotests/check | 12 ++++-
67
tests/qemu-iotests/256 | 122 ++++++++++++++++++++++++
66
tests/qemu-iotests/common.rc | 14 ++++++
68
tests/qemu-iotests/256.out | 119 ++++++++++++++++++++++++
67
tests/qemu-iotests/group | 15 +++---
69
tests/qemu-iotests/group | 2 +
68
tests/qemu-iotests/iotests.py | 16 ++++--
70
tests/qemu-iotests/iotests.py | 60 +++++++-----
69
16 files changed, 220 insertions(+), 73 deletions(-)
71
21 files changed, 772 insertions(+), 116 deletions(-)
70
create mode 100644 tests/qemu-iotests/283
72
create mode 100755 tests/qemu-iotests/251
71
create mode 100644 tests/qemu-iotests/283.out
73
create mode 100644 tests/qemu-iotests/251.out
74
create mode 100755 tests/qemu-iotests/256
75
create mode 100644 tests/qemu-iotests/256.out
76
72
77
--
73
--
78
2.21.0
74
2.24.1
79
75
80
76
diff view generated by jsdifflib
1
We do not support this combination (yet), so this should yield an error
1
From: Alberto Garcia <berto@igalia.com>
2
message.
3
2
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
The standard cluster descriptor in L2 table entries has a field to
5
Tested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
store the host cluster offset. When we need to get that offset from an
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
entry we use L2E_OFFSET_MASK to ensure that we only use the bits that
7
Message-id: 20190507203508.18026-8-mreitz@redhat.com
6
belong to that field.
7
8
But while that mask is used every time we read from an L2 entry, it
9
is never used when we write to it. Due to the QCOW_MAX_CLUSTER_OFFSET
10
limit set in the cluster allocation code QEMU can never produce
11
offsets that don't fit in that field so any such offset would indicate
12
a bug in QEMU.
13
14
Compressed cluster descriptors contain two fields (host cluster offset
15
and size of the compressed data) and the situation with them is
16
similar. In this case the masks are not constant but are stored in the
17
csize_mask and cluster_offset_mask fields of BDRVQcow2State.
18
19
Signed-off-by: Alberto Garcia <berto@igalia.com>
20
Reviewed-by: Eric Blake <eblake@redhat.com>
21
Message-id: 20200113161146.20099-1-berto@igalia.com
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
22
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
---
23
---
10
tests/qemu-iotests/082 | 1 +
24
block/qcow2-cluster.c | 14 ++++++++++++--
11
tests/qemu-iotests/082.out | 3 +++
25
1 file changed, 12 insertions(+), 2 deletions(-)
12
2 files changed, 4 insertions(+)
13
26
14
diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082
27
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
15
index XXXXXXX..XXXXXXX 100755
16
--- a/tests/qemu-iotests/082
17
+++ b/tests/qemu-iotests/082
18
@@ -XXX,XX +XXX,XX @@ echo === convert: -C and other options ===
19
run_qemu_img convert -C -S 4k -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target
20
run_qemu_img convert -C -S 8k -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target
21
run_qemu_img convert -C -c -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target
22
+run_qemu_img convert -C --salvage -O $IMGFMT "$TEST_IMG" "$TEST_IMG".target
23
24
echo
25
echo === amend: Options specified more than once ===
26
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
27
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
28
--- a/tests/qemu-iotests/082.out
29
--- a/block/qcow2-cluster.c
29
+++ b/tests/qemu-iotests/082.out
30
+++ b/block/qcow2-cluster.c
30
@@ -XXX,XX +XXX,XX @@ qemu-img: Cannot enable copy offloading when -S is used
31
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
31
Testing: convert -C -c -O qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.target
32
(cluster_offset + compressed_size - 1) / QCOW2_COMPRESSED_SECTOR_SIZE -
32
qemu-img: Cannot enable copy offloading when -c is used
33
(cluster_offset / QCOW2_COMPRESSED_SECTOR_SIZE);
33
34
34
+Testing: convert -C --salvage -O qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.target
35
+ /* The offset and size must fit in their fields of the L2 table entry */
35
+qemu-img: Cannot use copy offloading in salvaging mode
36
+ assert((cluster_offset & s->cluster_offset_mask) == cluster_offset);
37
+ assert((nb_csectors & s->csize_mask) == nb_csectors);
36
+
38
+
37
=== amend: Options specified more than once ===
39
cluster_offset |= QCOW_OFLAG_COMPRESSED |
38
40
((uint64_t)nb_csectors << s->csize_shift);
39
Testing: amend -f foo -f qcow2 -o lazy_refcounts=on TEST_DIR/t.qcow2
41
42
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
43
44
assert(l2_index + m->nb_clusters <= s->l2_slice_size);
45
for (i = 0; i < m->nb_clusters; i++) {
46
+ uint64_t offset = cluster_offset + (i << s->cluster_bits);
47
/* if two concurrent writes happen to the same unallocated cluster
48
* each write allocates separate cluster and writes data concurrently.
49
* The first one to complete updates l2 table with pointer to its
50
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
51
old_cluster[j++] = l2_slice[l2_index + i];
52
}
53
54
- l2_slice[l2_index + i] = cpu_to_be64((cluster_offset +
55
- (i << s->cluster_bits)) | QCOW_OFLAG_COPIED);
56
+ /* The offset must fit in the offset field of the L2 table entry */
57
+ assert((offset & L2E_OFFSET_MASK) == offset);
58
+
59
+ l2_slice[l2_index + i] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
60
}
61
62
63
@@ -XXX,XX +XXX,XX @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
64
goto fail;
65
}
66
67
+ /* The offset must fit in the offset field */
68
+ assert((offset & L2E_OFFSET_MASK) == offset);
69
+
70
if (l2_refcount > 1) {
71
/* For shared L2 tables, set the refcount accordingly
72
* (it is already 1 and needs to be l2_refcount) */
40
--
73
--
41
2.21.0
74
2.24.1
42
75
43
76
diff view generated by jsdifflib
1
Together with @iotypes and @sector, this can be used to trap e.g. the
1
From: Alberto Garcia <berto@igalia.com>
2
first read or write access to a certain sector without having to know
3
what happens internally in the block layer, i.e. which "real" events
4
happen right before such an access.
5
2
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
This is a bit more efficient than having to allocate and free memory
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
for each new permission.
8
Message-id: 20190507203508.18026-5-mreitz@redhat.com
5
6
The default size (30) is enough for "consistent read, write, resize".
7
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Message-id: 20200110171518.22168-1-berto@igalia.com
10
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
12
---
11
qapi/block-core.json | 4 +++-
13
block.c | 11 ++++++-----
12
block/blkdebug.c | 2 ++
14
1 file changed, 6 insertions(+), 5 deletions(-)
13
2 files changed, 5 insertions(+), 1 deletion(-)
14
15
15
diff --git a/qapi/block-core.json b/qapi/block-core.json
16
diff --git a/block.c b/block.c
16
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
17
--- a/qapi/block-core.json
18
--- a/block.c
18
+++ b/qapi/block-core.json
19
+++ b/block.c
19
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ char *bdrv_perm_names(uint64_t perm)
20
#
21
{ 0, NULL }
21
# @cluster_alloc_space: an allocation of file space for a cluster (since 4.1)
22
};
22
#
23
23
+# @none: triggers once at creation of the blkdebug node (since 4.1)
24
- char *result = g_strdup("");
24
+#
25
+ GString *result = g_string_sized_new(30);
25
# Since: 2.9
26
struct perm_name *p;
26
##
27
27
{ 'enum': 'BlkdebugEvent', 'prefix': 'BLKDBG',
28
for (p = permissions; p->name; p++) {
28
@@ -XXX,XX +XXX,XX @@
29
if (perm & p->perm) {
29
'pwritev_rmw_tail', 'pwritev_rmw_after_tail', 'pwritev',
30
- char *old = result;
30
'pwritev_zero', 'pwritev_done', 'empty_image_prepare',
31
- result = g_strdup_printf("%s%s%s", old, *old ? ", " : "", p->name);
31
'l1_shrink_write_table', 'l1_shrink_free_l2_clusters',
32
- g_free(old);
32
- 'cor_write', 'cluster_alloc_space'] }
33
+ if (result->len > 0) {
33
+ 'cor_write', 'cluster_alloc_space', 'none'] }
34
+ g_string_append(result, ", ");
34
35
+ }
35
##
36
+ g_string_append(result, p->name);
36
# @BlkdebugIOType:
37
}
37
diff --git a/block/blkdebug.c b/block/blkdebug.c
38
index XXXXXXX..XXXXXXX 100644
39
--- a/block/blkdebug.c
40
+++ b/block/blkdebug.c
41
@@ -XXX,XX +XXX,XX @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
42
goto out;
43
}
38
}
44
39
45
+ bdrv_debug_event(bs, BLKDBG_NONE);
40
- return result;
46
+
41
+ return g_string_free(result, FALSE);
47
ret = 0;
42
}
48
out:
43
49
if (ret < 0) {
44
/*
50
--
45
--
51
2.21.0
46
2.24.1
52
47
53
48
diff view generated by jsdifflib
1
Signed-off-by: Max Reitz <mreitz@redhat.com>
1
From: Pan Nengyuan <pannengyuan@huawei.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
2
3
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
3
If we call the qmp 'query-block' while qemu is working on
4
Message-id: 20190507203508.18026-6-mreitz@redhat.com
4
'block-commit', it will cause memleaks, the memory leak stack is as
5
follow:
6
7
Indirect leak of 12360 byte(s) in 3 object(s) allocated from:
8
#0 0x7f80f0b6d970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970)
9
#1 0x7f80ee86049d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d)
10
#2 0x55ea95b5bb67 in qdict_new /mnt/sdb/qemu-4.2.0-rc0/qobject/qdict.c:29
11
#3 0x55ea956cd043 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6427
12
#4 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6399
13
#5 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6399
14
#6 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6399
15
#7 0x55ea958818ea in bdrv_block_device_info /mnt/sdb/qemu-4.2.0-rc0/block/qapi.c:56
16
#8 0x55ea958879de in bdrv_query_info /mnt/sdb/qemu-4.2.0-rc0/block/qapi.c:392
17
#9 0x55ea9588b58f in qmp_query_block /mnt/sdb/qemu-4.2.0-rc0/block/qapi.c:578
18
#10 0x55ea95567392 in qmp_marshal_query_block qapi/qapi-commands-block-core.c:95
19
20
Indirect leak of 4120 byte(s) in 1 object(s) allocated from:
21
#0 0x7f80f0b6d970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970)
22
#1 0x7f80ee86049d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d)
23
#2 0x55ea95b5bb67 in qdict_new /mnt/sdb/qemu-4.2.0-rc0/qobject/qdict.c:29
24
#3 0x55ea956cd043 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6427
25
#4 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6399
26
#5 0x55ea956cc950 in bdrv_refresh_filename /mnt/sdb/qemu-4.2.0-rc0/block.c:6399
27
#6 0x55ea9569f301 in bdrv_backing_attach /mnt/sdb/qemu-4.2.0-rc0/block.c:1064
28
#7 0x55ea956a99dd in bdrv_replace_child_noperm /mnt/sdb/qemu-4.2.0-rc0/block.c:2283
29
#8 0x55ea956b9b53 in bdrv_replace_node /mnt/sdb/qemu-4.2.0-rc0/block.c:4196
30
#9 0x55ea956b9e49 in bdrv_append /mnt/sdb/qemu-4.2.0-rc0/block.c:4236
31
#10 0x55ea958c3472 in commit_start /mnt/sdb/qemu-4.2.0-rc0/block/commit.c:306
32
#11 0x55ea94b68ab0 in qmp_block_commit /mnt/sdb/qemu-4.2.0-rc0/blockdev.c:3459
33
#12 0x55ea9556a7a7 in qmp_marshal_block_commit qapi/qapi-commands-block-core.c:407
34
35
Fixes: bb808d5f5c0978828a974d547e6032402c339555
36
Reported-by: Euler Robot <euler.robot@huawei.com>
37
Signed-off-by: Pan Nengyuan <pannengyuan@huawei.com>
38
Message-id: 20200116085600.24056-1-pannengyuan@huawei.com
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
39
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
---
40
---
7
qapi/block-core.json | 5 ++++-
41
block.c | 1 +
8
block/blkdebug.c | 8 ++++++++
42
1 file changed, 1 insertion(+)
9
2 files changed, 12 insertions(+), 1 deletion(-)
10
43
11
diff --git a/qapi/block-core.json b/qapi/block-core.json
44
diff --git a/block.c b/block.c
12
index XXXXXXX..XXXXXXX 100644
45
index XXXXXXX..XXXXXXX 100644
13
--- a/qapi/block-core.json
46
--- a/block.c
14
+++ b/qapi/block-core.json
47
+++ b/block.c
15
@@ -XXX,XX +XXX,XX @@
48
@@ -XXX,XX +XXX,XX @@ void bdrv_refresh_filename(BlockDriverState *bs)
16
#
49
child->bs->exact_filename);
17
# @flush: .bdrv_co_flush_to_disk()
50
pstrcpy(bs->filename, sizeof(bs->filename), child->bs->filename);
18
#
51
19
+# @block-status: .bdrv_co_block_status()
52
+ qobject_unref(bs->full_open_options);
20
+#
53
bs->full_open_options = qobject_ref(child->bs->full_open_options);
21
# Since: 4.1
54
22
##
55
return;
23
{ 'enum': 'BlkdebugIOType', 'prefix': 'BLKDEBUG_IO_TYPE',
24
- 'data': [ 'read', 'write', 'write-zeroes', 'discard', 'flush' ] }
25
+ 'data': [ 'read', 'write', 'write-zeroes', 'discard', 'flush',
26
+ 'block-status' ] }
27
28
##
29
# @BlkdebugInjectErrorOptions:
30
diff --git a/block/blkdebug.c b/block/blkdebug.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/block/blkdebug.c
33
+++ b/block/blkdebug.c
34
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_block_status(BlockDriverState *bs,
35
int64_t *map,
36
BlockDriverState **file)
37
{
38
+ int err;
39
+
40
assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
41
+
42
+ err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_BLOCK_STATUS);
43
+ if (err) {
44
+ return err;
45
+ }
46
+
47
return bdrv_co_block_status_from_file(bs, want_zero, offset, bytes,
48
pnum, map, file);
49
}
50
--
56
--
51
2.21.0
57
2.24.1
52
58
53
59
diff view generated by jsdifflib
1
This adds a salvaging mode (--salvage) to qemu-img convert which ignores
1
From: Alberto Garcia <berto@igalia.com>
2
read errors and treats the respective areas as containing only zeroes.
3
This can be used for instance to at least partially recover the data
4
from terminally corrupted qcow2 images.
5
2
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
This is a bit more efficient than having to allocate and free memory
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
for each item.
8
Message-id: 20190507203508.18026-3-mreitz@redhat.com
5
6
The default size (60) is enough for all the existing incompatible
7
features or the "Unknown incompatible feature" message.
8
9
Suggested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
12
Message-id: 20200115135626.19442-1-berto@igalia.com
13
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
14
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
16
---
11
qemu-img.c | 90 +++++++++++++++++++++++++++++++++++++-----------
17
block/qcow2.c | 23 +++++++++++------------
12
qemu-img-cmds.hx | 4 +--
18
1 file changed, 11 insertions(+), 12 deletions(-)
13
qemu-img.texi | 4 +++
14
3 files changed, 75 insertions(+), 23 deletions(-)
15
19
16
diff --git a/qemu-img.c b/qemu-img.c
20
diff --git a/block/qcow2.c b/block/qcow2.c
17
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
18
--- a/qemu-img.c
22
--- a/block/qcow2.c
19
+++ b/qemu-img.c
23
+++ b/block/qcow2.c
20
@@ -XXX,XX +XXX,XX @@ enum {
24
@@ -XXX,XX +XXX,XX @@ static void cleanup_unknown_header_ext(BlockDriverState *bs)
21
OPTION_SIZE = 264,
25
static void report_unsupported_feature(Error **errp, Qcow2Feature *table,
22
OPTION_PREALLOCATION = 265,
26
uint64_t mask)
23
OPTION_SHRINK = 266,
27
{
24
+ OPTION_SALVAGE = 267,
28
- char *features = g_strdup("");
25
};
29
- char *old;
26
30
+ g_autoptr(GString) features = g_string_sized_new(60);
27
typedef enum OutputFormat {
31
28
@@ -XXX,XX +XXX,XX @@ typedef struct ImgConvertState {
32
while (table && table->name[0] != '\0') {
29
int64_t target_backing_sectors; /* negative if unknown */
33
if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) {
30
bool wr_in_order;
34
if (mask & (1ULL << table->bit)) {
31
bool copy_range;
35
- old = features;
32
+ bool salvage;
36
- features = g_strdup_printf("%s%s%.46s", old, *old ? ", " : "",
33
bool quiet;
37
- table->name);
34
int min_sparse;
38
- g_free(old);
35
int alignment;
39
+ if (features->len > 0) {
36
@@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
40
+ g_string_append(features, ", ");
41
+ }
42
+ g_string_append_printf(features, "%.46s", table->name);
43
mask &= ~(1ULL << table->bit);
44
}
45
}
46
@@ -XXX,XX +XXX,XX @@ static void report_unsupported_feature(Error **errp, Qcow2Feature *table,
37
}
47
}
38
48
39
if (s->sector_next_status <= sector_num) {
49
if (mask) {
40
- int64_t count = n * BDRV_SECTOR_SIZE;
50
- old = features;
41
+ uint64_t offset = (sector_num - src_cur_offset) * BDRV_SECTOR_SIZE;
51
- features = g_strdup_printf("%s%sUnknown incompatible feature: %" PRIx64,
42
+ int64_t count;
52
- old, *old ? ", " : "", mask);
43
53
- g_free(old);
44
- if (s->target_has_backing) {
54
+ if (features->len > 0) {
45
+ do {
55
+ g_string_append(features, ", ");
46
+ count = n * BDRV_SECTOR_SIZE;
47
+
48
+ if (s->target_has_backing) {
49
+ ret = bdrv_block_status(blk_bs(s->src[src_cur]), offset,
50
+ count, &count, NULL, NULL);
51
+ } else {
52
+ ret = bdrv_block_status_above(blk_bs(s->src[src_cur]), NULL,
53
+ offset, count, &count, NULL,
54
+ NULL);
55
+ }
56
+
57
+ if (ret < 0) {
58
+ if (s->salvage) {
59
+ if (n == 1) {
60
+ if (!s->quiet) {
61
+ warn_report("error while reading block status at "
62
+ "offset %" PRIu64 ": %s", offset,
63
+ strerror(-ret));
64
+ }
65
+ /* Just try to read the data, then */
66
+ ret = BDRV_BLOCK_DATA;
67
+ count = BDRV_SECTOR_SIZE;
68
+ } else {
69
+ /* Retry on a shorter range */
70
+ n = DIV_ROUND_UP(n, 4);
71
+ }
72
+ } else {
73
+ error_report("error while reading block status at offset "
74
+ "%" PRIu64 ": %s", offset, strerror(-ret));
75
+ return ret;
76
+ }
77
+ }
78
+ } while (ret < 0);
79
80
- ret = bdrv_block_status(blk_bs(s->src[src_cur]),
81
- (sector_num - src_cur_offset) *
82
- BDRV_SECTOR_SIZE,
83
- count, &count, NULL, NULL);
84
- } else {
85
- ret = bdrv_block_status_above(blk_bs(s->src[src_cur]), NULL,
86
- (sector_num - src_cur_offset) *
87
- BDRV_SECTOR_SIZE,
88
- count, &count, NULL, NULL);
89
- }
90
- if (ret < 0) {
91
- error_report("error while reading block status of sector %" PRId64
92
- ": %s", sector_num, strerror(-ret));
93
- return ret;
94
- }
95
n = DIV_ROUND_UP(count, BDRV_SECTOR_SIZE);
96
97
if (ret & BDRV_BLOCK_ZERO) {
98
@@ -XXX,XX +XXX,XX @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
99
static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num,
100
int nb_sectors, uint8_t *buf)
101
{
102
+ uint64_t single_read_until = 0;
103
int n, ret;
104
105
assert(nb_sectors <= s->buf_sectors);
106
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num,
107
BlockBackend *blk;
108
int src_cur;
109
int64_t bs_sectors, src_cur_offset;
110
+ uint64_t offset;
111
112
/* In the case of compression with multiple source files, we can get a
113
* nb_sectors that spreads into the next part. So we must be able to
114
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn convert_co_read(ImgConvertState *s, int64_t sector_num,
115
blk = s->src[src_cur];
116
bs_sectors = s->src_sectors[src_cur];
117
118
+ offset = (sector_num - src_cur_offset) << BDRV_SECTOR_BITS;
119
+
120
n = MIN(nb_sectors, bs_sectors - (sector_num - src_cur_offset));
121
+ if (single_read_until > offset) {
122
+ n = 1;
123
+ }
56
+ }
124
57
+ g_string_append_printf(features,
125
- ret = blk_co_pread(
58
+ "Unknown incompatible feature: %" PRIx64, mask);
126
- blk, (sector_num - src_cur_offset) << BDRV_SECTOR_BITS,
127
- n << BDRV_SECTOR_BITS, buf, 0);
128
+ ret = blk_co_pread(blk, offset, n << BDRV_SECTOR_BITS, buf, 0);
129
if (ret < 0) {
130
- return ret;
131
+ if (s->salvage) {
132
+ if (n > 1) {
133
+ single_read_until = offset + (n << BDRV_SECTOR_BITS);
134
+ continue;
135
+ } else {
136
+ if (!s->quiet) {
137
+ warn_report("error while reading offset %" PRIu64
138
+ ": %s", offset, strerror(-ret));
139
+ }
140
+ memset(buf, 0, BDRV_SECTOR_SIZE);
141
+ }
142
+ } else {
143
+ return ret;
144
+ }
145
}
146
147
sector_num += n;
148
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
149
{"image-opts", no_argument, 0, OPTION_IMAGE_OPTS},
150
{"force-share", no_argument, 0, 'U'},
151
{"target-image-opts", no_argument, 0, OPTION_TARGET_IMAGE_OPTS},
152
+ {"salvage", no_argument, 0, OPTION_SALVAGE},
153
{0, 0, 0, 0}
154
};
155
c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WU",
156
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
157
case OPTION_IMAGE_OPTS:
158
image_opts = true;
159
break;
160
+ case OPTION_SALVAGE:
161
+ s.salvage = true;
162
+ break;
163
case OPTION_TARGET_IMAGE_OPTS:
164
tgt_image_opts = true;
165
break;
166
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
167
goto fail_getopt;
168
}
59
}
169
60
170
+ if (s.copy_range && s.salvage) {
61
- error_setg(errp, "Unsupported qcow2 feature(s): %s", features);
171
+ error_report("Cannot use copy offloading in salvaging mode");
62
- g_free(features);
172
+ goto fail_getopt;
63
+ error_setg(errp, "Unsupported qcow2 feature(s): %s", features->str);
173
+ }
64
}
174
+
65
175
if (tgt_image_opts && !skip_create) {
66
/*
176
error_report("--target-image-opts requires use of -n flag");
177
goto fail_getopt;
178
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
179
index XXXXXXX..XXXXXXX 100644
180
--- a/qemu-img-cmds.hx
181
+++ b/qemu-img-cmds.hx
182
@@ -XXX,XX +XXX,XX @@ STEXI
183
ETEXI
184
185
DEF("convert", img_convert,
186
- "convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename")
187
+ "convert [--object objectdef] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename")
188
STEXI
189
-@item convert [--object @var{objectdef}] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename}
190
+@item convert [--object @var{objectdef}] [--image-opts] [--target-image-opts] [-U] [-C] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] [--salvage] @var{filename} [@var{filename2} [...]] @var{output_filename}
191
ETEXI
192
193
DEF("create", img_create,
194
diff --git a/qemu-img.texi b/qemu-img.texi
195
index XXXXXXX..XXXXXXX 100644
196
--- a/qemu-img.texi
197
+++ b/qemu-img.texi
198
@@ -XXX,XX +XXX,XX @@ improve performance if the data is remote, such as with NFS or iSCSI backends,
199
but will not automatically sparsify zero sectors, and may result in a fully
200
allocated target image depending on the host support for getting allocation
201
information.
202
+@item --salvage
203
+Try to ignore I/O errors when reading. Unless in quiet mode (@code{-q}), errors
204
+will still be printed. Areas that cannot be read from the source will be
205
+treated as containing only zeroes.
206
@end table
207
208
Parameters to dd subcommand:
209
--
67
--
210
2.21.0
68
2.24.1
211
69
212
70
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: John Snow <jsnow@redhat.com>
2
2
3
Don't pull events out of the queue that don't belong to us;
3
verify_platform will check an explicit whitelist and blacklist instead.
4
be choosier so that we can use this method to drive jobs that
4
The default will now be assumed to be allowed to run anywhere.
5
were launched by transactions that may have more jobs.
6
5
6
For tests that do not specify their platforms explicitly, this has the effect of
7
enabling these tests on non-linux platforms. For tests that always specified
8
linux explicitly, there is no change.
9
10
For Python tests on FreeBSD at least; only seven python tests fail:
11
045 147 149 169 194 199 211
12
13
045 and 149 appear to be misconfigurations,
14
147 and 194 are the AF_UNIX path too long error,
15
169 and 199 are bitmap migration bugs, and
16
211 is a bug that shows up on Linux platforms, too.
17
18
This is at least good evidence that these tests are not Linux-only. If
19
they aren't suitable for other platforms, they should be disabled on a
20
per-platform basis as appropriate.
21
22
Therefore, let's switch these on and deal with the failures.
23
24
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Signed-off-by: John Snow <jsnow@redhat.com>
25
Signed-off-by: John Snow <jsnow@redhat.com>
8
Message-id: 20190523170643.20794-5-jsnow@redhat.com
26
Message-id: 20200121095205.26323-2-thuth@redhat.com
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
27
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
28
---
12
tests/qemu-iotests/iotests.py | 48 +++++++++++++++++++++--------------
29
tests/qemu-iotests/iotests.py | 16 +++++++++++-----
13
1 file changed, 29 insertions(+), 19 deletions(-)
30
1 file changed, 11 insertions(+), 5 deletions(-)
14
31
15
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
32
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
16
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
17
--- a/tests/qemu-iotests/iotests.py
34
--- a/tests/qemu-iotests/iotests.py
18
+++ b/tests/qemu-iotests/iotests.py
35
+++ b/tests/qemu-iotests/iotests.py
19
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
36
@@ -XXX,XX +XXX,XX @@ def verify_protocol(supported=[], unsupported=[]):
20
# Returns None on success, and an error string on failure
37
if not_sup or (imgproto in unsupported):
21
def run_job(self, job, auto_finalize=True, auto_dismiss=False,
38
notrun('not suitable for this protocol: %s' % imgproto)
22
pre_finalize=None, wait=60.0):
39
23
+ match_device = {'data': {'device': job}}
40
-def verify_platform(supported_oses=['linux']):
24
+ match_id = {'data': {'id': job}}
41
- if True not in [sys.platform.startswith(x) for x in supported_oses]:
25
+ events = [
42
- notrun('not suitable for this OS: %s' % sys.platform)
26
+ ('BLOCK_JOB_COMPLETED', match_device),
43
+def verify_platform(supported=None, unsupported=None):
27
+ ('BLOCK_JOB_CANCELLED', match_device),
44
+ if unsupported is not None:
28
+ ('BLOCK_JOB_ERROR', match_device),
45
+ if any((sys.platform.startswith(x) for x in unsupported)):
29
+ ('BLOCK_JOB_READY', match_device),
46
+ notrun('not suitable for this OS: %s' % sys.platform)
30
+ ('BLOCK_JOB_PENDING', match_id),
47
+
31
+ ('JOB_STATUS_CHANGE', match_id)
48
+ if supported is not None:
32
+ ]
49
+ if not any((sys.platform.startswith(x) for x in supported)):
33
error = None
50
+ notrun('not suitable for this OS: %s' % sys.platform)
34
while True:
51
35
- for ev in self.get_qmp_events_filtered(wait=wait):
52
def verify_cache_mode(supported_cache_modes=[]):
36
- if ev['event'] == 'JOB_STATUS_CHANGE':
53
if supported_cache_modes and (cachemode not in supported_cache_modes):
37
- status = ev['data']['status']
54
@@ -XXX,XX +XXX,XX @@ def execute_unittest(output, verbosity, debug):
38
- if status == 'aborting':
55
sys.stderr.write(out)
39
- result = self.qmp('query-jobs')
56
40
- for j in result['return']:
57
def execute_test(test_function=None,
41
- if j['id'] == job:
58
- supported_fmts=[], supported_oses=['linux'],
42
- error = j['error']
59
+ supported_fmts=[],
43
- log('Job failed: %s' % (j['error']))
60
+ supported_platforms=None,
44
- elif status == 'pending' and not auto_finalize:
61
supported_cache_modes=[], supported_aio_modes={},
45
- if pre_finalize:
62
unsupported_fmts=[], supported_protocols=[],
46
- pre_finalize()
63
unsupported_protocols=[]):
47
- self.qmp_log('job-finalize', id=job)
64
@@ -XXX,XX +XXX,XX @@ def execute_test(test_function=None,
48
- elif status == 'concluded' and not auto_dismiss:
65
verbosity = 1
49
- self.qmp_log('job-dismiss', id=job)
66
verify_image_format(supported_fmts, unsupported_fmts)
50
- elif status == 'null':
67
verify_protocol(supported_protocols, unsupported_protocols)
51
- return error
68
- verify_platform(supported_oses)
52
- else:
69
+ verify_platform(supported=supported_platforms)
53
- log(ev)
70
verify_cache_mode(supported_cache_modes)
54
+ ev = filter_qmp_event(self.events_wait(events))
71
verify_aio_mode(supported_aio_modes)
55
+ if ev['event'] != 'JOB_STATUS_CHANGE':
72
56
+ log(ev)
57
+ continue
58
+ status = ev['data']['status']
59
+ if status == 'aborting':
60
+ result = self.qmp('query-jobs')
61
+ for j in result['return']:
62
+ if j['id'] == job:
63
+ error = j['error']
64
+ log('Job failed: %s' % (j['error']))
65
+ elif status == 'pending' and not auto_finalize:
66
+ if pre_finalize:
67
+ pre_finalize()
68
+ self.qmp_log('job-finalize', id=job)
69
+ elif status == 'concluded' and not auto_dismiss:
70
+ self.qmp_log('job-dismiss', id=job)
71
+ elif status == 'null':
72
+ return error
73
74
def node_info(self, node_name):
75
nodes = self.qmp('query-named-block-nodes')
76
--
73
--
77
2.21.0
74
2.24.1
78
75
79
76
diff view generated by jsdifflib
1
Move img_convert()'s quiet flag into the ImgConvertState so it is
1
From: Thomas Huth <thuth@redhat.com>
2
accessible by nested functions. -q dictates that it suppresses anything
3
but errors, so if those functions want to emit warnings, they need to
4
query this flag first. (There currently are no such warnings, but there
5
will be as of the next patch.)
6
2
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
041 works fine on Linux, FreeBSD, NetBSD and OpenBSD, but fails on macOS.
8
Reviewed-by: Eric Blake <eblake@redhat.com>
4
Let's mark it as only supported on the systems where we know that it is
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
working fine.
10
Message-id: 20190507203508.18026-2-mreitz@redhat.com
6
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Thomas Huth <thuth@redhat.com>
9
Message-id: 20200121095205.26323-3-thuth@redhat.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
11
---
13
qemu-img.c | 13 +++++++------
12
tests/qemu-iotests/041 | 3 ++-
14
1 file changed, 7 insertions(+), 6 deletions(-)
13
1 file changed, 2 insertions(+), 1 deletion(-)
15
14
16
diff --git a/qemu-img.c b/qemu-img.c
15
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
17
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100755
18
--- a/qemu-img.c
17
--- a/tests/qemu-iotests/041
19
+++ b/qemu-img.c
18
+++ b/tests/qemu-iotests/041
20
@@ -XXX,XX +XXX,XX @@ typedef struct ImgConvertState {
19
@@ -XXX,XX +XXX,XX @@ class TestOrphanedSource(iotests.QMPTestCase):
21
int64_t target_backing_sectors; /* negative if unknown */
20
22
bool wr_in_order;
21
if __name__ == '__main__':
23
bool copy_range;
22
iotests.main(supported_fmts=['qcow2', 'qed'],
24
+ bool quiet;
23
- supported_protocols=['file'])
25
int min_sparse;
24
+ supported_protocols=['file'],
26
int alignment;
25
+ supported_platforms=['linux', 'freebsd', 'netbsd', 'openbsd'])
27
size_t cluster_sectors;
28
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
29
QDict *open_opts = NULL;
30
char *options = NULL;
31
Error *local_err = NULL;
32
- bool writethrough, src_writethrough, quiet = false, image_opts = false,
33
+ bool writethrough, src_writethrough, image_opts = false,
34
skip_create = false, progress = false, tgt_image_opts = false;
35
int64_t ret = -EINVAL;
36
bool force_share = false;
37
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
38
src_cache = optarg;
39
break;
40
case 'q':
41
- quiet = true;
42
+ s.quiet = true;
43
break;
44
case 'n':
45
skip_create = true;
46
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
47
}
48
49
/* Initialize before goto out */
50
- if (quiet) {
51
+ if (s.quiet) {
52
progress = false;
53
}
54
qemu_progress_init(progress, 1.0);
55
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
56
57
for (bs_i = 0; bs_i < s.src_num; bs_i++) {
58
s.src[bs_i] = img_open(image_opts, argv[optind + bs_i],
59
- fmt, src_flags, src_writethrough, quiet,
60
+ fmt, src_flags, src_writethrough, s.quiet,
61
force_share);
62
if (!s.src[bs_i]) {
63
ret = -1;
64
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
65
66
if (skip_create) {
67
s.target = img_open(tgt_image_opts, out_filename, out_fmt,
68
- flags, writethrough, quiet, false);
69
+ flags, writethrough, s.quiet, false);
70
} else {
71
/* TODO ultimately we should allow --target-image-opts
72
* to be used even when -n is not given.
73
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
74
* to allow filenames in option syntax
75
*/
76
s.target = img_open_file(out_filename, open_opts, out_fmt,
77
- flags, writethrough, quiet, false);
78
+ flags, writethrough, s.quiet, false);
79
open_opts = NULL; /* blk_new_open will have freed it */
80
}
81
if (!s.target) {
82
--
26
--
83
2.21.0
27
2.24.1
84
28
85
29
diff view generated by jsdifflib
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
The uninitialized memory allocated for the command FIFO of the
3
In the long run, we might want to add test 183 to the "auto" group
4
floppy controller during the VM hardware initialization incurs
4
(but it still fails occasionally, so we cannot do that yet). However,
5
many unwanted reports by Valgrind when VM state is being saved.
5
when running 183 in Cirrus-CI on macOS, or with our vm-build-openbsd
6
That verbosity hardens a search for the real memory issues when
6
target, it currently always fails with an "Timeout waiting for return
7
the iotests run. Particularly, the patch eliminates 20 unnecessary
7
on handle 0" error.
8
reports of the Valgrind tool in the iotest #169.
9
8
10
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
9
Let's mark it as supported only on systems where the test is working
11
Message-id: 1559154027-282547-1-git-send-email-andrey.shinkevich@virtuozzo.com
10
most of the time (i.e. Linux, FreeBSD and NetBSD).
12
Reviewed-by: John Snow <jsnow@redhat.com>
11
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Signed-off-by: Thomas Huth <thuth@redhat.com>
14
Message-id: 20200121095205.26323-4-thuth@redhat.com
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
---
16
---
15
hw/block/fdc.c | 1 +
17
tests/qemu-iotests/183 | 1 +
16
1 file changed, 1 insertion(+)
18
1 file changed, 1 insertion(+)
17
19
18
diff --git a/hw/block/fdc.c b/hw/block/fdc.c
20
diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183
19
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100755
20
--- a/hw/block/fdc.c
22
--- a/tests/qemu-iotests/183
21
+++ b/hw/block/fdc.c
23
+++ b/tests/qemu-iotests/183
22
@@ -XXX,XX +XXX,XX @@ static void fdctrl_realize_common(DeviceState *dev, FDCtrl *fdctrl,
24
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
23
25
. ./common.filter
24
FLOPPY_DPRINTF("init controller\n");
26
. ./common.qemu
25
fdctrl->fifo = qemu_memalign(512, FD_SECTOR_LEN);
27
26
+ memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
28
+_supported_os Linux FreeBSD NetBSD
27
fdctrl->fifo_size = 512;
29
_supported_fmt qcow2 raw qed quorum
28
fdctrl->result_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
30
_supported_proto file
29
fdctrl_result_timer, fdctrl);
31
30
--
32
--
31
2.21.0
33
2.24.1
32
34
33
35
diff view generated by jsdifflib
1
It is possible for an empty file to take up blocks on a filesystem, for
1
From: Thomas Huth <thuth@redhat.com>
2
example:
3
2
4
$ qemu-img create -f raw test.img 1G
3
We are going to enable 127 in the "auto" group, but it only works if
5
Formatting 'test.img', fmt=raw size=1073741824
4
virtio-scsi and scsi-hd are available - which is not the case with
6
$ mkfs.ext4 -I 128 -q test.img
5
QEMU binaries like qemu-system-tricore for example, so we need a
7
$ mkdir test-mount
6
proper check for the availability of these devices here.
8
$ sudo mount -o loop test.img test-mount
9
$ sudo touch test-mount/test-file
10
$ stat -c 'blocks=%b' test-mount/test-file
11
blocks=8
12
7
13
These extra blocks (one cluster) are apparently used for metadata,
8
A very similar problem exists in iotest 267 - it has been added to
14
because they are always there, on top of blocks used for data:
9
the "auto" group already, but requires virtio-blk and thus currently
10
fails with qemu-system-tricore for example. Let's also add aproper
11
check there.
15
12
16
$ sudo dd if=/dev/zero of=test-mount/test-file bs=1M count=1
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
17
1+0 records in
14
Signed-off-by: Thomas Huth <thuth@redhat.com>
18
1+0 records out
15
Message-id: 20200121095205.26323-5-thuth@redhat.com
19
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.00135339 s, 775 MB/s
20
$ stat -c 'blocks=%b' test-mount/test-file
21
blocks=2056
22
23
Make iotest 175 take this into account.
24
25
Reported-by: Thomas Huth <thuth@redhat.com>
26
Signed-off-by: Max Reitz <mreitz@redhat.com>
27
Reviewed-by: Eric Blake <eblake@redhat.com>
28
Reviewed-by: Nir Soffer <nsoffer@redhat.com>
29
Message-id: 20190516144319.12570-1-mreitz@redhat.com
30
Signed-off-by: Max Reitz <mreitz@redhat.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
31
---
17
---
32
tests/qemu-iotests/175 | 26 ++++++++++++++++++++++----
18
tests/qemu-iotests/127 | 2 ++
33
tests/qemu-iotests/175.out | 8 ++++----
19
tests/qemu-iotests/267 | 2 ++
34
2 files changed, 26 insertions(+), 8 deletions(-)
20
tests/qemu-iotests/common.rc | 14 ++++++++++++++
21
3 files changed, 18 insertions(+)
35
22
36
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
23
diff --git a/tests/qemu-iotests/127 b/tests/qemu-iotests/127
37
index XXXXXXX..XXXXXXX 100755
24
index XXXXXXX..XXXXXXX 100755
38
--- a/tests/qemu-iotests/175
25
--- a/tests/qemu-iotests/127
39
+++ b/tests/qemu-iotests/175
26
+++ b/tests/qemu-iotests/127
40
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
27
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
41
28
_supported_fmt qcow2
42
_cleanup()
29
_supported_proto file
30
31
+_require_devices virtio-scsi scsi-hd
32
+
33
IMG_SIZE=64K
34
35
_make_test_img $IMG_SIZE
36
diff --git a/tests/qemu-iotests/267 b/tests/qemu-iotests/267
37
index XXXXXXX..XXXXXXX 100755
38
--- a/tests/qemu-iotests/267
39
+++ b/tests/qemu-iotests/267
40
@@ -XXX,XX +XXX,XX @@ _require_drivers copy-on-read
41
# and generally impossible with external data files
42
_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
43
44
+_require_devices virtio-blk
45
+
46
do_run_qemu()
43
{
47
{
44
-    _cleanup_test_img
48
echo Testing: "$@"
45
+ _cleanup_test_img
49
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
46
+ rm -f "$TEST_DIR/empty"
50
index XXXXXXX..XXXXXXX 100644
51
--- a/tests/qemu-iotests/common.rc
52
+++ b/tests/qemu-iotests/common.rc
53
@@ -XXX,XX +XXX,XX @@ _require_large_file()
54
rm "$TEST_IMG"
47
}
55
}
48
trap "_cleanup; exit \$status" 0 1 2 3 15
56
49
57
+# Check that a set of devices is available in the QEMU binary
50
+# Some file systems sometimes allocate extra blocks independently of
58
+#
51
+# the file size. This function hides the resulting difference in the
59
+_require_devices()
52
+# stat -c '%b' output.
53
+# Parameter 1: Number of blocks an empty file occupies
54
+# Parameter 2: Image size in bytes
55
+_filter_blocks()
56
+{
60
+{
57
+ extra_blocks=$1
61
+ available=$($QEMU -M none -device help | \
58
+ img_size=$2
62
+ grep ^name | sed -e 's/^name "//' -e 's/".*$//')
59
+
63
+ for device
60
+ sed -e "s/blocks=$extra_blocks\\(\$\\|[^0-9]\\)/nothing allocated/" \
64
+ do
61
+ -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/everything allocated/"
65
+ if ! echo "$available" | grep -q "$device" ; then
66
+ _notrun "$device not available"
67
+ fi
68
+ done
62
+}
69
+}
63
+
70
+
64
# get standard environment, filters and checks
71
# make sure this script returns success
65
. ./common.rc
72
true
66
. ./common.filter
67
@@ -XXX,XX +XXX,XX @@ _supported_fmt raw
68
_supported_proto file
69
_supported_os Linux
70
71
-size=1m
72
+size=$((1 * 1024 * 1024))
73
+
74
+touch "$TEST_DIR/empty"
75
+extra_blocks=$(stat -c '%b' "$TEST_DIR/empty")
76
77
echo
78
echo "== creating image with default preallocation =="
79
_make_test_img $size | _filter_imgfmt
80
-stat -c "size=%s, blocks=%b" $TEST_IMG
81
+stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size
82
83
for mode in off full falloc; do
84
echo
85
echo "== creating image with preallocation $mode =="
86
IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt
87
- stat -c "size=%s, blocks=%b" $TEST_IMG
88
+ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size
89
done
90
91
# success, all done
92
diff --git a/tests/qemu-iotests/175.out b/tests/qemu-iotests/175.out
93
index XXXXXXX..XXXXXXX 100644
94
--- a/tests/qemu-iotests/175.out
95
+++ b/tests/qemu-iotests/175.out
96
@@ -XXX,XX +XXX,XX @@ QA output created by 175
97
98
== creating image with default preallocation ==
99
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
100
-size=1048576, blocks=0
101
+size=1048576, nothing allocated
102
103
== creating image with preallocation off ==
104
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=off
105
-size=1048576, blocks=0
106
+size=1048576, nothing allocated
107
108
== creating image with preallocation full ==
109
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=full
110
-size=1048576, blocks=2048
111
+size=1048576, everything allocated
112
113
== creating image with preallocation falloc ==
114
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=falloc
115
-size=1048576, blocks=2048
116
+size=1048576, everything allocated
117
*** done
118
--
73
--
119
2.21.0
74
2.24.1
120
75
121
76
diff view generated by jsdifflib
1
A snapshot is something that reflects the state of something at a
1
From: Thomas Huth <thuth@redhat.com>
2
certain point in time. It does not change.
3
2
4
The file our snapshot commands create (or the node they install) is not
3
We are going to enable some of the python-based tests in the "auto" group,
5
a snapshot, as it does change over time. It is an overlay. We cannot
4
and these tests require virtio-blk to work properly. Running iotests
6
do anything about the parameter names, but we can at least adjust the
5
without virtio-blk likely does not make too much sense anyway, so instead
7
descriptions to reflect that fact.
6
of adding a check for the availability of virtio-blk to each and every
7
test (which does not sound very appealing), let's rather add a check for
8
this a central spot in the "check" script instead (so that it is still
9
possible to run "make check" for qemu-system-tricore for example).
8
10
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Thomas Huth <thuth@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Message-id: 20200121095205.26323-6-thuth@redhat.com
11
Message-id: 20190603202236.1342-2-mreitz@redhat.com
12
Reviewed-by: John Snow <jsnow@redhat.com>
13
Reviewed-by: Alberto Garcia <berto@igalia.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
14
---
16
qapi/block-core.json | 20 ++++++++++----------
15
tests/qemu-iotests/check | 12 ++++++++++--
17
1 file changed, 10 insertions(+), 10 deletions(-)
16
1 file changed, 10 insertions(+), 2 deletions(-)
18
17
19
diff --git a/qapi/block-core.json b/qapi/block-core.json
18
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
20
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100755
21
--- a/qapi/block-core.json
20
--- a/tests/qemu-iotests/check
22
+++ b/qapi/block-core.json
21
+++ b/tests/qemu-iotests/check
23
@@ -XXX,XX +XXX,XX @@
22
@@ -XXX,XX +XXX,XX @@ fi
24
#
23
python_usable=false
25
# Either @device or @node-name must be set but not both.
24
if $PYTHON -c 'import sys; sys.exit(0 if sys.version_info >= (3,6) else 1)'
26
#
25
then
27
-# @device: the name of the device to generate the snapshot from.
26
- python_usable=true
28
+# @device: the name of the device to take a snapshot of.
27
+ # Our python framework also requires virtio-blk
29
#
28
+ if "$QEMU_PROG" -M none -device help | grep -q virtio-blk >/dev/null 2>&1
30
# @node-name: graph node name to generate the snapshot from (Since 2.0)
29
+ then
31
#
30
+ python_usable=true
32
-# @snapshot-file: the target of the new image. If the file exists, or
31
+ else
33
-# if it is a device, the snapshot will be created in the existing
32
+ python_unusable_because="Missing virtio-blk in QEMU binary"
34
-# file/device. Otherwise, a new file will be created.
33
+ fi
35
+# @snapshot-file: the target of the new overlay image. If the file
34
+else
36
+# exists, or if it is a device, the overlay will be created in the
35
+ python_unusable_because="Unsupported Python version"
37
+# existing file/device. Otherwise, a new file will be created.
36
fi
38
#
37
39
# @snapshot-node-name: the graph node name of the new image (Since 2.0)
38
default_machine=$($QEMU_PROG -machine help | sed -n '/(default)/ s/ .*//p')
40
#
39
@@ -XXX,XX +XXX,XX @@ do
41
-# @format: the format of the snapshot image, default is 'qcow2'.
40
run_command="$PYTHON $seq"
42
+# @format: the format of the overlay image, default is 'qcow2'.
41
else
43
#
42
run_command="false"
44
# @mode: whether and how QEMU should create a new image, default is
43
- echo "Unsupported Python version" > $seq.notrun
45
# 'absolute-paths'.
44
+ echo "$python_unusable_because" > $seq.notrun
46
@@ -XXX,XX +XXX,XX @@
45
fi
47
##
46
else
48
# @BlockdevSnapshot:
47
run_command="./$seq"
49
#
50
-# @node: device or node name that will have a snapshot created.
51
+# @node: device or node name that will have a snapshot taken.
52
#
53
# @overlay: reference to the existing block device that will become
54
-# the overlay of @node, as part of creating the snapshot.
55
+# the overlay of @node, as part of taking the snapshot.
56
# It must not have a current backing file (this can be
57
# achieved by passing "backing": null to blockdev-add).
58
#
59
@@ -XXX,XX +XXX,XX @@
60
##
61
# @blockdev-snapshot-sync:
62
#
63
-# Generates a synchronous snapshot of a block device.
64
+# Takes a synchronous snapshot of a block device.
65
#
66
# For the arguments, see the documentation of BlockdevSnapshotSync.
67
#
68
@@ -XXX,XX +XXX,XX @@
69
##
70
# @blockdev-snapshot:
71
#
72
-# Generates a snapshot of a block device.
73
+# Takes a snapshot of a block device.
74
#
75
-# Create a snapshot, by installing 'node' as the backing image of
76
+# Take a snapshot, by installing 'node' as the backing image of
77
# 'overlay'. Additionally, if 'node' is associated with a block
78
# device, the block device changes to using 'overlay' as its new active
79
# image.
80
--
48
--
81
2.21.0
49
2.24.1
82
50
83
51
diff view generated by jsdifflib
1
This test converts a simple image to another, but blkdebug injects
1
From: Thomas Huth <thuth@redhat.com>
2
block_status and read faults at some offsets. The resulting image
3
should be the same as the input image, except that sectors that could
4
not be read have to be 0.
5
2
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
According to Kevin, tests 030, 040 and 041 are among the most valuable
7
Message-id: 20190507203508.18026-7-mreitz@redhat.com
4
tests that we have, so we should always run them if possible, even if
8
Tested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
they take a little bit longer.
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
10
[mreitz: Dropped superfluous printf from _filter_offsets, as suggested
7
According to Max, it would be good to have a test for iothreads and
11
by Vladimir; disable test for VDI and IMGOPTSSYNTAX]
8
migration. 127 and 256 seem to be good candidates for iothreads. For
9
migration, let's enable 181 and 203 (which also tests iothreads).
10
(091 would be a good candidate for migration, too, but Alex Bennée
11
reported that this test fails on ZFS file systems, so it can't be
12
included yet)
13
14
Reviewed-by: Max Reitz <mreitz@redhat.com>
15
Signed-off-by: Thomas Huth <thuth@redhat.com>
16
Message-id: 20200121095205.26323-7-thuth@redhat.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
18
---
14
tests/qemu-iotests/251 | 170 +++++++++++++++++++++++++++++++++++++
19
tests/qemu-iotests/group | 14 +++++++-------
15
tests/qemu-iotests/251.out | 43 ++++++++++
20
1 file changed, 7 insertions(+), 7 deletions(-)
16
tests/qemu-iotests/group | 1 +
17
3 files changed, 214 insertions(+)
18
create mode 100755 tests/qemu-iotests/251
19
create mode 100644 tests/qemu-iotests/251.out
20
21
21
diff --git a/tests/qemu-iotests/251 b/tests/qemu-iotests/251
22
new file mode 100755
23
index XXXXXXX..XXXXXXX
24
--- /dev/null
25
+++ b/tests/qemu-iotests/251
26
@@ -XXX,XX +XXX,XX @@
27
+#!/usr/bin/env bash
28
+#
29
+# Test qemu-img convert --salvage
30
+#
31
+# Copyright (C) 2019 Red Hat, Inc.
32
+#
33
+# This program is free software; you can redistribute it and/or modify
34
+# it under the terms of the GNU General Public License as published by
35
+# the Free Software Foundation; either version 2 of the License, or
36
+# (at your option) any later version.
37
+#
38
+# This program is distributed in the hope that it will be useful,
39
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
40
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41
+# GNU General Public License for more details.
42
+#
43
+# You should have received a copy of the GNU General Public License
44
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
45
+#
46
+
47
+# creator
48
+owner=mreitz@redhat.com
49
+
50
+seq=$(basename $0)
51
+echo "QA output created by $seq"
52
+
53
+status=1    # failure is the default!
54
+
55
+_cleanup()
56
+{
57
+ _cleanup_test_img
58
+}
59
+trap "_cleanup; exit \$status" 0 1 2 3 15
60
+
61
+# get standard environment, filters and checks
62
+. ./common.rc
63
+. ./common.filter
64
+. ./common.qemu
65
+
66
+_supported_fmt generic
67
+_supported_proto file
68
+_supported_os Linux
69
+
70
+if [ "$IMGOPTSSYNTAX" = "true" ]; then
71
+ # We use json:{} filenames here, so we cannot work with additional options.
72
+ _unsupported_fmt $IMGFMT
73
+else
74
+ # With VDI, the output is ordered differently. Just disable it.
75
+ _unsupported_fmt vdi
76
+fi
77
+
78
+
79
+TEST_IMG="$TEST_IMG.orig" _make_test_img 64M
80
+
81
+$QEMU_IO -c 'write -P 42 0 64M' "$TEST_IMG.orig" | _filter_qemu_io
82
+
83
+
84
+sector_size=512
85
+
86
+# Offsets on which to fail block-status. Keep in ascending order so
87
+# the indexing done by _filter_offsets will appear in ascending order
88
+# in the output as well.
89
+status_fail_offsets="$((16 * 1024 * 1024 + 8192))
90
+ $((33 * 1024 * 1024 + 512))"
91
+
92
+# Offsets on which to fail reads. Keep in ascending order for the
93
+# same reason.
94
+# The second element is shared with $status_fail_offsets on purpose.
95
+# Starting with the third element, we test what happens when a
96
+# continuous range of sectors is inaccessible.
97
+read_fail_offsets="$((32 * 1024 * 1024 - 65536))
98
+ $((33 * 1024 * 1024 + 512))
99
+ $(seq $((34 * 1024 * 1024)) $sector_size \
100
+ $((34 * 1024 * 1024 + 4096 - $sector_size)))"
101
+
102
+
103
+# blkdebug must be above the format layer so it can intercept all
104
+# block-status events
105
+source_img="json:{'driver': 'blkdebug',
106
+ 'image': {
107
+ 'driver': '$IMGFMT',
108
+ 'file': {
109
+ 'driver': 'file',
110
+ 'filename': '$TEST_IMG.orig'
111
+ }
112
+ },
113
+ 'inject-error': ["
114
+
115
+for ofs in $status_fail_offsets
116
+do
117
+ source_img+="{ 'event': 'none',
118
+ 'iotype': 'block-status',
119
+ 'errno': 5,
120
+ 'sector': $((ofs / sector_size)) },"
121
+done
122
+
123
+for ofs in $read_fail_offsets
124
+do
125
+ source_img+="{ 'event': 'none',
126
+ 'iotype': 'read',
127
+ 'errno': 5,
128
+ 'sector': $((ofs / sector_size)) },"
129
+done
130
+
131
+# Remove the trailing comma and terminate @inject-error and json:{}
132
+source_img="${source_img%,} ] }"
133
+
134
+
135
+echo
136
+
137
+
138
+_filter_offsets() {
139
+ filters=
140
+
141
+ index=0
142
+ for ofs in $1
143
+ do
144
+ filters+=" -e s/$ofs/status_fail_offset_$index/"
145
+ index=$((index + 1))
146
+ done
147
+
148
+ index=0
149
+ for ofs in $2
150
+ do
151
+ filters+=" -e s/$ofs/read_fail_offset_$index/"
152
+ index=$((index + 1))
153
+ done
154
+
155
+ sed $filters
156
+}
157
+
158
+# While determining the number of allocated sectors in the input
159
+# image, we should see one block status warning per element of
160
+# $status_fail_offsets.
161
+#
162
+# Then, the image is read. Since the block status is queried in
163
+# basically the same way, the same warnings as in the previous step
164
+# should reappear. Interleaved with those we should see a read
165
+# warning per element of $read_fail_offsets.
166
+# Note that $read_fail_offsets and $status_fail_offsets share an
167
+# element (read_fail_offset_1 == status_fail_offset_1), so
168
+# "status_fail_offset_1" in the output is the same as
169
+# "read_fail_offset_1".
170
+$QEMU_IMG convert --salvage "$source_img" "$TEST_IMG" 2>&1 \
171
+ | _filter_offsets "$status_fail_offsets" "$read_fail_offsets"
172
+
173
+echo
174
+
175
+# The offsets where the block status could not be determined should
176
+# have been treated as containing data and thus should be correct in
177
+# the output image.
178
+# The offsets where reading failed altogether should be 0. Make them
179
+# 0 in the input image, too, so we can compare both images.
180
+for ofs in $read_fail_offsets
181
+do
182
+ $QEMU_IO -c "write -z $ofs $sector_size" "$TEST_IMG.orig" \
183
+ | _filter_qemu_io \
184
+ | _filter_offsets '' "$read_fail_offsets"
185
+done
186
+
187
+echo
188
+
189
+# These should be equal now.
190
+$QEMU_IMG compare "$TEST_IMG.orig" "$TEST_IMG"
191
+
192
+
193
+# success, all done
194
+echo "*** done"
195
+rm -f $seq.full
196
+status=0
197
diff --git a/tests/qemu-iotests/251.out b/tests/qemu-iotests/251.out
198
new file mode 100644
199
index XXXXXXX..XXXXXXX
200
--- /dev/null
201
+++ b/tests/qemu-iotests/251.out
202
@@ -XXX,XX +XXX,XX @@
203
+QA output created by 251
204
+Formatting 'TEST_DIR/t.IMGFMT.orig', fmt=IMGFMT size=67108864
205
+wrote 67108864/67108864 bytes at offset 0
206
+64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
207
+
208
+qemu-img: warning: error while reading block status at offset status_fail_offset_0: Input/output error
209
+qemu-img: warning: error while reading block status at offset status_fail_offset_1: Input/output error
210
+qemu-img: warning: error while reading block status at offset status_fail_offset_0: Input/output error
211
+qemu-img: warning: error while reading offset read_fail_offset_0: Input/output error
212
+qemu-img: warning: error while reading block status at offset status_fail_offset_1: Input/output error
213
+qemu-img: warning: error while reading offset status_fail_offset_1: Input/output error
214
+qemu-img: warning: error while reading offset read_fail_offset_2: Input/output error
215
+qemu-img: warning: error while reading offset read_fail_offset_3: Input/output error
216
+qemu-img: warning: error while reading offset read_fail_offset_4: Input/output error
217
+qemu-img: warning: error while reading offset read_fail_offset_5: Input/output error
218
+qemu-img: warning: error while reading offset read_fail_offset_6: Input/output error
219
+qemu-img: warning: error while reading offset read_fail_offset_7: Input/output error
220
+qemu-img: warning: error while reading offset read_fail_offset_8: Input/output error
221
+qemu-img: warning: error while reading offset read_fail_offset_9: Input/output error
222
+
223
+wrote 512/512 bytes at offset read_fail_offset_0
224
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
225
+wrote 512/512 bytes at offset read_fail_offset_1
226
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
227
+wrote 512/512 bytes at offset read_fail_offset_2
228
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
229
+wrote 512/512 bytes at offset read_fail_offset_3
230
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
231
+wrote 512/512 bytes at offset read_fail_offset_4
232
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
233
+wrote 512/512 bytes at offset read_fail_offset_5
234
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
235
+wrote 512/512 bytes at offset read_fail_offset_6
236
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
237
+wrote 512/512 bytes at offset read_fail_offset_7
238
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
239
+wrote 512/512 bytes at offset read_fail_offset_8
240
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
241
+wrote 512/512 bytes at offset read_fail_offset_9
242
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
243
+
244
+Images are identical.
245
+*** done
246
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
22
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
247
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
248
--- a/tests/qemu-iotests/group
24
--- a/tests/qemu-iotests/group
249
+++ b/tests/qemu-iotests/group
25
+++ b/tests/qemu-iotests/group
250
@@ -XXX,XX +XXX,XX @@
26
@@ -XXX,XX +XXX,XX @@
251
248 rw quick
27
027 rw auto quick
252
249 rw auto quick
28
028 rw backing quick
253
250 rw auto quick
29
029 rw auto quick
254
+251 rw auto quick
30
-030 rw backing
255
252 rw auto backing quick
31
+030 rw auto backing
256
253 rw auto quick
32
031 rw auto quick
257
254 rw auto backing quick
33
032 rw auto quick
34
033 rw auto quick
35
@@ -XXX,XX +XXX,XX @@
36
037 rw auto backing quick
37
038 rw auto backing quick
38
039 rw auto quick
39
-040 rw
40
-041 rw backing
41
+040 rw auto
42
+041 rw auto backing
43
042 rw auto quick
44
043 rw auto backing
45
044 rw
46
@@ -XXX,XX +XXX,XX @@
47
124 rw backing
48
125 rw
49
126 rw auto backing
50
-127 rw backing quick
51
+127 rw auto backing quick
52
128 rw quick
53
129 rw quick
54
130 rw quick
55
@@ -XXX,XX +XXX,XX @@
56
177 rw auto quick
57
178 img
58
179 rw auto quick
59
-181 rw migration
60
+181 rw auto migration
61
182 rw quick
62
183 rw migration
63
184 rw auto quick
64
@@ -XXX,XX +XXX,XX @@
65
200 rw
66
201 rw migration
67
202 rw quick
68
-203 rw migration
69
+203 rw auto migration
70
204 rw quick
71
205 rw quick
72
206 rw
73
@@ -XXX,XX +XXX,XX @@
74
253 rw quick
75
254 rw backing quick
76
255 rw quick
77
-256 rw quick
78
+256 rw auto quick
79
257 rw
80
258 rw quick
81
260 rw quick
258
--
82
--
259
2.21.0
83
2.24.1
260
84
261
85
diff view generated by jsdifflib
1
img_rebase() can leak a QDict in two occasions. Fix it.
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Coverity: CID 1401416
3
The L1 table is read from disk using the byte-based bdrv_pread() and
4
Fixes: d16699b64671466b42079c45b89127aeea1ca565
4
is never accessed beyond its last element, so there's no need to
5
Fixes: 330c72957196e0ae382abcaa97ebf4eb9bc8574f
5
allocate more memory than that.
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
7
Message-id: 20190528195338.12376-1-mreitz@redhat.com
7
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: b2e27214ec7b03a585931bcf383ee1ac3a641a10.1579374329.git.berto@igalia.com
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
---
11
qemu-img.c | 3 +++
12
block/qcow2-cluster.c | 5 ++---
12
1 file changed, 3 insertions(+)
13
block/qcow2-refcount.c | 2 +-
14
block/qcow2-snapshot.c | 3 +--
15
block/qcow2.c | 2 +-
16
4 files changed, 5 insertions(+), 7 deletions(-)
13
17
14
diff --git a/qemu-img.c b/qemu-img.c
18
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
15
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
16
--- a/qemu-img.c
20
--- a/block/qcow2-cluster.c
17
+++ b/qemu-img.c
21
+++ b/block/qcow2-cluster.c
18
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
22
@@ -XXX,XX +XXX,XX @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
19
out_baseimg,
23
#endif
20
&local_err);
24
21
if (local_err) {
25
new_l1_size2 = sizeof(uint64_t) * new_l1_size;
22
+ qobject_unref(options);
26
- new_l1_table = qemu_try_blockalign(bs->file->bs,
23
error_reportf_err(local_err,
27
- ROUND_UP(new_l1_size2, 512));
24
"Could not resolve backing filename: ");
28
+ new_l1_table = qemu_try_blockalign(bs->file->bs, new_l1_size2);
25
ret = -1;
29
if (new_l1_table == NULL) {
26
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
30
return -ENOMEM;
27
*/
31
}
28
prefix_chain_bs = bdrv_find_backing_image(bs, out_real_path);
32
- memset(new_l1_table, 0, ROUND_UP(new_l1_size2, 512));
29
if (prefix_chain_bs) {
33
+ memset(new_l1_table, 0, new_l1_size2);
30
+ qobject_unref(options);
34
31
g_free(out_real_path);
35
if (s->l1_size) {
32
+
36
memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
33
blk_new_backing = blk_new(qemu_get_aio_context(),
37
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
34
BLK_PERM_CONSISTENT_READ,
38
index XXXXXXX..XXXXXXX 100644
35
BLK_PERM_ALL);
39
--- a/block/qcow2-refcount.c
40
+++ b/block/qcow2-refcount.c
41
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
42
* l1_table_offset when it is the current s->l1_table_offset! Be careful
43
* when changing this! */
44
if (l1_table_offset != s->l1_table_offset) {
45
- l1_table = g_try_malloc0(ROUND_UP(l1_size2, 512));
46
+ l1_table = g_try_malloc0(l1_size2);
47
if (l1_size2 && l1_table == NULL) {
48
ret = -ENOMEM;
49
goto fail;
50
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/block/qcow2-snapshot.c
53
+++ b/block/qcow2-snapshot.c
54
@@ -XXX,XX +XXX,XX @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
55
return ret;
56
}
57
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
58
- new_l1_table = qemu_try_blockalign(bs->file->bs,
59
- ROUND_UP(new_l1_bytes, 512));
60
+ new_l1_table = qemu_try_blockalign(bs->file->bs, new_l1_bytes);
61
if (new_l1_table == NULL) {
62
return -ENOMEM;
63
}
64
diff --git a/block/qcow2.c b/block/qcow2.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/block/qcow2.c
67
+++ b/block/qcow2.c
68
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
69
70
if (s->l1_size > 0) {
71
s->l1_table = qemu_try_blockalign(bs->file->bs,
72
- ROUND_UP(s->l1_size * sizeof(uint64_t), 512));
73
+ s->l1_size * sizeof(uint64_t));
74
if (s->l1_table == NULL) {
75
error_setg(errp, "Could not allocate L1 table");
76
ret = -ENOMEM;
36
--
77
--
37
2.21.0
78
2.24.1
38
79
39
80
diff view generated by jsdifflib
1
There are error messages which refer to an overlay node as the snapshot.
1
From: Alberto Garcia <berto@igalia.com>
2
That is wrong, those are two different things.
3
2
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
qcow2_alloc_cluster_offset() and qcow2_get_cluster_offset() always
5
Reviewed-by: Eric Blake <eblake@redhat.com>
4
return offsets that are cluster-aligned so don't just check that they
6
Message-id: 20190603202236.1342-3-mreitz@redhat.com
5
are sector-aligned.
7
Reviewed-by: John Snow <jsnow@redhat.com>
6
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
The check in qcow2_co_preadv_task() is also replaced by an assertion
8
for the same reason.
9
10
Signed-off-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Message-id: 558ba339965f858bede4c73ce3f50f0c0493597d.1579374329.git.berto@igalia.com
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
14
---
11
blockdev.c | 10 +++++-----
15
block/qcow2.c | 9 +++------
12
tests/qemu-iotests/085.out | 10 +++++-----
16
1 file changed, 3 insertions(+), 6 deletions(-)
13
2 files changed, 10 insertions(+), 10 deletions(-)
14
17
15
diff --git a/blockdev.c b/blockdev.c
18
diff --git a/block/qcow2.c b/block/qcow2.c
16
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
17
--- a/blockdev.c
20
--- a/block/qcow2.c
18
+++ b/blockdev.c
21
+++ b/block/qcow2.c
19
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
22
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
20
s->has_snapshot_node_name ? s->snapshot_node_name : NULL;
23
offset, bytes, qiov, qiov_offset);
21
24
22
if (node_name && !snapshot_node_name) {
25
case QCOW2_CLUSTER_NORMAL:
23
- error_setg(errp, "New snapshot node name missing");
26
- if ((file_cluster_offset & 511) != 0) {
24
+ error_setg(errp, "New overlay node name missing");
27
- return -EIO;
25
goto out;
28
- }
29
-
30
+ assert(offset_into_cluster(s, file_cluster_offset) == 0);
31
if (bs->encrypted) {
32
return qcow2_co_preadv_encrypted(bs, file_cluster_offset,
33
offset, bytes, qiov, qiov_offset);
34
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev_part(
35
goto out_locked;
26
}
36
}
27
37
28
if (snapshot_node_name &&
38
- assert((cluster_offset & 511) == 0);
29
bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) {
39
+ assert(offset_into_cluster(s, cluster_offset) == 0);
30
- error_setg(errp, "New snapshot node name already in use");
40
31
+ error_setg(errp, "New overlay node name already in use");
41
ret = qcow2_pre_write_overlap_check(bs, 0,
32
goto out;
42
cluster_offset + offset_in_cluster,
43
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_to(BlockDriverState *bs,
44
goto fail;
33
}
45
}
34
46
35
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
47
- assert((cluster_offset & 511) == 0);
36
}
48
+ assert(offset_into_cluster(s, cluster_offset) == 0);
37
49
38
if (bdrv_has_blk(state->new_bs)) {
50
ret = qcow2_pre_write_overlap_check(bs, 0,
39
- error_setg(errp, "The snapshot is already in use");
51
cluster_offset + offset_in_cluster, cur_bytes, true);
40
+ error_setg(errp, "The overlay is already in use");
41
goto out;
42
}
43
44
@@ -XXX,XX +XXX,XX @@ static void external_snapshot_prepare(BlkActionState *common,
45
}
46
47
if (state->new_bs->backing != NULL) {
48
- error_setg(errp, "The snapshot already has a backing image");
49
+ error_setg(errp, "The overlay already has a backing image");
50
goto out;
51
}
52
53
if (!state->new_bs->drv->supports_backing) {
54
- error_setg(errp, "The snapshot does not support backing images");
55
+ error_setg(errp, "The overlay does not support backing images");
56
goto out;
57
}
58
59
diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out
60
index XXXXXXX..XXXXXXX 100644
61
--- a/tests/qemu-iotests/085.out
62
+++ b/tests/qemu-iotests/085.out
63
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/
64
65
=== Invalid command - cannot create a snapshot using a file BDS ===
66
67
-{"error": {"class": "GenericError", "desc": "The snapshot does not support backing images"}}
68
+{"error": {"class": "GenericError", "desc": "The overlay does not support backing images"}}
69
70
=== Invalid command - snapshot node used as active layer ===
71
72
-{"error": {"class": "GenericError", "desc": "The snapshot is already in use"}}
73
-{"error": {"class": "GenericError", "desc": "The snapshot is already in use"}}
74
-{"error": {"class": "GenericError", "desc": "The snapshot is already in use"}}
75
+{"error": {"class": "GenericError", "desc": "The overlay is already in use"}}
76
+{"error": {"class": "GenericError", "desc": "The overlay is already in use"}}
77
+{"error": {"class": "GenericError", "desc": "The overlay is already in use"}}
78
79
=== Invalid command - snapshot node used as backing hd ===
80
81
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/
82
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
83
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base
84
{"return": {}}
85
-{"error": {"class": "GenericError", "desc": "The snapshot already has a backing image"}}
86
+{"error": {"class": "GenericError", "desc": "The overlay already has a backing image"}}
87
88
=== Invalid command - The node does not exist ===
89
90
--
52
--
91
2.21.0
53
2.24.1
92
54
93
55
diff view generated by jsdifflib
1
This new error option allows users of blkdebug to inject errors only on
1
From: Alberto Garcia <berto@igalia.com>
2
certain kinds of I/O operations. Users usually want to make a very
3
specific operation fail, not just any; but right now they simply hope
4
that the event that triggers the error injection is followed up with
5
that very operation. That may not be true, however, because the block
6
layer is changing (including blkdebug, which may increase the number of
7
types of I/O operations on which to inject errors).
8
2
9
The new option's default has been chosen to keep backwards
3
When updating an L1 entry the qcow2 driver writes a (512-byte) sector
10
compatibility.
4
worth of data to avoid a read-modify-write cycle. Instead of always
5
writing 512 bytes we should follow the alignment requirements of the
6
storage backend.
11
7
12
Note that similar to the internal representation, we could choose to
8
(the only exception is when the alignment is larger than the cluster
13
expose this option as a list of I/O types. But there is no practical
9
size because then we could be overwriting data after the L1 table)
14
use for this, because as described above, users usually know exactly
15
which kind of operation they want to make fail, so there is no need to
16
specify multiple I/O types at once. In addition, exposing this option
17
as a list would require non-trivial changes to qemu_opts_absorb_qdict().
18
10
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Alberto Garcia <berto@igalia.com>
20
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Message-id: 71f34d4ae4b367b32fb36134acbf4f4f7ee681f4.1579374329.git.berto@igalia.com
21
Message-id: 20190507203508.18026-4-mreitz@redhat.com
13
Reviewed-by: Max Reitz <mreitz@redhat.com>
22
Signed-off-by: Max Reitz <mreitz@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
23
---
15
---
24
qapi/block-core.json | 26 +++++++++++++++++++++++
16
block/qcow2-cluster.c | 25 +++++++++++++++----------
25
block/blkdebug.c | 50 ++++++++++++++++++++++++++++++++++++--------
17
1 file changed, 15 insertions(+), 10 deletions(-)
26
2 files changed, 67 insertions(+), 9 deletions(-)
27
18
28
diff --git a/qapi/block-core.json b/qapi/block-core.json
19
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
29
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
30
--- a/qapi/block-core.json
21
--- a/block/qcow2-cluster.c
31
+++ b/qapi/block-core.json
22
+++ b/block/qcow2-cluster.c
32
@@ -XXX,XX +XXX,XX @@
23
@@ -XXX,XX +XXX,XX @@ static int l2_load(BlockDriverState *bs, uint64_t offset,
33
'l1_shrink_write_table', 'l1_shrink_free_l2_clusters',
24
}
34
'cor_write', 'cluster_alloc_space'] }
25
35
26
/*
36
+##
27
- * Writes one sector of the L1 table to the disk (can't update single entries
37
+# @BlkdebugIOType:
28
- * and we really don't want bdrv_pread to perform a read-modify-write)
38
+#
29
+ * Writes an L1 entry to disk (note that depending on the alignment
39
+# Kinds of I/O that blkdebug can inject errors in.
30
+ * requirements this function may write more that just one entry in
40
+#
31
+ * order to prevent bdrv_pwrite from performing a read-modify-write)
41
+# @read: .bdrv_co_preadv()
32
*/
42
+#
33
-#define L1_ENTRIES_PER_SECTOR (512 / 8)
43
+# @write: .bdrv_co_pwritev()
34
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
44
+#
35
{
45
+# @write-zeroes: .bdrv_co_pwrite_zeroes()
36
BDRVQcow2State *s = bs->opaque;
46
+#
37
- uint64_t buf[L1_ENTRIES_PER_SECTOR] = { 0 };
47
+# @discard: .bdrv_co_pdiscard()
38
int l1_start_index;
48
+#
39
int i, ret;
49
+# @flush: .bdrv_co_flush_to_disk()
40
+ int bufsize = MAX(sizeof(uint64_t),
50
+#
41
+ MIN(bs->file->bs->bl.request_alignment, s->cluster_size));
51
+# Since: 4.1
42
+ int nentries = bufsize / sizeof(uint64_t);
52
+##
43
+ g_autofree uint64_t *buf = g_try_new0(uint64_t, nentries);
53
+{ 'enum': 'BlkdebugIOType', 'prefix': 'BLKDEBUG_IO_TYPE',
44
54
+ 'data': [ 'read', 'write', 'write-zeroes', 'discard', 'flush' ] }
45
- l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
46
- for (i = 0; i < L1_ENTRIES_PER_SECTOR && l1_start_index + i < s->l1_size;
47
- i++)
48
- {
49
+ if (buf == NULL) {
50
+ return -ENOMEM;
51
+ }
55
+
52
+
56
##
53
+ l1_start_index = QEMU_ALIGN_DOWN(l1_index, nentries);
57
# @BlkdebugInjectErrorOptions:
54
+ for (i = 0; i < MIN(nentries, s->l1_size - l1_start_index); i++) {
58
#
55
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
59
@@ -XXX,XX +XXX,XX @@
60
# @state: the state identifier blkdebug needs to be in to
61
# actually trigger the event; defaults to "any"
62
#
63
+# @iotype: the type of I/O operations on which this error should
64
+# be injected; defaults to "all read, write,
65
+# write-zeroes, discard, and flush operations"
66
+# (since: 4.1)
67
+#
68
# @errno: error identifier (errno) to be returned; defaults to
69
# EIO
70
#
71
@@ -XXX,XX +XXX,XX @@
72
{ 'struct': 'BlkdebugInjectErrorOptions',
73
'data': { 'event': 'BlkdebugEvent',
74
'*state': 'int',
75
+ '*iotype': 'BlkdebugIOType',
76
'*errno': 'int',
77
'*sector': 'int',
78
'*once': 'bool',
79
diff --git a/block/blkdebug.c b/block/blkdebug.c
80
index XXXXXXX..XXXXXXX 100644
81
--- a/block/blkdebug.c
82
+++ b/block/blkdebug.c
83
@@ -XXX,XX +XXX,XX @@ typedef struct BlkdebugRule {
84
int state;
85
union {
86
struct {
87
+ uint64_t iotype_mask;
88
int error;
89
int immediately;
90
int once;
91
@@ -XXX,XX +XXX,XX @@ typedef struct BlkdebugRule {
92
QSIMPLEQ_ENTRY(BlkdebugRule) active_next;
93
} BlkdebugRule;
94
95
+QEMU_BUILD_BUG_MSG(BLKDEBUG_IO_TYPE__MAX > 64,
96
+ "BlkdebugIOType mask does not fit into an uint64_t");
97
+
98
static QemuOptsList inject_error_opts = {
99
.name = "inject-error",
100
.head = QTAILQ_HEAD_INITIALIZER(inject_error_opts.head),
101
@@ -XXX,XX +XXX,XX @@ static QemuOptsList inject_error_opts = {
102
.name = "state",
103
.type = QEMU_OPT_NUMBER,
104
},
105
+ {
106
+ .name = "iotype",
107
+ .type = QEMU_OPT_STRING,
108
+ },
109
{
110
.name = "errno",
111
.type = QEMU_OPT_NUMBER,
112
@@ -XXX,XX +XXX,XX @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
113
int event;
114
struct BlkdebugRule *rule;
115
int64_t sector;
116
+ BlkdebugIOType iotype;
117
+ Error *local_error = NULL;
118
119
/* Find the right event for the rule */
120
event_name = qemu_opt_get(opts, "event");
121
@@ -XXX,XX +XXX,XX @@ static int add_rule(void *opaque, QemuOpts *opts, Error **errp)
122
sector = qemu_opt_get_number(opts, "sector", -1);
123
rule->options.inject.offset =
124
sector == -1 ? -1 : sector * BDRV_SECTOR_SIZE;
125
+
126
+ iotype = qapi_enum_parse(&BlkdebugIOType_lookup,
127
+ qemu_opt_get(opts, "iotype"),
128
+ BLKDEBUG_IO_TYPE__MAX, &local_error);
129
+ if (local_error) {
130
+ error_propagate(errp, local_error);
131
+ return -1;
132
+ }
133
+ if (iotype != BLKDEBUG_IO_TYPE__MAX) {
134
+ rule->options.inject.iotype_mask = (1ull << iotype);
135
+ } else {
136
+ /* Apply the default */
137
+ rule->options.inject.iotype_mask =
138
+ (1ull << BLKDEBUG_IO_TYPE_READ)
139
+ | (1ull << BLKDEBUG_IO_TYPE_WRITE)
140
+ | (1ull << BLKDEBUG_IO_TYPE_WRITE_ZEROES)
141
+ | (1ull << BLKDEBUG_IO_TYPE_DISCARD)
142
+ | (1ull << BLKDEBUG_IO_TYPE_FLUSH);
143
+ }
144
+
145
break;
146
147
case ACTION_SET_STATE:
148
@@ -XXX,XX +XXX,XX @@ out:
149
return ret;
150
}
151
152
-static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes)
153
+static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
154
+ BlkdebugIOType iotype)
155
{
156
BDRVBlkdebugState *s = bs->opaque;
157
BlkdebugRule *rule = NULL;
158
@@ -XXX,XX +XXX,XX @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes)
159
QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
160
uint64_t inject_offset = rule->options.inject.offset;
161
162
- if (inject_offset == -1 ||
163
- (bytes && inject_offset >= offset &&
164
- inject_offset < offset + bytes))
165
+ if ((inject_offset == -1 ||
166
+ (bytes && inject_offset >= offset &&
167
+ inject_offset < offset + bytes)) &&
168
+ (rule->options.inject.iotype_mask & (1ull << iotype)))
169
{
170
break;
171
}
172
@@ -XXX,XX +XXX,XX @@ blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
173
assert(bytes <= bs->bl.max_transfer);
174
}
56
}
175
57
176
- err = rule_check(bs, offset, bytes);
58
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1,
177
+ err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_READ);
59
- s->l1_table_offset + 8 * l1_start_index, sizeof(buf), false);
178
if (err) {
60
+ s->l1_table_offset + 8 * l1_start_index, bufsize, false);
179
return err;
61
if (ret < 0) {
62
return ret;
180
}
63
}
181
@@ -XXX,XX +XXX,XX @@ blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
64
@@ -XXX,XX +XXX,XX @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
182
assert(bytes <= bs->bl.max_transfer);
65
BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);
183
}
66
ret = bdrv_pwrite_sync(bs->file,
184
67
s->l1_table_offset + 8 * l1_start_index,
185
- err = rule_check(bs, offset, bytes);
68
- buf, sizeof(buf));
186
+ err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_WRITE);
69
+ buf, bufsize);
187
if (err) {
70
if (ret < 0) {
188
return err;
71
return ret;
189
}
190
@@ -XXX,XX +XXX,XX @@ blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
191
192
static int blkdebug_co_flush(BlockDriverState *bs)
193
{
194
- int err = rule_check(bs, 0, 0);
195
+ int err = rule_check(bs, 0, 0, BLKDEBUG_IO_TYPE_FLUSH);
196
197
if (err) {
198
return err;
199
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
200
assert(bytes <= bs->bl.max_pwrite_zeroes);
201
}
202
203
- err = rule_check(bs, offset, bytes);
204
+ err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_WRITE_ZEROES);
205
if (err) {
206
return err;
207
}
208
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
209
assert(bytes <= bs->bl.max_pdiscard);
210
}
211
212
- err = rule_check(bs, offset, bytes);
213
+ err = rule_check(bs, offset, bytes, BLKDEBUG_IO_TYPE_DISCARD);
214
if (err) {
215
return err;
216
}
72
}
217
--
73
--
218
2.21.0
74
2.24.1
219
75
220
76
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
in blockdev_backup_prepare, we check to make sure that the target is
3
qemu-img's convert_co_copy_range() operates at the sector level and
4
associated with a compatible aio context. However, do_blockdev_backup is
4
block_copy() operates at the cluster level so this condition is always
5
called later and has some logic to move the target to a compatible
5
true, but it is not necessary to restrict this here, so let's leave it
6
aio_context. The transaction version will fail certain commands
6
to the driver implementation return an error if there is any.
7
needlessly early as a result.
8
7
9
Allow blockdev_backup_prepare to simply call do_blockdev_backup, which
8
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
will ultimately decide if the contexts are compatible or not.
9
Message-id: a4264aaee656910c84161a2965f7a501437379ca.1579374329.git.berto@igalia.com
11
12
Note: the transaction version has always disallowed this operation since
13
its initial commit bd8baecd (2014), whereas the version of
14
qmp_blockdev_backup at the time, from commit c29c1dd312f, tried to
15
enforce the aio_context switch instead. It's not clear, and I can't see
16
from the mailing list archives at the time, why the two functions take a
17
different approach. It wasn't until later in efd7556708b (2016) that the
18
standalone version tried to determine if it could set the context or
19
not.
20
21
Reported-by: aihua liang <aliang@redhat.com>
22
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1683498
23
Signed-off-by: John Snow <jsnow@redhat.com>
24
Message-id: 20190523170643.20794-2-jsnow@redhat.com
25
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
26
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
27
---
12
---
28
blockdev.c | 4 ----
13
block/qcow2.c | 4 ----
29
1 file changed, 4 deletions(-)
14
1 file changed, 4 deletions(-)
30
15
31
diff --git a/blockdev.c b/blockdev.c
16
diff --git a/block/qcow2.c b/block/qcow2.c
32
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
33
--- a/blockdev.c
18
--- a/block/qcow2.c
34
+++ b/blockdev.c
19
+++ b/block/qcow2.c
35
@@ -XXX,XX +XXX,XX @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
20
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
36
}
21
case QCOW2_CLUSTER_NORMAL:
37
22
child = s->data_file;
38
aio_context = bdrv_get_aio_context(bs);
23
copy_offset += offset_into_cluster(s, src_offset);
39
- if (aio_context != bdrv_get_aio_context(target)) {
24
- if ((copy_offset & 511) != 0) {
40
- error_setg(errp, "Backup between two IO threads is not implemented");
25
- ret = -EIO;
41
- return;
26
- goto out;
42
- }
27
- }
43
aio_context_acquire(aio_context);
28
break;
44
state->bs = bs;
29
45
30
default:
46
--
31
--
47
2.21.0
32
2.24.1
48
33
49
34
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
Cap waits to 60 seconds so that iotests can fail gracefully if something
4
goes wrong.
5
6
Signed-off-by: John Snow <jsnow@redhat.com>
7
Message-id: 20190523170643.20794-3-jsnow@redhat.com
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
11
tests/qemu-iotests/iotests.py | 14 +++++++-------
12
1 file changed, 7 insertions(+), 7 deletions(-)
13
14
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
15
index XXXXXXX..XXXXXXX 100644
16
--- a/tests/qemu-iotests/iotests.py
17
+++ b/tests/qemu-iotests/iotests.py
18
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
19
output_list += [key + '=' + obj[key]]
20
return ','.join(output_list)
21
22
- def get_qmp_events_filtered(self, wait=True):
23
+ def get_qmp_events_filtered(self, wait=60.0):
24
result = []
25
for ev in self.get_qmp_events(wait=wait):
26
result.append(filter_qmp_event(ev))
27
@@ -XXX,XX +XXX,XX @@ class VM(qtest.QEMUQtestMachine):
28
29
# Returns None on success, and an error string on failure
30
def run_job(self, job, auto_finalize=True, auto_dismiss=False,
31
- pre_finalize=None):
32
+ pre_finalize=None, wait=60.0):
33
error = None
34
while True:
35
- for ev in self.get_qmp_events_filtered(wait=True):
36
+ for ev in self.get_qmp_events_filtered(wait=wait):
37
if ev['event'] == 'JOB_STATUS_CHANGE':
38
status = ev['data']['status']
39
if status == 'aborting':
40
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
41
self.assertEqual(self.vm.flatten_qmp_object(json.loads(json_filename[5:])),
42
self.vm.flatten_qmp_object(reference))
43
44
- def cancel_and_wait(self, drive='drive0', force=False, resume=False):
45
+ def cancel_and_wait(self, drive='drive0', force=False, resume=False, wait=60.0):
46
'''Cancel a block job and wait for it to finish, returning the event'''
47
result = self.vm.qmp('block-job-cancel', device=drive, force=force)
48
self.assert_qmp(result, 'return', {})
49
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
50
cancelled = False
51
result = None
52
while not cancelled:
53
- for event in self.vm.get_qmp_events(wait=True):
54
+ for event in self.vm.get_qmp_events(wait=wait):
55
if event['event'] == 'BLOCK_JOB_COMPLETED' or \
56
event['event'] == 'BLOCK_JOB_CANCELLED':
57
self.assert_qmp(event, 'data/device', drive)
58
@@ -XXX,XX +XXX,XX @@ class QMPTestCase(unittest.TestCase):
59
self.assert_no_active_block_jobs()
60
return result
61
62
- def wait_until_completed(self, drive='drive0', check_offset=True):
63
+ def wait_until_completed(self, drive='drive0', check_offset=True, wait=60.0):
64
'''Wait for a block job to finish, returning the event'''
65
while True:
66
- for event in self.vm.get_qmp_events(wait=True):
67
+ for event in self.vm.get_qmp_events(wait=wait):
68
if event['event'] == 'BLOCK_JOB_COMPLETED':
69
self.assert_qmp(event, 'data/device', drive)
70
self.assert_qmp_absent(event, 'data/error')
71
--
72
2.21.0
73
74
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
Instead of event_wait which looks for a single event, add an events_wait
3
This replaces all remaining instances in the qcow2 code.
4
which can look for any number of events simultaneously. However, it
5
will still only return one at a time, whichever happens first.
6
4
7
Signed-off-by: John Snow <jsnow@redhat.com>
5
Signed-off-by: Alberto Garcia <berto@igalia.com>
8
Message-id: 20190523170643.20794-4-jsnow@redhat.com
6
Message-id: b5f74b606c2d9873b12d29acdb7fd498029c4025.1579374329.git.berto@igalia.com
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
9
---
12
python/qemu/__init__.py | 69 +++++++++++++++++++++++++++++------------
10
block/qcow2.c | 8 +++++---
13
1 file changed, 49 insertions(+), 20 deletions(-)
11
1 file changed, 5 insertions(+), 3 deletions(-)
14
12
15
diff --git a/python/qemu/__init__.py b/python/qemu/__init__.py
13
diff --git a/block/qcow2.c b/block/qcow2.c
16
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
17
--- a/python/qemu/__init__.py
15
--- a/block/qcow2.c
18
+++ b/python/qemu/__init__.py
16
+++ b/block/qcow2.c
19
@@ -XXX,XX +XXX,XX @@ class QEMUMachine(object):
17
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
20
self._qmp.clear_events()
18
21
return events
19
/* Validate options and set default values */
22
20
if (!QEMU_IS_ALIGNED(qcow2_opts->size, BDRV_SECTOR_SIZE)) {
23
- def event_wait(self, name, timeout=60.0, match=None):
21
- error_setg(errp, "Image size must be a multiple of 512 bytes");
24
+ @staticmethod
22
+ error_setg(errp, "Image size must be a multiple of %u bytes",
25
+ def event_match(event, match=None):
23
+ (unsigned) BDRV_SECTOR_SIZE);
26
"""
24
ret = -EINVAL;
27
- Wait for specified timeout on named event in QMP; optionally filter
25
goto out;
28
- results by match.
26
}
29
+ Check if an event matches optional match criteria.
27
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
30
28
return -ENOTSUP;
31
- The 'match' is checked to be a recursive subset of the 'event'; skips
29
}
32
- branch processing on match's value None
30
33
- {"foo": {"bar": 1}} matches {"foo": None}
31
- if (offset & 511) {
34
- {"foo": {"bar": 1}} does not matches {"foo": {"baz": None}}
32
- error_setg(errp, "The new size must be a multiple of 512");
35
+ The match criteria takes the form of a matching subdict. The event is
33
+ if (!QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)) {
36
+ checked to be a superset of the subdict, recursively, with matching
34
+ error_setg(errp, "The new size must be a multiple of %u",
37
+ values whenever those values are not None.
35
+ (unsigned) BDRV_SECTOR_SIZE);
38
+
36
return -EINVAL;
39
+ Examples, with the subdict queries on the left:
37
}
40
+ - None matches any object.
41
+ - {"foo": None} matches {"foo": {"bar": 1}}
42
+ - {"foo": {"baz": None}} does not match {"foo": {"bar": 1}}
43
+ - {"foo": {"baz": 2}} matches {"foo": {"bar": 1, "baz": 2}}
44
"""
45
- def event_match(event, match=None):
46
- if match is None:
47
- return True
48
+ if match is None:
49
+ return True
50
51
- for key in match:
52
- if key in event:
53
- if isinstance(event[key], dict):
54
- if not event_match(event[key], match[key]):
55
- return False
56
- elif event[key] != match[key]:
57
+ for key in match:
58
+ if key in event:
59
+ if isinstance(event[key], dict):
60
+ if not QEMUMachine.event_match(event[key], match[key]):
61
return False
62
- else:
63
+ elif event[key] != match[key]:
64
return False
65
+ else:
66
+ return False
67
+ return True
68
69
- return True
70
+ def event_wait(self, name, timeout=60.0, match=None):
71
+ """
72
+ event_wait waits for and returns a named event from QMP with a timeout.
73
+
74
+ name: The event to wait for.
75
+ timeout: QEMUMonitorProtocol.pull_event timeout parameter.
76
+ match: Optional match criteria. See event_match for details.
77
+ """
78
+ return self.events_wait([(name, match)], timeout)
79
+
80
+ def events_wait(self, events, timeout=60.0):
81
+ """
82
+ events_wait waits for and returns a named event from QMP with a timeout.
83
+
84
+ events: a sequence of (name, match_criteria) tuples.
85
+ The match criteria are optional and may be None.
86
+ See event_match for details.
87
+ timeout: QEMUMonitorProtocol.pull_event timeout parameter.
88
+ """
89
+ def _match(event):
90
+ for name, match in events:
91
+ if (event['event'] == name and
92
+ self.event_match(event, match)):
93
+ return True
94
+ return False
95
96
# Search cached events
97
for event in self._events:
98
- if (event['event'] == name) and event_match(event, match):
99
+ if _match(event):
100
self._events.remove(event)
101
return event
102
103
# Poll for new events
104
while True:
105
event = self._qmp.pull_event(wait=timeout)
106
- if (event['event'] == name) and event_match(event, match):
107
+ if _match(event):
108
return event
109
self._events.append(event)
110
38
111
--
39
--
112
2.21.0
40
2.24.1
113
41
114
42
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Test fails at least for qcow, because of different cluster sizes in
3
We can't access top after call bdrv_backup_top_drop, as it is already
4
base and top (and therefore different granularities of bitmaps we are
4
freed at this time.
5
trying to merge).
6
5
7
The test aim is to check block-dirty-bitmap-merge between different
6
Also, no needs to unref target child by hand, it will be unrefed on
8
nodes functionality, no needs to check all formats. So, let's just drop
7
bdrv_close() automatically.
9
support for anything except qcow2.
10
8
11
Reported-by: Max Reitz <mreitz@redhat.com>
9
So, just do bdrv_backup_top_drop if append succeed and one bdrv_unref
10
otherwise.
11
12
Note, that in !appended case bdrv_unref(top) moved into drained section
13
on source. It doesn't really matter, but just for code simplicity.
14
15
Fixes: 7df7868b96404
16
Cc: qemu-stable@nongnu.org # v4.2.0
12
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
17
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Message-id: 20190605155405.104384-1-vsementsov@virtuozzo.com
18
Reviewed-by: Max Reitz <mreitz@redhat.com>
19
Message-id: 20200121142802.21467-2-vsementsov@virtuozzo.com
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
20
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
---
21
---
16
tests/qemu-iotests/254 | 2 ++
22
block/backup-top.c | 21 ++++++++++++---------
17
1 file changed, 2 insertions(+)
23
1 file changed, 12 insertions(+), 9 deletions(-)
18
24
19
diff --git a/tests/qemu-iotests/254 b/tests/qemu-iotests/254
25
diff --git a/block/backup-top.c b/block/backup-top.c
20
index XXXXXXX..XXXXXXX 100755
26
index XXXXXXX..XXXXXXX 100644
21
--- a/tests/qemu-iotests/254
27
--- a/block/backup-top.c
22
+++ b/tests/qemu-iotests/254
28
+++ b/block/backup-top.c
23
@@ -XXX,XX +XXX,XX @@
29
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
24
import iotests
30
BlockDriverState *top = bdrv_new_open_driver(&bdrv_backup_top_filter,
25
from iotests import qemu_img_create, file_path, log
31
filter_node_name,
26
32
BDRV_O_RDWR, errp);
27
+iotests.verify_image_format(supported_fmts=['qcow2'])
33
+ bool appended = false;
28
+
34
29
disk, top = file_path('disk', 'top')
35
if (!top) {
30
size = 1024 * 1024
36
return NULL;
31
37
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
38
bdrv_append(top, source, &local_err);
39
if (local_err) {
40
error_prepend(&local_err, "Cannot append backup-top filter: ");
41
- goto append_failed;
42
+ goto fail;
43
}
44
+ appended = true;
45
46
/*
47
* bdrv_append() finished successfully, now we can require permissions
48
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
49
if (local_err) {
50
error_prepend(&local_err,
51
"Cannot set permissions for backup-top filter: ");
52
- goto failed_after_append;
53
+ goto fail;
54
}
55
56
state->bcs = block_copy_state_new(top->backing, state->target,
57
cluster_size, write_flags, &local_err);
58
if (local_err) {
59
error_prepend(&local_err, "Cannot create block-copy-state: ");
60
- goto failed_after_append;
61
+ goto fail;
62
}
63
*bcs = state->bcs;
64
65
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
66
67
return top;
68
69
-failed_after_append:
70
- state->active = false;
71
- bdrv_backup_top_drop(top);
72
+fail:
73
+ if (appended) {
74
+ state->active = false;
75
+ bdrv_backup_top_drop(top);
76
+ } else {
77
+ bdrv_unref(top);
78
+ }
79
80
-append_failed:
81
bdrv_drained_end(source);
82
- bdrv_unref_child(top, state->target);
83
- bdrv_unref(top);
84
error_propagate(errp, local_err);
85
86
return NULL;
32
--
87
--
33
2.21.0
88
2.24.1
34
89
35
90
diff view generated by jsdifflib
1
From: John Snow <jsnow@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Signed-off-by: John Snow <jsnow@redhat.com>
3
This test checks that bug is really fixed by previous commit.
4
Message-id: 20190523170643.20794-6-jsnow@redhat.com
4
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Cc: qemu-stable@nongnu.org # v4.2.0
6
[mreitz: Moved from 250 to 256]
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Message-id: 20200121142802.21467-3-vsementsov@virtuozzo.com
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
9
---
9
tests/qemu-iotests/256 | 122 +++++++++++++++++++++++++++++++++++++
10
tests/qemu-iotests/283 | 92 ++++++++++++++++++++++++++++++++++++++
10
tests/qemu-iotests/256.out | 119 ++++++++++++++++++++++++++++++++++++
11
tests/qemu-iotests/283.out | 8 ++++
11
tests/qemu-iotests/group | 1 +
12
tests/qemu-iotests/group | 1 +
12
3 files changed, 242 insertions(+)
13
3 files changed, 101 insertions(+)
13
create mode 100755 tests/qemu-iotests/256
14
create mode 100644 tests/qemu-iotests/283
14
create mode 100644 tests/qemu-iotests/256.out
15
create mode 100644 tests/qemu-iotests/283.out
15
16
16
diff --git a/tests/qemu-iotests/256 b/tests/qemu-iotests/256
17
diff --git a/tests/qemu-iotests/283 b/tests/qemu-iotests/283
17
new file mode 100755
18
new file mode 100644
18
index XXXXXXX..XXXXXXX
19
index XXXXXXX..XXXXXXX
19
--- /dev/null
20
--- /dev/null
20
+++ b/tests/qemu-iotests/256
21
+++ b/tests/qemu-iotests/283
21
@@ -XXX,XX +XXX,XX @@
22
@@ -XXX,XX +XXX,XX @@
22
+#!/usr/bin/env python
23
+#!/usr/bin/env python
23
+#
24
+#
24
+# Test incremental/backup across iothread contexts
25
+# Test for backup-top filter permission activation failure
25
+#
26
+#
26
+# Copyright (c) 2019 John Snow for Red Hat, Inc.
27
+# Copyright (c) 2019 Virtuozzo International GmbH.
27
+#
28
+#
28
+# This program is free software; you can redistribute it and/or modify
29
+# This program is free software; you can redistribute it and/or modify
29
+# it under the terms of the GNU General Public License as published by
30
+# it under the terms of the GNU General Public License as published by
30
+# the Free Software Foundation; either version 2 of the License, or
31
+# the Free Software Foundation; either version 2 of the License, or
31
+# (at your option) any later version.
32
+# (at your option) any later version.
...
...
36
+# GNU General Public License for more details.
37
+# GNU General Public License for more details.
37
+#
38
+#
38
+# You should have received a copy of the GNU General Public License
39
+# You should have received a copy of the GNU General Public License
39
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
40
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
40
+#
41
+#
41
+# owner=jsnow@redhat.com
42
+
42
+
43
+import os
44
+import iotests
43
+import iotests
45
+from iotests import log
46
+
44
+
45
+# The test is unrelated to formats, restrict it to qcow2 to avoid extra runs
47
+iotests.verify_image_format(supported_fmts=['qcow2'])
46
+iotests.verify_image_format(supported_fmts=['qcow2'])
48
+size = 64 * 1024 * 1024
49
+
47
+
50
+with iotests.FilePath('img0') as img0_path, \
48
+size = 1024 * 1024
51
+ iotests.FilePath('img1') as img1_path, \
52
+ iotests.FilePath('img0-full') as img0_full_path, \
53
+ iotests.FilePath('img1-full') as img1_full_path, \
54
+ iotests.FilePath('img0-incr') as img0_incr_path, \
55
+ iotests.FilePath('img1-incr') as img1_incr_path, \
56
+ iotests.VM() as vm:
57
+
49
+
58
+ def create_target(filepath, name, size):
50
+""" Test description
59
+ basename = os.path.basename(filepath)
60
+ nodename = "file_{}".format(basename)
61
+ log(vm.command('blockdev-create', job_id='job1',
62
+ options={
63
+ 'driver': 'file',
64
+ 'filename': filepath,
65
+ 'size': 0,
66
+ }))
67
+ vm.run_job('job1')
68
+ log(vm.command('blockdev-add', driver='file',
69
+ node_name=nodename, filename=filepath))
70
+ log(vm.command('blockdev-create', job_id='job2',
71
+ options={
72
+ 'driver': iotests.imgfmt,
73
+ 'file': nodename,
74
+ 'size': size,
75
+ }))
76
+ vm.run_job('job2')
77
+ log(vm.command('blockdev-add', driver=iotests.imgfmt,
78
+ node_name=name,
79
+ file=nodename))
80
+
51
+
81
+ log('--- Preparing images & VM ---\n')
52
+When performing a backup, all writes on the source subtree must go through the
82
+ vm.add_object('iothread,id=iothread0')
53
+backup-top filter so it can copy all data to the target before it is changed.
83
+ vm.add_object('iothread,id=iothread1')
54
+backup-top filter is appended above source node, to achieve this thing, so all
84
+ vm.add_device('virtio-scsi-pci,id=scsi0,iothread=iothread0')
55
+parents of source node are handled. A configuration with side parents of source
85
+ vm.add_device('virtio-scsi-pci,id=scsi1,iothread=iothread1')
56
+sub-tree with write permission is unsupported (we'd have append several
86
+ iotests.qemu_img_create('-f', iotests.imgfmt, img0_path, str(size))
57
+backup-top filter like nodes to handle such parents). The test create an
87
+ iotests.qemu_img_create('-f', iotests.imgfmt, img1_path, str(size))
58
+example of such configuration and checks that a backup is then not allowed
88
+ vm.add_drive(img0_path, interface='none')
59
+(blockdev-backup command should fail).
89
+ vm.add_device('scsi-hd,id=device0,drive=drive0,bus=scsi0.0')
90
+ vm.add_drive(img1_path, interface='none')
91
+ vm.add_device('scsi-hd,id=device1,drive=drive1,bus=scsi1.0')
92
+
60
+
93
+ log('--- Starting VM ---\n')
61
+The configuration:
94
+ vm.launch()
95
+
62
+
96
+ log('--- Create Targets & Full Backups ---\n')
63
+ ┌────────┐ target ┌─────────────┐
97
+ create_target(img0_full_path, 'img0-full', size)
64
+ │ target │ ◀─────── │ backup_top │
98
+ create_target(img1_full_path, 'img1-full', size)
65
+ └────────┘ └─────────────┘
99
+ ret = vm.qmp_log('transaction', indent=2, actions=[
66
+ │
100
+ { 'type': 'block-dirty-bitmap-add',
67
+ │ backing
101
+ 'data': { 'node': 'drive0', 'name': 'bitmap0' }},
68
+ ▼
102
+ { 'type': 'block-dirty-bitmap-add',
69
+ ┌─────────────┐
103
+ 'data': { 'node': 'drive1', 'name': 'bitmap1' }},
70
+ │ source │
104
+ { 'type': 'blockdev-backup',
71
+ └─────────────┘
105
+ 'data': { 'device': 'drive0',
72
+ │
106
+ 'target': 'img0-full',
73
+ │ file
107
+ 'sync': 'full',
74
+ ▼
108
+ 'job-id': 'j0' }},
75
+ ┌─────────────┐ write perm ┌───────┐
109
+ { 'type': 'blockdev-backup',
76
+ │ base │ ◀──────────── │ other │
110
+ 'data': { 'device': 'drive1',
77
+ └─────────────┘ └───────┘
111
+ 'target': 'img1-full',
112
+ 'sync': 'full',
113
+ 'job-id': 'j1' }}
114
+ ])
115
+ if "error" in ret:
116
+ raise Exception(ret['error']['desc'])
117
+ vm.run_job('j0', auto_dismiss=True)
118
+ vm.run_job('j1', auto_dismiss=True)
119
+
78
+
120
+ log('\n--- Create Targets & Incremental Backups ---\n')
79
+On activation (see .active field of backup-top state in block/backup-top.c),
121
+ create_target(img0_incr_path, 'img0-incr', size)
80
+backup-top is going to unshare write permission on its source child. Write
122
+ create_target(img1_incr_path, 'img1-incr', size)
81
+unsharing will be propagated to the "source->base" link and will conflict with
123
+ ret = vm.qmp_log('transaction', indent=2, actions=[
82
+other node write permission. So permission update will fail and backup job will
124
+ { 'type': 'blockdev-backup',
83
+not be started.
125
+ 'data': { 'device': 'drive0',
126
+ 'target': 'img0-incr',
127
+ 'sync': 'incremental',
128
+ 'bitmap': 'bitmap0',
129
+ 'job-id': 'j2' }},
130
+ { 'type': 'blockdev-backup',
131
+ 'data': { 'device': 'drive1',
132
+ 'target': 'img1-incr',
133
+ 'sync': 'incremental',
134
+ 'bitmap': 'bitmap1',
135
+ 'job-id': 'j3' }}
136
+ ])
137
+ if "error" in ret:
138
+ raise Exception(ret['error']['desc'])
139
+ vm.run_job('j2', auto_dismiss=True)
140
+ vm.run_job('j3', auto_dismiss=True)
141
+
84
+
142
+ log('\n--- Done ---')
85
+Note, that the only thing which prevents backup of running on such
143
+ vm.shutdown()
86
+configuration is default permission propagation scheme. It may be altered by
144
diff --git a/tests/qemu-iotests/256.out b/tests/qemu-iotests/256.out
87
+different block drivers, so backup will run in invalid configuration. But
88
+something is better than nothing. Also, before the previous commit (commit
89
+preceding this test creation), starting backup on such configuration led to
90
+crash, so current "something" is a lot better, and this test actual goal is
91
+to check that crash is fixed :)
92
+"""
93
+
94
+vm = iotests.VM()
95
+vm.launch()
96
+
97
+vm.qmp_log('blockdev-add', **{'node-name': 'target', 'driver': 'null-co'})
98
+
99
+vm.qmp_log('blockdev-add', **{
100
+ 'node-name': 'source',
101
+ 'driver': 'blkdebug',
102
+ 'image': {'node-name': 'base', 'driver': 'null-co', 'size': size}
103
+})
104
+
105
+vm.qmp_log('blockdev-add', **{
106
+ 'node-name': 'other',
107
+ 'driver': 'blkdebug',
108
+ 'image': 'base',
109
+ 'take-child-perms': ['write']
110
+})
111
+
112
+vm.qmp_log('blockdev-backup', sync='full', device='source', target='target')
113
+
114
+vm.shutdown()
115
diff --git a/tests/qemu-iotests/283.out b/tests/qemu-iotests/283.out
145
new file mode 100644
116
new file mode 100644
146
index XXXXXXX..XXXXXXX
117
index XXXXXXX..XXXXXXX
147
--- /dev/null
118
--- /dev/null
148
+++ b/tests/qemu-iotests/256.out
119
+++ b/tests/qemu-iotests/283.out
149
@@ -XXX,XX +XXX,XX @@
120
@@ -XXX,XX +XXX,XX @@
150
+--- Preparing images & VM ---
121
+{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "target"}}
151
+
152
+--- Starting VM ---
153
+
154
+--- Create Targets & Full Backups ---
155
+
156
+{}
157
+{"execute": "job-dismiss", "arguments": {"id": "job1"}}
158
+{"return": {}}
122
+{"return": {}}
159
+{}
123
+{"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": {"driver": "null-co", "node-name": "base", "size": 1048576}, "node-name": "source"}}
160
+{}
161
+{"execute": "job-dismiss", "arguments": {"id": "job2"}}
162
+{"return": {}}
124
+{"return": {}}
163
+{}
125
+{"execute": "blockdev-add", "arguments": {"driver": "blkdebug", "image": "base", "node-name": "other", "take-child-perms": ["write"]}}
164
+{}
165
+{"execute": "job-dismiss", "arguments": {"id": "job1"}}
166
+{"return": {}}
126
+{"return": {}}
167
+{}
127
+{"execute": "blockdev-backup", "arguments": {"device": "source", "sync": "full", "target": "target"}}
168
+{}
128
+{"error": {"class": "GenericError", "desc": "Cannot set permissions for backup-top filter: Conflicts with use by other as 'image', which uses 'write' on base"}}
169
+{"execute": "job-dismiss", "arguments": {"id": "job2"}}
170
+{"return": {}}
171
+{}
172
+{
173
+ "execute": "transaction",
174
+ "arguments": {
175
+ "actions": [
176
+ {
177
+ "data": {
178
+ "name": "bitmap0",
179
+ "node": "drive0"
180
+ },
181
+ "type": "block-dirty-bitmap-add"
182
+ },
183
+ {
184
+ "data": {
185
+ "name": "bitmap1",
186
+ "node": "drive1"
187
+ },
188
+ "type": "block-dirty-bitmap-add"
189
+ },
190
+ {
191
+ "data": {
192
+ "device": "drive0",
193
+ "job-id": "j0",
194
+ "sync": "full",
195
+ "target": "img0-full"
196
+ },
197
+ "type": "blockdev-backup"
198
+ },
199
+ {
200
+ "data": {
201
+ "device": "drive1",
202
+ "job-id": "j1",
203
+ "sync": "full",
204
+ "target": "img1-full"
205
+ },
206
+ "type": "blockdev-backup"
207
+ }
208
+ ]
209
+ }
210
+}
211
+{
212
+ "return": {}
213
+}
214
+{"data": {"device": "j0", "len": 67108864, "offset": 67108864, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
215
+{"data": {"device": "j1", "len": 67108864, "offset": 67108864, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
216
+
217
+--- Create Targets & Incremental Backups ---
218
+
219
+{}
220
+{"execute": "job-dismiss", "arguments": {"id": "job1"}}
221
+{"return": {}}
222
+{}
223
+{}
224
+{"execute": "job-dismiss", "arguments": {"id": "job2"}}
225
+{"return": {}}
226
+{}
227
+{}
228
+{"execute": "job-dismiss", "arguments": {"id": "job1"}}
229
+{"return": {}}
230
+{}
231
+{}
232
+{"execute": "job-dismiss", "arguments": {"id": "job2"}}
233
+{"return": {}}
234
+{}
235
+{
236
+ "execute": "transaction",
237
+ "arguments": {
238
+ "actions": [
239
+ {
240
+ "data": {
241
+ "bitmap": "bitmap0",
242
+ "device": "drive0",
243
+ "job-id": "j2",
244
+ "sync": "incremental",
245
+ "target": "img0-incr"
246
+ },
247
+ "type": "blockdev-backup"
248
+ },
249
+ {
250
+ "data": {
251
+ "bitmap": "bitmap1",
252
+ "device": "drive1",
253
+ "job-id": "j3",
254
+ "sync": "incremental",
255
+ "target": "img1-incr"
256
+ },
257
+ "type": "blockdev-backup"
258
+ }
259
+ ]
260
+ }
261
+}
262
+{
263
+ "return": {}
264
+}
265
+{"data": {"device": "j2", "len": 67108864, "offset": 67108864, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
266
+{"data": {"device": "j3", "len": 67108864, "offset": 67108864, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
267
+
268
+--- Done ---
269
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
129
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
270
index XXXXXXX..XXXXXXX 100644
130
index XXXXXXX..XXXXXXX 100644
271
--- a/tests/qemu-iotests/group
131
--- a/tests/qemu-iotests/group
272
+++ b/tests/qemu-iotests/group
132
+++ b/tests/qemu-iotests/group
273
@@ -XXX,XX +XXX,XX @@
133
@@ -XXX,XX +XXX,XX @@
274
253 rw auto quick
134
279 rw backing quick
275
254 rw auto backing quick
135
280 rw migration quick
276
255 rw auto quick
136
281 rw quick
277
+256 rw auto quick
137
+283 auto quick
278
--
138
--
279
2.21.0
139
2.24.1
280
140
281
141
diff view generated by jsdifflib
Deleted patch
1
From: John Snow <jsnow@redhat.com>
2
1
3
Before, event_match didn't always recurse if the event value was not a
4
dictionary, and would instead check for equality immediately.
5
6
By delaying equality checking to post-recursion, we can allow leaf
7
values like "5" to match "None" and take advantage of the generic
8
None-returns-True clause.
9
10
This makes the matching a little more obviously consistent at the
11
expense of being able to check for explicit None values, which is
12
probably not that important given what this function is used for.
13
14
Signed-off-by: John Snow <jsnow@redhat.com>
15
Message-id: 20190528183857.26167-1-jsnow@redhat.com
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
python/qemu/__init__.py | 24 ++++++++++++++----------
19
1 file changed, 14 insertions(+), 10 deletions(-)
20
21
diff --git a/python/qemu/__init__.py b/python/qemu/__init__.py
22
index XXXXXXX..XXXXXXX 100644
23
--- a/python/qemu/__init__.py
24
+++ b/python/qemu/__init__.py
25
@@ -XXX,XX +XXX,XX @@ class QEMUMachine(object):
26
27
The match criteria takes the form of a matching subdict. The event is
28
checked to be a superset of the subdict, recursively, with matching
29
- values whenever those values are not None.
30
+ values whenever the subdict values are not None.
31
+
32
+ This has a limitation that you cannot explicitly check for None values.
33
34
Examples, with the subdict queries on the left:
35
- None matches any object.
36
- {"foo": None} matches {"foo": {"bar": 1}}
37
- - {"foo": {"baz": None}} does not match {"foo": {"bar": 1}}
38
- - {"foo": {"baz": 2}} matches {"foo": {"bar": 1, "baz": 2}}
39
+ - {"foo": None} matches {"foo": 5}
40
+ - {"foo": {"abc": None}} does not match {"foo": {"bar": 1}}
41
+ - {"foo": {"rab": 2}} matches {"foo": {"bar": 1, "rab": 2}}
42
"""
43
if match is None:
44
return True
45
46
- for key in match:
47
- if key in event:
48
- if isinstance(event[key], dict):
49
+ try:
50
+ for key in match:
51
+ if key in event:
52
if not QEMUMachine.event_match(event[key], match[key]):
53
return False
54
- elif event[key] != match[key]:
55
+ else:
56
return False
57
- else:
58
- return False
59
- return True
60
+ return True
61
+ except TypeError:
62
+ # either match or event wasn't iterable (not a dict)
63
+ return match == event
64
65
def event_wait(self, name, timeout=60.0, match=None):
66
"""
67
--
68
2.21.0
69
70
diff view generated by jsdifflib
Deleted patch
1
In 219, we wait for the job to make progress before we emit its status.
2
This makes the output reliable. We do not wait for any more progress if
3
the job's current-progress already matches its total-progress.
4
1
5
Unfortunately, there is a bug: Right after the job has been started,
6
it's possible that total-progress is still 0. In that case, we may skip
7
the first progress-making step and keep ending up 64 kB short.
8
9
To fix that bug, we can simply wait for total-progress to reach 4 MB
10
(the image size) after starting the job.
11
12
Reported-by: Karen Mezick <kmezick@redhat.com>
13
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1686651
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
15
Message-id: 20190516161114.27596-1-mreitz@redhat.com
16
Reviewed-by: John Snow <jsnow@redhat.com>
17
[mreitz: Adjusted commit message as per John's proposal]
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
---
20
tests/qemu-iotests/219 | 13 ++++++++++---
21
1 file changed, 10 insertions(+), 3 deletions(-)
22
23
diff --git a/tests/qemu-iotests/219 b/tests/qemu-iotests/219
24
index XXXXXXX..XXXXXXX 100755
25
--- a/tests/qemu-iotests/219
26
+++ b/tests/qemu-iotests/219
27
@@ -XXX,XX +XXX,XX @@ import iotests
28
29
iotests.verify_image_format(supported_fmts=['qcow2'])
30
31
+img_size = 4 * 1024 * 1024
32
+
33
def pause_wait(vm, job_id):
34
with iotests.Timeout(3, "Timeout waiting for job to pause"):
35
while True:
36
@@ -XXX,XX +XXX,XX @@ def test_pause_resume(vm):
37
iotests.log(vm.qmp('query-jobs'))
38
39
def test_job_lifecycle(vm, job, job_args, has_ready=False):
40
+ global img_size
41
+
42
iotests.log('')
43
iotests.log('')
44
iotests.log('Starting block job: %s (auto-finalize: %s; auto-dismiss: %s)' %
45
@@ -XXX,XX +XXX,XX @@ def test_job_lifecycle(vm, job, job_args, has_ready=False):
46
iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
47
iotests.log(iotests.filter_qmp_event(vm.event_wait('JOB_STATUS_CHANGE')))
48
49
+ # Wait for total-progress to stabilize
50
+ while vm.qmp('query-jobs')['return'][0]['total-progress'] < img_size:
51
+ pass
52
+
53
# RUNNING state:
54
# pause/resume should work, complete/finalize/dismiss should error out
55
iotests.log('')
56
@@ -XXX,XX +XXX,XX @@ with iotests.FilePath('disk.img') as disk_path, \
57
iotests.FilePath('copy.img') as copy_path, \
58
iotests.VM() as vm:
59
60
- img_size = '4M'
61
- iotests.qemu_img_create('-f', iotests.imgfmt, disk_path, img_size)
62
- iotests.qemu_io('-c', 'write 0 %s' % (img_size),
63
+ iotests.qemu_img_create('-f', iotests.imgfmt, disk_path, str(img_size))
64
+ iotests.qemu_io('-c', 'write 0 %i' % (img_size),
65
'-f', iotests.imgfmt, disk_path)
66
67
iotests.log('Launching VM...')
68
--
69
2.21.0
70
71
diff view generated by jsdifflib