1
The following changes since commit 23919ddfd56135cad3cb468a8f54d5a595f024f4:
1
The following changes since commit 0b6206b9c6825619cd721085fe082d7a0abc9af4:
2
2
3
Merge remote-tracking branch 'remotes/aperard/tags/pull-xen-20190827' into staging (2019-08-27 15:52:36 +0100)
3
Merge remote-tracking branch 'remotes/rth-gitlab/tags/pull-tcg-20210914-4' into staging (2021-09-15 13:27:49 +0100)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
https://github.com/XanClic/qemu.git tags/pull-block-2019-08-27
7
https://github.com/XanClic/qemu.git tags/pull-block-2021-09-15
8
8
9
for you to fetch changes up to bb043c056cffcc2f3ce88bfdaf2e76e455c09e2c:
9
for you to fetch changes up to 1899bf47375ad40555dcdff12ba49b4b8b82df38:
10
10
11
iotests: Unify cache mode quoting (2019-08-27 19:48:44 +0200)
11
qemu-img: Add -F shorthand to convert (2021-09-15 18:42:38 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches:
14
Block patches:
15
- qemu-io now accepts a file to read a write pattern from
15
- Block-status cache for data regions
16
- Ensure that raw files have their first block allocated so we can probe
16
- qcow2 optimization (when using subclusters)
17
the O_DIRECT alignment if necessary
17
- iotests delinting, and let 297 (lint checker) cover named iotests
18
- Various fixes
18
- qcow2 check improvements
19
- Added -F (target backing file format) option to qemu-img convert
20
- Mirror job fix
21
- Fix for when a migration is initiated while a backup job runs
22
- Fix for uncached qemu-img convert to a volume with 4k sectors (for an
23
unaligned image)
24
- Minor gluster driver fix
19
25
20
----------------------------------------------------------------
26
----------------------------------------------------------------
21
Denis Plotnikov (1):
27
Eric Blake (1):
22
qemu-io: add pattern file for write command
28
qemu-img: Add -F shorthand to convert
23
29
24
Max Reitz (7):
30
Hanna Reitz (15):
25
iotests: Fix _filter_img_create()
31
gluster: Align block-status tail
26
vmdk: Use bdrv_dirname() for relative extent paths
32
block: Drop BDS comment regarding bdrv_append()
27
iotests: Keep testing broken relative extent paths
33
block: block-status cache for data regions
28
vmdk: Reject invalid compressed writes
34
block: Clarify that @bytes is no limit on *pnum
29
iotests: Disable broken streamOptimized tests
35
block/file-posix: Do not force-cap *pnum
30
iotests: Disable 110 for vmdk.twoGbMaxExtentSparse
36
block/gluster: Do not force-cap *pnum
31
iotests: Disable 126 for flat vmdk subformats
37
block/iscsi: Do not force-cap *pnum
38
iotests: Fix unspecified-encoding pylint warnings
39
iotests: Fix use-{list,dict}-literal warnings
40
iotests/297: Drop 169 and 199 from the skip list
41
migrate-bitmaps-postcopy-test: Fix pylint warnings
42
migrate-bitmaps-test: Fix pylint warnings
43
mirror-top-perms: Fix AbnormalShutdown path
44
iotests/297: Cover tests/
45
qemu-img: Allow target be aligned to sector size
32
46
33
Nir Soffer (3):
47
Stefano Garzarella (1):
34
block: posix: Always allocate the first block
48
block/mirror: fix NULL pointer dereference in
35
iotests: Test allocate_first_block() with O_DIRECT
49
mirror_wait_on_conflicts()
36
iotests: Unify cache mode quoting
37
50
38
Stefan Hajnoczi (1):
51
Vladimir Sementsov-Ogievskiy (15):
39
file-posix: fix request_alignment typo
52
tests: add migrate-during-backup
53
block: bdrv_inactivate_recurse(): check for permissions and fix crash
54
simplebench: add img_bench_templater.py
55
qcow2: refactor handle_dependencies() loop body
56
qcow2: handle_dependencies(): relax conflict detection
57
qcow2-refcount: improve style of check_refcounts_l2()
58
qcow2: compressed read: simplify cluster descriptor passing
59
qcow2: introduce qcow2_parse_compressed_l2_entry() helper
60
qcow2-refcount: introduce fix_l2_entry_by_zero()
61
qcow2-refcount: fix_l2_entry_by_zero(): also zero L2 entry bitmap
62
qcow2-refcount: check_refcounts_l2(): check l2_bitmap
63
qcow2-refcount: check_refcounts_l2(): check reserved bits
64
qcow2-refcount: improve style of check_refcounts_l1()
65
qcow2-refcount: check_refcounts_l1(): check reserved bits
66
qcow2-refcount: check_refblocks(): add separate message for reserved
40
67
41
Thomas Huth (2):
68
docs/tools/qemu-img.rst | 4 +-
42
iotests: Check for enabled drivers before testing them
69
block/qcow2.h | 7 +-
43
tests/check-block: Skip iotests when sanitizers are enabled
70
include/block/block_int.h | 61 +++-
44
71
block.c | 88 +++++
45
Vladimir Sementsov-Ogievskiy (1):
72
block/file-posix.c | 7 +-
46
block: fix permission update in bdrv_replace_node
73
block/gluster.c | 23 +-
47
74
block/io.c | 68 +++-
48
block.c | 5 +-
75
block/iscsi.c | 3 -
49
block/file-posix.c | 53 +++++++++-
76
block/mirror.c | 25 +-
50
block/vmdk.c | 64 ++++++++----
77
block/qcow2-cluster.c | 78 +++--
51
qemu-io-cmds.c | 99 +++++++++++++++++--
78
block/qcow2-refcount.c | 326 ++++++++++++------
52
tests/check-block.sh | 5 +
79
block/qcow2.c | 13 +-
53
tests/qemu-iotests/002 | 1 +
80
qemu-img.c | 18 +-
54
tests/qemu-iotests/003 | 1 +
81
qemu-img-cmds.hx | 2 +-
55
tests/qemu-iotests/005 | 3 +-
82
scripts/simplebench/img_bench_templater.py | 95 +++++
56
tests/qemu-iotests/009 | 1 +
83
scripts/simplebench/table_templater.py | 62 ++++
57
tests/qemu-iotests/010 | 1 +
84
tests/qemu-iotests/122 | 2 +-
58
tests/qemu-iotests/011 | 1 +
85
tests/qemu-iotests/271 | 5 +-
59
tests/qemu-iotests/017 | 3 +-
86
tests/qemu-iotests/271.out | 4 +-
60
tests/qemu-iotests/018 | 3 +-
87
tests/qemu-iotests/297 | 9 +-
61
tests/qemu-iotests/019 | 3 +-
88
tests/qemu-iotests/iotests.py | 12 +-
62
tests/qemu-iotests/020 | 3 +-
89
.../tests/migrate-bitmaps-postcopy-test | 13 +-
63
tests/qemu-iotests/026 | 4 +-
90
tests/qemu-iotests/tests/migrate-bitmaps-test | 43 ++-
64
tests/qemu-iotests/027 | 1 +
91
.../qemu-iotests/tests/migrate-during-backup | 97 ++++++
65
tests/qemu-iotests/032 | 1 +
92
.../tests/migrate-during-backup.out | 5 +
66
tests/qemu-iotests/033 | 1 +
93
tests/qemu-iotests/tests/mirror-top-perms | 2 +-
67
tests/qemu-iotests/034 | 3 +-
94
26 files changed, 855 insertions(+), 217 deletions(-)
68
tests/qemu-iotests/037 | 3 +-
95
create mode 100755 scripts/simplebench/img_bench_templater.py
69
tests/qemu-iotests/039 | 4 +-
96
create mode 100644 scripts/simplebench/table_templater.py
70
tests/qemu-iotests/052 | 2 +-
97
create mode 100755 tests/qemu-iotests/tests/migrate-during-backup
71
tests/qemu-iotests/059 | 34 ++++++-
98
create mode 100644 tests/qemu-iotests/tests/migrate-during-backup.out
72
tests/qemu-iotests/059.out | 26 +++--
73
tests/qemu-iotests/063 | 3 +-
74
tests/qemu-iotests/071 | 1 +
75
tests/qemu-iotests/072 | 1 +
76
tests/qemu-iotests/081 | 4 +-
77
tests/qemu-iotests/091 | 4 +-
78
tests/qemu-iotests/099 | 1 +
79
tests/qemu-iotests/105 | 3 +-
80
tests/qemu-iotests/110 | 3 +-
81
tests/qemu-iotests/120 | 1 +
82
tests/qemu-iotests/126 | 2 +
83
tests/qemu-iotests/{150.out => 150.out.qcow2} | 0
84
tests/qemu-iotests/150.out.raw | 12 +++
85
tests/qemu-iotests/162 | 4 +-
86
tests/qemu-iotests/175 | 47 +++++++--
87
tests/qemu-iotests/175.out | 16 ++-
88
tests/qemu-iotests/178.out.qcow2 | 4 +-
89
tests/qemu-iotests/184 | 1 +
90
tests/qemu-iotests/186 | 1 +
91
tests/qemu-iotests/197 | 1 +
92
tests/qemu-iotests/215 | 1 +
93
tests/qemu-iotests/221.out | 12 ++-
94
tests/qemu-iotests/251 | 1 +
95
tests/qemu-iotests/253.out | 12 ++-
96
tests/qemu-iotests/common.filter | 4 +-
97
tests/qemu-iotests/common.rc | 14 +++
98
50 files changed, 391 insertions(+), 87 deletions(-)
99
rename tests/qemu-iotests/{150.out => 150.out.qcow2} (100%)
100
create mode 100644 tests/qemu-iotests/150.out.raw
101
99
102
--
100
--
103
2.21.0
101
2.31.1
104
102
105
103
diff view generated by jsdifflib
New patch
1
From: Max Reitz <mreitz@redhat.com>
1
2
3
gluster's block-status implementation is basically a copy of that in
4
block/file-posix.c, there is only one thing missing, and that is
5
aligning trailing data extents to the request alignment (as added by
6
commit 9c3db310ff0).
7
8
Note that 9c3db310ff0 mentions that "there seems to be no other block
9
driver that sets request_alignment and [...]", but while block/gluster.c
10
does indeed not set request_alignment, block/io.c's
11
bdrv_refresh_limits() will still default to an alignment of 512 because
12
block/gluster.c does not provide a byte-aligned read function.
13
Therefore, unaligned tails can conceivably occur, and so we should apply
14
the change from 9c3db310ff0 to gluster's block-status implementation.
15
16
Reported-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
17
Signed-off-by: Max Reitz <mreitz@redhat.com>
18
Message-Id: <20210805143603.59503-1-mreitz@redhat.com>
19
Reviewed-by: Eric Blake <eblake@redhat.com>
20
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
21
---
22
block/gluster.c | 16 ++++++++++++++++
23
1 file changed, 16 insertions(+)
24
25
diff --git a/block/gluster.c b/block/gluster.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/block/gluster.c
28
+++ b/block/gluster.c
29
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
30
off_t data = 0, hole = 0;
31
int ret = -EINVAL;
32
33
+ assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
34
+
35
if (!s->fd) {
36
return ret;
37
}
38
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
39
/* On a data extent, compute bytes to the end of the extent,
40
* possibly including a partial sector at EOF. */
41
*pnum = MIN(bytes, hole - offset);
42
+
43
+ /*
44
+ * We are not allowed to return partial sectors, though, so
45
+ * round up if necessary.
46
+ */
47
+ if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) {
48
+ int64_t file_length = qemu_gluster_getlength(bs);
49
+ if (file_length > 0) {
50
+ /* Ignore errors, this is just a safeguard */
51
+ assert(hole == file_length);
52
+ }
53
+ *pnum = ROUND_UP(*pnum, bs->bl.request_alignment);
54
+ }
55
+
56
ret = BDRV_BLOCK_DATA;
57
} else {
58
/* On a hole, compute bytes to the beginning of the next extent. */
59
--
60
2.31.1
61
62
diff view generated by jsdifflib
New patch
1
There is a comment above the BDS definition stating care must be taken
2
to consider handling newly added fields in bdrv_append().
1
3
4
Actually, this comment should have said "bdrv_swap()" as of 4ddc07cac
5
(nine years ago), and in any case, bdrv_swap() was dropped in
6
8e419aefa (six years ago). So no such care is necessary anymore.
7
8
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
12
Message-Id: <20210812084148.14458-2-hreitz@redhat.com>
13
---
14
include/block/block_int.h | 6 ------
15
1 file changed, 6 deletions(-)
16
17
diff --git a/include/block/block_int.h b/include/block/block_int.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/include/block/block_int.h
20
+++ b/include/block/block_int.h
21
@@ -XXX,XX +XXX,XX @@ struct BdrvChild {
22
QLIST_ENTRY(BdrvChild) next_parent;
23
};
24
25
-/*
26
- * Note: the function bdrv_append() copies and swaps contents of
27
- * BlockDriverStates, so if you add new fields to this struct, please
28
- * inspect bdrv_append() to determine if the new fields need to be
29
- * copied as well.
30
- */
31
struct BlockDriverState {
32
/* Protected by big QEMU lock or read-only after opening. No special
33
* locking needed during I/O...
34
--
35
2.31.1
36
37
diff view generated by jsdifflib
New patch
1
1
As we have attempted before
2
(https://lists.gnu.org/archive/html/qemu-devel/2019-01/msg06451.html,
3
"file-posix: Cache lseek result for data regions";
4
https://lists.nongnu.org/archive/html/qemu-block/2021-02/msg00934.html,
5
"file-posix: Cache next hole"), this patch seeks to reduce the number of
6
SEEK_DATA/HOLE operations the file-posix driver has to perform. The
7
main difference is that this time it is implemented as part of the
8
general block layer code.
9
10
The problem we face is that on some filesystems or in some
11
circumstances, SEEK_DATA/HOLE is unreasonably slow. Given the
12
implementation is outside of qemu, there is little we can do about its
13
performance.
14
15
We have already introduced the want_zero parameter to
16
bdrv_co_block_status() to reduce the number of SEEK_DATA/HOLE calls
17
unless we really want zero information; but sometimes we do want that
18
information, because for files that consist largely of zero areas,
19
special-casing those areas can give large performance boosts. So the
20
real problem is with files that consist largely of data, so that
21
inquiring the block status does not gain us much performance, but where
22
such an inquiry itself takes a lot of time.
23
24
To address this, we want to cache data regions. Most of the time, when
25
bad performance is reported, it is in places where the image is iterated
26
over from start to end (qemu-img convert or the mirror job), so a simple
27
yet effective solution is to cache only the current data region.
28
29
(Note that only caching data regions but not zero regions means that
30
returning false information from the cache is not catastrophic: Treating
31
zeroes as data is fine. While we try to invalidate the cache on zero
32
writes and discards, such incongruences may still occur when there are
33
other processes writing to the image.)
34
35
We only use the cache for nodes without children (i.e. protocol nodes),
36
because that is where the problem is: Drivers that rely on block-status
37
implementations outside of qemu (e.g. SEEK_DATA/HOLE).
38
39
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/307
40
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
41
Message-Id: <20210812084148.14458-3-hreitz@redhat.com>
42
Reviewed-by: Eric Blake <eblake@redhat.com>
43
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
44
[hreitz: Added `local_file == bs` assertion, as suggested by Vladimir]
45
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
46
---
47
include/block/block_int.h | 50 ++++++++++++++++++++++++
48
block.c | 80 +++++++++++++++++++++++++++++++++++++++
49
block/io.c | 68 +++++++++++++++++++++++++++++++--
50
3 files changed, 195 insertions(+), 3 deletions(-)
51
52
diff --git a/include/block/block_int.h b/include/block/block_int.h
53
index XXXXXXX..XXXXXXX 100644
54
--- a/include/block/block_int.h
55
+++ b/include/block/block_int.h
56
@@ -XXX,XX +XXX,XX @@
57
#include "qemu/hbitmap.h"
58
#include "block/snapshot.h"
59
#include "qemu/throttle.h"
60
+#include "qemu/rcu.h"
61
62
#define BLOCK_FLAG_LAZY_REFCOUNTS 8
63
64
@@ -XXX,XX +XXX,XX @@ struct BdrvChild {
65
QLIST_ENTRY(BdrvChild) next_parent;
66
};
67
68
+/*
69
+ * Allows bdrv_co_block_status() to cache one data region for a
70
+ * protocol node.
71
+ *
72
+ * @valid: Whether the cache is valid (should be accessed with atomic
73
+ * functions so this can be reset by RCU readers)
74
+ * @data_start: Offset where we know (or strongly assume) is data
75
+ * @data_end: Offset where the data region ends (which is not necessarily
76
+ * the start of a zeroed region)
77
+ */
78
+typedef struct BdrvBlockStatusCache {
79
+ struct rcu_head rcu;
80
+
81
+ bool valid;
82
+ int64_t data_start;
83
+ int64_t data_end;
84
+} BdrvBlockStatusCache;
85
+
86
struct BlockDriverState {
87
/* Protected by big QEMU lock or read-only after opening. No special
88
* locking needed during I/O...
89
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
90
91
/* BdrvChild links to this node may never be frozen */
92
bool never_freeze;
93
+
94
+ /* Lock for block-status cache RCU writers */
95
+ CoMutex bsc_modify_lock;
96
+ /* Always non-NULL, but must only be dereferenced under an RCU read guard */
97
+ BdrvBlockStatusCache *block_status_cache;
98
};
99
100
struct BlockBackendRootState {
101
@@ -XXX,XX +XXX,XX @@ static inline BlockDriverState *bdrv_primary_bs(BlockDriverState *bs)
102
*/
103
void bdrv_drain_all_end_quiesce(BlockDriverState *bs);
104
105
+/**
106
+ * Check whether the given offset is in the cached block-status data
107
+ * region.
108
+ *
109
+ * If it is, and @pnum is not NULL, *pnum is set to
110
+ * `bsc.data_end - offset`, i.e. how many bytes, starting from
111
+ * @offset, are data (according to the cache).
112
+ * Otherwise, *pnum is not touched.
113
+ */
114
+bool bdrv_bsc_is_data(BlockDriverState *bs, int64_t offset, int64_t *pnum);
115
+
116
+/**
117
+ * If [offset, offset + bytes) overlaps with the currently cached
118
+ * block-status region, invalidate the cache.
119
+ *
120
+ * (To be used by I/O paths that cause data regions to be zero or
121
+ * holes.)
122
+ */
123
+void bdrv_bsc_invalidate_range(BlockDriverState *bs,
124
+ int64_t offset, int64_t bytes);
125
+
126
+/**
127
+ * Mark the range [offset, offset + bytes) as a data region.
128
+ */
129
+void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes);
130
+
131
#endif /* BLOCK_INT_H */
132
diff --git a/block.c b/block.c
133
index XXXXXXX..XXXXXXX 100644
134
--- a/block.c
135
+++ b/block.c
136
@@ -XXX,XX +XXX,XX @@
137
#include "qemu/timer.h"
138
#include "qemu/cutils.h"
139
#include "qemu/id.h"
140
+#include "qemu/range.h"
141
+#include "qemu/rcu.h"
142
#include "block/coroutines.h"
143
144
#ifdef CONFIG_BSD
145
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_new(void)
146
147
qemu_co_queue_init(&bs->flush_queue);
148
149
+ qemu_co_mutex_init(&bs->bsc_modify_lock);
150
+ bs->block_status_cache = g_new0(BdrvBlockStatusCache, 1);
151
+
152
for (i = 0; i < bdrv_drain_all_count; i++) {
153
bdrv_drained_begin(bs);
154
}
155
@@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs)
156
bs->explicit_options = NULL;
157
qobject_unref(bs->full_open_options);
158
bs->full_open_options = NULL;
159
+ g_free(bs->block_status_cache);
160
+ bs->block_status_cache = NULL;
161
162
bdrv_release_named_dirty_bitmaps(bs);
163
assert(QLIST_EMPTY(&bs->dirty_bitmaps));
164
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_backing_chain_next(BlockDriverState *bs)
165
{
166
return bdrv_skip_filters(bdrv_cow_bs(bdrv_skip_filters(bs)));
167
}
168
+
169
+/**
170
+ * Check whether [offset, offset + bytes) overlaps with the cached
171
+ * block-status data region.
172
+ *
173
+ * If so, and @pnum is not NULL, set *pnum to `bsc.data_end - offset`,
174
+ * which is what bdrv_bsc_is_data()'s interface needs.
175
+ * Otherwise, *pnum is not touched.
176
+ */
177
+static bool bdrv_bsc_range_overlaps_locked(BlockDriverState *bs,
178
+ int64_t offset, int64_t bytes,
179
+ int64_t *pnum)
180
+{
181
+ BdrvBlockStatusCache *bsc = qatomic_rcu_read(&bs->block_status_cache);
182
+ bool overlaps;
183
+
184
+ overlaps =
185
+ qatomic_read(&bsc->valid) &&
186
+ ranges_overlap(offset, bytes, bsc->data_start,
187
+ bsc->data_end - bsc->data_start);
188
+
189
+ if (overlaps && pnum) {
190
+ *pnum = bsc->data_end - offset;
191
+ }
192
+
193
+ return overlaps;
194
+}
195
+
196
+/**
197
+ * See block_int.h for this function's documentation.
198
+ */
199
+bool bdrv_bsc_is_data(BlockDriverState *bs, int64_t offset, int64_t *pnum)
200
+{
201
+ RCU_READ_LOCK_GUARD();
202
+
203
+ return bdrv_bsc_range_overlaps_locked(bs, offset, 1, pnum);
204
+}
205
+
206
+/**
207
+ * See block_int.h for this function's documentation.
208
+ */
209
+void bdrv_bsc_invalidate_range(BlockDriverState *bs,
210
+ int64_t offset, int64_t bytes)
211
+{
212
+ RCU_READ_LOCK_GUARD();
213
+
214
+ if (bdrv_bsc_range_overlaps_locked(bs, offset, bytes, NULL)) {
215
+ qatomic_set(&bs->block_status_cache->valid, false);
216
+ }
217
+}
218
+
219
+/**
220
+ * See block_int.h for this function's documentation.
221
+ */
222
+void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes)
223
+{
224
+ BdrvBlockStatusCache *new_bsc = g_new(BdrvBlockStatusCache, 1);
225
+ BdrvBlockStatusCache *old_bsc;
226
+
227
+ *new_bsc = (BdrvBlockStatusCache) {
228
+ .valid = true,
229
+ .data_start = offset,
230
+ .data_end = offset + bytes,
231
+ };
232
+
233
+ QEMU_LOCK_GUARD(&bs->bsc_modify_lock);
234
+
235
+ old_bsc = qatomic_rcu_read(&bs->block_status_cache);
236
+ qatomic_rcu_set(&bs->block_status_cache, new_bsc);
237
+ if (old_bsc) {
238
+ g_free_rcu(old_bsc, rcu);
239
+ }
240
+}
241
diff --git a/block/io.c b/block/io.c
242
index XXXXXXX..XXXXXXX 100644
243
--- a/block/io.c
244
+++ b/block/io.c
245
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
246
return -ENOTSUP;
247
}
248
249
+ /* Invalidate the cached block-status data range if this write overlaps */
250
+ bdrv_bsc_invalidate_range(bs, offset, bytes);
251
+
252
assert(alignment % bs->bl.request_alignment == 0);
253
head = offset % alignment;
254
tail = (offset + bytes) % alignment;
255
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
256
aligned_bytes = ROUND_UP(offset + bytes, align) - aligned_offset;
257
258
if (bs->drv->bdrv_co_block_status) {
259
- ret = bs->drv->bdrv_co_block_status(bs, want_zero, aligned_offset,
260
- aligned_bytes, pnum, &local_map,
261
- &local_file);
262
+ /*
263
+ * Use the block-status cache only for protocol nodes: Format
264
+ * drivers are generally quick to inquire the status, but protocol
265
+ * drivers often need to get information from outside of qemu, so
266
+ * we do not have control over the actual implementation. There
267
+ * have been cases where inquiring the status took an unreasonably
268
+ * long time, and we can do nothing in qemu to fix it.
269
+ * This is especially problematic for images with large data areas,
270
+ * because finding the few holes in them and giving them special
271
+ * treatment does not gain much performance. Therefore, we try to
272
+ * cache the last-identified data region.
273
+ *
274
+ * Second, limiting ourselves to protocol nodes allows us to assume
275
+ * the block status for data regions to be DATA | OFFSET_VALID, and
276
+ * that the host offset is the same as the guest offset.
277
+ *
278
+ * Note that it is possible that external writers zero parts of
279
+ * the cached regions without the cache being invalidated, and so
280
+ * we may report zeroes as data. This is not catastrophic,
281
+ * however, because reporting zeroes as data is fine.
282
+ */
283
+ if (QLIST_EMPTY(&bs->children) &&
284
+ bdrv_bsc_is_data(bs, aligned_offset, pnum))
285
+ {
286
+ ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
287
+ local_file = bs;
288
+ local_map = aligned_offset;
289
+ } else {
290
+ ret = bs->drv->bdrv_co_block_status(bs, want_zero, aligned_offset,
291
+ aligned_bytes, pnum, &local_map,
292
+ &local_file);
293
+
294
+ /*
295
+ * Note that checking QLIST_EMPTY(&bs->children) is also done when
296
+ * the cache is queried above. Technically, we do not need to check
297
+ * it here; the worst that can happen is that we fill the cache for
298
+ * non-protocol nodes, and then it is never used. However, filling
299
+ * the cache requires an RCU update, so double check here to avoid
300
+ * such an update if possible.
301
+ */
302
+ if (ret == (BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID) &&
303
+ QLIST_EMPTY(&bs->children))
304
+ {
305
+ /*
306
+ * When a protocol driver reports BLOCK_OFFSET_VALID, the
307
+ * returned local_map value must be the same as the offset we
308
+ * have passed (aligned_offset), and local_bs must be the node
309
+ * itself.
310
+ * Assert this, because we follow this rule when reading from
311
+ * the cache (see the `local_file = bs` and
312
+ * `local_map = aligned_offset` assignments above), and the
313
+ * result the cache delivers must be the same as the driver
314
+ * would deliver.
315
+ */
316
+ assert(local_file == bs);
317
+ assert(local_map == aligned_offset);
318
+ bdrv_bsc_fill(bs, aligned_offset, *pnum);
319
+ }
320
+ }
321
} else {
322
/* Default code for filters */
323
324
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
325
return 0;
326
}
327
328
+ /* Invalidate the cached block-status data range if this discard overlaps */
329
+ bdrv_bsc_invalidate_range(bs, offset, bytes);
330
+
331
/* Discard is advisory, but some devices track and coalesce
332
* unaligned requests, so we must pass everything down rather than
333
* round here. Still, most devices will just silently ignore
334
--
335
2.31.1
336
337
diff view generated by jsdifflib
New patch
1
.bdrv_co_block_status() implementations are free to return a *pnum that
2
exceeds @bytes, because bdrv_co_block_status() in block/io.c will clamp
3
*pnum as necessary.
1
4
5
On the other hand, if drivers' implementations return values for *pnum
6
that are as large as possible, our recently introduced block-status
7
cache will become more effective.
8
9
So, make a note in block_int.h that @bytes is no upper limit for *pnum.
10
11
Suggested-by: Eric Blake <eblake@redhat.com>
12
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
13
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
Message-Id: <20210812084148.14458-4-hreitz@redhat.com>
15
Reviewed-by: Eric Blake <eblake@redhat.com>
16
---
17
include/block/block_int.h | 9 +++++++++
18
1 file changed, 9 insertions(+)
19
20
diff --git a/include/block/block_int.h b/include/block/block_int.h
21
index XXXXXXX..XXXXXXX 100644
22
--- a/include/block/block_int.h
23
+++ b/include/block/block_int.h
24
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
25
* clamped to bdrv_getlength() and aligned to request_alignment,
26
* as well as non-NULL pnum, map, and file; in turn, the driver
27
* must return an error or set pnum to an aligned non-zero value.
28
+ *
29
+ * Note that @bytes is just a hint on how big of a region the
30
+ * caller wants to inspect. It is not a limit on *pnum.
31
+ * Implementations are free to return larger values of *pnum if
32
+ * doing so does not incur a performance penalty.
33
+ *
34
+ * block/io.c's bdrv_co_block_status() will utilize an unclamped
35
+ * *pnum value for the block-status cache on protocol nodes, prior
36
+ * to clamping *pnum for return to its caller.
37
*/
38
int coroutine_fn (*bdrv_co_block_status)(BlockDriverState *bs,
39
bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum,
40
--
41
2.31.1
42
43
diff view generated by jsdifflib
1
From: Stefan Hajnoczi <stefanha@redhat.com>
1
bdrv_co_block_status() does it for us, we do not need to do it here.
2
2
3
Fixes: a6b257a08e3d72219f03e461a52152672fec0612
3
The advantage of not capping *pnum is that bdrv_co_block_status() can
4
("file-posix: Handle undetectable alignment")
4
cache larger data regions than requested by its caller.
5
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
5
6
Message-id: 20190827101328.4062-1-stefanha@redhat.com
6
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
7
Reviewed-by: Thomas Huth <thuth@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Message-Id: <20210812084148.14458-5-hreitz@redhat.com>
9
---
11
---
10
block/file-posix.c | 2 +-
12
block/file-posix.c | 7 ++++---
11
1 file changed, 1 insertion(+), 1 deletion(-)
13
1 file changed, 4 insertions(+), 3 deletions(-)
12
14
13
diff --git a/block/file-posix.c b/block/file-posix.c
15
diff --git a/block/file-posix.c b/block/file-posix.c
14
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
15
--- a/block/file-posix.c
17
--- a/block/file-posix.c
16
+++ b/block/file-posix.c
18
+++ b/block/file-posix.c
17
@@ -XXX,XX +XXX,XX @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
19
@@ -XXX,XX +XXX,XX @@ static int find_allocation(BlockDriverState *bs, off_t start,
18
for (i = 0; i < ARRAY_SIZE(alignments); i++) {
20
* the specified offset) that are known to be in the same
19
align = alignments[i];
21
* allocated/unallocated state.
20
if (raw_is_io_aligned(fd, buf + align, max_align)) {
22
*
21
- /* Fallback to request_aligment. */
23
- * 'bytes' is the max value 'pnum' should be set to.
22
+ /* Fallback to request_alignment. */
24
+ * 'bytes' is a soft cap for 'pnum'. If the information is free, 'pnum' may
23
s->buf_align = (align != 1) ? align : bs->bl.request_alignment;
25
+ * well exceed it.
24
break;
26
*/
25
}
27
static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
28
bool want_zero,
29
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
30
} else if (data == offset) {
31
/* On a data extent, compute bytes to the end of the extent,
32
* possibly including a partial sector at EOF. */
33
- *pnum = MIN(bytes, hole - offset);
34
+ *pnum = hole - offset;
35
36
/*
37
* We are not allowed to return partial sectors, though, so
38
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
39
} else {
40
/* On a hole, compute bytes to the beginning of the next extent. */
41
assert(hole == offset);
42
- *pnum = MIN(bytes, data - offset);
43
+ *pnum = data - offset;
44
ret = BDRV_BLOCK_ZERO;
45
}
46
*map = offset;
26
--
47
--
27
2.21.0
48
2.31.1
28
49
29
50
diff view generated by jsdifflib
New patch
1
bdrv_co_block_status() does it for us, we do not need to do it here.
1
2
3
The advantage of not capping *pnum is that bdrv_co_block_status() can
4
cache larger data regions than requested by its caller.
5
6
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Message-Id: <20210812084148.14458-6-hreitz@redhat.com>
11
---
12
block/gluster.c | 7 ++++---
13
1 file changed, 4 insertions(+), 3 deletions(-)
14
15
diff --git a/block/gluster.c b/block/gluster.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/gluster.c
18
+++ b/block/gluster.c
19
@@ -XXX,XX +XXX,XX @@ exit:
20
* the specified offset) that are known to be in the same
21
* allocated/unallocated state.
22
*
23
- * 'bytes' is the max value 'pnum' should be set to.
24
+ * 'bytes' is a soft cap for 'pnum'. If the information is free, 'pnum' may
25
+ * well exceed it.
26
*
27
* (Based on raw_co_block_status() from file-posix.c.)
28
*/
29
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
30
} else if (data == offset) {
31
/* On a data extent, compute bytes to the end of the extent,
32
* possibly including a partial sector at EOF. */
33
- *pnum = MIN(bytes, hole - offset);
34
+ *pnum = hole - offset;
35
36
/*
37
* We are not allowed to return partial sectors, though, so
38
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
39
} else {
40
/* On a hole, compute bytes to the beginning of the next extent. */
41
assert(hole == offset);
42
- *pnum = MIN(bytes, data - offset);
43
+ *pnum = data - offset;
44
ret = BDRV_BLOCK_ZERO;
45
}
46
47
--
48
2.31.1
49
50
diff view generated by jsdifflib
New patch
1
bdrv_co_block_status() does it for us, we do not need to do it here.
1
2
3
The advantage of not capping *pnum is that bdrv_co_block_status() can
4
cache larger data regions than requested by its caller.
5
6
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
10
Message-Id: <20210812084148.14458-7-hreitz@redhat.com>
11
---
12
block/iscsi.c | 3 ---
13
1 file changed, 3 deletions(-)
14
15
diff --git a/block/iscsi.c b/block/iscsi.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/iscsi.c
18
+++ b/block/iscsi.c
19
@@ -XXX,XX +XXX,XX @@ retry:
20
iscsi_allocmap_set_allocated(iscsilun, offset, *pnum);
21
}
22
23
- if (*pnum > bytes) {
24
- *pnum = bytes;
25
- }
26
out_unlock:
27
qemu_mutex_unlock(&iscsilun->mutex);
28
g_free(iTask.err_str);
29
--
30
2.31.1
31
32
diff view generated by jsdifflib
New patch
1
As of recently, pylint complains when `open()` calls are missing an
2
`encoding=` specified. Everything we have should be UTF-8 (and in fact,
3
everything should be UTF-8, period (exceptions apply)), so use that.
1
4
5
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
6
Message-Id: <20210824153540.177128-2-hreitz@redhat.com>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
9
---
10
tests/qemu-iotests/297 | 2 +-
11
tests/qemu-iotests/iotests.py | 8 +++++---
12
2 files changed, 6 insertions(+), 4 deletions(-)
13
14
diff --git a/tests/qemu-iotests/297 b/tests/qemu-iotests/297
15
index XXXXXXX..XXXXXXX 100755
16
--- a/tests/qemu-iotests/297
17
+++ b/tests/qemu-iotests/297
18
@@ -XXX,XX +XXX,XX @@ def is_python_file(filename):
19
if filename.endswith('.py'):
20
return True
21
22
- with open(filename) as f:
23
+ with open(filename, encoding='utf-8') as f:
24
try:
25
first_line = f.readline()
26
return re.match('^#!.*python', first_line) is not None
27
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
28
index XXXXXXX..XXXXXXX 100644
29
--- a/tests/qemu-iotests/iotests.py
30
+++ b/tests/qemu-iotests/iotests.py
31
@@ -XXX,XX +XXX,XX @@ def _post_shutdown(self) -> None:
32
return
33
valgrind_filename = f"{test_dir}/{self._popen.pid}.valgrind"
34
if self.exitcode() == 99:
35
- with open(valgrind_filename) as f:
36
+ with open(valgrind_filename, encoding='utf-8') as f:
37
print(f.read())
38
else:
39
os.remove(valgrind_filename)
40
@@ -XXX,XX +XXX,XX @@ def notrun(reason):
41
# Each test in qemu-iotests has a number ("seq")
42
seq = os.path.basename(sys.argv[0])
43
44
- with open('%s/%s.notrun' % (output_dir, seq), 'w') as outfile:
45
+ with open('%s/%s.notrun' % (output_dir, seq), 'w', encoding='utf-8') \
46
+ as outfile:
47
outfile.write(reason + '\n')
48
logger.warning("%s not run: %s", seq, reason)
49
sys.exit(0)
50
@@ -XXX,XX +XXX,XX @@ def case_notrun(reason):
51
# Each test in qemu-iotests has a number ("seq")
52
seq = os.path.basename(sys.argv[0])
53
54
- with open('%s/%s.casenotrun' % (output_dir, seq), 'a') as outfile:
55
+ with open('%s/%s.casenotrun' % (output_dir, seq), 'a', encoding='utf-8') \
56
+ as outfile:
57
outfile.write(' [case not run] ' + reason + '\n')
58
59
def _verify_image_format(supported_fmts: Sequence[str] = (),
60
--
61
2.31.1
62
63
diff view generated by jsdifflib
New patch
1
pylint proposes using `[]` instead of `list()` and `{}` instead of
2
`dict()`, because it is faster. That seems simple enough, so heed its
3
advice.
1
4
5
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
6
Message-Id: <20210824153540.177128-3-hreitz@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
---
9
tests/qemu-iotests/iotests.py | 4 ++--
10
1 file changed, 2 insertions(+), 2 deletions(-)
11
12
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
13
index XXXXXXX..XXXXXXX 100644
14
--- a/tests/qemu-iotests/iotests.py
15
+++ b/tests/qemu-iotests/iotests.py
16
@@ -XXX,XX +XXX,XX @@ def hmp_qemu_io(self, drive: str, cmd: str,
17
18
def flatten_qmp_object(self, obj, output=None, basestr=''):
19
if output is None:
20
- output = dict()
21
+ output = {}
22
if isinstance(obj, list):
23
for i, item in enumerate(obj):
24
self.flatten_qmp_object(item, output, basestr + str(i) + '.')
25
@@ -XXX,XX +XXX,XX @@ def flatten_qmp_object(self, obj, output=None, basestr=''):
26
27
def qmp_to_opts(self, obj):
28
obj = self.flatten_qmp_object(obj)
29
- output_list = list()
30
+ output_list = []
31
for key in obj:
32
output_list += [key + '=' + obj[key]]
33
return ','.join(output_list)
34
--
35
2.31.1
36
37
diff view generated by jsdifflib
New patch
1
169 and 199 have been renamed and moved to tests/ (commit a44be0334be:
2
"iotests: rename and move 169 and 199 tests"), so we can drop them from
3
the skip list.
1
4
5
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
6
Reviewed-by: Willian Rampazzo <willianr@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
9
Message-Id: <20210902094017.32902-2-hreitz@redhat.com>
10
---
11
tests/qemu-iotests/297 | 2 +-
12
1 file changed, 1 insertion(+), 1 deletion(-)
13
14
diff --git a/tests/qemu-iotests/297 b/tests/qemu-iotests/297
15
index XXXXXXX..XXXXXXX 100755
16
--- a/tests/qemu-iotests/297
17
+++ b/tests/qemu-iotests/297
18
@@ -XXX,XX +XXX,XX @@ import iotests
19
SKIP_FILES = (
20
'030', '040', '041', '044', '045', '055', '056', '057', '065', '093',
21
'096', '118', '124', '132', '136', '139', '147', '148', '149',
22
- '151', '152', '155', '163', '165', '169', '194', '196', '199', '202',
23
+ '151', '152', '155', '163', '165', '194', '196', '202',
24
'203', '205', '206', '207', '208', '210', '211', '212', '213', '216',
25
'218', '219', '224', '228', '234', '235', '236', '237', '238',
26
'240', '242', '245', '246', '248', '255', '256', '257', '258', '260',
27
--
28
2.31.1
29
30
diff view generated by jsdifflib
New patch
1
pylint complains that discards1_sha256 and all_discards_sha256 are first
2
set in non-__init__ methods.
1
3
4
These variables are not really class-variables anyway, so let them
5
instead be returned by start_postcopy(), thus silencing pylint.
6
7
Suggested-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Message-Id: <20210902094017.32902-3-hreitz@redhat.com>
11
---
12
.../tests/migrate-bitmaps-postcopy-test | 13 +++++++------
13
1 file changed, 7 insertions(+), 6 deletions(-)
14
15
diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test
16
index XXXXXXX..XXXXXXX 100755
17
--- a/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test
18
+++ b/tests/qemu-iotests/tests/migrate-bitmaps-postcopy-test
19
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase):
20
21
result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256',
22
node='drive0', name='bitmap0')
23
- self.discards1_sha256 = result['return']['sha256']
24
+ discards1_sha256 = result['return']['sha256']
25
26
# Check, that updating the bitmap by discards works
27
- assert self.discards1_sha256 != empty_sha256
28
+ assert discards1_sha256 != empty_sha256
29
30
# We want to calculate resulting sha256. Do it in bitmap0, so, disable
31
# other bitmaps
32
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase):
33
34
result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256',
35
node='drive0', name='bitmap0')
36
- self.all_discards_sha256 = result['return']['sha256']
37
+ all_discards_sha256 = result['return']['sha256']
38
39
# Now, enable some bitmaps, to be updated during migration
40
for i in range(2, nb_bitmaps, 2):
41
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase):
42
43
event_resume = self.vm_b.event_wait('RESUME')
44
self.vm_b_events.append(event_resume)
45
- return event_resume
46
+ return (event_resume, discards1_sha256, all_discards_sha256)
47
48
def test_postcopy_success(self):
49
- event_resume = self.start_postcopy()
50
+ event_resume, discards1_sha256, all_discards_sha256 = \
51
+ self.start_postcopy()
52
53
# enabled bitmaps should be updated
54
apply_discards(self.vm_b, discards2)
55
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase):
56
for i in range(0, nb_bitmaps, 5):
57
result = self.vm_b.qmp('x-debug-block-dirty-bitmap-sha256',
58
node='drive0', name='bitmap{}'.format(i))
59
- sha = self.discards1_sha256 if i % 2 else self.all_discards_sha256
60
+ sha = discards1_sha256 if i % 2 else all_discards_sha256
61
self.assert_qmp(result, 'return/sha256', sha)
62
63
def test_early_shutdown_destination(self):
64
--
65
2.31.1
66
67
diff view generated by jsdifflib
New patch
1
There are a couple of things pylint takes issue with:
2
- The "time" import is unused
3
- The import order (iotests should come last)
4
- get_bitmap_hash() doesn't use @self and so should be a function
5
- Semicolons at the end of some lines
6
- Parentheses after "if"
7
- Some lines are too long (80 characters instead of 79)
8
- inject_test_case()'s @name parameter shadows a top-level @name
9
variable
10
- "lambda self: mc(self)" were equivalent to just "mc", but in
11
inject_test_case(), it is not equivalent, so add a comment and disable
12
the warning locally
13
- Always put two empty lines after a function
14
- f'exec: cat > /dev/null' does not need to be an f-string
1
15
16
Fix them.
17
18
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
19
Message-Id: <20210902094017.32902-4-hreitz@redhat.com>
20
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
21
---
22
tests/qemu-iotests/tests/migrate-bitmaps-test | 43 +++++++++++--------
23
1 file changed, 25 insertions(+), 18 deletions(-)
24
25
diff --git a/tests/qemu-iotests/tests/migrate-bitmaps-test b/tests/qemu-iotests/tests/migrate-bitmaps-test
26
index XXXXXXX..XXXXXXX 100755
27
--- a/tests/qemu-iotests/tests/migrate-bitmaps-test
28
+++ b/tests/qemu-iotests/tests/migrate-bitmaps-test
29
@@ -XXX,XX +XXX,XX @@
30
#
31
32
import os
33
-import iotests
34
-import time
35
import itertools
36
import operator
37
import re
38
+import iotests
39
from iotests import qemu_img, qemu_img_create, Timeout
40
41
42
@@ -XXX,XX +XXX,XX @@ mig_cmd = 'exec: cat > ' + mig_file
43
incoming_cmd = 'exec: cat ' + mig_file
44
45
46
+def get_bitmap_hash(vm):
47
+ result = vm.qmp('x-debug-block-dirty-bitmap-sha256',
48
+ node='drive0', name='bitmap0')
49
+ return result['return']['sha256']
50
+
51
+
52
class TestDirtyBitmapMigration(iotests.QMPTestCase):
53
def tearDown(self):
54
self.vm_a.shutdown()
55
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapMigration(iotests.QMPTestCase):
56
params['persistent'] = True
57
58
result = vm.qmp('block-dirty-bitmap-add', **params)
59
- self.assert_qmp(result, 'return', {});
60
-
61
- def get_bitmap_hash(self, vm):
62
- result = vm.qmp('x-debug-block-dirty-bitmap-sha256',
63
- node='drive0', name='bitmap0')
64
- return result['return']['sha256']
65
+ self.assert_qmp(result, 'return', {})
66
67
def check_bitmap(self, vm, sha256):
68
result = vm.qmp('x-debug-block-dirty-bitmap-sha256',
69
node='drive0', name='bitmap0')
70
if sha256:
71
- self.assert_qmp(result, 'return/sha256', sha256);
72
+ self.assert_qmp(result, 'return/sha256', sha256)
73
else:
74
self.assert_qmp(result, 'error/desc',
75
- "Dirty bitmap 'bitmap0' not found");
76
+ "Dirty bitmap 'bitmap0' not found")
77
78
def do_test_migration_resume_source(self, persistent, migrate_bitmaps):
79
granularity = 512
80
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapMigration(iotests.QMPTestCase):
81
self.add_bitmap(self.vm_a, granularity, persistent)
82
for r in regions:
83
self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % r)
84
- sha256 = self.get_bitmap_hash(self.vm_a)
85
+ sha256 = get_bitmap_hash(self.vm_a)
86
87
result = self.vm_a.qmp('migrate', uri=mig_cmd)
88
while True:
89
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapMigration(iotests.QMPTestCase):
90
break
91
while True:
92
result = self.vm_a.qmp('query-status')
93
- if (result['return']['status'] == 'postmigrate'):
94
+ if result['return']['status'] == 'postmigrate':
95
break
96
97
# test that bitmap is still here
98
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapMigration(iotests.QMPTestCase):
99
self.add_bitmap(self.vm_a, granularity, persistent)
100
for r in regions:
101
self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % r)
102
- sha256 = self.get_bitmap_hash(self.vm_a)
103
+ sha256 = get_bitmap_hash(self.vm_a)
104
105
if pre_shutdown:
106
self.vm_a.shutdown()
107
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapMigration(iotests.QMPTestCase):
108
self.check_bitmap(self.vm_b, sha256 if persistent else False)
109
110
111
-def inject_test_case(klass, name, method, *args, **kwargs):
112
+def inject_test_case(klass, suffix, method, *args, **kwargs):
113
mc = operator.methodcaller(method, *args, **kwargs)
114
- setattr(klass, 'test_' + method + name, lambda self: mc(self))
115
+ # We want to add a function attribute to `klass`, so that it is
116
+ # correctly converted to a method on instantiation. The
117
+ # methodcaller object `mc` is a callable, not a function, so we
118
+ # need the lambda to turn it into a function.
119
+ # pylint: disable=unnecessary-lambda
120
+ setattr(klass, 'test_' + method + suffix, lambda self: mc(self))
121
+
122
123
for cmb in list(itertools.product((True, False), repeat=5)):
124
name = ('_' if cmb[0] else '_not_') + 'persistent_'
125
name += ('_' if cmb[1] else '_not_') + 'migbitmap_'
126
name += '_online' if cmb[2] else '_offline'
127
name += '_shared' if cmb[3] else '_nonshared'
128
- if (cmb[4]):
129
+ if cmb[4]:
130
name += '__pre_shutdown'
131
132
inject_test_case(TestDirtyBitmapMigration, name, 'do_test_migration',
133
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapBackingMigration(iotests.QMPTestCase):
134
self.assert_qmp(result, 'return', {})
135
136
# Check that the bitmaps are there
137
- for node in self.vm.qmp('query-named-block-nodes', flat=True)['return']:
138
+ nodes = self.vm.qmp('query-named-block-nodes', flat=True)['return']
139
+ for node in nodes:
140
if 'node0' in node['node-name']:
141
self.assert_qmp(node, 'dirty-bitmaps[0]/name', 'bmap0')
142
143
@@ -XXX,XX +XXX,XX @@ class TestDirtyBitmapBackingMigration(iotests.QMPTestCase):
144
"""
145
Continue the source after migration.
146
"""
147
- result = self.vm.qmp('migrate', uri=f'exec: cat > /dev/null')
148
+ result = self.vm.qmp('migrate', uri='exec: cat > /dev/null')
149
self.assert_qmp(result, 'return', {})
150
151
with Timeout(10, 'Migration timeout'):
152
--
153
2.31.1
154
155
diff view generated by jsdifflib
New patch
1
The AbnormalShutdown exception class is not in qemu.machine, but in
2
qemu.machine.machine. (qemu.machine.AbnormalShutdown was enough for
3
Python to find it in order to run this test, but pylint complains about
4
it.)
1
5
6
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
7
Message-Id: <20210902094017.32902-5-hreitz@redhat.com>
8
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
---
10
tests/qemu-iotests/tests/mirror-top-perms | 2 +-
11
1 file changed, 1 insertion(+), 1 deletion(-)
12
13
diff --git a/tests/qemu-iotests/tests/mirror-top-perms b/tests/qemu-iotests/tests/mirror-top-perms
14
index XXXXXXX..XXXXXXX 100755
15
--- a/tests/qemu-iotests/tests/mirror-top-perms
16
+++ b/tests/qemu-iotests/tests/mirror-top-perms
17
@@ -XXX,XX +XXX,XX @@ class TestMirrorTopPerms(iotests.QMPTestCase):
18
def tearDown(self):
19
try:
20
self.vm.shutdown()
21
- except qemu.machine.AbnormalShutdown:
22
+ except qemu.machine.machine.AbnormalShutdown:
23
pass
24
25
if self.vm_b is not None:
26
--
27
2.31.1
28
29
diff view generated by jsdifflib
New patch
1
297 so far does not check the named tests, which reside in the tests/
2
directory (i.e. full path tests/qemu-iotests/tests). Fix it.
1
3
4
Thanks to the previous two commits, all named tests pass its scrutiny,
5
so we do not have to add anything to SKIP_FILES.
6
7
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
8
Reviewed-by: Willian Rampazzo <willianr@redhat.com>
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
Message-Id: <20210902094017.32902-6-hreitz@redhat.com>
12
---
13
tests/qemu-iotests/297 | 5 +++--
14
1 file changed, 3 insertions(+), 2 deletions(-)
15
16
diff --git a/tests/qemu-iotests/297 b/tests/qemu-iotests/297
17
index XXXXXXX..XXXXXXX 100755
18
--- a/tests/qemu-iotests/297
19
+++ b/tests/qemu-iotests/297
20
@@ -XXX,XX +XXX,XX @@ def is_python_file(filename):
21
22
23
def run_linters():
24
- files = [filename for filename in (set(os.listdir('.')) - set(SKIP_FILES))
25
- if is_python_file(filename)]
26
+ named_tests = [f'tests/{entry}' for entry in os.listdir('tests')]
27
+ check_tests = set(os.listdir('.') + named_tests) - set(SKIP_FILES)
28
+ files = [filename for filename in check_tests if is_python_file(filename)]
29
30
iotests.logger.debug('Files to be checked:')
31
iotests.logger.debug(', '.join(sorted(files)))
32
--
33
2.31.1
34
35
diff view generated by jsdifflib
New patch
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
2
3
In mirror_iteration() we call mirror_wait_on_conflicts() with
4
`self` parameter set to NULL.
5
6
Starting from commit d44dae1a7c we dereference `self` pointer in
7
mirror_wait_on_conflicts() without checks if it is not NULL.
8
9
Backtrace:
10
Program terminated with signal SIGSEGV, Segmentation fault.
11
#0 mirror_wait_on_conflicts (self=0x0, s=<optimized out>, offset=<optimized out>, bytes=<optimized out>)
12
at ../block/mirror.c:172
13
172     self->waiting_for_op = op;
14
[Current thread is 1 (Thread 0x7f0908931ec0 (LWP 380249))]
15
(gdb) bt
16
#0 mirror_wait_on_conflicts (self=0x0, s=<optimized out>, offset=<optimized out>, bytes=<optimized out>)
17
at ../block/mirror.c:172
18
#1 0x00005610c5d9d631 in mirror_run (job=0x5610c76a2c00, errp=<optimized out>) at ../block/mirror.c:491
19
#2 0x00005610c5d58726 in job_co_entry (opaque=0x5610c76a2c00) at ../job.c:917
20
#3 0x00005610c5f046c6 in coroutine_trampoline (i0=<optimized out>, i1=<optimized out>)
21
at ../util/coroutine-ucontext.c:173
22
#4 0x00007f0909975820 in ?? () at ../sysdeps/unix/sysv/linux/x86_64/__start_context.S:91
23
from /usr/lib64/libc.so.6
24
25
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2001404
26
Fixes: d44dae1a7c ("block/mirror: fix active mirror dead-lock in mirror_wait_on_conflicts")
27
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
28
Message-Id: <20210910124533.288318-1-sgarzare@redhat.com>
29
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
30
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
31
---
32
block/mirror.c | 25 ++++++++++++++++---------
33
1 file changed, 16 insertions(+), 9 deletions(-)
34
35
diff --git a/block/mirror.c b/block/mirror.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/block/mirror.c
38
+++ b/block/mirror.c
39
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn mirror_wait_on_conflicts(MirrorOp *self,
40
if (ranges_overlap(self_start_chunk, self_nb_chunks,
41
op_start_chunk, op_nb_chunks))
42
{
43
- /*
44
- * If the operation is already (indirectly) waiting for us, or
45
- * will wait for us as soon as it wakes up, then just go on
46
- * (instead of producing a deadlock in the former case).
47
- */
48
- if (op->waiting_for_op) {
49
- continue;
50
+ if (self) {
51
+ /*
52
+ * If the operation is already (indirectly) waiting for us,
53
+ * or will wait for us as soon as it wakes up, then just go
54
+ * on (instead of producing a deadlock in the former case).
55
+ */
56
+ if (op->waiting_for_op) {
57
+ continue;
58
+ }
59
+
60
+ self->waiting_for_op = op;
61
}
62
63
- self->waiting_for_op = op;
64
qemu_co_queue_wait(&op->waiting_requests, NULL);
65
- self->waiting_for_op = NULL;
66
+
67
+ if (self) {
68
+ self->waiting_for_op = NULL;
69
+ }
70
+
71
break;
72
}
73
}
74
--
75
2.31.1
76
77
diff view generated by jsdifflib
1
We had a test for a case where relative extent paths did not work, but
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
unfortunately we just fixed the underlying problem, so it works now.
3
This patch adds a new test case that still fails.
4
2
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
Add a simple test which tries to run migration during backup.
6
Reviewed-by: John Snow <jsnow@redhat.com>
4
bdrv_inactivate_all() should fail. But due to bug (see next commit with
7
Message-id: 20190815153638.4600-4-mreitz@redhat.com
5
fix) it doesn't, nodes are inactivated and continued backup crashes
8
Reviewed-by: John Snow <jsnow@redhat.com>
6
on assertion "assert(!(bs->open_flags & BDRV_O_INACTIVE));" in
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
bdrv_co_write_req_prepare().
8
9
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Message-Id: <20210911120027.8063-2-vsementsov@virtuozzo.com>
11
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
10
---
12
---
11
tests/qemu-iotests/059 | 27 +++++++++++++++++++++++++++
13
.../qemu-iotests/tests/migrate-during-backup | 97 +++++++++++++++++++
12
tests/qemu-iotests/059.out | 4 ++++
14
.../tests/migrate-during-backup.out | 5 +
13
2 files changed, 31 insertions(+)
15
2 files changed, 102 insertions(+)
16
create mode 100755 tests/qemu-iotests/tests/migrate-during-backup
17
create mode 100644 tests/qemu-iotests/tests/migrate-during-backup.out
14
18
15
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
19
diff --git a/tests/qemu-iotests/tests/migrate-during-backup b/tests/qemu-iotests/tests/migrate-during-backup
16
index XXXXXXX..XXXXXXX 100755
20
new file mode 100755
17
--- a/tests/qemu-iotests/059
21
index XXXXXXX..XXXXXXX
18
+++ b/tests/qemu-iotests/059
22
--- /dev/null
19
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2
23
+++ b/tests/qemu-iotests/tests/migrate-during-backup
20
24
@@ -XXX,XX +XXX,XX @@
21
echo
25
+#!/usr/bin/env python3
22
echo "=== Testing monolithicFlat with internally generated JSON file name ==="
26
+# group: migration disabled
27
+#
28
+# Copyright (c) 2021 Virtuozzo International GmbH
29
+#
30
+# This program is free software; you can redistribute it and/or modify
31
+# it under the terms of the GNU General Public License as published by
32
+# the Free Software Foundation; either version 2 of the License, or
33
+# (at your option) any later version.
34
+#
35
+# This program is distributed in the hope that it will be useful,
36
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
37
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38
+# GNU General Public License for more details.
39
+#
40
+# You should have received a copy of the GNU General Public License
41
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
42
+#
23
+
43
+
24
+echo '--- blkdebug ---'
44
+import os
25
# Should work, because bdrv_dirname() works fine with blkdebug
45
+import iotests
26
IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
46
+from iotests import qemu_img_create, qemu_io
27
$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" \
28
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TE
29
| _filter_testdir | _filter_imgfmt | _filter_img_info
30
_cleanup_test_img
31
32
+echo '--- quorum ---'
33
+# Should not work, because bdrv_dirname() does not work with quorum
34
+IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
35
+cp "$TEST_IMG" "$TEST_IMG.orig"
36
+
37
+filename="json:{
38
+ \"driver\": \"$IMGFMT\",
39
+ \"file\": {
40
+ \"driver\": \"quorum\",
41
+ \"children\": [ {
42
+ \"driver\": \"file\",
43
+ \"filename\": \"$TEST_IMG\"
44
+ }, {
45
+ \"driver\": \"file\",
46
+ \"filename\": \"$TEST_IMG.orig\"
47
+ } ],
48
+ \"vote-threshold\": 1
49
+ } }"
50
+
51
+filename=$(echo "$filename" | tr '\n' ' ' | sed -e 's/\s\+/ /g')
52
+$QEMU_IMG info "$filename" 2>&1 \
53
+ | sed -e "s/'json:[^']*'/\$QUORUM_FILE/g" \
54
+ | _filter_testdir | _filter_imgfmt | _filter_img_info
55
+
47
+
56
+
48
+
57
echo
49
+disk_a = os.path.join(iotests.test_dir, 'disk_a')
58
echo "=== Testing version 3 ==="
50
+disk_b = os.path.join(iotests.test_dir, 'disk_b')
59
_use_sample_img iotest-version3.vmdk.bz2
51
+size = '1M'
60
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
52
+mig_file = os.path.join(iotests.test_dir, 'mig_file')
61
index XXXXXXX..XXXXXXX 100644
53
+mig_cmd = 'exec: cat > ' + mig_file
62
--- a/tests/qemu-iotests/059.out
54
+
63
+++ b/tests/qemu-iotests/059.out
55
+
64
@@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 10240
56
+class TestMigrateDuringBackup(iotests.QMPTestCase):
65
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
57
+ def tearDown(self):
66
58
+ self.vm.shutdown()
67
=== Testing monolithicFlat with internally generated JSON file name ===
59
+ os.remove(disk_a)
68
+--- blkdebug ---
60
+ os.remove(disk_b)
69
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
61
+ os.remove(mig_file)
70
format name: IMGFMT
62
+
71
cluster size: 0 bytes
63
+ def setUp(self):
72
vm state offset: 0 bytes
64
+ qemu_img_create('-f', iotests.imgfmt, disk_a, size)
73
+--- quorum ---
65
+ qemu_img_create('-f', iotests.imgfmt, disk_b, size)
74
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
66
+ qemu_io('-c', f'write 0 {size}', disk_a)
75
+qemu-img: Could not open $QUORUM_FILE: Cannot use relative paths with VMDK descriptor file $QUORUM_FILE: Cannot generate a base directory for quorum nodes
67
+
76
68
+ self.vm = iotests.VM().add_drive(disk_a)
77
=== Testing version 3 ===
69
+ self.vm.launch()
78
image: TEST_DIR/iotest-version3.IMGFMT
70
+ result = self.vm.qmp('blockdev-add', {
71
+ 'node-name': 'target',
72
+ 'driver': iotests.imgfmt,
73
+ 'file': {
74
+ 'driver': 'file',
75
+ 'filename': disk_b
76
+ }
77
+ })
78
+ self.assert_qmp(result, 'return', {})
79
+
80
+ def test_migrate(self):
81
+ result = self.vm.qmp('blockdev-backup', device='drive0',
82
+ target='target', sync='full',
83
+ speed=1, x_perf={
84
+ 'max-workers': 1,
85
+ 'max-chunk': 64 * 1024
86
+ })
87
+ self.assert_qmp(result, 'return', {})
88
+
89
+ result = self.vm.qmp('job-pause', id='drive0')
90
+ self.assert_qmp(result, 'return', {})
91
+
92
+ result = self.vm.qmp('migrate-set-capabilities',
93
+ capabilities=[{'capability': 'events',
94
+ 'state': True}])
95
+ self.assert_qmp(result, 'return', {})
96
+ result = self.vm.qmp('migrate', uri=mig_cmd)
97
+ self.assert_qmp(result, 'return', {})
98
+
99
+ e = self.vm.events_wait((('MIGRATION',
100
+ {'data': {'status': 'completed'}}),
101
+ ('MIGRATION',
102
+ {'data': {'status': 'failed'}})))
103
+
104
+ # Don't assert that e is 'failed' now: this way we'll miss
105
+ # possible crash when backup continues :)
106
+
107
+ result = self.vm.qmp('block-job-set-speed', device='drive0',
108
+ speed=0)
109
+ self.assert_qmp(result, 'return', {})
110
+ result = self.vm.qmp('job-resume', id='drive0')
111
+ self.assert_qmp(result, 'return', {})
112
+
113
+ # For future: if something changes so that both migration
114
+ # and backup pass, let's not miss that moment, as it may
115
+ # be a bug as well as improvement.
116
+ self.assert_qmp(e, 'data/status', 'failed')
117
+
118
+
119
+if __name__ == '__main__':
120
+ iotests.main(supported_fmts=['qcow2'],
121
+ supported_protocols=['file'])
122
diff --git a/tests/qemu-iotests/tests/migrate-during-backup.out b/tests/qemu-iotests/tests/migrate-during-backup.out
123
new file mode 100644
124
index XXXXXXX..XXXXXXX
125
--- /dev/null
126
+++ b/tests/qemu-iotests/tests/migrate-during-backup.out
127
@@ -XXX,XX +XXX,XX @@
128
+.
129
+----------------------------------------------------------------------
130
+Ran 1 tests
131
+
132
+OK
79
--
133
--
80
2.21.0
134
2.31.1
81
135
82
136
diff view generated by jsdifflib
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
It's wrong to OR shared permissions. It may lead to crash on further
3
We must not inactivate child when parent has write permissions on
4
permission updates.
4
it.
5
Also, no needs to consider previously calculated permissions, as at
6
this point we already bind all new parents and bdrv_get_cumulative_perm
7
result is enough. So fix the bug by just set permissions by
8
bdrv_get_cumulative_perm result.
9
5
10
Bug was introduced in long ago 234ac1a9025, in 2.9.
6
Calling .bdrv_inactivate() doesn't help: actually only qcow2 has this
7
handler and it is used to flush caches, not for permission
8
manipulations.
9
10
So, let's simply check cumulative parent permissions before
11
inactivating the node.
12
13
This commit fixes a crash when we do migration during backup: prior to
14
the commit nothing prevents all nodes inactivation at migration finish
15
and following backup write to the target crashes on assertion
16
"assert(!(bs->open_flags & BDRV_O_INACTIVE));" in
17
bdrv_co_write_req_prepare().
18
19
After the commit, we rely on the fact that copy-before-write filter
20
keeps write permission on target node to be able to write to it. So
21
inactivation fails and migration fails as expected.
22
23
Corresponding test now passes, so, enable it.
11
24
12
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
25
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
Message-id: 20190824100740.61635-1-vsementsov@virtuozzo.com
26
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
27
Message-Id: <20210911120027.8063-3-vsementsov@virtuozzo.com>
28
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
15
---
29
---
16
block.c | 5 ++---
30
block.c | 8 ++++++++
17
1 file changed, 2 insertions(+), 3 deletions(-)
31
tests/qemu-iotests/tests/migrate-during-backup | 2 +-
32
2 files changed, 9 insertions(+), 1 deletion(-)
18
33
19
diff --git a/block.c b/block.c
34
diff --git a/block.c b/block.c
20
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
21
--- a/block.c
36
--- a/block.c
22
+++ b/block.c
37
+++ b/block.c
23
@@ -XXX,XX +XXX,XX @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
38
@@ -XXX,XX +XXX,XX @@ static int bdrv_inactivate_recurse(BlockDriverState *bs)
24
{
39
{
25
BdrvChild *c, *next;
40
BdrvChild *child, *parent;
26
GSList *list = NULL, *p;
27
- uint64_t old_perm, old_shared;
28
uint64_t perm = 0, shared = BLK_PERM_ALL;
29
int ret;
41
int ret;
30
42
+ uint64_t cumulative_perms, cumulative_shared_perms;
31
@@ -XXX,XX +XXX,XX @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
43
32
bdrv_unref(from);
44
if (!bs->drv) {
45
return -ENOMEDIUM;
46
@@ -XXX,XX +XXX,XX @@ static int bdrv_inactivate_recurse(BlockDriverState *bs)
47
}
33
}
48
}
34
49
35
- bdrv_get_cumulative_perm(to, &old_perm, &old_shared);
50
+ bdrv_get_cumulative_perm(bs, &cumulative_perms,
36
- bdrv_set_perm(to, old_perm | perm, old_shared | shared);
51
+ &cumulative_shared_perms);
37
+ bdrv_get_cumulative_perm(to, &perm, &shared);
52
+ if (cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) {
38
+ bdrv_set_perm(to, perm, shared);
53
+ /* Our inactive parents still need write access. Inactivation failed. */
39
54
+ return -EPERM;
40
out:
55
+ }
41
g_slist_free(list);
56
+
57
bs->open_flags |= BDRV_O_INACTIVE;
58
59
/*
60
diff --git a/tests/qemu-iotests/tests/migrate-during-backup b/tests/qemu-iotests/tests/migrate-during-backup
61
index XXXXXXX..XXXXXXX 100755
62
--- a/tests/qemu-iotests/tests/migrate-during-backup
63
+++ b/tests/qemu-iotests/tests/migrate-during-backup
64
@@ -XXX,XX +XXX,XX @@
65
#!/usr/bin/env python3
66
-# group: migration disabled
67
+# group: migration
68
#
69
# Copyright (c) 2021 Virtuozzo International GmbH
70
#
42
--
71
--
43
2.21.0
72
2.31.1
44
73
45
74
diff view generated by jsdifflib
1
From: Nir Soffer <nirsof@gmail.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
When creating an image with preallocation "off" or "falloc", the first
3
Add simple grammar-parsing template benchmark. New tool consume test
4
block of the image is typically not allocated. When using Gluster
4
template written in bash with some special grammar injections and
5
storage backed by XFS filesystem, reading this block using direct I/O
5
produces multiple tests, run them and finally print a performance
6
succeeds regardless of request length, fooling alignment detection.
6
comparison table of different tests produced from one template.
7
7
8
In this case we fallback to a safe value (4096) instead of the optimal
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
value (512), which may lead to unneeded data copying when aligning
9
Message-Id: <20210824101517.59802-2-vsementsov@virtuozzo.com>
10
requests. Allocating the first block avoids the fallback.
10
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
11
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
12
---
13
scripts/simplebench/img_bench_templater.py | 95 ++++++++++++++++++++++
14
scripts/simplebench/table_templater.py | 62 ++++++++++++++
15
2 files changed, 157 insertions(+)
16
create mode 100755 scripts/simplebench/img_bench_templater.py
17
create mode 100644 scripts/simplebench/table_templater.py
11
18
12
Since we allocate the first block even with preallocation=off, we no
19
diff --git a/scripts/simplebench/img_bench_templater.py b/scripts/simplebench/img_bench_templater.py
13
longer create images with zero disk size:
20
new file mode 100755
14
21
index XXXXXXX..XXXXXXX
15
$ ./qemu-img create -f raw test.raw 1g
22
--- /dev/null
16
Formatting 'test.raw', fmt=raw size=1073741824
23
+++ b/scripts/simplebench/img_bench_templater.py
17
24
@@ -XXX,XX +XXX,XX @@
18
$ ls -lhs test.raw
25
+#!/usr/bin/env python3
19
4.0K -rw-r--r--. 1 nsoffer nsoffer 1.0G Aug 16 23:48 test.raw
26
+#
20
27
+# Process img-bench test templates
21
And converting the image requires additional cluster:
28
+#
22
29
+# Copyright (c) 2021 Virtuozzo International GmbH.
23
$ ./qemu-img measure -f raw -O qcow2 test.raw
30
+#
24
required size: 458752
31
+# This program is free software; you can redistribute it and/or modify
25
fully allocated size: 1074135040
32
+# it under the terms of the GNU General Public License as published by
26
33
+# the Free Software Foundation; either version 2 of the License, or
27
When using format like vmdk with multiple files per image, we allocate
34
+# (at your option) any later version.
28
one block per file:
35
+#
29
36
+# This program is distributed in the hope that it will be useful,
30
$ ./qemu-img create -f vmdk -o subformat=twoGbMaxExtentFlat test.vmdk 4g
37
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
31
Formatting 'test.vmdk', fmt=vmdk size=4294967296 compat6=off hwversion=undefined subformat=twoGbMaxExtentFlat
38
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32
39
+# GNU General Public License for more details.
33
$ ls -lhs test*.vmdk
40
+#
34
4.0K -rw-r--r--. 1 nsoffer nsoffer 2.0G Aug 27 03:23 test-f001.vmdk
41
+# You should have received a copy of the GNU General Public License
35
4.0K -rw-r--r--. 1 nsoffer nsoffer 2.0G Aug 27 03:23 test-f002.vmdk
42
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
36
4.0K -rw-r--r--. 1 nsoffer nsoffer 353 Aug 27 03:23 test.vmdk
43
+#
37
38
I did quick performance test for copying disks with qemu-img convert to
39
new raw target image to Gluster storage with sector size of 512 bytes:
40
41
for i in $(seq 10); do
42
rm -f dst.raw
43
sleep 10
44
time ./qemu-img convert -f raw -O raw -t none -T none src.raw dst.raw
45
done
46
47
Here is a table comparing the total time spent:
48
49
Type Before(s) After(s) Diff(%)
50
---------------------------------------
51
real 530.028 469.123 -11.4
52
user 17.204 10.768 -37.4
53
sys 17.881 7.011 -60.7
54
55
We can see very clear improvement in CPU usage.
56
57
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
58
Message-id: 20190827010528.8818-2-nsoffer@redhat.com
59
Reviewed-by: Max Reitz <mreitz@redhat.com>
60
Signed-off-by: Max Reitz <mreitz@redhat.com>
61
---
62
block/file-posix.c | 51 +++++++++++++++++++
63
tests/qemu-iotests/059.out | 2 +-
64
tests/qemu-iotests/{150.out => 150.out.qcow2} | 0
65
tests/qemu-iotests/150.out.raw | 12 +++++
66
tests/qemu-iotests/175 | 19 ++++---
67
tests/qemu-iotests/175.out | 8 +--
68
tests/qemu-iotests/178.out.qcow2 | 4 +-
69
tests/qemu-iotests/221.out | 12 +++--
70
tests/qemu-iotests/253.out | 12 +++--
71
9 files changed, 99 insertions(+), 21 deletions(-)
72
rename tests/qemu-iotests/{150.out => 150.out.qcow2} (100%)
73
create mode 100644 tests/qemu-iotests/150.out.raw
74
75
diff --git a/block/file-posix.c b/block/file-posix.c
76
index XXXXXXX..XXXXXXX 100644
77
--- a/block/file-posix.c
78
+++ b/block/file-posix.c
79
@@ -XXX,XX +XXX,XX @@ static int handle_aiocb_discard(void *opaque)
80
return ret;
81
}
82
83
+/*
84
+ * Help alignment probing by allocating the first block.
85
+ *
86
+ * When reading with direct I/O from unallocated area on Gluster backed by XFS,
87
+ * reading succeeds regardless of request length. In this case we fallback to
88
+ * safe alignment which is not optimal. Allocating the first block avoids this
89
+ * fallback.
90
+ *
91
+ * fd may be opened with O_DIRECT, but we don't know the buffer alignment or
92
+ * request alignment, so we use safe values.
93
+ *
94
+ * Returns: 0 on success, -errno on failure. Since this is an optimization,
95
+ * caller may ignore failures.
96
+ */
97
+static int allocate_first_block(int fd, size_t max_size)
98
+{
99
+ size_t write_size = (max_size < MAX_BLOCKSIZE)
100
+ ? BDRV_SECTOR_SIZE
101
+ : MAX_BLOCKSIZE;
102
+ size_t max_align = MAX(MAX_BLOCKSIZE, getpagesize());
103
+ void *buf;
104
+ ssize_t n;
105
+ int ret;
106
+
44
+
107
+ buf = qemu_memalign(max_align, write_size);
108
+ memset(buf, 0, write_size);
109
+
45
+
110
+ do {
46
+import sys
111
+ n = pwrite(fd, buf, write_size, 0);
47
+import subprocess
112
+ } while (n == -1 && errno == EINTR);
48
+import re
49
+import json
113
+
50
+
114
+ ret = (n == -1) ? -errno : 0;
51
+import simplebench
52
+from results_to_text import results_to_text
53
+from table_templater import Templater
115
+
54
+
116
+ qemu_vfree(buf);
117
+ return ret;
118
+}
119
+
55
+
120
static int handle_aiocb_truncate(void *opaque)
56
+def bench_func(env, case):
121
{
57
+ test = templater.gen(env['data'], case['data'])
122
RawPosixAIOData *aiocb = opaque;
58
+
123
@@ -XXX,XX +XXX,XX @@ static int handle_aiocb_truncate(void *opaque)
59
+ p = subprocess.run(test, shell=True, stdout=subprocess.PIPE,
124
/* posix_fallocate() doesn't set errno. */
60
+ stderr=subprocess.STDOUT, universal_newlines=True)
125
error_setg_errno(errp, -result,
61
+
126
"Could not preallocate new data");
62
+ if p.returncode == 0:
127
+ } else if (current_length == 0) {
63
+ try:
128
+ /*
64
+ m = re.search(r'Run completed in (\d+.\d+) seconds.', p.stdout)
129
+ * posix_fallocate() uses fallocate() if the filesystem
65
+ return {'seconds': float(m.group(1))}
130
+ * supports it, or fallback to manually writing zeroes. If
66
+ except Exception:
131
+ * fallocate() was used, unaligned reads from the fallocated
67
+ return {'error': f'failed to parse qemu-img output: {p.stdout}'}
132
+ * area in raw_probe_alignment() will succeed, hence we need to
68
+ else:
133
+ * allocate the first block.
69
+ return {'error': f'qemu-img failed: {p.returncode}: {p.stdout}'}
134
+ *
70
+
135
+ * Optimize future alignment probing; ignore failures.
71
+
136
+ */
72
+if __name__ == '__main__':
137
+ allocate_first_block(fd, offset);
73
+ if len(sys.argv) > 1:
138
}
74
+ print("""
139
} else {
75
+Usage: img_bench_templater.py < path/to/test-template.sh
140
result = 0;
76
+
141
@@ -XXX,XX +XXX,XX @@ static int handle_aiocb_truncate(void *opaque)
77
+This script generates performance tests from a test template (example below),
142
if (ftruncate(fd, offset) != 0) {
78
+runs them, and displays the results in a table. The template is read from
143
result = -errno;
79
+stdin. It must be written in bash and end with a `qemu-img bench` invocation
144
error_setg_errno(errp, -result, "Could not resize file");
80
+(whose result is parsed to get the test instance’s result).
145
+ } else if (current_length == 0 && offset > current_length) {
81
+
146
+ /* Optimize future alignment probing; ignore failures. */
82
+Use the following syntax in the template to create the various different test
147
+ allocate_first_block(fd, offset);
83
+instances:
148
}
84
+
149
return result;
85
+ column templating: {var1|var2|...} - test will use different values in
150
default:
86
+ different columns. You may use several {} constructions in the test, in this
151
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
87
+ case product of all choice-sets will be used.
152
index XXXXXXX..XXXXXXX 100644
88
+
153
--- a/tests/qemu-iotests/059.out
89
+ row templating: [var1|var2|...] - similar thing to define rows (test-cases)
154
+++ b/tests/qemu-iotests/059.out
90
+
155
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 subformat=twoGbMax
91
+Test template example:
156
image: TEST_DIR/t.vmdk
92
+
157
file format: vmdk
93
+Assume you want to compare two qemu-img binaries, called qemu-img-old and
158
virtual size: 0.977 TiB (1073741824000 bytes)
94
+qemu-img-new in your build directory in two test-cases with 4K writes and 64K
159
-disk size: 16 KiB
95
+writes. The template may look like this:
160
+disk size: 1.97 MiB
96
+
161
Format specific information:
97
+qemu_img=/path/to/qemu/build/qemu-img-{old|new}
162
cid: XXXXXXXX
98
+$qemu_img create -f qcow2 /ssd/x.qcow2 1G
163
parent cid: XXXXXXXX
99
+$qemu_img bench -c 100 -d 8 [-s 4K|-s 64K] -w -t none -n /ssd/x.qcow2
164
diff --git a/tests/qemu-iotests/150.out b/tests/qemu-iotests/150.out.qcow2
100
+
165
similarity index 100%
101
+When passing this to stdin of img_bench_templater.py, the resulting comparison
166
rename from tests/qemu-iotests/150.out
102
+table will contain two columns (for two binaries) and two rows (for two
167
rename to tests/qemu-iotests/150.out.qcow2
103
+test-cases).
168
diff --git a/tests/qemu-iotests/150.out.raw b/tests/qemu-iotests/150.out.raw
104
+
105
+In addition to displaying the results, script also stores results in JSON
106
+format into results.json file in current directory.
107
+""")
108
+ sys.exit()
109
+
110
+ templater = Templater(sys.stdin.read())
111
+
112
+ envs = [{'id': ' / '.join(x), 'data': x} for x in templater.columns]
113
+ cases = [{'id': ' / '.join(x), 'data': x} for x in templater.rows]
114
+
115
+ result = simplebench.bench(bench_func, envs, cases, count=5,
116
+ initial_run=False)
117
+ print(results_to_text(result))
118
+ with open('results.json', 'w') as f:
119
+ json.dump(result, f, indent=4)
120
diff --git a/scripts/simplebench/table_templater.py b/scripts/simplebench/table_templater.py
169
new file mode 100644
121
new file mode 100644
170
index XXXXXXX..XXXXXXX
122
index XXXXXXX..XXXXXXX
171
--- /dev/null
123
--- /dev/null
172
+++ b/tests/qemu-iotests/150.out.raw
124
+++ b/scripts/simplebench/table_templater.py
173
@@ -XXX,XX +XXX,XX @@
125
@@ -XXX,XX +XXX,XX @@
174
+QA output created by 150
126
+# Parser for test templates
127
+#
128
+# Copyright (c) 2021 Virtuozzo International GmbH.
129
+#
130
+# This program is free software; you can redistribute it and/or modify
131
+# it under the terms of the GNU General Public License as published by
132
+# the Free Software Foundation; either version 2 of the License, or
133
+# (at your option) any later version.
134
+#
135
+# This program is distributed in the hope that it will be useful,
136
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
137
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
138
+# GNU General Public License for more details.
139
+#
140
+# You should have received a copy of the GNU General Public License
141
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
142
+#
175
+
143
+
176
+=== Mapping sparse conversion ===
144
+import itertools
145
+from lark import Lark
177
+
146
+
178
+Offset Length File
147
+grammar = """
179
+0 0x1000 TEST_DIR/t.IMGFMT
148
+start: ( text | column_switch | row_switch )+
180
+
149
+
181
+=== Mapping non-sparse conversion ===
150
+column_switch: "{" text ["|" text]+ "}"
151
+row_switch: "[" text ["|" text]+ "]"
152
+text: /[^|{}\[\]]+/
153
+"""
182
+
154
+
183
+Offset Length File
155
+parser = Lark(grammar)
184
+0 0x100000 TEST_DIR/t.IMGFMT
185
+*** done
186
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
187
index XXXXXXX..XXXXXXX 100755
188
--- a/tests/qemu-iotests/175
189
+++ b/tests/qemu-iotests/175
190
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
191
# the file size. This function hides the resulting difference in the
192
# stat -c '%b' output.
193
# Parameter 1: Number of blocks an empty file occupies
194
-# Parameter 2: Image size in bytes
195
+# Parameter 2: Minimal number of blocks in an image
196
+# Parameter 3: Image size in bytes
197
_filter_blocks()
198
{
199
extra_blocks=$1
200
- img_size=$2
201
+ min_blocks=$2
202
+ img_size=$3
203
204
- sed -e "s/blocks=$extra_blocks\\(\$\\|[^0-9]\\)/nothing allocated/" \
205
- -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/everything allocated/"
206
+ sed -e "s/blocks=$min_blocks\\(\$\\|[^0-9]\\)/min allocation/" \
207
+ -e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/max allocation/"
208
}
209
210
# get standard environment, filters and checks
211
@@ -XXX,XX +XXX,XX @@ size=$((1 * 1024 * 1024))
212
touch "$TEST_DIR/empty"
213
extra_blocks=$(stat -c '%b' "$TEST_DIR/empty")
214
215
+# We always write the first byte; check how many blocks this filesystem
216
+# allocates to match empty image alloation.
217
+printf "\0" > "$TEST_DIR/empty"
218
+min_blocks=$(stat -c '%b' "$TEST_DIR/empty")
219
+
156
+
220
echo
157
+class Templater:
221
echo "== creating image with default preallocation =="
158
+ def __init__(self, template):
222
_make_test_img $size | _filter_imgfmt
159
+ self.tree = parser.parse(template)
223
-stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size
160
+
224
+stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
161
+ c_switches = []
225
162
+ r_switches = []
226
for mode in off full falloc; do
163
+ for x in self.tree.children:
227
echo
164
+ if x.data == 'column_switch':
228
echo "== creating image with preallocation $mode =="
165
+ c_switches.append([el.children[0].value for el in x.children])
229
IMGOPTS=preallocation=$mode _make_test_img $size | _filter_imgfmt
166
+ elif x.data == 'row_switch':
230
- stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $size
167
+ r_switches.append([el.children[0].value for el in x.children])
231
+ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
168
+
232
done
169
+ self.columns = list(itertools.product(*c_switches))
233
170
+ self.rows = list(itertools.product(*r_switches))
234
# success, all done
171
+
235
diff --git a/tests/qemu-iotests/175.out b/tests/qemu-iotests/175.out
172
+ def gen(self, column, row):
236
index XXXXXXX..XXXXXXX 100644
173
+ i = 0
237
--- a/tests/qemu-iotests/175.out
174
+ j = 0
238
+++ b/tests/qemu-iotests/175.out
175
+ result = []
239
@@ -XXX,XX +XXX,XX @@ QA output created by 175
176
+
240
177
+ for x in self.tree.children:
241
== creating image with default preallocation ==
178
+ if x.data == 'text':
242
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
179
+ result.append(x.children[0].value)
243
-size=1048576, nothing allocated
180
+ elif x.data == 'column_switch':
244
+size=1048576, min allocation
181
+ result.append(column[i])
245
182
+ i += 1
246
== creating image with preallocation off ==
183
+ elif x.data == 'row_switch':
247
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=off
184
+ result.append(row[j])
248
-size=1048576, nothing allocated
185
+ j += 1
249
+size=1048576, min allocation
186
+
250
187
+ return ''.join(result)
251
== creating image with preallocation full ==
252
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=full
253
-size=1048576, everything allocated
254
+size=1048576, max allocation
255
256
== creating image with preallocation falloc ==
257
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=falloc
258
-size=1048576, everything allocated
259
+size=1048576, max allocation
260
*** done
261
diff --git a/tests/qemu-iotests/178.out.qcow2 b/tests/qemu-iotests/178.out.qcow2
262
index XXXXXXX..XXXXXXX 100644
263
--- a/tests/qemu-iotests/178.out.qcow2
264
+++ b/tests/qemu-iotests/178.out.qcow2
265
@@ -XXX,XX +XXX,XX @@ converted image file size in bytes: 196608
266
== raw input image with data (human) ==
267
268
Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824
269
-required size: 393216
270
+required size: 458752
271
fully allocated size: 1074135040
272
wrote 512/512 bytes at offset 512
273
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
274
@@ -XXX,XX +XXX,XX @@ converted image file size in bytes: 196608
275
276
Formatting 'TEST_DIR/t.qcow2', fmt=IMGFMT size=1073741824
277
{
278
- "required": 393216,
279
+ "required": 458752,
280
"fully-allocated": 1074135040
281
}
282
wrote 512/512 bytes at offset 512
283
diff --git a/tests/qemu-iotests/221.out b/tests/qemu-iotests/221.out
284
index XXXXXXX..XXXXXXX 100644
285
--- a/tests/qemu-iotests/221.out
286
+++ b/tests/qemu-iotests/221.out
287
@@ -XXX,XX +XXX,XX @@ QA output created by 221
288
=== Check mapping of unaligned raw image ===
289
290
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65537
291
-[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
292
-[{ "start": 0, "length": 66048, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
293
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
294
+{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
295
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
296
+{ "start": 4096, "length": 61952, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
297
wrote 1/1 bytes at offset 65536
298
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
299
-[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
300
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
301
+{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
302
{ "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
303
{ "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
304
-[{ "start": 0, "length": 65536, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
305
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
306
+{ "start": 4096, "length": 61440, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
307
{ "start": 65536, "length": 1, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
308
{ "start": 65537, "length": 511, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
309
*** done
310
diff --git a/tests/qemu-iotests/253.out b/tests/qemu-iotests/253.out
311
index XXXXXXX..XXXXXXX 100644
312
--- a/tests/qemu-iotests/253.out
313
+++ b/tests/qemu-iotests/253.out
314
@@ -XXX,XX +XXX,XX @@ QA output created by 253
315
=== Check mapping of unaligned raw image ===
316
317
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048575
318
-[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
319
-[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
320
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
321
+{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
322
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
323
+{ "start": 4096, "length": 1044480, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
324
wrote 65535/65535 bytes at offset 983040
325
63.999 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
326
-[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
327
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
328
+{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
329
{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
330
-[{ "start": 0, "length": 983040, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
331
+[{ "start": 0, "length": 4096, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
332
+{ "start": 4096, "length": 978944, "depth": 0, "zero": true, "data": false, "offset": OFFSET},
333
{ "start": 983040, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": OFFSET}]
334
*** done
335
--
188
--
336
2.21.0
189
2.31.1
337
190
338
191
diff view generated by jsdifflib
1
From: Nir Soffer <nirsof@gmail.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Quoting cache mode is not needed, and most tests use unquoted values.
3
No logic change, just prepare for the following commit. While being
4
Unify all test to use the same style.
4
here do also small grammar fix in a comment.
5
5
6
Message-id: 20190827173432.7656-1-nsoffer@redhat.com
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
9
Message-Id: <20210824101517.59802-3-vsementsov@virtuozzo.com>
10
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
---
11
---
10
tests/qemu-iotests/026 | 4 ++--
12
block/qcow2-cluster.c | 49 ++++++++++++++++++++++++-------------------
11
tests/qemu-iotests/039 | 4 ++--
13
1 file changed, 28 insertions(+), 21 deletions(-)
12
tests/qemu-iotests/052 | 2 +-
13
tests/qemu-iotests/091 | 4 ++--
14
4 files changed, 7 insertions(+), 7 deletions(-)
15
14
16
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
15
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
17
index XXXXXXX..XXXXXXX 100755
16
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/qemu-iotests/026
17
--- a/block/qcow2-cluster.c
19
+++ b/tests/qemu-iotests/026
18
+++ b/block/qcow2-cluster.c
20
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
19
@@ -XXX,XX +XXX,XX @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
21
# Currently only qcow2 supports rebasing
20
22
_supported_fmt qcow2
21
if (end <= old_start || start >= old_end) {
23
_supported_proto file
22
/* No intersection */
24
-_default_cache_mode "writethrough"
23
- } else {
25
-_supported_cache_modes "writethrough" "none"
24
- if (start < old_start) {
26
+_default_cache_mode writethrough
25
- /* Stop at the start of a running allocation */
27
+_supported_cache_modes writethrough none
26
- bytes = old_start - start;
28
# The refcount table tests expect a certain minimum width for refcount entries
27
- } else {
29
# (so that the refcount table actually needs to grow); that minimum is 16 bits,
28
- bytes = 0;
30
# being the default refcount entry width.
29
- }
31
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
30
+ continue;
32
index XXXXXXX..XXXXXXX 100755
31
+ }
33
--- a/tests/qemu-iotests/039
32
34
+++ b/tests/qemu-iotests/039
33
- /* Stop if already an l2meta exists. After yielding, it wouldn't
35
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
34
- * be valid any more, so we'd have to clean up the old L2Metas
36
_supported_fmt qcow2
35
- * and deal with requests depending on them before starting to
37
_supported_proto file
36
- * gather new ones. Not worth the trouble. */
38
_supported_os Linux
37
- if (bytes == 0 && *m) {
39
-_default_cache_mode "writethrough"
38
- *cur_bytes = 0;
40
-_supported_cache_modes "writethrough"
39
- return 0;
41
+_default_cache_mode writethrough
40
- }
42
+_supported_cache_modes writethrough
41
+ /* Conflict */
43
42
44
size=128M
43
- if (bytes == 0) {
45
44
- /* Wait for the dependency to complete. We need to recheck
46
diff --git a/tests/qemu-iotests/052 b/tests/qemu-iotests/052
45
- * the free/allocated clusters when we continue. */
47
index XXXXXXX..XXXXXXX 100755
46
- qemu_co_queue_wait(&old_alloc->dependent_requests, &s->lock);
48
--- a/tests/qemu-iotests/052
47
- return -EAGAIN;
49
+++ b/tests/qemu-iotests/052
48
- }
50
@@ -XXX,XX +XXX,XX @@ _supported_fmt generic
49
+ if (start < old_start) {
51
_supported_proto file
50
+ /* Stop at the start of a running allocation */
52
51
+ bytes = old_start - start;
53
# Don't do O_DIRECT on tmpfs
52
+ } else {
54
-_supported_cache_modes "writeback" "writethrough" "unsafe"
53
+ bytes = 0;
55
+_supported_cache_modes writeback writethrough unsafe
54
+ }
56
55
+
57
size=128M
56
+ /*
58
_make_test_img $size
57
+ * Stop if an l2meta already exists. After yielding, it wouldn't
59
diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091
58
+ * be valid any more, so we'd have to clean up the old L2Metas
60
index XXXXXXX..XXXXXXX 100755
59
+ * and deal with requests depending on them before starting to
61
--- a/tests/qemu-iotests/091
60
+ * gather new ones. Not worth the trouble.
62
+++ b/tests/qemu-iotests/091
61
+ */
63
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
62
+ if (bytes == 0 && *m) {
64
_supported_fmt qcow2
63
+ *cur_bytes = 0;
65
_supported_proto file
64
+ return 0;
66
_supported_os Linux
65
+ }
67
-_default_cache_mode "none"
66
+
68
-_supported_cache_modes "writethrough" "none" "writeback"
67
+ if (bytes == 0) {
69
+_default_cache_mode none
68
+ /*
70
+_supported_cache_modes writethrough none writeback
69
+ * Wait for the dependency to complete. We need to recheck
71
70
+ * the free/allocated clusters when we continue.
72
size=1G
71
+ */
72
+ qemu_co_queue_wait(&old_alloc->dependent_requests, &s->lock);
73
+ return -EAGAIN;
74
}
75
}
73
76
74
--
77
--
75
2.21.0
78
2.31.1
76
79
77
80
diff view generated by jsdifflib
1
This makes iotest 033 pass with e.g. subformat=monolithicFlat. It also
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
turns a former error in 059 into success.
3
2
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
There is no conflict and no dependency if we have parallel writes to
5
Message-id: 20190815153638.4600-3-mreitz@redhat.com
4
different subclusters of one cluster when the cluster itself is already
6
Reviewed-by: John Snow <jsnow@redhat.com>
5
allocated. So, relax extra dependency.
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
7
Measure performance:
8
First, prepare build/qemu-img-old and build/qemu-img-new images.
9
10
cd scripts/simplebench
11
./img_bench_templater.py
12
13
Paste the following to stdin of running script:
14
15
qemu_img=../../build/qemu-img-{old|new}
16
$qemu_img create -f qcow2 -o extended_l2=on /ssd/x.qcow2 1G
17
$qemu_img bench -c 100000 -d 8 [-s 2K|-s 2K -o 512|-s $((1024*2+512))] \
18
-w -t none -n /ssd/x.qcow2
19
20
The result:
21
22
All results are in seconds
23
24
------------------ --------- ---------
25
old new
26
-s 2K 6.7 ± 15% 6.2 ± 12%
27
-7%
28
-s 2K -o 512 13 ± 3% 11 ± 5%
29
-16%
30
-s $((1024*2+512)) 9.5 ± 4% 8.4
31
-12%
32
------------------ --------- ---------
33
34
So small writes are more independent now and that helps to keep deeper
35
io queue which improves performance.
36
37
271 iotest output becomes racy for three allocation in one cluster.
38
Second and third writes may finish in different order. Second and
39
third requests don't depend on each other any more. Still they both
40
depend on first request anyway. Filter out second and third write
41
offsets to cover both possible outputs.
42
43
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
44
Message-Id: <20210824101517.59802-4-vsementsov@virtuozzo.com>
45
Reviewed-by: Eric Blake <eblake@redhat.com>
46
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
47
[hreitz: s/ an / and /]
48
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
8
---
49
---
9
block/vmdk.c | 54 ++++++++++++++++++++++++--------------
50
block/qcow2-cluster.c | 11 +++++++++++
10
tests/qemu-iotests/059 | 7 +++--
51
tests/qemu-iotests/271 | 5 ++++-
11
tests/qemu-iotests/059.out | 4 ++-
52
tests/qemu-iotests/271.out | 4 ++--
12
3 files changed, 42 insertions(+), 23 deletions(-)
53
3 files changed, 17 insertions(+), 3 deletions(-)
13
54
14
diff --git a/block/vmdk.c b/block/vmdk.c
55
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
15
index XXXXXXX..XXXXXXX 100644
56
index XXXXXXX..XXXXXXX 100644
16
--- a/block/vmdk.c
57
--- a/block/qcow2-cluster.c
17
+++ b/block/vmdk.c
58
+++ b/block/qcow2-cluster.c
18
@@ -XXX,XX +XXX,XX @@ static const char *next_line(const char *s)
59
@@ -XXX,XX +XXX,XX @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
19
}
20
21
static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
22
- const char *desc_file_path, QDict *options,
23
- Error **errp)
24
+ QDict *options, Error **errp)
25
{
26
int ret;
27
int matches;
28
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
29
const char *p, *np;
30
int64_t sectors = 0;
31
int64_t flat_offset;
32
+ char *desc_file_dir = NULL;
33
char *extent_path;
34
BdrvChild *extent_file;
35
BDRVVmdkState *s = bs->opaque;
36
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
37
continue;
60
continue;
38
}
61
}
39
62
40
- if (!path_is_absolute(fname) && !path_has_protocol(fname) &&
63
+ if (old_alloc->keep_old_clusters &&
41
- !desc_file_path[0])
64
+ (end <= l2meta_cow_start(old_alloc) ||
42
- {
65
+ start >= l2meta_cow_end(old_alloc)))
43
- bdrv_refresh_filename(bs->file->bs);
66
+ {
44
- error_setg(errp, "Cannot use relative extent paths with VMDK "
67
+ /*
45
- "descriptor file '%s'", bs->file->bs->filename);
68
+ * Clusters intersect but COW areas don't. And cluster itself is
46
- return -EINVAL;
69
+ * already allocated. So, there is no actual conflict.
47
- }
70
+ */
48
+ if (path_is_absolute(fname)) {
71
+ continue;
49
+ extent_path = g_strdup(fname);
50
+ } else {
51
+ if (!desc_file_dir) {
52
+ desc_file_dir = bdrv_dirname(bs->file->bs, errp);
53
+ if (!desc_file_dir) {
54
+ bdrv_refresh_filename(bs->file->bs);
55
+ error_prepend(errp, "Cannot use relative paths with VMDK "
56
+ "descriptor file '%s': ",
57
+ bs->file->bs->filename);
58
+ ret = -EINVAL;
59
+ goto out;
60
+ }
61
+ }
62
63
- extent_path = path_combine(desc_file_path, fname);
64
+ extent_path = g_strconcat(desc_file_dir, fname, NULL);
65
+ }
72
+ }
66
67
ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents);
68
assert(ret < 32);
69
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
70
g_free(extent_path);
71
if (local_err) {
72
error_propagate(errp, local_err);
73
- return -EINVAL;
74
+ ret = -EINVAL;
75
+ goto out;
76
}
77
78
/* save to extents array */
79
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
80
0, 0, 0, 0, 0, &extent, errp);
81
if (ret < 0) {
82
bdrv_unref_child(bs, extent_file);
83
- return ret;
84
+ goto out;
85
}
86
extent->flat_start_offset = flat_offset << 9;
87
} else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) {
88
@@ -XXX,XX +XXX,XX @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
89
g_free(buf);
90
if (ret) {
91
bdrv_unref_child(bs, extent_file);
92
- return ret;
93
+ goto out;
94
}
95
extent = &s->extents[s->num_extents - 1];
96
} else if (!strcmp(type, "SESPARSE")) {
97
ret = vmdk_open_se_sparse(bs, extent_file, bs->open_flags, errp);
98
if (ret) {
99
bdrv_unref_child(bs, extent_file);
100
- return ret;
101
+ goto out;
102
}
103
extent = &s->extents[s->num_extents - 1];
104
} else {
105
error_setg(errp, "Unsupported extent type '%s'", type);
106
bdrv_unref_child(bs, extent_file);
107
- return -ENOTSUP;
108
+ ret = -ENOTSUP;
109
+ goto out;
110
}
111
extent->type = g_strdup(type);
112
}
113
- return 0;
114
+
73
+
115
+ ret = 0;
74
/* Conflict */
116
+ goto out;
75
117
76
if (start < old_start) {
118
invalid:
77
diff --git a/tests/qemu-iotests/271 b/tests/qemu-iotests/271
119
np = next_line(p);
78
index XXXXXXX..XXXXXXX 100755
120
@@ -XXX,XX +XXX,XX @@ invalid:
79
--- a/tests/qemu-iotests/271
121
np--;
80
+++ b/tests/qemu-iotests/271
122
}
81
@@ -XXX,XX +XXX,XX @@ EOF
123
error_setg(errp, "Invalid extent line: %.*s", (int)(np - p), p);
124
- return -EINVAL;
125
+ ret = -EINVAL;
126
+
127
+out:
128
+ g_free(desc_file_dir);
129
+ return ret;
130
}
82
}
131
83
132
static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
84
_make_test_img -o extended_l2=on 1M
133
@@ -XXX,XX +XXX,XX @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf,
85
-_concurrent_io | $QEMU_IO | _filter_qemu_io
134
}
86
+# Second and third writes in _concurrent_io() are independent and may finish in
135
s->create_type = g_strdup(ct);
87
+# different order. So, filter offset out to match both possible variants.
136
s->desc_offset = 0;
88
+_concurrent_io | $QEMU_IO | _filter_qemu_io | \
137
- ret = vmdk_parse_extents(buf, bs, bs->file->bs->exact_filename, options,
89
+ $SED -e 's/\(20480\|40960\)/OFFSET/'
138
- errp);
90
_concurrent_verify | $QEMU_IO | _filter_qemu_io
139
+ ret = vmdk_parse_extents(buf, bs, options, errp);
91
140
exit:
92
# success, all done
141
return ret;
93
diff --git a/tests/qemu-iotests/271.out b/tests/qemu-iotests/271.out
142
}
143
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
144
index XXXXXXX..XXXXXXX 100755
145
--- a/tests/qemu-iotests/059
146
+++ b/tests/qemu-iotests/059
147
@@ -XXX,XX +XXX,XX @@ $QEMU_IMG convert -f qcow2 -O vmdk -o subformat=streamOptimized "$TEST_IMG.qcow2
148
149
echo
150
echo "=== Testing monolithicFlat with internally generated JSON file name ==="
151
+# Should work, because bdrv_dirname() works fine with blkdebug
152
IMGOPTS="subformat=monolithicFlat" _make_test_img 64M
153
-$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" 2>&1 \
154
- | _filter_testdir | _filter_imgfmt
155
+$QEMU_IO -c "open -o driver=$IMGFMT,file.driver=blkdebug,file.image.filename=$TEST_IMG,file.inject-error.0.event=read_aio" \
156
+ -c info \
157
+ 2>&1 \
158
+ | _filter_testdir | _filter_imgfmt | _filter_img_info
159
_cleanup_test_img
160
161
echo
162
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
163
index XXXXXXX..XXXXXXX 100644
94
index XXXXXXX..XXXXXXX 100644
164
--- a/tests/qemu-iotests/059.out
95
--- a/tests/qemu-iotests/271.out
165
+++ b/tests/qemu-iotests/059.out
96
+++ b/tests/qemu-iotests/271.out
166
@@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 10240
97
@@ -XXX,XX +XXX,XX @@ blkdebug: Suspended request 'A'
167
98
blkdebug: Resuming request 'A'
168
=== Testing monolithicFlat with internally generated JSON file name ===
99
wrote 2048/2048 bytes at offset 30720
169
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
100
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
170
-qemu-io: can't open: Cannot use relative extent paths with VMDK descriptor file 'json:{"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "inject-error.0.event": "read_aio"}'
101
-wrote 2048/2048 bytes at offset 20480
171
+format name: IMGFMT
102
+wrote 2048/2048 bytes at offset OFFSET
172
+cluster size: 0 bytes
103
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
173
+vm state offset: 0 bytes
104
-wrote 2048/2048 bytes at offset 40960
174
105
+wrote 2048/2048 bytes at offset OFFSET
175
=== Testing version 3 ===
106
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
176
image: TEST_DIR/iotest-version3.IMGFMT
107
*** done
177
--
108
--
178
2.21.0
109
2.31.1
179
110
180
111
diff view generated by jsdifflib
New patch
1
We cannot write to images opened with O_DIRECT unless we allow them to
2
be resized so they are aligned to the sector size: Since 9c60a5d1978,
3
bdrv_node_refresh_perm() ensures that for nodes whose length is not
4
aligned to the request alignment and where someone has taken a WRITE
5
permission, the RESIZE permission is taken, too).
1
6
7
Let qemu-img convert pass the BDRV_O_RESIZE flag (which causes
8
blk_new_open() to take the RESIZE permission) when using cache=none for
9
the target, so that when writing to it, it can be aligned to the target
10
sector size.
11
12
Without this patch, an error is returned:
13
14
$ qemu-img convert -f raw -O raw -t none foo.img /mnt/tmp/foo.img
15
qemu-img: Could not open '/mnt/tmp/foo.img': Cannot get 'write'
16
permission without 'resize': Image size is not a multiple of request
17
alignment
18
19
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1994266
20
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
21
Message-Id: <20210819101200.64235-1-hreitz@redhat.com>
22
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
23
---
24
qemu-img.c | 8 ++++++++
25
1 file changed, 8 insertions(+)
26
27
diff --git a/qemu-img.c b/qemu-img.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/qemu-img.c
30
+++ b/qemu-img.c
31
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
32
goto out;
33
}
34
35
+ if (flags & BDRV_O_NOCACHE) {
36
+ /*
37
+ * If we open the target with O_DIRECT, it may be necessary to
38
+ * extend its size to align to the physical sector size.
39
+ */
40
+ flags |= BDRV_O_RESIZE;
41
+ }
42
+
43
if (skip_create) {
44
s.target = img_open(tgt_image_opts, out_filename, out_fmt,
45
flags, writethrough, s.quiet, false);
46
--
47
2.31.1
48
49
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
It is possible to enable only a subset of the block drivers with the
3
- don't use same name for size in bytes and in entries
4
"--block-drv-rw-whitelist" option of the "configure" script. All other
4
- use g_autofree for l2_table
5
drivers are marked as unusable (or only included as read-only with the
5
- add whitespace
6
"--block-drv-ro-whitelist" option). If an iotest is now using such a
6
- fix block comment style
7
disabled block driver, it is failing - which is bad, since at least the
8
tests in the "auto" group should be able to deal with this situation.
9
Thus let's introduce a "_require_drivers" function that can be used by
10
the shell tests to check for the availability of certain drivers first,
11
and marks the test as "not run" if one of the drivers is missing.
12
7
13
This patch mainly targets the test in the "auto" group which should
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
14
never fail in such a case, but also improves some of the other tests
9
Reviewed-by: Eric Blake <eblake@redhat.com>
15
along the way. Note that we also assume that the "qcow2" and "file"
10
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
16
drivers are always available - otherwise it does not make sense to
11
Message-Id: <20210914122454.141075-2-vsementsov@virtuozzo.com>
17
run "make check-block" at all (which only tests with qcow2 by default).
12
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
13
---
14
block/qcow2-refcount.c | 47 +++++++++++++++++++++---------------------
15
1 file changed, 24 insertions(+), 23 deletions(-)
18
16
19
Signed-off-by: Thomas Huth <thuth@redhat.com>
17
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
20
Message-id: 20190823133552.11680-1-thuth@redhat.com
18
index XXXXXXX..XXXXXXX 100644
21
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
--- a/block/qcow2-refcount.c
22
---
20
+++ b/block/qcow2-refcount.c
23
tests/qemu-iotests/071 | 1 +
21
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
24
tests/qemu-iotests/081 | 4 +---
22
int flags, BdrvCheckMode fix, bool active)
25
tests/qemu-iotests/099 | 1 +
26
tests/qemu-iotests/120 | 1 +
27
tests/qemu-iotests/162 | 4 +---
28
tests/qemu-iotests/184 | 1 +
29
tests/qemu-iotests/186 | 1 +
30
tests/qemu-iotests/common.rc | 14 ++++++++++++++
31
8 files changed, 21 insertions(+), 6 deletions(-)
32
33
diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
34
index XXXXXXX..XXXXXXX 100755
35
--- a/tests/qemu-iotests/071
36
+++ b/tests/qemu-iotests/071
37
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
38
39
_supported_fmt qcow2
40
_supported_proto file
41
+_require_drivers blkdebug blkverify
42
43
do_run_qemu()
44
{
23
{
45
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
24
BDRVQcow2State *s = bs->opaque;
46
index XXXXXXX..XXXXXXX 100755
25
- uint64_t *l2_table, l2_entry;
47
--- a/tests/qemu-iotests/081
26
+ uint64_t l2_entry;
48
+++ b/tests/qemu-iotests/081
27
uint64_t next_contiguous_offset = 0;
49
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
28
- int i, l2_size, nb_csectors, ret;
50
_supported_fmt raw
29
+ int i, nb_csectors, ret;
51
_supported_proto file
30
+ size_t l2_size_bytes = s->l2_size * l2_entry_size(s);
52
_supported_os Linux
31
+ g_autofree uint64_t *l2_table = g_malloc(l2_size_bytes);
53
+_require_drivers quorum
32
54
33
/* Read L2 table from disk */
55
do_run_qemu()
34
- l2_size = s->l2_size * l2_entry_size(s);
56
{
35
- l2_table = g_malloc(l2_size);
57
@@ -XXX,XX +XXX,XX @@ run_qemu()
36
-
58
| _filter_qemu_io | _filter_generated_node_ids
37
- ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size);
38
+ ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size_bytes);
39
if (ret < 0) {
40
fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n");
41
res->check_errors++;
42
- goto fail;
43
+ return ret;
44
}
45
46
/* Do the actual checks */
47
- for(i = 0; i < s->l2_size; i++) {
48
+ for (i = 0; i < s->l2_size; i++) {
49
l2_entry = get_l2_entry(s, l2_table, i);
50
51
switch (qcow2_get_cluster_type(bs, l2_entry)) {
52
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
53
l2_entry & QCOW2_COMPRESSED_SECTOR_MASK,
54
nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE);
55
if (ret < 0) {
56
- goto fail;
57
+ return ret;
58
}
59
60
if (flags & CHECK_FRAG_INFO) {
61
res->bfi.allocated_clusters++;
62
res->bfi.compressed_clusters++;
63
64
- /* Compressed clusters are fragmented by nature. Since they
65
+ /*
66
+ * Compressed clusters are fragmented by nature. Since they
67
* take up sub-sector space but we only have sector granularity
68
* I/O we need to re-read the same sectors even for adjacent
69
* compressed clusters.
70
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
71
if (ret < 0) {
72
fprintf(stderr, "ERROR: Overlap check failed\n");
73
res->check_errors++;
74
- /* Something is seriously wrong, so abort checking
75
- * this L2 table */
76
- goto fail;
77
+ /*
78
+ * Something is seriously wrong, so abort checking
79
+ * this L2 table.
80
+ */
81
+ return ret;
82
}
83
84
ret = bdrv_pwrite_sync(bs->file, l2e_offset,
85
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
86
fprintf(stderr, "ERROR: Failed to overwrite L2 "
87
"table entry: %s\n", strerror(-ret));
88
res->check_errors++;
89
- /* Do not abort, continue checking the rest of this
90
- * L2 table's entries */
91
+ /*
92
+ * Do not abort, continue checking the rest of this
93
+ * L2 table's entries.
94
+ */
95
} else {
96
res->corruptions--;
97
res->corruptions_fixed++;
98
- /* Skip marking the cluster as used
99
- * (it is unused now) */
100
+ /*
101
+ * Skip marking the cluster as used
102
+ * (it is unused now).
103
+ */
104
continue;
105
}
106
}
107
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
108
refcount_table_size,
109
offset, s->cluster_size);
110
if (ret < 0) {
111
- goto fail;
112
+ return ret;
113
}
114
}
115
break;
116
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
117
}
118
}
119
120
- g_free(l2_table);
121
return 0;
122
-
123
-fail:
124
- g_free(l2_table);
125
- return ret;
59
}
126
}
60
127
61
-test_quorum=$($QEMU_IMG --help|grep quorum)
128
/*
62
-[ "$test_quorum" = "" ] && _supported_fmt quorum
63
-
64
quorum="driver=raw,file.driver=quorum,file.vote-threshold=2"
65
quorum="$quorum,file.children.0.file.filename=$TEST_DIR/1.raw"
66
quorum="$quorum,file.children.1.file.filename=$TEST_DIR/2.raw"
67
diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099
68
index XXXXXXX..XXXXXXX 100755
69
--- a/tests/qemu-iotests/099
70
+++ b/tests/qemu-iotests/099
71
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
72
_supported_fmt qcow qcow2 qed vdi vhdx vmdk vpc
73
_supported_proto file
74
_supported_os Linux
75
+_require_drivers blkdebug blkverify
76
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
77
"subformat=twoGbMaxExtentSparse"
78
79
diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120
80
index XXXXXXX..XXXXXXX 100755
81
--- a/tests/qemu-iotests/120
82
+++ b/tests/qemu-iotests/120
83
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
84
_supported_fmt generic
85
_supported_proto file
86
_unsupported_fmt luks
87
+_require_drivers raw
88
89
_make_test_img 64M
90
91
diff --git a/tests/qemu-iotests/162 b/tests/qemu-iotests/162
92
index XXXXXXX..XXXXXXX 100755
93
--- a/tests/qemu-iotests/162
94
+++ b/tests/qemu-iotests/162
95
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
96
. ./common.filter
97
98
_supported_fmt generic
99
-
100
-test_ssh=$($QEMU_IMG --help | grep '^Supported formats:.* ssh\( \|$\)')
101
-[ "$test_ssh" = "" ] && _notrun "ssh support required"
102
+_require_drivers ssh
103
104
echo
105
echo '=== NBD ==='
106
diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
107
index XXXXXXX..XXXXXXX 100755
108
--- a/tests/qemu-iotests/184
109
+++ b/tests/qemu-iotests/184
110
@@ -XXX,XX +XXX,XX @@ trap "exit \$status" 0 1 2 3 15
111
. ./common.filter
112
113
_supported_os Linux
114
+_require_drivers throttle
115
116
do_run_qemu()
117
{
118
diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186
119
index XXXXXXX..XXXXXXX 100755
120
--- a/tests/qemu-iotests/186
121
+++ b/tests/qemu-iotests/186
122
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
123
124
_supported_fmt qcow2
125
_supported_proto file
126
+_require_drivers null-co
127
128
if [ "$QEMU_DEFAULT_MACHINE" != "pc" ]; then
129
_notrun "Requires a PC machine"
130
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
131
index XXXXXXX..XXXXXXX 100644
132
--- a/tests/qemu-iotests/common.rc
133
+++ b/tests/qemu-iotests/common.rc
134
@@ -XXX,XX +XXX,XX @@ _require_command()
135
[ -x "$c" ] || _notrun "$1 utility required, skipped this test"
136
}
137
138
+# Check that a set of drivers has been whitelisted in the QEMU binary
139
+#
140
+_require_drivers()
141
+{
142
+ available=$($QEMU -drive format=help | \
143
+ sed -e '/Supported formats:/!d' -e 's/Supported formats://')
144
+ for driver
145
+ do
146
+ if ! echo "$available" | grep -q " $driver\( \|$\)"; then
147
+ _notrun "$driver not available"
148
+ fi
149
+ done
150
+}
151
+
152
# make sure this script returns success
153
true
154
--
129
--
155
2.21.0
130
2.31.1
156
131
157
132
diff view generated by jsdifflib
1
The error message for the test case where we have a quorum node for
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
which no directory name can be generated is different: For
3
twoGbMaxExtentSparse, it complains that it cannot open the extent file.
4
For other (sub)formats, it just notes that it cannot determine the
5
backing file path. Both are fine, but just disable twoGbMaxExtentSparse
6
for simplicity's sake.
7
2
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
Let's pass the whole L2 entry and not bother with
9
Reviewed-by: John Snow <jsnow@redhat.com>
4
L2E_COMPRESSED_OFFSET_SIZE_MASK.
10
Message-id: 20190815153638.4600-7-mreitz@redhat.com
5
11
Reviewed-by: John Snow <jsnow@redhat.com>
6
It also helps further refactoring that adds generic
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
qcow2_parse_compressed_l2_entry() helper.
8
9
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: Alberto Garcia <berto@igalia.com>
12
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
13
Message-Id: <20210914122454.141075-3-vsementsov@virtuozzo.com>
14
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
13
---
15
---
14
tests/qemu-iotests/110 | 3 ++-
16
block/qcow2.h | 1 -
15
1 file changed, 2 insertions(+), 1 deletion(-)
17
block/qcow2-cluster.c | 5 ++---
18
block/qcow2.c | 12 +++++++-----
19
3 files changed, 9 insertions(+), 9 deletions(-)
16
20
17
diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110
21
diff --git a/block/qcow2.h b/block/qcow2.h
18
index XXXXXXX..XXXXXXX 100755
22
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/qemu-iotests/110
23
--- a/block/qcow2.h
20
+++ b/tests/qemu-iotests/110
24
+++ b/block/qcow2.h
21
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
25
@@ -XXX,XX +XXX,XX @@ typedef enum QCow2MetadataOverlap {
22
# Any format supporting backing files
26
23
_supported_fmt qed qcow qcow2 vmdk
27
#define L1E_OFFSET_MASK 0x00fffffffffffe00ULL
24
_supported_proto file
28
#define L2E_OFFSET_MASK 0x00fffffffffffe00ULL
25
-_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
29
-#define L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
26
+_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
30
27
+ "subformat=twoGbMaxExtentSparse"
31
#define REFT_OFFSET_MASK 0xfffffffffffffe00ULL
28
32
29
TEST_IMG_REL=$(basename "$TEST_IMG")
33
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/block/qcow2-cluster.c
36
+++ b/block/qcow2-cluster.c
37
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
38
* offset needs to be aligned to a cluster boundary.
39
*
40
* If the cluster is unallocated then *host_offset will be 0.
41
- * If the cluster is compressed then *host_offset will contain the
42
- * complete compressed cluster descriptor.
43
+ * If the cluster is compressed then *host_offset will contain the l2 entry.
44
*
45
* On entry, *bytes is the maximum number of contiguous bytes starting at
46
* offset that we are interested in.
47
@@ -XXX,XX +XXX,XX @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
48
ret = -EIO;
49
goto fail;
50
}
51
- *host_offset = l2_entry & L2E_COMPRESSED_OFFSET_SIZE_MASK;
52
+ *host_offset = l2_entry;
53
break;
54
case QCOW2_SUBCLUSTER_ZERO_PLAIN:
55
case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
56
diff --git a/block/qcow2.c b/block/qcow2.c
57
index XXXXXXX..XXXXXXX 100644
58
--- a/block/qcow2.c
59
+++ b/block/qcow2.c
60
@@ -XXX,XX +XXX,XX @@ typedef struct {
61
62
static int coroutine_fn
63
qcow2_co_preadv_compressed(BlockDriverState *bs,
64
- uint64_t cluster_descriptor,
65
+ uint64_t l2_entry,
66
uint64_t offset,
67
uint64_t bytes,
68
QEMUIOVector *qiov,
69
@@ -XXX,XX +XXX,XX @@ typedef struct Qcow2AioTask {
70
71
BlockDriverState *bs;
72
QCow2SubclusterType subcluster_type; /* only for read */
73
- uint64_t host_offset; /* or full descriptor in compressed clusters */
74
+ uint64_t host_offset; /* or l2_entry for compressed read */
75
uint64_t offset;
76
uint64_t bytes;
77
QEMUIOVector *qiov;
78
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
79
80
static int coroutine_fn
81
qcow2_co_preadv_compressed(BlockDriverState *bs,
82
- uint64_t cluster_descriptor,
83
+ uint64_t l2_entry,
84
uint64_t offset,
85
uint64_t bytes,
86
QEMUIOVector *qiov,
87
@@ -XXX,XX +XXX,XX @@ qcow2_co_preadv_compressed(BlockDriverState *bs,
88
uint8_t *buf, *out_buf;
89
int offset_in_cluster = offset_into_cluster(s, offset);
90
91
- coffset = cluster_descriptor & s->cluster_offset_mask;
92
- nb_csectors = ((cluster_descriptor >> s->csize_shift) & s->csize_mask) + 1;
93
+ assert(qcow2_get_cluster_type(bs, l2_entry) == QCOW2_CLUSTER_COMPRESSED);
94
+
95
+ coffset = l2_entry & s->cluster_offset_mask;
96
+ nb_csectors = ((l2_entry >> s->csize_shift) & s->csize_mask) + 1;
97
csize = nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE -
98
(coffset & ~QCOW2_COMPRESSED_SECTOR_MASK);
30
99
31
--
100
--
32
2.21.0
101
2.31.1
33
102
34
103
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Add helper to parse compressed l2_entry and use it everywhere instead
4
of open-coding.
5
6
Note, that in most places we move to precise coffset/csize instead of
7
sector-aligned. Still it should work good enough for updating
8
refcounts.
9
10
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
12
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
13
Message-Id: <20210914122454.141075-4-vsementsov@virtuozzo.com>
14
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
15
---
16
block/qcow2.h | 3 ++-
17
block/qcow2-cluster.c | 15 +++++++++++++++
18
block/qcow2-refcount.c | 36 +++++++++++++++++-------------------
19
block/qcow2.c | 9 ++-------
20
4 files changed, 36 insertions(+), 27 deletions(-)
21
22
diff --git a/block/qcow2.h b/block/qcow2.h
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2.h
25
+++ b/block/qcow2.h
26
@@ -XXX,XX +XXX,XX @@
27
28
/* Defined in the qcow2 spec (compressed cluster descriptor) */
29
#define QCOW2_COMPRESSED_SECTOR_SIZE 512U
30
-#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1ULL))
31
32
/* Must be at least 2 to cover COW */
33
#define MIN_L2_CACHE_SIZE 2 /* cache entries */
34
@@ -XXX,XX +XXX,XX @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
35
uint64_t offset,
36
int compressed_size,
37
uint64_t *host_offset);
38
+void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
39
+ uint64_t *coffset, int *csize);
40
41
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
42
void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
43
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/block/qcow2-cluster.c
46
+++ b/block/qcow2-cluster.c
47
@@ -XXX,XX +XXX,XX @@ fail:
48
g_free(l1_table);
49
return ret;
50
}
51
+
52
+void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
53
+ uint64_t *coffset, int *csize)
54
+{
55
+ BDRVQcow2State *s = bs->opaque;
56
+ int nb_csectors;
57
+
58
+ assert(qcow2_get_cluster_type(bs, l2_entry) == QCOW2_CLUSTER_COMPRESSED);
59
+
60
+ *coffset = l2_entry & s->cluster_offset_mask;
61
+
62
+ nb_csectors = ((l2_entry >> s->csize_shift) & s->csize_mask) + 1;
63
+ *csize = nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE -
64
+ (*coffset & (QCOW2_COMPRESSED_SECTOR_SIZE - 1));
65
+}
66
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
67
index XXXXXXX..XXXXXXX 100644
68
--- a/block/qcow2-refcount.c
69
+++ b/block/qcow2-refcount.c
70
@@ -XXX,XX +XXX,XX @@ void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry,
71
switch (ctype) {
72
case QCOW2_CLUSTER_COMPRESSED:
73
{
74
- int64_t offset = (l2_entry & s->cluster_offset_mask)
75
- & QCOW2_COMPRESSED_SECTOR_MASK;
76
- int size = QCOW2_COMPRESSED_SECTOR_SIZE *
77
- (((l2_entry >> s->csize_shift) & s->csize_mask) + 1);
78
- qcow2_free_clusters(bs, offset, size, type);
79
+ uint64_t coffset;
80
+ int csize;
81
+
82
+ qcow2_parse_compressed_l2_entry(bs, l2_entry, &coffset, &csize);
83
+ qcow2_free_clusters(bs, coffset, csize, type);
84
}
85
break;
86
case QCOW2_CLUSTER_NORMAL:
87
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
88
bool l1_allocated = false;
89
int64_t old_entry, old_l2_offset;
90
unsigned slice, slice_size2, n_slices;
91
- int i, j, l1_modified = 0, nb_csectors;
92
+ int i, j, l1_modified = 0;
93
int ret;
94
95
assert(addend >= -1 && addend <= 1);
96
@@ -XXX,XX +XXX,XX @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
97
98
switch (qcow2_get_cluster_type(bs, entry)) {
99
case QCOW2_CLUSTER_COMPRESSED:
100
- nb_csectors = ((entry >> s->csize_shift) &
101
- s->csize_mask) + 1;
102
if (addend != 0) {
103
- uint64_t coffset = (entry & s->cluster_offset_mask)
104
- & QCOW2_COMPRESSED_SECTOR_MASK;
105
+ uint64_t coffset;
106
+ int csize;
107
+
108
+ qcow2_parse_compressed_l2_entry(bs, entry,
109
+ &coffset, &csize);
110
ret = update_refcount(
111
- bs, coffset,
112
- nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE,
113
+ bs, coffset, csize,
114
abs(addend), addend < 0,
115
QCOW2_DISCARD_SNAPSHOT);
116
if (ret < 0) {
117
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
118
BDRVQcow2State *s = bs->opaque;
119
uint64_t l2_entry;
120
uint64_t next_contiguous_offset = 0;
121
- int i, nb_csectors, ret;
122
+ int i, ret;
123
size_t l2_size_bytes = s->l2_size * l2_entry_size(s);
124
g_autofree uint64_t *l2_table = g_malloc(l2_size_bytes);
125
126
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
127
128
/* Do the actual checks */
129
for (i = 0; i < s->l2_size; i++) {
130
+ uint64_t coffset;
131
+ int csize;
132
l2_entry = get_l2_entry(s, l2_table, i);
133
134
switch (qcow2_get_cluster_type(bs, l2_entry)) {
135
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
136
}
137
138
/* Mark cluster as used */
139
- nb_csectors = ((l2_entry >> s->csize_shift) &
140
- s->csize_mask) + 1;
141
- l2_entry &= s->cluster_offset_mask;
142
+ qcow2_parse_compressed_l2_entry(bs, l2_entry, &coffset, &csize);
143
ret = qcow2_inc_refcounts_imrt(
144
- bs, res, refcount_table, refcount_table_size,
145
- l2_entry & QCOW2_COMPRESSED_SECTOR_MASK,
146
- nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE);
147
+ bs, res, refcount_table, refcount_table_size, coffset, csize);
148
if (ret < 0) {
149
return ret;
150
}
151
diff --git a/block/qcow2.c b/block/qcow2.c
152
index XXXXXXX..XXXXXXX 100644
153
--- a/block/qcow2.c
154
+++ b/block/qcow2.c
155
@@ -XXX,XX +XXX,XX @@ qcow2_co_preadv_compressed(BlockDriverState *bs,
156
size_t qiov_offset)
157
{
158
BDRVQcow2State *s = bs->opaque;
159
- int ret = 0, csize, nb_csectors;
160
+ int ret = 0, csize;
161
uint64_t coffset;
162
uint8_t *buf, *out_buf;
163
int offset_in_cluster = offset_into_cluster(s, offset);
164
165
- assert(qcow2_get_cluster_type(bs, l2_entry) == QCOW2_CLUSTER_COMPRESSED);
166
-
167
- coffset = l2_entry & s->cluster_offset_mask;
168
- nb_csectors = ((l2_entry >> s->csize_shift) & s->csize_mask) + 1;
169
- csize = nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE -
170
- (coffset & ~QCOW2_COMPRESSED_SECTOR_MASK);
171
+ qcow2_parse_compressed_l2_entry(bs, l2_entry, &coffset, &csize);
172
173
buf = g_try_malloc(csize);
174
if (!buf) {
175
--
176
2.31.1
177
178
diff view generated by jsdifflib
1
From: Denis Plotnikov <dplotnikov@virtuozzo.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
The patch allows to provide a pattern file for write
3
Split fix_l2_entry_by_zero() out of check_refcounts_l2() to be
4
command. There was no similar ability before.
4
reused in further patch.
5
5
6
Signed-off-by: Denis Plotnikov <dplotnikov@virtuozzo.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Message-id: 20190820164616.4072-1-dplotnikov@virtuozzo.com
8
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Eric Blake <eblake@redhat.com>
9
[mreitz: Keep optstring in alphabetical order]
8
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
9
Message-Id: <20210914122454.141075-5-vsementsov@virtuozzo.com>
10
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
11
---
11
---
12
qemu-io-cmds.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++---
12
block/qcow2-refcount.c | 87 +++++++++++++++++++++++++++++-------------
13
1 file changed, 93 insertions(+), 6 deletions(-)
13
1 file changed, 60 insertions(+), 27 deletions(-)
14
14
15
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
15
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
16
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
17
--- a/qemu-io-cmds.c
17
--- a/block/qcow2-refcount.c
18
+++ b/qemu-io-cmds.c
18
+++ b/block/qcow2-refcount.c
19
@@ -XXX,XX +XXX,XX @@ static void qemu_io_free(void *p)
19
@@ -XXX,XX +XXX,XX @@ enum {
20
qemu_vfree(p);
20
CHECK_FRAG_INFO = 0x2, /* update BlockFragInfo counters */
21
}
21
};
22
22
23
+/*
23
+/*
24
+ * qemu_io_alloc_from_file()
24
+ * Fix L2 entry by making it QCOW2_CLUSTER_ZERO_PLAIN.
25
+ *
25
+ *
26
+ * Allocates the buffer and populates it with the content of the given file
26
+ * This function decrements res->corruptions on success, so the caller is
27
+ * up to @len bytes. If the file length is less than @len, then the buffer
27
+ * responsible to increment res->corruptions prior to the call.
28
+ * is populated with the file content cyclically.
29
+ *
28
+ *
30
+ * @blk - the block backend where the buffer content is going to be written to
29
+ * On failure in-memory @l2_table may be modified.
31
+ * @len - the buffer length
32
+ * @file_name - the file to read the content from
33
+ *
34
+ * Returns: the buffer pointer on success
35
+ * NULL on error
36
+ */
30
+ */
37
+static void *qemu_io_alloc_from_file(BlockBackend *blk, size_t len,
31
+static int fix_l2_entry_by_zero(BlockDriverState *bs, BdrvCheckResult *res,
38
+ const char *file_name)
32
+ uint64_t l2_offset,
33
+ uint64_t *l2_table, int l2_index, bool active,
34
+ bool *metadata_overlap)
39
+{
35
+{
40
+ char *buf, *buf_origin;
36
+ BDRVQcow2State *s = bs->opaque;
41
+ FILE *f = fopen(file_name, "r");
37
+ int ret;
42
+ int pattern_len;
38
+ int idx = l2_index * (l2_entry_size(s) / sizeof(uint64_t));
39
+ uint64_t l2e_offset = l2_offset + (uint64_t)l2_index * l2_entry_size(s);
40
+ int ign = active ? QCOW2_OL_ACTIVE_L2 : QCOW2_OL_INACTIVE_L2;
41
+ uint64_t l2_entry = has_subclusters(s) ? 0 : QCOW_OFLAG_ZERO;
43
+
42
+
44
+ if (!f) {
43
+ set_l2_entry(s, l2_table, l2_index, l2_entry);
45
+ perror(file_name);
44
+ ret = qcow2_pre_write_overlap_check(bs, ign, l2e_offset, l2_entry_size(s),
46
+ return NULL;
45
+ false);
46
+ if (metadata_overlap) {
47
+ *metadata_overlap = ret < 0;
48
+ }
49
+ if (ret < 0) {
50
+ fprintf(stderr, "ERROR: Overlap check failed\n");
51
+ goto fail;
47
+ }
52
+ }
48
+
53
+
49
+ if (qemuio_misalign) {
54
+ ret = bdrv_pwrite_sync(bs->file, l2e_offset, &l2_table[idx],
50
+ len += MISALIGN_OFFSET;
55
+ l2_entry_size(s));
56
+ if (ret < 0) {
57
+ fprintf(stderr, "ERROR: Failed to overwrite L2 "
58
+ "table entry: %s\n", strerror(-ret));
59
+ goto fail;
51
+ }
60
+ }
52
+
61
+
53
+ buf_origin = buf = blk_blockalign(blk, len);
62
+ res->corruptions--;
63
+ res->corruptions_fixed++;
64
+ return 0;
54
+
65
+
55
+ if (qemuio_misalign) {
66
+fail:
56
+ buf_origin += MISALIGN_OFFSET;
67
+ res->check_errors++;
57
+ buf += MISALIGN_OFFSET;
68
+ return ret;
58
+ len -= MISALIGN_OFFSET;
59
+ }
60
+
61
+ pattern_len = fread(buf_origin, 1, len, f);
62
+
63
+ if (ferror(f)) {
64
+ perror(file_name);
65
+ goto error;
66
+ }
67
+
68
+ if (pattern_len == 0) {
69
+ fprintf(stderr, "%s: file is empty\n", file_name);
70
+ goto error;
71
+ }
72
+
73
+ fclose(f);
74
+
75
+ if (len > pattern_len) {
76
+ len -= pattern_len;
77
+ buf += pattern_len;
78
+
79
+ while (len > 0) {
80
+ size_t len_to_copy = MIN(pattern_len, len);
81
+
82
+ memcpy(buf, buf_origin, len_to_copy);
83
+
84
+ len -= len_to_copy;
85
+ buf += len_to_copy;
86
+ }
87
+ }
88
+
89
+ return buf_origin;
90
+
91
+error:
92
+ qemu_io_free(buf_origin);
93
+ return NULL;
94
+}
69
+}
95
+
70
+
96
static void dump_buffer(const void *buffer, int64_t offset, int64_t len)
71
/*
97
{
72
* Increases the refcount in the given refcount table for the all clusters
98
uint64_t i;
73
* referenced in the L2 table. While doing so, performs some checks on L2
99
@@ -XXX,XX +XXX,XX @@ static void write_help(void)
74
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
100
" -n, -- with -z, don't allow slow fallback\n"
75
int i, ret;
101
" -p, -- ignored for backwards compatibility\n"
76
size_t l2_size_bytes = s->l2_size * l2_entry_size(s);
102
" -P, -- use different pattern to fill file\n"
77
g_autofree uint64_t *l2_table = g_malloc(l2_size_bytes);
103
+" -s, -- use a pattern file to fill the write buffer\n"
78
+ bool metadata_overlap;
104
" -C, -- report statistics in a machine parsable format\n"
79
105
" -q, -- quiet mode, do not show I/O statistics\n"
80
/* Read L2 table from disk */
106
" -u, -- with -z, allow unmapping\n"
81
ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size_bytes);
107
@@ -XXX,XX +XXX,XX @@ static const cmdinfo_t write_cmd = {
82
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
108
.perm = BLK_PERM_WRITE,
83
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR",
109
.argmin = 2,
84
offset);
110
.argmax = -1,
85
if (fix & BDRV_FIX_ERRORS) {
111
- .args = "[-bcCfnquz] [-P pattern] off len",
86
- int idx = i * (l2_entry_size(s) / sizeof(uint64_t));
112
+ .args = "[-bcCfnquz] [-P pattern | -s source_file] off len",
87
- uint64_t l2e_offset =
113
.oneline = "writes a number of bytes at a specified offset",
88
- l2_offset + (uint64_t)i * l2_entry_size(s);
114
.help = write_help,
89
- int ign = active ? QCOW2_OL_ACTIVE_L2 :
115
};
90
- QCOW2_OL_INACTIVE_L2;
116
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
91
-
117
{
92
- l2_entry = has_subclusters(s) ? 0 : QCOW_OFLAG_ZERO;
118
struct timespec t1, t2;
93
- set_l2_entry(s, l2_table, i, l2_entry);
119
bool Cflag = false, qflag = false, bflag = false;
94
- ret = qcow2_pre_write_overlap_check(bs, ign,
120
- bool Pflag = false, zflag = false, cflag = false;
95
- l2e_offset, l2_entry_size(s), false);
121
+ bool Pflag = false, zflag = false, cflag = false, sflag = false;
96
- if (ret < 0) {
122
int flags = 0;
97
- fprintf(stderr, "ERROR: Overlap check failed\n");
123
int c, cnt, ret;
98
- res->check_errors++;
124
char *buf = NULL;
99
+ ret = fix_l2_entry_by_zero(bs, res, l2_offset,
125
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
100
+ l2_table, i, active,
126
/* Some compilers get confused and warn if this is not initialized. */
101
+ &metadata_overlap);
127
int64_t total = 0;
102
+ if (metadata_overlap) {
128
int pattern = 0xcd;
103
/*
129
+ const char *file_name = NULL;
104
* Something is seriously wrong, so abort checking
130
105
* this L2 table.
131
- while ((c = getopt(argc, argv, "bcCfnpP:quz")) != -1) {
106
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
132
+ while ((c = getopt(argc, argv, "bcCfnpP:qs:uz")) != -1) {
107
return ret;
133
switch (c) {
108
}
134
case 'b':
109
135
bflag = true;
110
- ret = bdrv_pwrite_sync(bs->file, l2e_offset,
136
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
111
- &l2_table[idx],
137
case 'q':
112
- l2_entry_size(s));
138
qflag = true;
113
- if (ret < 0) {
139
break;
114
- fprintf(stderr, "ERROR: Failed to overwrite L2 "
140
+ case 's':
115
- "table entry: %s\n", strerror(-ret));
141
+ sflag = true;
116
- res->check_errors++;
142
+ file_name = optarg;
117
- /*
143
+ break;
118
- * Do not abort, continue checking the rest of this
144
case 'u':
119
- * L2 table's entries.
145
flags |= BDRV_REQ_MAY_UNMAP;
120
- */
146
break;
121
- } else {
147
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
122
- res->corruptions--;
148
return -EINVAL;
123
- res->corruptions_fixed++;
149
}
124
+ if (ret == 0) {
150
125
/*
151
- if (zflag && Pflag) {
126
* Skip marking the cluster as used
152
- printf("-z and -P cannot be specified at the same time\n");
127
* (it is unused now).
153
+ if (zflag + Pflag + sflag > 1) {
128
*/
154
+ printf("Only one of -z, -P, and -s "
129
continue;
155
+ "can be specified at the same time\n");
130
}
156
return -EINVAL;
131
+
157
}
132
+ /*
158
133
+ * Failed to fix.
159
@@ -XXX,XX +XXX,XX @@ static int write_f(BlockBackend *blk, int argc, char **argv)
134
+ * Do not abort, continue checking the rest of this
160
}
135
+ * L2 table's entries.
161
136
+ */
162
if (!zflag) {
137
}
163
- buf = qemu_io_alloc(blk, count, pattern);
138
} else {
164
+ if (sflag) {
139
fprintf(stderr, "ERROR offset=%" PRIx64 ": Data cluster is "
165
+ buf = qemu_io_alloc_from_file(blk, count, file_name);
166
+ if (!buf) {
167
+ return -EINVAL;
168
+ }
169
+ } else {
170
+ buf = qemu_io_alloc(blk, count, pattern);
171
+ }
172
}
173
174
clock_gettime(CLOCK_MONOTONIC, &t1);
175
--
140
--
176
2.21.0
141
2.31.1
177
142
178
143
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
We'll reuse the function to fix wrong L2 entry bitmap. Support it now.
4
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
8
Message-Id: <20210914122454.141075-6-vsementsov@virtuozzo.com>
9
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
10
---
11
block/qcow2-refcount.c | 18 +++++++++++++++---
12
1 file changed, 15 insertions(+), 3 deletions(-)
13
14
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/qcow2-refcount.c
17
+++ b/block/qcow2-refcount.c
18
@@ -XXX,XX +XXX,XX @@ enum {
19
};
20
21
/*
22
- * Fix L2 entry by making it QCOW2_CLUSTER_ZERO_PLAIN.
23
+ * Fix L2 entry by making it QCOW2_CLUSTER_ZERO_PLAIN (or making all its present
24
+ * subclusters QCOW2_SUBCLUSTER_ZERO_PLAIN).
25
*
26
* This function decrements res->corruptions on success, so the caller is
27
* responsible to increment res->corruptions prior to the call.
28
@@ -XXX,XX +XXX,XX @@ static int fix_l2_entry_by_zero(BlockDriverState *bs, BdrvCheckResult *res,
29
int idx = l2_index * (l2_entry_size(s) / sizeof(uint64_t));
30
uint64_t l2e_offset = l2_offset + (uint64_t)l2_index * l2_entry_size(s);
31
int ign = active ? QCOW2_OL_ACTIVE_L2 : QCOW2_OL_INACTIVE_L2;
32
- uint64_t l2_entry = has_subclusters(s) ? 0 : QCOW_OFLAG_ZERO;
33
34
- set_l2_entry(s, l2_table, l2_index, l2_entry);
35
+ if (has_subclusters(s)) {
36
+ uint64_t l2_bitmap = get_l2_bitmap(s, l2_table, l2_index);
37
+
38
+ /* Allocated subclusters become zero */
39
+ l2_bitmap |= l2_bitmap << 32;
40
+ l2_bitmap &= QCOW_L2_BITMAP_ALL_ZEROES;
41
+
42
+ set_l2_bitmap(s, l2_table, l2_index, l2_bitmap);
43
+ set_l2_entry(s, l2_table, l2_index, 0);
44
+ } else {
45
+ set_l2_entry(s, l2_table, l2_index, QCOW_OFLAG_ZERO);
46
+ }
47
+
48
ret = qcow2_pre_write_overlap_check(bs, ign, l2e_offset, l2_entry_size(s),
49
false);
50
if (metadata_overlap) {
51
--
52
2.31.1
53
54
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
The sanitizers (especially the address sanitizer from Clang) are
3
Check subcluster bitmap of the l2 entry for different types of
4
sometimes printing out warnings or false positives - this spoils
4
clusters:
5
the output of the iotests, causing some of the tests to fail.
6
Thus let's skip the automatic iotests during "make check" when the
7
user configured QEMU with --enable-sanitizers.
8
5
9
Signed-off-by: Thomas Huth <thuth@redhat.com>
6
- for compressed it must be zero
10
Message-id: 20190823084203.29734-1-thuth@redhat.com
7
- for allocated check consistency of two parts of the bitmap
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
- for unallocated all subclusters should be unallocated
9
(or zero-plain)
10
11
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Tested-by: Kirill Tkhai <ktkhai@virtuozzo.com>
13
Message-Id: <20210914122454.141075-7-vsementsov@virtuozzo.com>
14
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
16
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
12
---
17
---
13
tests/check-block.sh | 5 +++++
18
block/qcow2-refcount.c | 28 ++++++++++++++++++++++++++--
14
1 file changed, 5 insertions(+)
19
1 file changed, 26 insertions(+), 2 deletions(-)
15
20
16
diff --git a/tests/check-block.sh b/tests/check-block.sh
21
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
17
index XXXXXXX..XXXXXXX 100755
22
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/check-block.sh
23
--- a/block/qcow2-refcount.c
19
+++ b/tests/check-block.sh
24
+++ b/block/qcow2-refcount.c
20
@@ -XXX,XX +XXX,XX @@ if grep -q "TARGET_GPROF=y" *-softmmu/config-target.mak 2>/dev/null ; then
25
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
21
exit 0
26
int flags, BdrvCheckMode fix, bool active)
22
fi
27
{
23
28
BDRVQcow2State *s = bs->opaque;
24
+if grep -q "CFLAGS.*-fsanitize" config-host.mak 2>/dev/null ; then
29
- uint64_t l2_entry;
25
+ echo "Sanitizers are enabled ==> Not running the qemu-iotests."
30
+ uint64_t l2_entry, l2_bitmap;
26
+ exit 0
31
uint64_t next_contiguous_offset = 0;
27
+fi
32
int i, ret;
33
size_t l2_size_bytes = s->l2_size * l2_entry_size(s);
34
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
35
uint64_t coffset;
36
int csize;
37
l2_entry = get_l2_entry(s, l2_table, i);
38
+ l2_bitmap = get_l2_bitmap(s, l2_table, i);
39
40
switch (qcow2_get_cluster_type(bs, l2_entry)) {
41
case QCOW2_CLUSTER_COMPRESSED:
42
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
43
break;
44
}
45
46
+ if (l2_bitmap) {
47
+ fprintf(stderr, "ERROR compressed cluster %d with non-zero "
48
+ "subcluster allocation bitmap, entry=0x%" PRIx64 "\n",
49
+ i, l2_entry);
50
+ res->corruptions++;
51
+ break;
52
+ }
28
+
53
+
29
if [ -z "$(find . -name 'qemu-system-*' -print)" ]; then
54
/* Mark cluster as used */
30
echo "No qemu-system binary available ==> Not running the qemu-iotests."
55
qcow2_parse_compressed_l2_entry(bs, l2_entry, &coffset, &csize);
31
exit 0
56
ret = qcow2_inc_refcounts_imrt(
57
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
58
{
59
uint64_t offset = l2_entry & L2E_OFFSET_MASK;
60
61
+ if ((l2_bitmap >> 32) & l2_bitmap) {
62
+ res->corruptions++;
63
+ fprintf(stderr, "ERROR offset=%" PRIx64 ": Allocated "
64
+ "cluster has corrupted subcluster allocation bitmap\n",
65
+ offset);
66
+ }
67
+
68
/* Correct offsets are cluster aligned */
69
if (offset_into_cluster(s, offset)) {
70
bool contains_data;
71
res->corruptions++;
72
73
if (has_subclusters(s)) {
74
- uint64_t l2_bitmap = get_l2_bitmap(s, l2_table, i);
75
contains_data = (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC);
76
} else {
77
contains_data = !(l2_entry & QCOW_OFLAG_ZERO);
78
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
79
}
80
81
case QCOW2_CLUSTER_ZERO_PLAIN:
82
+ /* Impossible when image has subclusters */
83
+ assert(!l2_bitmap);
84
+ break;
85
+
86
case QCOW2_CLUSTER_UNALLOCATED:
87
+ if (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC) {
88
+ res->corruptions++;
89
+ fprintf(stderr, "ERROR: Unallocated "
90
+ "cluster has non-zero subcluster allocation map\n");
91
+ }
92
break;
93
94
default:
32
--
95
--
33
2.21.0
96
2.31.1
34
97
35
98
diff view generated by jsdifflib
1
iotest 126 requires backing file support, which flat vmdks cannot offer.
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
Skip this test for such subformats.
3
2
4
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
Message-id: 20190815153638.4600-8-mreitz@redhat.com
4
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: John Snow <jsnow@redhat.com>
5
Tested-by: Kirill Tkhai <ktkhai@virtuozzo.com>
7
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
7
Message-Id: <20210914122454.141075-8-vsementsov@virtuozzo.com>
8
[hreitz: Separated `type` declaration from statements]
9
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
8
---
10
---
9
tests/qemu-iotests/126 | 2 ++
11
block/qcow2.h | 1 +
10
1 file changed, 2 insertions(+)
12
block/qcow2-refcount.c | 14 +++++++++++++-
13
2 files changed, 14 insertions(+), 1 deletion(-)
11
14
12
diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126
15
diff --git a/block/qcow2.h b/block/qcow2.h
13
index XXXXXXX..XXXXXXX 100755
16
index XXXXXXX..XXXXXXX 100644
14
--- a/tests/qemu-iotests/126
17
--- a/block/qcow2.h
15
+++ b/tests/qemu-iotests/126
18
+++ b/block/qcow2.h
16
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
19
@@ -XXX,XX +XXX,XX @@ typedef enum QCow2MetadataOverlap {
17
20
18
# Needs backing file support
21
#define L1E_OFFSET_MASK 0x00fffffffffffe00ULL
19
_supported_fmt qcow qcow2 qed vmdk
22
#define L2E_OFFSET_MASK 0x00fffffffffffe00ULL
20
+_unsupported_imgopts "subformat=monolithicFlat" \
23
+#define L2E_STD_RESERVED_MASK 0x3f000000000001feULL
21
+ "subformat=twoGbMaxExtentFlat"
24
22
# This is the default protocol (and we want to test the difference between
25
#define REFT_OFFSET_MASK 0xfffffffffffffe00ULL
23
# colons which separate a protocol prefix from the rest and colons which are
26
24
# just part of the filename, so we cannot test protocols which require a prefix)
27
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/block/qcow2-refcount.c
30
+++ b/block/qcow2-refcount.c
31
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
32
for (i = 0; i < s->l2_size; i++) {
33
uint64_t coffset;
34
int csize;
35
+ QCow2ClusterType type;
36
+
37
l2_entry = get_l2_entry(s, l2_table, i);
38
l2_bitmap = get_l2_bitmap(s, l2_table, i);
39
+ type = qcow2_get_cluster_type(bs, l2_entry);
40
+
41
+ if (type != QCOW2_CLUSTER_COMPRESSED) {
42
+ /* Check reserved bits of Standard Cluster Descriptor */
43
+ if (l2_entry & L2E_STD_RESERVED_MASK) {
44
+ fprintf(stderr, "ERROR found l2 entry with reserved bits set: "
45
+ "%" PRIx64 "\n", l2_entry);
46
+ res->corruptions++;
47
+ }
48
+ }
49
50
- switch (qcow2_get_cluster_type(bs, l2_entry)) {
51
+ switch (type) {
52
case QCOW2_CLUSTER_COMPRESSED:
53
/* Compressed clusters don't have QCOW_OFLAG_COPIED */
54
if (l2_entry & QCOW_OFLAG_COPIED) {
25
--
55
--
26
2.21.0
56
2.31.1
27
57
28
58
diff view generated by jsdifflib
1
From: Nir Soffer <nirsof@gmail.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Using block_resize we can test allocate_first_block() with file
3
- use g_autofree for l1_table
4
descriptor opened with O_DIRECT, ensuring that it works for any size
4
- better name for size in bytes variable
5
larger than 4096 bytes.
5
- reduce code blocks nesting
6
- whitespaces, braces, newlines
6
7
7
Testing smaller sizes is tricky as the result depends on the filesystem
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
used for testing. For example on NFS any size will work since O_DIRECT
9
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
9
does not require any alignment.
10
Message-Id: <20210914122454.141075-9-vsementsov@virtuozzo.com>
11
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
12
---
13
block/qcow2-refcount.c | 98 +++++++++++++++++++++---------------------
14
1 file changed, 50 insertions(+), 48 deletions(-)
10
15
11
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
16
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
12
Reviewed-by: Max Reitz <mreitz@redhat.com>
17
index XXXXXXX..XXXXXXX 100644
13
Message-id: 20190827010528.8818-3-nsoffer@redhat.com
18
--- a/block/qcow2-refcount.c
14
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
+++ b/block/qcow2-refcount.c
15
---
20
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l1(BlockDriverState *bs,
16
tests/qemu-iotests/175 | 28 ++++++++++++++++++++++++++++
21
int flags, BdrvCheckMode fix, bool active)
17
tests/qemu-iotests/175.out | 8 ++++++++
22
{
18
2 files changed, 36 insertions(+)
23
BDRVQcow2State *s = bs->opaque;
19
24
- uint64_t *l1_table = NULL, l2_offset, l1_size2;
20
diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175
25
+ size_t l1_size_bytes = l1_size * L1E_SIZE;
21
index XXXXXXX..XXXXXXX 100755
26
+ g_autofree uint64_t *l1_table = NULL;
22
--- a/tests/qemu-iotests/175
27
+ uint64_t l2_offset;
23
+++ b/tests/qemu-iotests/175
28
int i, ret;
24
@@ -XXX,XX +XXX,XX @@ _filter_blocks()
29
25
-e "s/blocks=$((extra_blocks + img_size / 512))\\(\$\\|[^0-9]\\)/max allocation/"
30
- l1_size2 = l1_size * L1E_SIZE;
31
+ if (!l1_size) {
32
+ return 0;
33
+ }
34
35
/* Mark L1 table as used */
36
ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size,
37
- l1_table_offset, l1_size2);
38
+ l1_table_offset, l1_size_bytes);
39
if (ret < 0) {
40
- goto fail;
41
+ return ret;
42
+ }
43
+
44
+ l1_table = g_try_malloc(l1_size_bytes);
45
+ if (l1_table == NULL) {
46
+ res->check_errors++;
47
+ return -ENOMEM;
48
}
49
50
/* Read L1 table entries from disk */
51
- if (l1_size2 > 0) {
52
- l1_table = g_try_malloc(l1_size2);
53
- if (l1_table == NULL) {
54
- ret = -ENOMEM;
55
- res->check_errors++;
56
- goto fail;
57
- }
58
- ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
59
- if (ret < 0) {
60
- fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
61
- res->check_errors++;
62
- goto fail;
63
- }
64
- for(i = 0;i < l1_size; i++)
65
- be64_to_cpus(&l1_table[i]);
66
+ ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size_bytes);
67
+ if (ret < 0) {
68
+ fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
69
+ res->check_errors++;
70
+ return ret;
71
+ }
72
+
73
+ for (i = 0; i < l1_size; i++) {
74
+ be64_to_cpus(&l1_table[i]);
75
}
76
77
/* Do the actual checks */
78
- for(i = 0; i < l1_size; i++) {
79
- l2_offset = l1_table[i];
80
- if (l2_offset) {
81
- /* Mark L2 table as used */
82
- l2_offset &= L1E_OFFSET_MASK;
83
- ret = qcow2_inc_refcounts_imrt(bs, res,
84
- refcount_table, refcount_table_size,
85
- l2_offset, s->cluster_size);
86
- if (ret < 0) {
87
- goto fail;
88
- }
89
+ for (i = 0; i < l1_size; i++) {
90
+ if (!l1_table[i]) {
91
+ continue;
92
+ }
93
94
- /* L2 tables are cluster aligned */
95
- if (offset_into_cluster(s, l2_offset)) {
96
- fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not "
97
- "cluster aligned; L1 entry corrupted\n", l2_offset);
98
- res->corruptions++;
99
- }
100
+ l2_offset = l1_table[i] & L1E_OFFSET_MASK;
101
102
- /* Process and check L2 entries */
103
- ret = check_refcounts_l2(bs, res, refcount_table,
104
- refcount_table_size, l2_offset, flags,
105
- fix, active);
106
- if (ret < 0) {
107
- goto fail;
108
- }
109
+ /* Mark L2 table as used */
110
+ ret = qcow2_inc_refcounts_imrt(bs, res,
111
+ refcount_table, refcount_table_size,
112
+ l2_offset, s->cluster_size);
113
+ if (ret < 0) {
114
+ return ret;
115
+ }
116
+
117
+ /* L2 tables are cluster aligned */
118
+ if (offset_into_cluster(s, l2_offset)) {
119
+ fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not "
120
+ "cluster aligned; L1 entry corrupted\n", l2_offset);
121
+ res->corruptions++;
122
+ }
123
+
124
+ /* Process and check L2 entries */
125
+ ret = check_refcounts_l2(bs, res, refcount_table,
126
+ refcount_table_size, l2_offset, flags,
127
+ fix, active);
128
+ if (ret < 0) {
129
+ return ret;
130
}
131
}
132
- g_free(l1_table);
133
- return 0;
134
135
-fail:
136
- g_free(l1_table);
137
- return ret;
138
+ return 0;
26
}
139
}
27
140
28
+# Resize image using block_resize.
141
/*
29
+# Parameter 1: image path
30
+# Parameter 2: new size
31
+_block_resize()
32
+{
33
+ local path=$1
34
+ local size=$2
35
+
36
+ $QEMU -qmp stdio -nographic -nodefaults \
37
+ -blockdev file,node-name=file,filename=$path,cache.direct=on \
38
+ <<EOF
39
+{'execute': 'qmp_capabilities'}
40
+{'execute': 'block_resize', 'arguments': {'node-name': 'file', 'size': $size}}
41
+{'execute': 'quit'}
42
+EOF
43
+}
44
+
45
# get standard environment, filters and checks
46
. ./common.rc
47
. ./common.filter
48
@@ -XXX,XX +XXX,XX @@ _supported_fmt raw
49
_supported_proto file
50
_supported_os Linux
51
52
+_default_cache_mode none
53
+_supported_cache_modes none directsync
54
+
55
size=$((1 * 1024 * 1024))
56
57
touch "$TEST_DIR/empty"
58
@@ -XXX,XX +XXX,XX @@ for mode in off full falloc; do
59
stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $size
60
done
61
62
+for new_size in 4096 1048576; do
63
+ echo
64
+ echo "== resize empty image with block_resize =="
65
+ _make_test_img 0 | _filter_imgfmt
66
+ _block_resize $TEST_IMG $new_size >/dev/null
67
+ stat -c "size=%s, blocks=%b" $TEST_IMG | _filter_blocks $extra_blocks $min_blocks $new_size
68
+done
69
+
70
# success, all done
71
echo "*** done"
72
rm -f $seq.full
73
diff --git a/tests/qemu-iotests/175.out b/tests/qemu-iotests/175.out
74
index XXXXXXX..XXXXXXX 100644
75
--- a/tests/qemu-iotests/175.out
76
+++ b/tests/qemu-iotests/175.out
77
@@ -XXX,XX +XXX,XX @@ size=1048576, max allocation
78
== creating image with preallocation falloc ==
79
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 preallocation=falloc
80
size=1048576, max allocation
81
+
82
+== resize empty image with block_resize ==
83
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
84
+size=4096, min allocation
85
+
86
+== resize empty image with block_resize ==
87
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=0
88
+size=1048576, min allocation
89
*** done
90
--
142
--
91
2.21.0
143
2.31.1
92
144
93
145
diff view generated by jsdifflib
1
streamOptimized does not support writes that do not span exactly one
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
cluster. Furthermore, it cannot rewrite already allocated clusters.
3
As such, many iotests do not work with it. Disable them.
4
2
5
Signed-off-by: Max Reitz <mreitz@redhat.com>
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Message-id: 20190815153638.4600-6-mreitz@redhat.com
4
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Reviewed-by: John Snow <jsnow@redhat.com>
5
Tested-by: Kirill Tkhai <ktkhai@virtuozzo.com>
8
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
7
Message-Id: <20210914122454.141075-10-vsementsov@virtuozzo.com>
8
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
9
---
9
---
10
tests/qemu-iotests/002 | 1 +
10
block/qcow2.h | 1 +
11
tests/qemu-iotests/003 | 1 +
11
block/qcow2-refcount.c | 6 ++++++
12
tests/qemu-iotests/005 | 3 ++-
12
2 files changed, 7 insertions(+)
13
tests/qemu-iotests/009 | 1 +
14
tests/qemu-iotests/010 | 1 +
15
tests/qemu-iotests/011 | 1 +
16
tests/qemu-iotests/017 | 3 ++-
17
tests/qemu-iotests/018 | 3 ++-
18
tests/qemu-iotests/019 | 3 ++-
19
tests/qemu-iotests/020 | 3 ++-
20
tests/qemu-iotests/027 | 1 +
21
tests/qemu-iotests/032 | 1 +
22
tests/qemu-iotests/033 | 1 +
23
tests/qemu-iotests/034 | 3 ++-
24
tests/qemu-iotests/037 | 3 ++-
25
tests/qemu-iotests/063 | 3 ++-
26
tests/qemu-iotests/072 | 1 +
27
tests/qemu-iotests/105 | 3 ++-
28
tests/qemu-iotests/197 | 1 +
29
tests/qemu-iotests/215 | 1 +
30
tests/qemu-iotests/251 | 1 +
31
21 files changed, 30 insertions(+), 9 deletions(-)
32
13
33
diff --git a/tests/qemu-iotests/002 b/tests/qemu-iotests/002
14
diff --git a/block/qcow2.h b/block/qcow2.h
34
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
35
--- a/tests/qemu-iotests/002
16
--- a/block/qcow2.h
36
+++ b/tests/qemu-iotests/002
17
+++ b/block/qcow2.h
37
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
18
@@ -XXX,XX +XXX,XX @@ typedef enum QCow2MetadataOverlap {
38
19
(QCOW2_OL_CACHED | QCOW2_OL_INACTIVE_L2)
39
_supported_fmt generic
20
40
_supported_proto generic
21
#define L1E_OFFSET_MASK 0x00fffffffffffe00ULL
41
+_unsupported_imgopts "subformat=streamOptimized"
22
+#define L1E_RESERVED_MASK 0x7f000000000001ffULL
42
23
#define L2E_OFFSET_MASK 0x00fffffffffffe00ULL
43
24
#define L2E_STD_RESERVED_MASK 0x3f000000000001feULL
44
size=128M
25
45
diff --git a/tests/qemu-iotests/003 b/tests/qemu-iotests/003
26
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
46
index XXXXXXX..XXXXXXX 100755
27
index XXXXXXX..XXXXXXX 100644
47
--- a/tests/qemu-iotests/003
28
--- a/block/qcow2-refcount.c
48
+++ b/tests/qemu-iotests/003
29
+++ b/block/qcow2-refcount.c
49
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
30
@@ -XXX,XX +XXX,XX @@ static int check_refcounts_l1(BlockDriverState *bs,
50
31
continue;
51
_supported_fmt generic
32
}
52
_supported_proto generic
33
53
+_unsupported_imgopts "subformat=streamOptimized"
34
+ if (l1_table[i] & L1E_RESERVED_MASK) {
54
35
+ fprintf(stderr, "ERROR found L1 entry with reserved bits set: "
55
size=128M
36
+ "%" PRIx64 "\n", l1_table[i]);
56
offset=67M
37
+ res->corruptions++;
57
diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005
38
+ }
58
index XXXXXXX..XXXXXXX 100755
39
+
59
--- a/tests/qemu-iotests/005
40
l2_offset = l1_table[i] & L1E_OFFSET_MASK;
60
+++ b/tests/qemu-iotests/005
41
61
@@ -XXX,XX +XXX,XX @@ _supported_fmt generic
42
/* Mark L2 table as used */
62
_supported_proto generic
63
_supported_os Linux
64
_unsupported_imgopts "subformat=twoGbMaxExtentFlat" \
65
- "subformat=twoGbMaxExtentSparse"
66
+ "subformat=twoGbMaxExtentSparse" \
67
+ "subformat=streamOptimized"
68
69
# vpc is limited to 127GB, so we can't test it here
70
if [ "$IMGFMT" = "vpc" ]; then
71
diff --git a/tests/qemu-iotests/009 b/tests/qemu-iotests/009
72
index XXXXXXX..XXXXXXX 100755
73
--- a/tests/qemu-iotests/009
74
+++ b/tests/qemu-iotests/009
75
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
76
77
_supported_fmt generic
78
_supported_proto generic
79
+_unsupported_imgopts "subformat=streamOptimized"
80
81
82
size=6G
83
diff --git a/tests/qemu-iotests/010 b/tests/qemu-iotests/010
84
index XXXXXXX..XXXXXXX 100755
85
--- a/tests/qemu-iotests/010
86
+++ b/tests/qemu-iotests/010
87
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
88
89
_supported_fmt generic
90
_supported_proto generic
91
+_unsupported_imgopts "subformat=streamOptimized"
92
93
94
size=6G
95
diff --git a/tests/qemu-iotests/011 b/tests/qemu-iotests/011
96
index XXXXXXX..XXXXXXX 100755
97
--- a/tests/qemu-iotests/011
98
+++ b/tests/qemu-iotests/011
99
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
100
101
_supported_fmt generic
102
_supported_proto generic
103
+_unsupported_imgopts "subformat=streamOptimized"
104
105
106
size=6G
107
diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017
108
index XXXXXXX..XXXXXXX 100755
109
--- a/tests/qemu-iotests/017
110
+++ b/tests/qemu-iotests/017
111
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
112
_supported_fmt qcow qcow2 vmdk qed
113
_supported_proto generic
114
_unsupported_proto vxhs
115
-_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
116
+_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
117
+ "subformat=streamOptimized"
118
119
TEST_OFFSETS="0 4294967296"
120
121
diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018
122
index XXXXXXX..XXXXXXX 100755
123
--- a/tests/qemu-iotests/018
124
+++ b/tests/qemu-iotests/018
125
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
126
_supported_fmt qcow qcow2 vmdk qed
127
_supported_proto file
128
_supported_os Linux
129
-_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
130
+_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat" \
131
+ "streamOptimized"
132
133
TEST_OFFSETS="0 4294967296"
134
135
diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019
136
index XXXXXXX..XXXXXXX 100755
137
--- a/tests/qemu-iotests/019
138
+++ b/tests/qemu-iotests/019
139
@@ -XXX,XX +XXX,XX @@ _supported_proto file
140
_supported_os Linux
141
_unsupported_imgopts "subformat=monolithicFlat" \
142
"subformat=twoGbMaxExtentFlat" \
143
- "subformat=twoGbMaxExtentSparse"
144
+ "subformat=twoGbMaxExtentSparse" \
145
+ "subformat=streamOptimized"
146
147
TEST_OFFSETS="0 4294967296"
148
CLUSTER_SIZE=65536
149
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
150
index XXXXXXX..XXXXXXX 100755
151
--- a/tests/qemu-iotests/020
152
+++ b/tests/qemu-iotests/020
153
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow qcow2 vmdk qed
154
_supported_proto file
155
_unsupported_imgopts "subformat=monolithicFlat" \
156
"subformat=twoGbMaxExtentFlat" \
157
- "subformat=twoGbMaxExtentSparse"
158
+ "subformat=twoGbMaxExtentSparse" \
159
+ "subformat=streamOptimized"
160
161
TEST_OFFSETS="0 4294967296"
162
163
diff --git a/tests/qemu-iotests/027 b/tests/qemu-iotests/027
164
index XXXXXXX..XXXXXXX 100755
165
--- a/tests/qemu-iotests/027
166
+++ b/tests/qemu-iotests/027
167
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
168
169
_supported_fmt vmdk qcow qcow2 qed
170
_supported_proto generic
171
+_unsupported_imgopts "subformat=streamOptimized"
172
173
174
size=128M
175
diff --git a/tests/qemu-iotests/032 b/tests/qemu-iotests/032
176
index XXXXXXX..XXXXXXX 100755
177
--- a/tests/qemu-iotests/032
178
+++ b/tests/qemu-iotests/032
179
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
180
# This works for any image format (though unlikely to segfault for raw)
181
_supported_fmt generic
182
_supported_proto generic
183
+_unsupported_imgopts "subformat=streamOptimized"
184
185
echo
186
echo === Prepare image ===
187
diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033
188
index XXXXXXX..XXXXXXX 100755
189
--- a/tests/qemu-iotests/033
190
+++ b/tests/qemu-iotests/033
191
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
192
193
_supported_fmt generic
194
_supported_proto generic
195
+_unsupported_imgopts "subformat=streamOptimized"
196
197
198
size=128M
199
diff --git a/tests/qemu-iotests/034 b/tests/qemu-iotests/034
200
index XXXXXXX..XXXXXXX 100755
201
--- a/tests/qemu-iotests/034
202
+++ b/tests/qemu-iotests/034
203
@@ -XXX,XX +XXX,XX @@ _supported_proto file
204
_supported_os Linux
205
_unsupported_imgopts "subformat=monolithicFlat" \
206
"subformat=twoGbMaxExtentFlat" \
207
- "subformat=twoGbMaxExtentSparse"
208
+ "subformat=twoGbMaxExtentSparse" \
209
+ "subformat=streamOptimized"
210
211
CLUSTER_SIZE=4k
212
size=128M
213
diff --git a/tests/qemu-iotests/037 b/tests/qemu-iotests/037
214
index XXXXXXX..XXXXXXX 100755
215
--- a/tests/qemu-iotests/037
216
+++ b/tests/qemu-iotests/037
217
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow qcow2 vmdk qed
218
_supported_proto file
219
_unsupported_imgopts "subformat=monolithicFlat" \
220
"subformat=twoGbMaxExtentFlat" \
221
- "subformat=twoGbMaxExtentSparse"
222
+ "subformat=twoGbMaxExtentSparse" \
223
+ "subformat=streamOptimized"
224
225
CLUSTER_SIZE=4k
226
size=128M
227
diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063
228
index XXXXXXX..XXXXXXX 100755
229
--- a/tests/qemu-iotests/063
230
+++ b/tests/qemu-iotests/063
231
@@ -XXX,XX +XXX,XX @@ _supported_fmt qcow qcow2 vmdk qed raw
232
_supported_proto file
233
_unsupported_imgopts "subformat=monolithicFlat" \
234
"subformat=twoGbMaxExtentFlat" \
235
- "subformat=twoGbMaxExtentSparse"
236
+ "subformat=twoGbMaxExtentSparse" \
237
+ "subformat=streamOptimized"
238
239
_make_test_img 4M
240
241
diff --git a/tests/qemu-iotests/072 b/tests/qemu-iotests/072
242
index XXXXXXX..XXXXXXX 100755
243
--- a/tests/qemu-iotests/072
244
+++ b/tests/qemu-iotests/072
245
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
246
247
_supported_fmt vpc vmdk vhdx vdi qed qcow2 qcow
248
_supported_proto file
249
+_unsupported_imgopts "subformat=streamOptimized"
250
251
IMG_SIZE=64M
252
253
diff --git a/tests/qemu-iotests/105 b/tests/qemu-iotests/105
254
index XXXXXXX..XXXXXXX 100755
255
--- a/tests/qemu-iotests/105
256
+++ b/tests/qemu-iotests/105
257
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
258
_supported_fmt qcow2 vmdk vhdx qed
259
_supported_proto generic
260
_unsupported_imgopts "subformat=twoGbMaxExtentFlat" \
261
- "subformat=twoGbMaxExtentSparse"
262
+ "subformat=twoGbMaxExtentSparse" \
263
+ "subformat=streamOptimized"
264
265
echo
266
echo "creating large image"
267
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
268
index XXXXXXX..XXXXXXX 100755
269
--- a/tests/qemu-iotests/197
270
+++ b/tests/qemu-iotests/197
271
@@ -XXX,XX +XXX,XX @@ _supported_fmt generic
272
_supported_proto generic
273
# LUKS support may be possible, but it complicates things.
274
_unsupported_fmt luks
275
+_unsupported_imgopts "subformat=streamOptimized"
276
277
echo
278
echo '=== Copy-on-read ==='
279
diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215
280
index XXXXXXX..XXXXXXX 100755
281
--- a/tests/qemu-iotests/215
282
+++ b/tests/qemu-iotests/215
283
@@ -XXX,XX +XXX,XX @@ _supported_fmt generic
284
_supported_proto generic
285
# LUKS support may be possible, but it complicates things.
286
_unsupported_fmt luks
287
+_unsupported_imgopts "subformat=streamOptimized"
288
289
echo
290
echo '=== Copy-on-read ==='
291
diff --git a/tests/qemu-iotests/251 b/tests/qemu-iotests/251
292
index XXXXXXX..XXXXXXX 100755
293
--- a/tests/qemu-iotests/251
294
+++ b/tests/qemu-iotests/251
295
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
296
_supported_fmt generic
297
_supported_proto file
298
_supported_os Linux
299
+_unsupported_imgopts "subformat=streamOptimized"
300
301
if [ "$IMGOPTSSYNTAX" = "true" ]; then
302
# We use json:{} filenames here, so we cannot work with additional options.
303
--
43
--
304
2.21.0
44
2.31.1
305
45
306
46
diff view generated by jsdifflib
1
Compressed writes generally have to write full clusters, not just in
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
theory but also in practice when it comes to vmdk's streamOptimized
3
subformat. It currently is just silently broken for writes with
4
non-zero in-cluster offsets:
5
2
6
$ qemu-img create -f vmdk -o subformat=streamOptimized foo.vmdk 1M
3
Split checking for reserved bits out of aligned offset check.
7
$ qemu-io -c 'write 4k 4k' -c 'read 4k 4k' foo.vmdk
8
wrote 4096/4096 bytes at offset 4096
9
4 KiB, 1 ops; 00.01 sec (443.724 KiB/sec and 110.9309 ops/sec)
10
read failed: Invalid argument
11
4
12
(The technical reason is that vmdk_write_extent() just writes the
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
13
incomplete compressed data actually to offset 4k. When reading the
6
Reviewed-by: Eric Blake <eblake@redhat.com>
14
data, vmdk_read_extent() looks at offset 0 and finds the compressed data
7
Tested-by: Kirill Tkhai <ktkhai@virtuozzo.com>
15
size to be 0, because that is what it reads from there. This yields an
8
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
16
error.)
9
Message-Id: <20210914122454.141075-11-vsementsov@virtuozzo.com>
10
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
11
---
12
block/qcow2.h | 1 +
13
block/qcow2-refcount.c | 10 +++++++++-
14
2 files changed, 10 insertions(+), 1 deletion(-)
17
15
18
For incomplete writes with zero in-cluster offsets, the error path when
16
diff --git a/block/qcow2.h b/block/qcow2.h
19
reading the rest of the cluster is a bit different, but the result is
20
the same:
21
22
$ qemu-img create -f vmdk -o subformat=streamOptimized foo.vmdk 1M
23
$ qemu-io -c 'write 0k 4k' -c 'read 4k 4k' foo.vmdk
24
wrote 4096/4096 bytes at offset 0
25
4 KiB, 1 ops; 00.01 sec (362.641 KiB/sec and 90.6603 ops/sec)
26
read failed: Invalid argument
27
28
(Here, vmdk_read_extent() finds the data and then sees that the
29
uncompressed data is short.)
30
31
It is better to reject invalid writes than to make the user believe they
32
might have succeeded and then fail when trying to read it back.
33
34
Signed-off-by: Max Reitz <mreitz@redhat.com>
35
Reviewed-by: John Snow <jsnow@redhat.com>
36
Message-id: 20190815153638.4600-5-mreitz@redhat.com
37
Reviewed-by: John Snow <jsnow@redhat.com>
38
Signed-off-by: Max Reitz <mreitz@redhat.com>
39
---
40
block/vmdk.c | 10 ++++++++++
41
1 file changed, 10 insertions(+)
42
43
diff --git a/block/vmdk.c b/block/vmdk.c
44
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
45
--- a/block/vmdk.c
18
--- a/block/qcow2.h
46
+++ b/block/vmdk.c
19
+++ b/block/qcow2.h
47
@@ -XXX,XX +XXX,XX @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
20
@@ -XXX,XX +XXX,XX @@ typedef enum QCow2MetadataOverlap {
48
if (extent->compressed) {
21
#define L2E_STD_RESERVED_MASK 0x3f000000000001feULL
49
void *compressed_data;
22
50
23
#define REFT_OFFSET_MASK 0xfffffffffffffe00ULL
51
+ /* Only whole clusters */
24
+#define REFT_RESERVED_MASK 0x1ffULL
52
+ if (offset_in_cluster ||
25
53
+ n_bytes > (extent->cluster_sectors * SECTOR_SIZE) ||
26
#define INV_OFFSET (-1ULL)
54
+ (n_bytes < (extent->cluster_sectors * SECTOR_SIZE) &&
27
55
+ offset + n_bytes != extent->end_sector * SECTOR_SIZE))
28
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
56
+ {
29
index XXXXXXX..XXXXXXX 100644
57
+ ret = -EINVAL;
30
--- a/block/qcow2-refcount.c
58
+ goto out;
31
+++ b/block/qcow2-refcount.c
32
@@ -XXX,XX +XXX,XX @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
33
34
for(i = 0; i < s->refcount_table_size; i++) {
35
uint64_t offset, cluster;
36
- offset = s->refcount_table[i];
37
+ offset = s->refcount_table[i] & REFT_OFFSET_MASK;
38
cluster = offset >> s->cluster_bits;
39
40
+ if (s->refcount_table[i] & REFT_RESERVED_MASK) {
41
+ fprintf(stderr, "ERROR refcount table entry %" PRId64 " has "
42
+ "reserved bits set\n", i);
43
+ res->corruptions++;
44
+ *rebuild = true;
45
+ continue;
59
+ }
46
+ }
60
+
47
+
61
if (!extent->has_marker) {
48
/* Refcount blocks are cluster aligned */
62
ret = -EINVAL;
49
if (offset_into_cluster(s, offset)) {
63
goto out;
50
fprintf(stderr, "ERROR refcount block %" PRId64 " is not "
64
--
51
--
65
2.21.0
52
2.31.1
66
53
67
54
diff view generated by jsdifflib
1
fe646693acc changed qemu-img create's output so that it no longer prints
1
From: Eric Blake <eblake@redhat.com>
2
single quotes around parameter values. The subformat and adapter_type
3
filters in _filter_img_create() have never been adapted to that change.
4
2
5
Fixes: fe646693acc13ac48b98435d14149ab04dc597bc
3
Although we have long supported 'qemu-img convert -o
6
Signed-off-by: Max Reitz <mreitz@redhat.com>
4
backing_file=foo,backing_fmt=bar', the fact that we have a shortcut -B
7
Reviewed-by: John Snow <jsnow@redhat.com>
5
for backing_file but none for backing_fmt has made it more likely that
8
Message-id: 20190815153638.4600-2-mreitz@redhat.com
6
users accidentally run into:
9
Reviewed-by: John Snow <jsnow@redhat.com>
7
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
qemu-img: warning: Deprecated use of backing file without explicit backing format
9
10
when using -B instead of -o. For similarity with other qemu-img
11
commands, such as create and compare, add '-F $fmt' as the shorthand
12
for '-o backing_fmt=$fmt'. Update iotest 122 for coverage of both
13
spellings.
14
15
Signed-off-by: Eric Blake <eblake@redhat.com>
16
Message-Id: <20210913131735.1948339-1-eblake@redhat.com>
17
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
18
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
19
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
11
---
20
---
12
tests/qemu-iotests/059.out | 16 ++++++++--------
21
docs/tools/qemu-img.rst | 4 ++--
13
tests/qemu-iotests/common.filter | 4 ++--
22
qemu-img.c | 10 +++++++---
14
2 files changed, 10 insertions(+), 10 deletions(-)
23
qemu-img-cmds.hx | 2 +-
24
tests/qemu-iotests/122 | 2 +-
25
4 files changed, 11 insertions(+), 7 deletions(-)
15
26
16
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
27
diff --git a/docs/tools/qemu-img.rst b/docs/tools/qemu-img.rst
17
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/qemu-iotests/059.out
29
--- a/docs/tools/qemu-img.rst
19
+++ b/tests/qemu-iotests/059.out
30
+++ b/docs/tools/qemu-img.rst
20
@@ -XXX,XX +XXX,XX @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
31
@@ -XXX,XX +XXX,XX @@ Command description:
21
qemu-io: can't open device TEST_DIR/t.vmdk: L1 size too big
32
4
22
33
Error on reading data
23
=== Testing monolithicFlat creation and opening ===
34
24
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 subformat=monolithicFlat
35
-.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps [--skip-broken-bitmaps]] [-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] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
25
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
36
+.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps [--skip-broken-bitmaps]] [-U] [-C] [-c] [-p] [-q] [-n] [-f FMT] [-t CACHE] [-T SRC_CACHE] [-O OUTPUT_FMT] [-B BACKING_FILE [-F backing_fmt]] [-o OPTIONS] [-l SNAPSHOT_PARAM] [-S SPARSE_SIZE] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
26
image: TEST_DIR/t.IMGFMT
37
27
file format: IMGFMT
38
Convert the disk image *FILENAME* or a snapshot *SNAPSHOT_PARAM*
28
virtual size: 2 GiB (2147483648 bytes)
39
to disk image *OUTPUT_FILENAME* using format *OUTPUT_FMT*. It can
29
40
@@ -XXX,XX +XXX,XX @@ Command description:
30
=== Testing monolithicFlat with zeroed_grain ===
41
You can use the *BACKING_FILE* option to force the output image to be
31
qemu-img: TEST_DIR/t.IMGFMT: Flat image can't enable zeroed grain
42
created as a copy on write image of the specified base image; the
32
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 subformat=monolithicFlat
43
*BACKING_FILE* should have the same content as the input's base image,
33
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
44
- however the path, image format, etc may differ.
34
45
+ however the path, image format (as given by *BACKING_FMT*), etc may differ.
35
=== Testing big twoGbMaxExtentFlat ===
46
36
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 subformat=twoGbMaxExtentFlat
47
If a relative path name is given, the backing file is looked up relative to
37
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000
48
the directory containing *OUTPUT_FILENAME*.
38
image: TEST_DIR/t.vmdk
49
diff --git a/qemu-img.c b/qemu-img.c
39
file format: vmdk
40
virtual size: 0.977 TiB (1073741824000 bytes)
41
@@ -XXX,XX +XXX,XX @@ Format specific information:
42
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Invalid extent line: RW 12582912 VMFS "dummy.IMGFMT" 1
43
44
=== Testing truncated sparse ===
45
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 subformat=monolithicSparse
46
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400
47
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': File truncated, expecting at least 13172736 bytes
48
49
=== Converting to streamOptimized from image with small cluster size===
50
@@ -XXX,XX +XXX,XX @@ wrote 512/512 bytes at offset 10240
51
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
52
53
=== Testing monolithicFlat with internally generated JSON file name ===
54
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 subformat=monolithicFlat
55
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
56
qemu-io: can't open: Cannot use relative extent paths with VMDK descriptor file 'json:{"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "inject-error.0.event": "read_aio"}'
57
58
=== Testing version 3 ===
59
@@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 64931328
60
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
61
62
=== Testing 4TB monolithicFlat creation and IO ===
63
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4398046511104 subformat=monolithicFlat
64
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4398046511104
65
image: TEST_DIR/t.IMGFMT
66
file format: IMGFMT
67
virtual size: 4 TiB (4398046511104 bytes)
68
@@ -XXX,XX +XXX,XX @@ read 1024/1024 bytes at offset 966367641600
69
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
70
71
=== Testing qemu-img map on extents ===
72
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544 subformat=monolithicSparse
73
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544
74
wrote 1024/1024 bytes at offset 65024
75
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
76
wrote 1024/1024 bytes at offset 2147483136
77
@@ -XXX,XX +XXX,XX @@ Offset Length Mapped to File
78
0 0x20000 0x3f0000 TEST_DIR/t.vmdk
79
0x7fff0000 0x20000 0x410000 TEST_DIR/t.vmdk
80
0x140000000 0x10000 0x430000 TEST_DIR/t.vmdk
81
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544 subformat=twoGbMaxExtentSparse
82
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33285996544
83
wrote 1024/1024 bytes at offset 65024
84
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
85
wrote 1024/1024 bytes at offset 2147483136
86
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
87
index XXXXXXX..XXXXXXX 100644
50
index XXXXXXX..XXXXXXX 100644
88
--- a/tests/qemu-iotests/common.filter
51
--- a/qemu-img.c
89
+++ b/tests/qemu-iotests/common.filter
52
+++ b/qemu-img.c
90
@@ -XXX,XX +XXX,XX @@ _filter_img_create()
53
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
91
-e "s# compat6=\\(on\\|off\\)##g" \
54
int c, bs_i, flags, src_flags = BDRV_O_NO_SHARE;
92
-e "s# static=\\(on\\|off\\)##g" \
55
const char *fmt = NULL, *out_fmt = NULL, *cache = "unsafe",
93
-e "s# zeroed_grain=\\(on\\|off\\)##g" \
56
*src_cache = BDRV_DEFAULT_CACHE, *out_baseimg = NULL,
94
- -e "s# subformat='[^']*'##g" \
57
- *out_filename, *out_baseimg_param, *snapshot_name = NULL;
95
- -e "s# adapter_type='[^']*'##g" \
58
+ *out_filename, *out_baseimg_param, *snapshot_name = NULL,
96
+ -e "s# subformat=[^ ]*##g" \
59
+ *backing_fmt = NULL;
97
+ -e "s# adapter_type=[^ ]*##g" \
60
BlockDriver *drv = NULL, *proto_drv = NULL;
98
-e "s# hwversion=[^ ]*##g" \
61
BlockDriverInfo bdi;
99
-e "s# lazy_refcounts=\\(on\\|off\\)##g" \
62
BlockDriverState *out_bs;
100
-e "s# block_size=[0-9]\\+##g" \
63
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
64
{"skip-broken-bitmaps", no_argument, 0, OPTION_SKIP_BROKEN},
65
{0, 0, 0, 0}
66
};
67
- c = getopt_long(argc, argv, ":hf:O:B:Cco:l:S:pt:T:qnm:WUr:",
68
+ c = getopt_long(argc, argv, ":hf:O:B:CcF:o:l:S:pt:T:qnm:WUr:",
69
long_options, NULL);
70
if (c == -1) {
71
break;
72
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
73
case 'c':
74
s.compressed = true;
75
break;
76
+ case 'F':
77
+ backing_fmt = optarg;
78
+ break;
79
case 'o':
80
if (accumulate_options(&options, optarg) < 0) {
81
goto fail_getopt;
82
@@ -XXX,XX +XXX,XX @@ static int img_convert(int argc, char **argv)
83
84
qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
85
s.total_sectors * BDRV_SECTOR_SIZE, &error_abort);
86
- ret = add_old_style_options(out_fmt, opts, out_baseimg, NULL);
87
+ ret = add_old_style_options(out_fmt, opts, out_baseimg, backing_fmt);
88
if (ret < 0) {
89
goto out;
90
}
91
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
92
index XXXXXXX..XXXXXXX 100644
93
--- a/qemu-img-cmds.hx
94
+++ b/qemu-img-cmds.hx
95
@@ -XXX,XX +XXX,XX @@ SRST
96
ERST
97
98
DEF("convert", img_convert,
99
- "convert [--object objectdef] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-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] [-r rate_limit] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename")
100
+ "convert [--object objectdef] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-U] [-C] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file [-F backing_fmt]] [-o options] [-l snapshot_param] [-S sparse_size] [-r rate_limit] [-m num_coroutines] [-W] [--salvage] filename [filename2 [...]] output_filename")
101
SRST
102
.. option:: convert [--object OBJECTDEF] [--image-opts] [--target-image-opts] [--target-is-zero] [--bitmaps] [-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] [-r RATE_LIMIT] [-m NUM_COROUTINES] [-W] [--salvage] FILENAME [FILENAME2 [...]] OUTPUT_FILENAME
103
ERST
104
diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122
105
index XXXXXXX..XXXXXXX 100755
106
--- a/tests/qemu-iotests/122
107
+++ b/tests/qemu-iotests/122
108
@@ -XXX,XX +XXX,XX @@ echo
109
_make_test_img -b "$TEST_IMG".base -F $IMGFMT
110
111
$QEMU_IO -c "write -P 0 0 3M" "$TEST_IMG" 2>&1 | _filter_qemu_io | _filter_testdir
112
-$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \
113
+$QEMU_IMG convert -O $IMGFMT -B "$TEST_IMG".base -F $IMGFMT \
114
"$TEST_IMG" "$TEST_IMG".orig
115
$QEMU_IO -c "read -P 0 0 3M" "$TEST_IMG".orig 2>&1 | _filter_qemu_io | _filter_testdir
116
$QEMU_IMG convert -O $IMGFMT -c -B "$TEST_IMG".base -o backing_fmt=$IMGFMT \
101
--
117
--
102
2.21.0
118
2.31.1
103
119
104
120
diff view generated by jsdifflib